Skip to content

Commit

Permalink
Merge pull request #5 from sampila/UP-247/globalsign-dss
Browse files Browse the repository at this point in the history
[UP-247] GlobalSign DSS Cert and OCSP support
  • Loading branch information
gunnsth authored Mar 29, 2022
2 parents 8a0e673 + 12f70a2 commit dd59b9e
Show file tree
Hide file tree
Showing 4 changed files with 262 additions and 8 deletions.
45 changes: 38 additions & 7 deletions pkcs7.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,16 @@ type unsignedData []byte

var (
// Signed Data OIDs
OIDData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
OIDSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
OIDEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
OIDEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
OIDAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
OIDAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
OIDData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
OIDSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
OIDEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
OIDEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
OIDAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
OIDAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
OIDAttributeTimeStampToken = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 14}
OIDAttributeSigningCertificateV2 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 2, 47}
OIDAttributeAdobeRevocation = asn1.ObjectIdentifier{1, 2, 840, 113583, 1, 1, 8}

// Digest Algorithms
OIDDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
Expand Down Expand Up @@ -115,9 +118,37 @@ func getDigestOIDForSignatureAlgorithm(digestAlg x509.SignatureAlgorithm) (asn1.
return nil, fmt.Errorf("pkcs7: cannot convert hash to oid, unknown hash algorithm")
}

// getDigestOIDForHashAlgorithm takes a pkix algorithm identifier
// and returns the corresponding OID digest algorithm.
func getDigestOIDForHashAlgorithm(digestAlg crypto.Hash) (asn1.ObjectIdentifier, error) {
switch digestAlg {
case crypto.SHA1:
return OIDDigestAlgorithmSHA1, nil
case crypto.SHA256:
return OIDDigestAlgorithmSHA256, nil
case crypto.SHA384:
return OIDDigestAlgorithmSHA384, nil
case crypto.SHA512:
return OIDDigestAlgorithmSHA512, nil
}
return nil, ErrUnsupportedAlgorithm
}

// EncryptionAlgorithmReporter allows custom crypto.Signer implementations
// to report their encryption algorithm OID.
type EncryptionAlgorithmReporter interface {
EncryptionAlgorithmOID() asn1.ObjectIdentifier
}

// getOIDForEncryptionAlgorithm takes the private key type of the signer and
// the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm
func getOIDForEncryptionAlgorithm(pkey crypto.PrivateKey, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) {
// Evaluate whether pkey implements custom EncryptionAlgorithmReporter.
reporter, ok := pkey.(EncryptionAlgorithmReporter)
if ok {
return reporter.EncryptionAlgorithmOID(), nil
}

switch pkey.(type) {
case *rsa.PrivateKey:
switch {
Expand Down
77 changes: 77 additions & 0 deletions sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto"
"crypto/dsa"
"crypto/rand"
"crypto/sha256"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
Expand Down Expand Up @@ -204,6 +205,12 @@ func (sd *SignedData) addSignerChain(ee *x509.Certificate, pkey crypto.PrivateKe
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
attrs.Add(OIDAttributeMessageDigest, sd.messageDigest)
attrs.Add(OIDAttributeSigningTime, time.Now())

// Add id-aa-signing-certificate-v2.
if b, err := populateSigningCertificateV2Ext(ee); err == nil {
attrs.Add(OIDAttributeSigningCertificateV2, asn1.RawValue{FullBytes: b})
}

for _, attr := range config.ExtraSignedAttributes {
attrs.Add(attr.Type, attr.Value)
}
Expand All @@ -224,6 +231,8 @@ func (sd *SignedData) addSignerChain(ee *x509.Certificate, pkey crypto.PrivateKe
return err
}
var ias issuerAndSerial
// No parent, the issue is the end-entity cert itself
ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer}
ias.SerialNumber = ee.SerialNumber
if len(chain) == 0 {
// no parent, the issue is the end-entity cert itself
Expand Down Expand Up @@ -339,6 +348,48 @@ func (si *signerInfo) SetUnauthenticatedAttributes(extraUnsignedAttrs []Attribut
return nil
}

// TimestampTokenRequestCallback callback of timestamp token request.
type TimestampTokenRequestCallback func(digest []byte) ([]byte, error)

// RequestSignerTimestampToken add request of timestamp token with `signerID`
// the request of timestamp token is called within `callback` function.
func (sd *SignedData) RequestSignerTimestampToken(signerID int, callback TimestampTokenRequestCallback) error {
if len(sd.sd.SignerInfos) < (signerID + 1) {
return fmt.Errorf("no signer information found for ID %d", signerID)
}

if callback == nil {
return fmt.Errorf("no callback defined")
}

tst, err := callback(sd.sd.SignerInfos[signerID].EncryptedDigest)
if err != nil {
return err
}
return sd.AddTimestampTokenToSigner(signerID, tst)
}

// AddTimestampTokenToSigner inserts `tst` TimestampToken which described in RFC3161 into
// unauthenticated attribute of `signerID` which obtaioned from identity service.
func (sd *SignedData) AddTimestampTokenToSigner(signerID int, tst []byte) (err error) {
if len(sd.sd.SignerInfos) < (signerID + 1) {
return fmt.Errorf("no signer information found for ID %d", signerID)
}

// Add the timestamp token to the unauthenticated attributes.
attrs := &attributes{}
for _, attr := range sd.sd.SignerInfos[signerID].UnauthenticatedAttributes {
attrs.Add(attr.Type, attr.Value)
}

attrs.Add(OIDAttributeTimeStampToken, asn1.RawValue{FullBytes: tst})
sd.sd.SignerInfos[signerID].UnauthenticatedAttributes, err = attrs.ForMarshalling()
if err != nil {
return err
}
return nil
}

// AddCertificate adds the certificate to the payload. Useful for parent certificates
func (sd *SignedData) AddCertificate(cert *x509.Certificate) {
sd.certs = append(sd.certs, cert)
Expand Down Expand Up @@ -491,3 +542,29 @@ func DegenerateCertificate(cert []byte) ([]byte, error) {
}
return asn1.Marshal(signedContent)
}

func populateSigningCertificateV2Ext(certificate *x509.Certificate) ([]byte, error) {
h := sha256.New()
h.Write(certificate.Raw)

signingCertificateV2 := signingCertificateV2{
Certs: []essCertIDv2{
{
HashAlgorithm: pkix.AlgorithmIdentifier{
Algorithm: asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1},
Parameters: asn1.NullRawValue,
},
CertHash: h.Sum(nil),
IssuerSerial: issuerAndSerial{
IssuerName: asn1.RawValue{FullBytes: certificate.RawIssuer},
SerialNumber: certificate.SerialNumber,
},
},
},
}
signingCertV2Bytes, err := asn1.Marshal(signingCertificateV2)
if err != nil {
return nil, err
}
return signingCertV2Bytes, nil
}
20 changes: 20 additions & 0 deletions sign_cert_v2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pkcs7

import (
"crypto/x509/pkix"
"encoding/asn1"
)

type generalNames struct {
Name asn1.RawValue `asn1:"optional,tag:4"`
}

type essCertIDv2 struct {
HashAlgorithm pkix.AlgorithmIdentifier `asn1:"optional"` // default sha256
CertHash []byte
IssuerSerial issuerAndSerial `asn1:"optional"`
}

type signingCertificateV2 struct {
Certs []essCertIDv2
}
Loading

0 comments on commit dd59b9e

Please sign in to comment.