Skip to content

Commit 3b99965

Browse files
authored
Split ReadCertificate functions into parsing files and bytes (#546)
* Update ParseCertificateRequest and ParseCertificateBundle - Call ParseXXX functions from ReadXXX functions.
1 parent 3993a06 commit 3b99965

File tree

2 files changed

+228
-180
lines changed

2 files changed

+228
-180
lines changed

pemutil/pem.go

Lines changed: 95 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -231,52 +231,93 @@ func ParseCertificate(pemData []byte) (*x509.Certificate, error) {
231231
return nil, errors.New("error parsing certificate: no certificate found")
232232
}
233233

234-
// ParseCertificateBundle extracts all the certificates in the given data.
235-
func ParseCertificateBundle(pemData []byte) ([]*x509.Certificate, error) {
236-
var block *pem.Block
237-
var certs []*x509.Certificate
238-
for len(pemData) > 0 {
239-
block, pemData = pem.Decode(pemData)
240-
if block == nil {
241-
return nil, errors.New("error decoding pem block")
234+
// ParseCertificateBundle returns a list of *x509.Certificate parsed from
235+
// the given bytes.
236+
//
237+
// - supports PEM and DER certificate formats
238+
// - If a DER-formatted file is given only one certificate will be returned.
239+
func ParseCertificateBundle(data []byte) ([]*x509.Certificate, error) {
240+
var err error
241+
242+
// PEM format
243+
if bytes.Contains(data, PEMBlockHeader) {
244+
var block *pem.Block
245+
var bundle []*x509.Certificate
246+
for len(data) > 0 {
247+
block, data = pem.Decode(data)
248+
if block == nil {
249+
break
250+
}
251+
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
252+
continue
253+
}
254+
var crt *x509.Certificate
255+
crt, err = x509.ParseCertificate(block.Bytes)
256+
if err != nil {
257+
return nil, &InvalidPEMError{
258+
Err: err,
259+
Type: PEMTypeCertificate,
260+
}
261+
}
262+
bundle = append(bundle, crt)
242263
}
243-
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
244-
continue
264+
if len(bundle) == 0 {
265+
return nil, &InvalidPEMError{
266+
Type: PEMTypeCertificate,
267+
}
245268
}
269+
return bundle, nil
270+
}
246271

247-
cert, err := x509.ParseCertificate(block.Bytes)
248-
if err != nil {
249-
return nil, errors.Wrap(err, "error parsing certificate")
272+
// DER format (binary)
273+
crt, err := x509.ParseCertificate(data)
274+
if err != nil {
275+
return nil, &InvalidPEMError{
276+
Message: fmt.Sprintf("error parsing certificate as DER format: %v", err),
277+
Type: PEMTypeCertificate,
250278
}
251-
certs = append(certs, cert)
252-
}
253-
if len(certs) == 0 {
254-
return nil, errors.New("error parsing certificate: no certificate found")
255279
}
256-
return certs, nil
280+
return []*x509.Certificate{crt}, nil
257281
}
258282

259-
// ParseCertificateRequest extracts the first certificate from the given pem.
260-
func ParseCertificateRequest(pemData []byte) (*x509.CertificateRequest, error) {
261-
var block *pem.Block
262-
for len(pemData) > 0 {
263-
block, pemData = pem.Decode(pemData)
264-
if block == nil {
265-
return nil, errors.New("error decoding pem block")
266-
}
267-
if (block.Type != "CERTIFICATE REQUEST" && block.Type != "NEW CERTIFICATE REQUEST") ||
268-
len(block.Headers) != 0 {
269-
continue
270-
}
283+
// ParseCertificateRequest extracts the first *x509.CertificateRequest
284+
// from the given data.
285+
//
286+
// - supports PEM and DER certificate formats
287+
// - If a DER-formatted file is given only one certificate will be returned.
288+
func ParseCertificateRequest(data []byte) (*x509.CertificateRequest, error) {
289+
// PEM format
290+
if bytes.Contains(data, PEMBlockHeader) {
291+
var block *pem.Block
292+
for len(data) > 0 {
293+
block, data = pem.Decode(data)
294+
if block == nil {
295+
break
296+
}
297+
if !strings.HasSuffix(block.Type, "CERTIFICATE REQUEST") {
298+
continue
299+
}
300+
csr, err := x509.ParseCertificateRequest(block.Bytes)
301+
if err != nil {
302+
return nil, &InvalidPEMError{
303+
Type: PEMTypeCertificateRequest,
304+
Err: err,
305+
}
306+
}
271307

272-
csr, err := x509.ParseCertificateRequest(block.Bytes)
273-
if err != nil {
274-
return nil, errors.Wrap(err, "error parsing certificate request")
308+
return csr, nil
275309
}
276-
return csr, nil
277310
}
278311

279-
return nil, errors.New("error parsing certificate request: no certificate found")
312+
// DER format (binary)
313+
csr, err := x509.ParseCertificateRequest(data)
314+
if err != nil {
315+
return nil, &InvalidPEMError{
316+
Message: fmt.Sprintf("error parsing certificate request as DER format: %v", err),
317+
Type: PEMTypeCertificateRequest,
318+
}
319+
}
320+
return csr, nil
280321
}
281322

282323
// PEMType represents a PEM block type. (e.g., CERTIFICATE, CERTIFICATE REQUEST, etc.)
@@ -318,14 +359,10 @@ func (e *InvalidPEMError) Error() string {
318359
case e.Err != nil:
319360
return fmt.Sprintf("error decoding PEM data: %v", e.Err)
320361
default:
321-
var prefix = "input"
322-
if e.File != "" {
323-
prefix = fmt.Sprintf("file %s", e.File)
324-
}
325362
if e.Type == PEMTypeUndefined {
326-
return fmt.Sprintf("%s does not contain valid PEM encoded data", prefix)
363+
return "does not contain valid PEM encoded data"
327364
}
328-
return fmt.Sprintf("%s does not contain a valid PEM encoded %s", prefix, e.Type)
365+
return fmt.Sprintf("does not contain a valid PEM encoded %s", e.Type)
329366
}
330367
}
331368

@@ -355,83 +392,40 @@ func ReadCertificate(filename string, opts ...Options) (*x509.Certificate, error
355392
}
356393
}
357394

358-
// ReadCertificateBundle returns a list of *x509.Certificate from the given
359-
// filename. It supports certificates formats PEM and DER. If a DER-formatted
360-
// file is given only one certificate will be returned.
395+
// ReadCertificateBundle reads the given filename and returns a list of
396+
// *x509.Certificate.
397+
//
398+
// - supports PEM and DER certificate formats
399+
// - If a DER-formatted file is given only one certificate will be returned.
361400
func ReadCertificateBundle(filename string) ([]*x509.Certificate, error) {
362401
b, err := utils.ReadFile(filename)
363402
if err != nil {
364403
return nil, err
365404
}
366405

367-
// PEM format
368-
if bytes.Contains(b, PEMBlockHeader) {
369-
var block *pem.Block
370-
var bundle []*x509.Certificate
371-
for len(b) > 0 {
372-
block, b = pem.Decode(b)
373-
if block == nil {
374-
break
375-
}
376-
if block.Type != "CERTIFICATE" {
377-
continue
378-
}
379-
var crt *x509.Certificate
380-
crt, err = x509.ParseCertificate(block.Bytes)
381-
if err != nil {
382-
return nil, errors.Wrapf(err, "error parsing %s", filename)
383-
}
384-
bundle = append(bundle, crt)
385-
}
386-
if len(bundle) == 0 {
387-
return nil, &InvalidPEMError{File: filename, Type: PEMTypeCertificate}
388-
}
389-
return bundle, nil
390-
}
391-
392-
// DER format (binary)
393-
crt, err := x509.ParseCertificate(b)
406+
bundle, err := ParseCertificateBundle(b)
394407
if err != nil {
395-
return nil, errors.Wrapf(err, "error parsing %s", filename)
408+
return nil, fmt.Errorf("error parsing %s: %w", filename, err)
396409
}
397-
return []*x509.Certificate{crt}, nil
410+
return bundle, nil
398411
}
399412

400-
// ReadCertificateRequest returns a *x509.CertificateRequest from the given
401-
// filename. It supports certificates formats PEM and DER.
413+
// ReadCertificateRequest reads the given filename and returns a
414+
// *x509.CertificateRequest.
415+
//
416+
// - supports PEM and DER Certificate formats.
417+
// - supports reading from STDIN with filename `-`.
402418
func ReadCertificateRequest(filename string) (*x509.CertificateRequest, error) {
403419
b, err := utils.ReadFile(filename)
404420
if err != nil {
405421
return nil, err
406422
}
407423

408-
// PEM format
409-
if bytes.Contains(b, PEMBlockHeader) {
410-
var block *pem.Block
411-
for len(b) > 0 {
412-
block, b = pem.Decode(b)
413-
if block == nil {
414-
break
415-
}
416-
if !strings.HasSuffix(block.Type, "CERTIFICATE REQUEST") {
417-
continue
418-
}
419-
csr, err := x509.ParseCertificateRequest(block.Bytes)
420-
if err != nil {
421-
return nil, &InvalidPEMError{
422-
File: filename, Type: PEMTypeCertificateRequest,
423-
Message: fmt.Sprintf("error parsing %s: CSR PEM block is invalid: %v", filename, err),
424-
Err: err,
425-
}
426-
}
427-
428-
return csr, nil
429-
}
424+
cr, err := ParseCertificateRequest(b)
425+
if err != nil {
426+
return nil, fmt.Errorf("error parsing %s: %w", filename, err)
430427
}
431-
432-
// DER format (binary)
433-
csr, err := x509.ParseCertificateRequest(b)
434-
return csr, errors.Wrapf(err, "error parsing %s", filename)
428+
return cr, nil
435429
}
436430

437431
// Parse returns the key or certificate PEM-encoded in the given bytes.

0 commit comments

Comments
 (0)