diff options
Diffstat (limited to 'src/pkg/crypto/x509/x509.go')
-rw-r--r-- | src/pkg/crypto/x509/x509.go | 222 |
1 files changed, 128 insertions, 94 deletions
diff --git a/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go index 728116850..6199e8db9 100644 --- a/src/pkg/crypto/x509/x509.go +++ b/src/pkg/crypto/x509/x509.go @@ -36,7 +36,7 @@ func rawValueIsInteger(raw *asn1.RawValue) bool { // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form. func ParsePKCS1PrivateKey(der []byte) (key *rsa.PrivateKey, err os.Error) { var priv pkcs1PrivateKey - rest, err := asn1.Unmarshal(&priv, der) + rest, err := asn1.Unmarshal(der, &priv) if len(rest) > 0 { err = asn1.SyntaxError{"trailing data"} return @@ -81,7 +81,7 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { Q: asn1.RawValue{Tag: 2, Bytes: key.Q.Bytes()}, } - b, _ := asn1.MarshalToMemory(priv) + b, _ := asn1.Marshal(priv) return b } @@ -162,9 +162,10 @@ const ( // Name represents an X.509 distinguished name. This only includes the common // elements of a DN. Additional elements in the name are ignored. type Name struct { - Country, Organization, OrganizationalUnit string - CommonName, SerialNumber, Locality string - Province, StreetAddress, PostalCode string + Country, Organization, OrganizationalUnit []string + Locality, Province []string + StreetAddress, PostalCode []string + SerialNumber, CommonName string } func (n *Name) fillFromRDNSequence(rdns *rdnSequence) { @@ -186,19 +187,19 @@ func (n *Name) fillFromRDNSequence(rdns *rdnSequence) { case 5: n.SerialNumber = value case 6: - n.Country = value + n.Country = append(n.Country, value) case 7: - n.Locality = value + n.Locality = append(n.Locality, value) case 8: - n.Province = value + n.Province = append(n.Province, value) case 9: - n.StreetAddress = value + n.StreetAddress = append(n.StreetAddress, value) case 10: - n.Organization = value + n.Organization = append(n.Organization, value) case 11: - n.OrganizationalUnit = value + n.OrganizationalUnit = append(n.OrganizationalUnit, value) case 17: - n.PostalCode = value + n.PostalCode = append(n.PostalCode, value) } } } @@ -216,50 +217,40 @@ var ( oidPostalCode = []int{2, 5, 4, 17} ) -func (n Name) toRDNSequence() (ret rdnSequence) { - ret = make([]relativeDistinguishedNameSET, 9 /* maximum number of elements */ ) - i := 0 - if len(n.Country) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidCountry, n.Country}} - i++ - } - if len(n.Organization) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidOrganization, n.Organization}} - i++ +// appendRDNs appends a relativeDistinguishedNameSET to the given rdnSequence +// and returns the new value. The relativeDistinguishedNameSET contains an +// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and +// search for AttributeTypeAndValue. +func appendRDNs(in rdnSequence, values []string, oid asn1.ObjectIdentifier) rdnSequence { + if len(values) == 0 { + return in } - if len(n.OrganizationalUnit) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidOrganizationalUnit, n.OrganizationalUnit}} - i++ + + s := make([]attributeTypeAndValue, len(values)) + for i, value := range values { + s[i].Type = oid + s[i].Value = value } + + return append(in, s) +} + +func (n Name) toRDNSequence() (ret rdnSequence) { + ret = appendRDNs(ret, n.Country, oidCountry) + ret = appendRDNs(ret, n.Organization, oidOrganization) + ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) + ret = appendRDNs(ret, n.Locality, oidLocatity) + ret = appendRDNs(ret, n.Province, oidProvince) + ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress) + ret = appendRDNs(ret, n.PostalCode, oidPostalCode) if len(n.CommonName) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidCommonName, n.CommonName}} - i++ + ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName) } if len(n.SerialNumber) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidSerialNumber, n.SerialNumber}} - i++ - } - if len(n.Locality) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidLocatity, n.Locality}} - i++ - } - if len(n.Province) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidProvince, n.Province}} - i++ - } - if len(n.StreetAddress) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidStreetAddress, n.StreetAddress}} - i++ - } - if len(n.PostalCode) > 0 { - ret[i] = []attributeTypeAndValue{attributeTypeAndValue{oidPostalCode, n.PostalCode}} - i++ + ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) } - // Adding another RDN here? Remember to update the maximum number of - // elements in the make() at the top of the function. - - return ret[0:i] + return ret } func getSignatureAlgorithmFromOID(oid []int) SignatureAlgorithm { @@ -338,6 +329,8 @@ type Certificate struct { // Subject Alternate Name values DNSNames []string EmailAddresses []string + + PolicyIdentifiers []asn1.ObjectIdentifier } // UnsupportedAlgorithmError results from attempting to perform an operation @@ -426,19 +419,37 @@ func matchHostnames(pattern, host string) bool { return true } -// IsValidForHost returns true iff c is a valid certificate for the given host. -func (c *Certificate) IsValidForHost(h string) bool { +type HostnameError struct { + Certificate *Certificate + Host string +} + +func (h *HostnameError) String() string { + var valid string + c := h.Certificate + if len(c.DNSNames) > 0 { + valid = strings.Join(c.DNSNames, ", ") + } else { + valid = c.Subject.CommonName + } + return "certificate is valid for " + valid + ", not " + h.Host +} + +// VerifyHostname returns nil if c is a valid certificate for the named host. +// Otherwise it returns an os.Error describing the mismatch. +func (c *Certificate) VerifyHostname(h string) os.Error { if len(c.DNSNames) > 0 { for _, match := range c.DNSNames { if matchHostnames(match, h) { - return true + return nil } } // If Subject Alt Name is given, we ignore the common name. - return false + } else if matchHostnames(c.Subject.CommonName, h) { + return nil } - return matchHostnames(c.Subject.CommonName, h) + return &HostnameError{c, h} } type UnhandledCriticalExtension struct{} @@ -457,11 +468,17 @@ type rsaPublicKey struct { E int } +// RFC 5280 4.2.1.4 +type policyInformation struct { + Policy asn1.ObjectIdentifier + // policyQualifiers omitted +} + func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.Error) { switch algo { case RSA: p := new(rsaPublicKey) - _, err := asn1.Unmarshal(p, asn1Data) + _, err := asn1.Unmarshal(asn1Data, p) if err != nil { return nil, err } @@ -482,19 +499,6 @@ func parsePublicKey(algo PublicKeyAlgorithm, asn1Data []byte) (interface{}, os.E panic("unreachable") } -func appendString(in []string, v string) (out []string) { - if cap(in)-len(in) < 1 { - out = make([]string, len(in)+1, len(in)*2+1) - for i, v := range in { - out[i] = v - } - } else { - out = in[0 : len(in)+1] - } - out[len(in)] = v - return out -} - func parseCertificate(in *certificate) (*Certificate, os.Error) { out := new(Certificate) out.Raw = in.TBSCertificate.Raw @@ -511,7 +515,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { return nil, err } - out.Version = in.TBSCertificate.Version + out.Version = in.TBSCertificate.Version + 1 out.SerialNumber = in.TBSCertificate.SerialNumber.Bytes out.Issuer.fillFromRDNSequence(&in.TBSCertificate.Issuer) out.Subject.fillFromRDNSequence(&in.TBSCertificate.Subject) @@ -524,7 +528,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { case 15: // RFC 5280, 4.2.1.3 var usageBits asn1.BitString - _, err := asn1.Unmarshal(&usageBits, e.Value) + _, err := asn1.Unmarshal(e.Value, &usageBits) if err == nil { var usage int @@ -539,7 +543,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { case 19: // RFC 5280, 4.2.1.9 var constriants basicConstraints - _, err := asn1.Unmarshal(&constriants, e.Value) + _, err := asn1.Unmarshal(e.Value, &constriants) if err == nil { out.BasicConstraintsValid = true @@ -565,7 +569,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue - _, err := asn1.Unmarshal(&seq, e.Value) + _, err := asn1.Unmarshal(e.Value, &seq) if err != nil { return nil, err } @@ -578,16 +582,16 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { rest := seq.Bytes for len(rest) > 0 { var v asn1.RawValue - rest, err = asn1.Unmarshal(&v, rest) + rest, err = asn1.Unmarshal(rest, &v) if err != nil { return nil, err } switch v.Tag { case 1: - out.EmailAddresses = appendString(out.EmailAddresses, string(v.Bytes)) + out.EmailAddresses = append(out.EmailAddresses, string(v.Bytes)) parsedName = true case 2: - out.DNSNames = appendString(out.DNSNames, string(v.Bytes)) + out.DNSNames = append(out.DNSNames, string(v.Bytes)) parsedName = true } } @@ -601,7 +605,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { case 35: // RFC 5280, 4.2.1.1 var a authKeyId - _, err = asn1.Unmarshal(&a, e.Value) + _, err = asn1.Unmarshal(e.Value, &a) if err != nil { return nil, err } @@ -610,8 +614,24 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { case 14: // RFC 5280, 4.2.1.2 - out.SubjectKeyId = e.Value + 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 + } } } @@ -626,7 +646,7 @@ func parseCertificate(in *certificate) (*Certificate, os.Error) { // ParseCertificate parses a single certificate from the given ASN.1 DER data. func ParseCertificate(asn1Data []byte) (*Certificate, os.Error) { var cert certificate - rest, err := asn1.Unmarshal(&cert, asn1Data) + rest, err := asn1.Unmarshal(asn1Data, &cert) if err != nil { return nil, err } @@ -645,7 +665,7 @@ func ParseCertificates(asn1Data []byte) ([]*Certificate, os.Error) { for len(asn1Data) > 0 { cert := new(certificate) var err os.Error - asn1Data, err = asn1.Unmarshal(cert, asn1Data) + asn1Data, err = asn1.Unmarshal(asn1Data, cert) if err != nil { return nil, err } @@ -672,15 +692,16 @@ func reverseBitsInAByte(in byte) byte { } var ( - oidExtensionSubjectKeyId = []int{2, 5, 29, 14} - oidExtensionKeyUsage = []int{2, 5, 29, 15} - oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} - oidExtensionBasicConstraints = []int{2, 5, 29, 19} - oidExtensionSubjectAltName = []int{2, 5, 29, 17} + oidExtensionSubjectKeyId = []int{2, 5, 29, 14} + oidExtensionKeyUsage = []int{2, 5, 29, 15} + oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} + oidExtensionBasicConstraints = []int{2, 5, 29, 19} + oidExtensionSubjectAltName = []int{2, 5, 29, 17} + oidExtensionCertificatePolicies = []int{2, 5, 29, 32} ) func buildExtensions(template *Certificate) (ret []extension, err os.Error) { - ret = make([]extension, 5 /* maximum number of elements. */ ) + ret = make([]extension, 6 /* maximum number of elements. */ ) n := 0 if template.KeyUsage != 0 { @@ -696,7 +717,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) { l = 2 } - ret[n].Value, err = asn1.MarshalToMemory(asn1.BitString{Bytes: a[0:l], BitLength: l * 8}) + ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8}) if err != nil { return } @@ -705,7 +726,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) { if template.BasicConstraintsValid { ret[n].Id = oidExtensionBasicConstraints - ret[n].Value, err = asn1.MarshalToMemory(basicConstraints{template.IsCA, template.MaxPathLen}) + ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen}) ret[n].Critical = true if err != nil { return @@ -715,7 +736,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) { if len(template.SubjectKeyId) > 0 { ret[n].Id = oidExtensionSubjectKeyId - ret[n].Value, err = asn1.MarshalToMemory(template.SubjectKeyId) + ret[n].Value, err = asn1.Marshal(template.SubjectKeyId) if err != nil { return } @@ -724,7 +745,7 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) { if len(template.AuthorityKeyId) > 0 { ret[n].Id = oidExtensionAuthorityKeyId - ret[n].Value, err = asn1.MarshalToMemory(authKeyId{template.AuthorityKeyId}) + ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId}) if err != nil { return } @@ -737,7 +758,20 @@ func buildExtensions(template *Certificate) (ret []extension, err os.Error) { for i, name := range template.DNSNames { rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)} } - ret[n].Value, err = asn1.MarshalToMemory(rawValues) + ret[n].Value, err = asn1.Marshal(rawValues) + if err != nil { + return + } + n++ + } + + if len(template.PolicyIdentifiers) > 0 { + ret[n].Id = oidExtensionCertificatePolicies + policies := make([]policyInformation, len(template.PolicyIdentifiers)) + for i, policy := range template.PolicyIdentifiers { + policies[i].Policy = policy + } + ret[n].Value, err = asn1.Marshal(policies) if err != nil { return } @@ -766,7 +800,7 @@ var ( // // The returned slice is the certificate in DER encoding. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.PublicKey, priv *rsa.PrivateKey) (cert []byte, err os.Error) { - asn1PublicKey, err := asn1.MarshalToMemory(rsaPublicKey{ + asn1PublicKey, err := asn1.Marshal(rsaPublicKey{ N: asn1.RawValue{Tag: 2, Bytes: pub.N.Bytes()}, E: pub.E, }) @@ -785,7 +819,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey} c := tbsCertificate{ - Version: 3, + Version: 2, SerialNumber: asn1.RawValue{Bytes: template.SerialNumber, Tag: 2}, SignatureAlgorithm: algorithmIdentifier{oidSHA1WithRSA}, Issuer: parent.Subject.toRDNSequence(), @@ -795,7 +829,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P Extensions: extensions, } - tbsCertContents, err := asn1.MarshalToMemory(c) + tbsCertContents, err := asn1.Marshal(c) if err != nil { return } @@ -811,7 +845,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub *rsa.P return } - cert, err = asn1.MarshalToMemory(certificate{ + cert, err = asn1.Marshal(certificate{ c, algorithmIdentifier{oidSHA1WithRSA}, asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, |