aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/crypto/x509/x509.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/crypto/x509/x509.go')
-rw-r--r--libgo/go/crypto/x509/x509.go193
1 files changed, 171 insertions, 22 deletions
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go
index 013f1c9..8ce57fb 100644
--- a/libgo/go/crypto/x509/x509.go
+++ b/libgo/go/crypto/x509/x509.go
@@ -3,10 +3,6 @@
// license that can be found in the LICENSE file.
// Package x509 parses X.509-encoded keys and certificates.
-//
-// On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR
-// can be used to override the system default locations for the SSL certificate
-// file and SSL certificate files directory, respectively.
package x509
import (
@@ -17,6 +13,7 @@ import (
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
+ "crypto/sha1"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
@@ -46,6 +43,8 @@ type pkixPublicKey struct {
}
// ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form.
+// The encoded public key is a SubjectPublicKeyInfo structure
+// (see RFC 5280, Section 4.1).
//
// It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, or
// ed25519.PublicKey. More types might be supported in the future.
@@ -106,6 +105,8 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith
}
// MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form.
+// The encoded public key is a SubjectPublicKeyInfo structure
+// (see RFC 5280, Section 4.1).
//
// The following key types are currently supported: *rsa.PublicKey, *ecdsa.PublicKey
// and ed25519.PublicKey. Unsupported key types result in an error.
@@ -163,8 +164,6 @@ type dsaSignature struct {
R, S *big.Int
}
-type ecdsaSignature dsaSignature
-
type validity struct {
NotBefore, NotAfter time.Time
}
@@ -905,16 +904,7 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
if pubKeyAlgo != ECDSA {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
}
- ecdsaSig := new(ecdsaSignature)
- if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
- return err
- } else if len(rest) != 0 {
- return errors.New("x509: trailing data after ECDSA signature")
- }
- if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- return errors.New("x509: ECDSA signature contained zero or negative values")
- }
- if !ecdsa.Verify(pub, signed, ecdsaSig.R, ecdsaSig.S) {
+ if !ecdsa.VerifyASN1(pub, signed, signature) {
return errors.New("x509: ECDSA verification failure")
}
return
@@ -1374,7 +1364,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
return nil, err
} else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 subject")
+ return nil, errors.New("x509: trailing data after X.509 issuer")
}
out.Issuer.FillFromRDNSequence(&issuer)
@@ -1644,6 +1634,7 @@ var (
oidExtensionNameConstraints = []int{2, 5, 29, 30}
oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31}
oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
+ oidExtensionCRLNumber = []int{2, 5, 29, 20}
)
var (
@@ -1696,7 +1687,7 @@ func isIA5String(s string) error {
return nil
}
-func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) {
+func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0
@@ -1761,9 +1752,9 @@ func buildExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId
n++
}
- if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
+ if len(subjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
ret[n].Id = oidExtensionSubjectKeyId
- ret[n].Value, err = asn1.Marshal(template.SubjectKeyId)
+ ret[n].Value, err = asn1.Marshal(subjectKeyId)
if err != nil {
return
}
@@ -2092,6 +2083,9 @@ var emptyASN1Subject = []byte{0x30, 0}
// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
// unless the resulting certificate is self-signed. Otherwise the value from
// template will be used.
+//
+// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId
+// will be generated from the hash of the public key.
func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
@@ -2102,6 +2096,10 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return nil, errors.New("x509: no SerialNumber given")
}
+ if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) {
+ return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
+ }
+
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
if err != nil {
return nil, err
@@ -2127,7 +2125,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
authorityKeyId = parent.SubjectKeyId
}
- extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
+ subjectKeyId := template.SubjectKeyId
+ if len(subjectKeyId) == 0 && template.IsCA {
+ // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2:
+ // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ // value of the BIT STRING subjectPublicKey (excluding the tag,
+ // length, and number of unused bits).
+ h := sha1.Sum(publicKeyBytes)
+ subjectKeyId = h[:]
+ }
+
+ extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
if err != nil {
return
}
@@ -2213,6 +2221,9 @@ func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
// contains the given list of revoked certificates.
+//
+// Note: this method does not generate an RFC 5280 conformant X.509 v2 CRL.
+// To generate a standards compliant CRL, use CreateRevocationList instead.
func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
@@ -2338,7 +2349,7 @@ type certificateRequest struct {
SignatureValue asn1.BitString
}
-// oidExtensionRequest is a PKCS#9 OBJECT IDENTIFIER that indicates requested
+// oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested
// extensions in a CSR.
var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
@@ -2660,3 +2671,141 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
func (c *CertificateRequest) CheckSignature() error {
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
}
+
+// RevocationList contains the fields used to create an X.509 v2 Certificate
+// Revocation list with CreateRevocationList.
+type RevocationList struct {
+ // SignatureAlgorithm is used to determine the signature algorithm to be
+ // used when signing the CRL. If 0 the default algorithm for the signing
+ // key will be used.
+ SignatureAlgorithm SignatureAlgorithm
+
+ // RevokedCertificates is used to populate the revokedCertificates
+ // sequence in the CRL, it may be empty. RevokedCertificates may be nil,
+ // in which case an empty CRL will be created.
+ RevokedCertificates []pkix.RevokedCertificate
+
+ // Number is used to populate the X.509 v2 cRLNumber extension in the CRL,
+ // which should be a monotonically increasing sequence number for a given
+ // CRL scope and CRL issuer.
+ Number *big.Int
+ // ThisUpdate is used to populate the thisUpdate field in the CRL, which
+ // indicates the issuance date of the CRL.
+ ThisUpdate time.Time
+ // NextUpdate is used to populate the nextUpdate field in the CRL, which
+ // indicates the date by which the next CRL will be issued. NextUpdate
+ // must be greater than ThisUpdate.
+ NextUpdate time.Time
+ // ExtraExtensions contains any additional extensions to add directly to
+ // the CRL.
+ ExtraExtensions []pkix.Extension
+}
+
+// CreateRevocationList creates a new X.509 v2 Certificate Revocation List,
+// according to RFC 5280, based on template.
+//
+// The CRL is signed by priv which should be the private key associated with
+// the public key in the issuer certificate.
+//
+// The issuer may not be nil, and the crlSign bit must be set in KeyUsage in
+// order to use it as a CRL issuer.
+//
+// The issuer distinguished name CRL field and authority key identifier
+// extension are populated using the issuer certificate. issuer must have
+// SubjectKeyId set.
+func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) {
+ if template == nil {
+ return nil, errors.New("x509: template can not be nil")
+ }
+ if issuer == nil {
+ return nil, errors.New("x509: issuer can not be nil")
+ }
+ if (issuer.KeyUsage & KeyUsageCRLSign) == 0 {
+ return nil, errors.New("x509: issuer must have the crlSign key usage bit set")
+ }
+ if len(issuer.SubjectKeyId) == 0 {
+ return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier")
+ }
+ if template.NextUpdate.Before(template.ThisUpdate) {
+ return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate")
+ }
+ if template.Number == nil {
+ return nil, errors.New("x509: template contains nil Number field")
+ }
+
+ hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+
+ // Force revocation times to UTC per RFC 5280.
+ revokedCertsUTC := make([]pkix.RevokedCertificate, len(template.RevokedCertificates))
+ for i, rc := range template.RevokedCertificates {
+ rc.RevocationTime = rc.RevocationTime.UTC()
+ revokedCertsUTC[i] = rc
+ }
+
+ aki, err := asn1.Marshal(authKeyId{Id: issuer.SubjectKeyId})
+ if err != nil {
+ return nil, err
+ }
+ crlNum, err := asn1.Marshal(template.Number)
+ if err != nil {
+ return nil, err
+ }
+
+ tbsCertList := pkix.TBSCertificateList{
+ Version: 1, // v2
+ Signature: signatureAlgorithm,
+ Issuer: issuer.Subject.ToRDNSequence(),
+ ThisUpdate: template.ThisUpdate.UTC(),
+ NextUpdate: template.NextUpdate.UTC(),
+ Extensions: []pkix.Extension{
+ {
+ Id: oidExtensionAuthorityKeyId,
+ Value: aki,
+ },
+ {
+ Id: oidExtensionCRLNumber,
+ Value: crlNum,
+ },
+ },
+ }
+ if len(revokedCertsUTC) > 0 {
+ tbsCertList.RevokedCertificates = revokedCertsUTC
+ }
+
+ if len(template.ExtraExtensions) > 0 {
+ tbsCertList.Extensions = append(tbsCertList.Extensions, template.ExtraExtensions...)
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return nil, err
+ }
+
+ input := tbsCertListContents
+ if hashFunc != 0 {
+ h := hashFunc.New()
+ h.Write(tbsCertListContents)
+ input = h.Sum(nil)
+ }
+ var signerOpts crypto.SignerOpts = hashFunc
+ if template.SignatureAlgorithm.isRSAPSS() {
+ signerOpts = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ Hash: hashFunc,
+ }
+ }
+
+ signature, err := priv.Sign(rand, input, signerOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ return asn1.Marshal(pkix.CertificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: signatureAlgorithm,
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}