func parseCertificate(in *certificate) (*Certificate, error) { out := new(Certificate) out.Raw = in.Raw out.RawTBSCertificate = in.TBSCertificate.Raw out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw out.RawSubject = in.TBSCertificate.Subject.FullBytes out.RawIssuer = in.TBSCertificate.Issuer.FullBytes out.Signature = in.SignatureValue.RightAlign() out.SignatureAlgorithm = getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm) out.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) var err error out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey) if err != nil { return nil, err } if in.TBSCertificate.SerialNumber.Sign() < 0 { return nil, errors.New("negative serial number") } out.Version = in.TBSCertificate.Version + 1 out.SerialNumber = in.TBSCertificate.SerialNumber var issuer, subject pkix.RDNSequence if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil { return nil, err } if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { return nil, err } out.Issuer.FillFromRDNSequence(&issuer) out.Subject.FillFromRDNSequence(&subject) out.NotBefore = in.TBSCertificate.Validity.NotBefore out.NotAfter = in.TBSCertificate.Validity.NotAfter for _, e := range in.TBSCertificate.Extensions { if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { switch e.Id[3] { case 15: // RFC 5280, 4.2.1.3 var usageBits asn1.BitString _, err := asn1.Unmarshal(e.Value, &usageBits) if err == nil { var usage int for i := 0; i < 9; i++ { if usageBits.At(i) != 0 { usage |= 1 << uint(i) } } out.KeyUsage = KeyUsage(usage) continue } case 19: // RFC 5280, 4.2.1.9 var constraints basicConstraints _, err := asn1.Unmarshal(e.Value, &constraints) if err == nil { out.BasicConstraintsValid = true out.IsCA = constraints.IsCA out.MaxPathLen = constraints.MaxPathLen continue } case 17: // RFC 5280, 4.2.1.6 // SubjectAltName ::= GeneralNames // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue _, err := asn1.Unmarshal(e.Value, &seq) if err != nil { return nil, err } if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { return nil, asn1.StructuralError{Msg: "bad SAN sequence"} } parsedName := false rest := seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { return nil, err } switch v.Tag { case 1: out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes)) parsedName = true case 2: out.DNSNames = append(out.DNSNames, string(v.Bytes)) parsedName = true } } if parsedName { continue } // If we didn't parse any of the names then we // fall through to the critical check below. case 30: // RFC 5280, 4.2.1.10 // NameConstraints ::= SEQUENCE { // permittedSubtrees [0] GeneralSubtrees OPTIONAL, // excludedSubtrees [1] GeneralSubtrees OPTIONAL } // // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree // // GeneralSubtree ::= SEQUENCE { // base GeneralName, // minimum [0] BaseDistance DEFAULT 0, // maximum [1] BaseDistance OPTIONAL } // // BaseDistance ::= INTEGER (0..MAX) var constraints nameConstraints _, err := asn1.Unmarshal(e.Value, &constraints) if err != nil { return nil, err } if len(constraints.Excluded) > 0 && e.Critical { return out, UnhandledCriticalExtension{} } for _, subtree := range constraints.Permitted { if subtree.Min > 0 || subtree.Max > 0 || len(subtree.Name) == 0 { if e.Critical { return out, UnhandledCriticalExtension{} } continue } out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) } continue case 35: // RFC 5280, 4.2.1.1 var a authKeyId _, err = asn1.Unmarshal(e.Value, &a) if err != nil { return nil, err } out.AuthorityKeyId = a.Id continue case 37: // RFC 5280, 4.2.1.12. Extended Key Usage // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } // // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId // // KeyPurposeId ::= OBJECT IDENTIFIER var keyUsage []asn1.ObjectIdentifier _, err = asn1.Unmarshal(e.Value, &keyUsage) if err != nil { return nil, err } for _, u := range keyUsage { switch { case u.Equal(oidExtKeyUsageAny): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageAny) case u.Equal(oidExtKeyUsageServerAuth): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageServerAuth) case u.Equal(oidExtKeyUsageClientAuth): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageClientAuth) case u.Equal(oidExtKeyUsageCodeSigning): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageCodeSigning) case u.Equal(oidExtKeyUsageEmailProtection): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageEmailProtection) case u.Equal(oidExtKeyUsageTimeStamping): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageTimeStamping) case u.Equal(oidExtKeyUsageOCSPSigning): out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageOCSPSigning) default: out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u) } } continue case 14: // RFC 5280, 4.2.1.2 var keyid []byte _, err = asn1.Unmarshal(e.Value, &keyid) if err != nil { return nil, err } out.SubjectKeyId = keyid continue case 32: // RFC 5280 4.2.1.4: Certificate Policies var policies []policyInformation if _, err = asn1.Unmarshal(e.Value, &policies); err != nil { return nil, err } out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies)) for i, policy := range policies { out.PolicyIdentifiers[i] = policy.Policy } } } if e.Critical { return out, UnhandledCriticalExtension{} } } return out, nil }
func parseCertificate(in *certificate) (*Certificate, error) { out := new(Certificate) out.Raw = in.Raw out.RawTBSCertificate = in.TBSCertificate.Raw out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw out.RawSubject = in.TBSCertificate.Subject.FullBytes out.RawIssuer = in.TBSCertificate.Issuer.FullBytes out.Signature = in.SignatureValue.RightAlign() out.SignatureAlgorithm = getSignatureAlgorithmFromOID(in.TBSCertificate.SignatureAlgorithm.Algorithm) out.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm) var err error out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey) if err != nil { return nil, err } if in.TBSCertificate.SerialNumber.Sign() < 0 { return nil, errors.New("x509: negative serial number") } out.Version = in.TBSCertificate.Version + 1 out.SerialNumber = in.TBSCertificate.SerialNumber var issuer, subject pkix.RDNSequence if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil { return nil, err } if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { return nil, err } out.Issuer.FillFromRDNSequence(&issuer) out.Subject.FillFromRDNSequence(&subject) out.NotBefore = in.TBSCertificate.Validity.NotBefore out.NotAfter = in.TBSCertificate.Validity.NotAfter for _, e := range in.TBSCertificate.Extensions { out.Extensions = append(out.Extensions, e) if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { switch e.Id[3] { case 15: // RFC 5280, 4.2.1.3 var usageBits asn1.BitString _, err := asn1.Unmarshal(e.Value, &usageBits) if err == nil { var usage int for i := 0; i < 9; i++ { if usageBits.At(i) != 0 { usage |= 1 << uint(i) } } out.KeyUsage = KeyUsage(usage) continue } case 19: // RFC 5280, 4.2.1.9 var constraints basicConstraints _, err := asn1.Unmarshal(e.Value, &constraints) if err == nil { out.BasicConstraintsValid = true out.IsCA = constraints.IsCA out.MaxPathLen = constraints.MaxPathLen continue } case 17: // RFC 5280, 4.2.1.6 // SubjectAltName ::= GeneralNames // // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName // // GeneralName ::= CHOICE { // otherName [0] OtherName, // rfc822Name [1] IA5String, // dNSName [2] IA5String, // x400Address [3] ORAddress, // directoryName [4] Name, // ediPartyName [5] EDIPartyName, // uniformResourceIdentifier [6] IA5String, // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue _, err := asn1.Unmarshal(e.Value, &seq) if err != nil { return nil, err } if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { return nil, asn1.StructuralError{Msg: "bad SAN sequence"} } parsedName := false rest := seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) if err != nil { return nil, err } switch v.Tag { case 1: out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes)) parsedName = true case 2: out.DNSNames = append(out.DNSNames, string(v.Bytes)) parsedName = true case 7: switch len(v.Bytes) { case net.IPv4len, net.IPv6len: out.IPAddresses = append(out.IPAddresses, v.Bytes) default: return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes))) } } } if parsedName { continue } // If we didn't parse any of the names then we // fall through to the critical check below. case 30: // RFC 5280, 4.2.1.10 // NameConstraints ::= SEQUENCE { // permittedSubtrees [0] GeneralSubtrees OPTIONAL, // excludedSubtrees [1] GeneralSubtrees OPTIONAL } // // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree // // GeneralSubtree ::= SEQUENCE { // base GeneralName, // minimum [0] BaseDistance DEFAULT 0, // maximum [1] BaseDistance OPTIONAL } // // BaseDistance ::= INTEGER (0..MAX) var constraints nameConstraints _, err := asn1.Unmarshal(e.Value, &constraints) if err != nil { return nil, err } if len(constraints.Excluded) > 0 && e.Critical { return out, UnhandledCriticalExtension{} } for _, subtree := range constraints.Permitted { if len(subtree.Name) == 0 { if e.Critical { return out, UnhandledCriticalExtension{} } continue } out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) } continue case 31: // RFC 5280, 4.2.1.14 // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // // DistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // reasons [1] ReasonFlags OPTIONAL, // cRLIssuer [2] GeneralNames OPTIONAL } // // DistributionPointName ::= CHOICE { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } var cdp []distributionPoint _, err := asn1.Unmarshal(e.Value, &cdp) if err != nil { return nil, err } for _, dp := range cdp { var n asn1.RawValue _, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n) if err != nil { return nil, err } if n.Tag == 6 { out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes)) } } continue case 35: // RFC 5280, 4.2.1.1 var a authKeyId _, err = asn1.Unmarshal(e.Value, &a) if err != nil { return nil, err } out.AuthorityKeyId = a.Id continue case 37: // RFC 5280, 4.2.1.12. Extended Key Usage // id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } // // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId // // KeyPurposeId ::= OBJECT IDENTIFIER var keyUsage []asn1.ObjectIdentifier _, err = asn1.Unmarshal(e.Value, &keyUsage) if err != nil { return nil, err } for _, u := range keyUsage { if extKeyUsage, ok := extKeyUsageFromOID(u); ok { out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage) } else { out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u) } } continue case 14: // RFC 5280, 4.2.1.2 var keyid []byte _, err = asn1.Unmarshal(e.Value, &keyid) if err != nil { return nil, err } out.SubjectKeyId = keyid continue case 32: // RFC 5280 4.2.1.4: Certificate Policies var policies []policyInformation if _, err = asn1.Unmarshal(e.Value, &policies); err != nil { return nil, err } out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies)) for i, policy := range policies { out.PolicyIdentifiers[i] = policy.Policy } } } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access var aia []authorityInfoAccess if _, err = asn1.Unmarshal(e.Value, &aia); err != nil { return nil, err } for _, v := range aia { // GeneralName: uniformResourceIdentifier [6] IA5String if v.Location.Tag != 6 { continue } if v.Method.Equal(oidAuthorityInfoAccessOcsp) { out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes)) } else if v.Method.Equal(oidAuthorityInfoAccessIssuers) { out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes)) } } } if e.Critical { return out, UnhandledCriticalExtension{} } } return out, nil }