1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
|
// 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}
)
|