155 lines
4.1 KiB
Go
155 lines
4.1 KiB
Go
|
// 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}
|
||
|
)
|