in ietf-cms/protocol/protocol.go [628:738]
func (sd *SignedData) AddSignerInfo(chain []*x509.Certificate, signer crypto.Signer) error {
// figure out which certificate is associated with signer.
pub, err := x509.MarshalPKIXPublicKey(signer.Public())
if err != nil {
return err
}
var (
cert *x509.Certificate
certPub []byte
)
for _, c := range chain {
if err = sd.AddCertificate(c); err != nil {
return err
}
if certPub, err = x509.MarshalPKIXPublicKey(c.PublicKey); err != nil {
return err
}
if bytes.Equal(pub, certPub) {
cert = c
}
}
if cert == nil {
return ErrNoCertificate
}
sid, err := NewIssuerAndSerialNumber(cert)
if err != nil {
return err
}
digestAlgorithmID := digestAlgorithmForPublicKey(pub)
signatureAlgorithmOID, ok := oid.X509PublicKeyAndDigestAlgorithmToSignatureAlgorithm[cert.PublicKeyAlgorithm][digestAlgorithmID.Algorithm.String()]
if !ok {
return errors.New("unsupported certificate public key algorithm")
}
signatureAlgorithmID := pkix.AlgorithmIdentifier{Algorithm: signatureAlgorithmOID}
si := SignerInfo{
Version: 1,
SID: sid,
DigestAlgorithm: digestAlgorithmID,
SignedAttrs: nil,
SignatureAlgorithm: signatureAlgorithmID,
Signature: nil,
UnsignedAttrs: nil,
}
// Get the message
content, err := sd.EncapContentInfo.EContentValue()
if err != nil {
return err
}
if content == nil {
return errors.New("already detached")
}
// Digest the message.
hash, err := si.Hash()
if err != nil {
return err
}
md := hash.New()
if _, err = md.Write(content); err != nil {
return err
}
// Build our SignedAttributes
stAttr, err := NewAttribute(oid.AttributeSigningTime, time.Now().UTC())
if err != nil {
return err
}
mdAttr, err := NewAttribute(oid.AttributeMessageDigest, md.Sum(nil))
if err != nil {
return err
}
ctAttr, err := NewAttribute(oid.AttributeContentType, sd.EncapContentInfo.EContentType)
if err != nil {
return err
}
// sort attributes to match required order in marshaled form
si.SignedAttrs, err = sortAttributes(stAttr, mdAttr, ctAttr)
if err != nil {
return err
}
// Signature is over the marshaled signed attributes
sm, err := si.SignedAttrs.MarshaledForSigning()
if err != nil {
return err
}
smd := hash.New()
if _, errr := smd.Write(sm); errr != nil {
return errr
}
if si.Signature, err = signer.Sign(rand.Reader, smd.Sum(nil), hash); err != nil {
return err
}
sd.addDigestAlgorithm(si.DigestAlgorithm)
sd.SignerInfos = append(sd.SignerInfos, si)
return nil
}