| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "crypto" |
| "crypto/rsa" |
| "crypto/sha1" |
| "crypto/x509" |
| "crypto/x509/pkix" |
| "encoding/asn1" |
| "io" |
| "math/big" |
| "time" |
| ) |
| |
| // signPKCS7 does the minimal amount of work necessary to embed an RSA |
| // signature into a PKCS#7 certificate. |
| // |
| // We prepare the certificate using the x509 package, read it back in |
| // to our custom data type and then write it back out with the signature. |
| func signPKCS7(rand io.Reader, priv *rsa.PrivateKey, msg []byte) ([]byte, error) { |
| const serialNumber = 0x5462c4dd // arbitrary |
| name := pkix.Name{CommonName: "gomobile"} |
| |
| template := &x509.Certificate{ |
| SerialNumber: big.NewInt(serialNumber), |
| SignatureAlgorithm: x509.SHA1WithRSA, |
| Subject: name, |
| } |
| |
| b, err := x509.CreateCertificate(rand, template, template, priv.Public(), priv) |
| if err != nil { |
| return nil, err |
| } |
| |
| c := certificate{} |
| if _, err := asn1.Unmarshal(b, &c); err != nil { |
| return nil, err |
| } |
| |
| h := sha1.New() |
| h.Write(msg) |
| hashed := h.Sum(nil) |
| |
| signed, err := rsa.SignPKCS1v15(rand, priv, crypto.SHA1, hashed) |
| if err != nil { |
| return nil, err |
| } |
| |
| content := pkcs7SignedData{ |
| ContentType: oidSignedData, |
| Content: signedData{ |
| Version: 1, |
| DigestAlgorithms: []pkix.AlgorithmIdentifier{{ |
| Algorithm: oidSHA1, |
| Parameters: asn1.RawValue{Tag: 5}, |
| }}, |
| ContentInfo: contentInfo{Type: oidData}, |
| Certificates: c, |
| SignerInfos: []signerInfo{{ |
| Version: 1, |
| IssuerAndSerialNumber: issuerAndSerialNumber{ |
| Issuer: name.ToRDNSequence(), |
| SerialNumber: serialNumber, |
| }, |
| DigestAlgorithm: pkix.AlgorithmIdentifier{ |
| Algorithm: oidSHA1, |
| Parameters: asn1.RawValue{Tag: 5}, |
| }, |
| DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{ |
| Algorithm: oidRSAEncryption, |
| Parameters: asn1.RawValue{Tag: 5}, |
| }, |
| EncryptedDigest: signed, |
| }}, |
| }, |
| } |
| |
| return asn1.Marshal(content) |
| } |
| |
| type pkcs7SignedData struct { |
| ContentType asn1.ObjectIdentifier |
| Content signedData `asn1:"tag:0,explicit"` |
| } |
| |
| // signedData is defined in rfc2315, section 9.1. |
| type signedData struct { |
| Version int |
| DigestAlgorithms []pkix.AlgorithmIdentifier `asn1:"set"` |
| ContentInfo contentInfo |
| Certificates certificate `asn1:"tag0,explicit"` |
| SignerInfos []signerInfo `asn1:"set"` |
| } |
| |
| type contentInfo struct { |
| Type asn1.ObjectIdentifier |
| // Content is optional in PKCS#7 and not provided here. |
| } |
| |
| // certificate is defined in rfc2459, section 4.1. |
| type certificate struct { |
| TBSCertificate tbsCertificate |
| SignatureAlgorithm pkix.AlgorithmIdentifier |
| SignatureValue asn1.BitString |
| } |
| |
| // tbsCertificate is defined in rfc2459, section 4.1. |
| type tbsCertificate struct { |
| Version int `asn1:"tag:0,default:2,explicit"` |
| SerialNumber int |
| Signature pkix.AlgorithmIdentifier |
| Issuer pkix.RDNSequence // pkix.Name |
| Validity validity |
| Subject pkix.RDNSequence // pkix.Name |
| SubjectPKI subjectPublicKeyInfo |
| } |
| |
| // validity is defined in rfc2459, section 4.1. |
| type validity struct { |
| NotBefore time.Time |
| NotAfter time.Time |
| } |
| |
| // subjectPublicKeyInfo is defined in rfc2459, section 4.1. |
| type subjectPublicKeyInfo struct { |
| Algorithm pkix.AlgorithmIdentifier |
| SubjectPublicKey asn1.BitString |
| } |
| |
| type signerInfo struct { |
| Version int |
| IssuerAndSerialNumber issuerAndSerialNumber |
| DigestAlgorithm pkix.AlgorithmIdentifier |
| DigestEncryptionAlgorithm pkix.AlgorithmIdentifier |
| EncryptedDigest []byte |
| } |
| |
| type issuerAndSerialNumber struct { |
| Issuer pkix.RDNSequence // pkix.Name |
| SerialNumber int |
| } |
| |
| // Various ASN.1 Object Identifies, mostly from rfc3852. |
| var ( |
| oidPKCS7 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7} |
| oidData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1} |
| oidSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2} |
| oidSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26} |
| oidRSAEncryption = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} |
| ) |