@@ -16,6 +16,7 @@ import (
1616 "fmt"
1717 "math/big"
1818 "os"
19+ "strings"
1920
2021 "github.com/pkg/errors"
2122 "go.step.sm/crypto/internal/utils"
@@ -277,6 +278,60 @@ func ParseCertificateRequest(pemData []byte) (*x509.CertificateRequest, error) {
277278 return nil , errors .New ("error parsing certificate request: no certificate found" )
278279}
279280
281+ // PEMType represents a PEM block type. (e.g., CERTIFICATE, CERTIFICATE REQUEST, etc.)
282+ type PEMType int
283+
284+ func (pt PEMType ) String () string {
285+ switch pt {
286+ case PEMTypeCertificate :
287+ return "certificate"
288+ case PEMTypeCertificateRequest :
289+ return "certificate request"
290+ default :
291+ return "undefined"
292+ }
293+ }
294+
295+ const (
296+ // PEMTypeUndefined undefined
297+ PEMTypeUndefined = iota
298+ // PEMTypeCertificate CERTIFICATE
299+ PEMTypeCertificate
300+ // PEMTypeCertificateRequest CERTIFICATE REQUEST
301+ PEMTypeCertificateRequest
302+ )
303+
304+ // InvalidPEMError represents an error that occurs when parsing a file with
305+ // PEM encoded data.
306+ type InvalidPEMError struct {
307+ Type PEMType
308+ File string
309+ Message string
310+ Err error
311+ }
312+
313+ func (e * InvalidPEMError ) Error () string {
314+ switch {
315+ case e .Message != "" :
316+ return e .Message
317+ case e .Err != nil :
318+ return fmt .Sprintf ("error decoding PEM data: %v" , e .Err )
319+ default :
320+ var prefix = "input"
321+ if e .File != "" {
322+ prefix = fmt .Sprintf ("file %s" , e .File )
323+ }
324+ if e .Type == PEMTypeUndefined {
325+ return fmt .Sprintf ("%s does not contain valid PEM encoded data" , prefix )
326+ }
327+ return fmt .Sprintf ("%s does not contain a valid PEM encoded %s" , prefix , e .Type )
328+ }
329+ }
330+
331+ func (e * InvalidPEMError ) Unwrap () error {
332+ return e .Err
333+ }
334+
280335// ReadCertificate returns a *x509.Certificate from the given filename. It
281336// supports certificates formats PEM and DER.
282337func ReadCertificate (filename string , opts ... Options ) (* x509.Certificate , error ) {
@@ -328,7 +383,7 @@ func ReadCertificateBundle(filename string) ([]*x509.Certificate, error) {
328383 bundle = append (bundle , crt )
329384 }
330385 if len (bundle ) == 0 {
331- return nil , errors . Errorf ( "file %s does not contain a valid PEM formatted certificate" , filename )
386+ return nil , & InvalidPEMError { File : filename , Type : PEMTypeCertificate }
332387 }
333388 return bundle , nil
334389 }
@@ -351,15 +406,25 @@ func ReadCertificateRequest(filename string) (*x509.CertificateRequest, error) {
351406
352407 // PEM format
353408 if bytes .Contains (b , PEMBlockHeader ) {
354- csr , err := Parse (b , WithFilename (filename ))
355- if err != nil {
356- return nil , err
357- }
358- switch csr := csr .(type ) {
359- case * x509.CertificateRequest :
409+ var block * pem.Block
410+ for len (b ) > 0 {
411+ block , b = pem .Decode (b )
412+ if block == nil {
413+ break
414+ }
415+ if ! strings .HasSuffix (block .Type , "CERTIFICATE REQUEST" ) {
416+ continue
417+ }
418+ csr , err := x509 .ParseCertificateRequest (block .Bytes )
419+ if err != nil {
420+ return nil , & InvalidPEMError {
421+ File : filename , Type : PEMTypeCertificateRequest ,
422+ Message : fmt .Sprintf ("error parsing %s: CSR PEM block is invalid: %v" , filename , err ),
423+ Err : err ,
424+ }
425+ }
426+
360427 return csr , nil
361- default :
362- return nil , errors .Errorf ("error decoding PEM: file '%s' does not contain a certificate request" , filename )
363428 }
364429 }
365430
0 commit comments