// ParseOneCertificateFromPEM attempts to parse one PEM encoded certificate object, // either a raw x509 certificate or a PKCS #7 structure possibly containing // multiple certificates, from the top of certsPEM, which itself may // contain multiple PEM encoded certificate objects. func ParseOneCertificateFromPEM(certsPEM []byte) ([]*x509.Certificate, []byte, error) { block, rest := pem.Decode(certsPEM) if block == nil { return nil, rest, nil } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { pkcs7data, err := pkcs7.ParsePKCS7(block.Bytes) if err != nil { return nil, rest, err } if pkcs7data.ContentInfo != "SignedData" { return nil, rest, errors.New("only PKCS #7 Signed Data Content Info supported for certificate parsing") } certs := pkcs7data.Content.SignedData.Certificates if certs == nil { return nil, rest, errors.New("PKCS #7 structure contains no certificates") } return certs, rest, nil } var certs = []*x509.Certificate{cert} return certs, rest, nil }
// Given a slice of PKCS #7 content infos containing PKCS #12 Safe Bag Data, // getBags returns those Safe Bags. func getBags(authenticatedSafe []asn1.RawValue, password []byte) (bags []safeBag, err error) { for _, contentInfo := range authenticatedSafe { var safeContents []safeBag bagContainer, err := pkcs7.ParsePKCS7(contentInfo.FullBytes) if err != nil { return nil, err } switch { case bagContainer.ContentInfo == "Data": if _, err = asn1.Unmarshal(bagContainer.Content.Data, &safeContents); err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } case bagContainer.ContentInfo == "EncryptedData": data, err := decrypt(bagContainer.Content.EncryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm, bagContainer.Content.EncryptedData.EncryptedContentInfo.EncryptedContent, password) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } if _, err = asn1.Unmarshal(data, &safeContents); err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } default: return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for bags encoded in Data and EncryptedData types")) } bags = append(bags, safeContents...) } return bags, nil }
// ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key, // either PKCS #7, PKCS #12, or raw x509. func ParseCertificatesDER(certsDER []byte, password string) ([]*x509.Certificate, crypto.Signer, error) { var certs []*x509.Certificate var key crypto.Signer certsDER = bytes.TrimSpace(certsDER) pkcs7data, err := pkcs7.ParsePKCS7(certsDER) if err != nil { pkcs12data, err := pkcs12.ParsePKCS12(certsDER, []byte(password)) if err != nil { certs, err = x509.ParseCertificates(certsDER) if err != nil { return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } } else { key = pkcs12data.PrivateKey certs = pkcs12data.Certificates } } else { if pkcs7data.ContentInfo != "SignedData" { return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info")) } certs = pkcs7data.Content.SignedData.Certificates } if certs == nil { return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } return certs, key, nil }
// ParsePKCS12 parses a pkcs12 syntax object // into a container for a private key, certificate(s), and // version number func ParsePKCS12(raw, password []byte) (msg *PKCS12, err error) { msg = new(PKCS12) password, err = pbkdf.BMPString(password) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } var Pfx pfx _, err = asn1.Unmarshal(raw, &Pfx) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } if msg.Version = Pfx.Version; msg.Version != 3 { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for PKCS #12 PFX version 3")) } authSafe, err := pkcs7.ParsePKCS7(Pfx.AuthSafe.FullBytes) if err != nil { return nil, err } if authSafe.ContentInfo != "Data" { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("No support for AuthSafe Format")) } var authenticatedSafe []asn1.RawValue _, err = asn1.Unmarshal(authSafe.Content.Data, &authenticatedSafe) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } if len(authenticatedSafe) != 2 { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("No support for AuthSafe Format")) } var bags []safeBag bags, err = getBags(authenticatedSafe, password) if err != nil { return nil, err } if len(bags) > 2 || bags == nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("No support for AuthSafe Format")) } certs, pkey, err := parseBags(bags, password) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } msg.Certificates = certs msg.PrivateKey = pkey return }