Added support for ECDH in enveloped data with ECDSA certificates.
- fixed parsing of choice(was compatible with Apple mail.app which tagged kari explicitly) - minor fixes
This commit is contained in:
12
cms/cms.go
12
cms/cms.go
@ -65,7 +65,11 @@ func (cms *CMS) Encrypt(data []byte, recipients []*x509.Certificate) (der []byte
|
||||
var reciInfos []protocol.RecipientInfo
|
||||
|
||||
for _, recipient := range recipients {
|
||||
rInfo := protocol.NewRecipientInfo(recipient, key)
|
||||
var rInfo protocol.RecipientInfo
|
||||
rInfo, err = protocol.NewRecipientInfo(recipient, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
reciInfos = append(reciInfos, rInfo)
|
||||
}
|
||||
|
||||
@ -90,7 +94,11 @@ func (cms *CMS) AuthEncrypt(data []byte, recipients []*x509.Certificate) (der []
|
||||
var reciInfos []protocol.RecipientInfo
|
||||
|
||||
for _, recipient := range recipients {
|
||||
rInfo := protocol.NewRecipientInfo(recipient, key)
|
||||
var rInfo protocol.RecipientInfo
|
||||
rInfo, err = protocol.NewRecipientInfo(recipient, key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
reciInfos = append(reciInfos, rInfo)
|
||||
}
|
||||
|
||||
|
253
cms/cms_test.go
253
cms/cms_test.go
@ -3,10 +3,13 @@ package cms
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"log"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
openssl "github.com/InfiniteLoopSpace/go_S-MIME/openssl"
|
||||
@ -26,162 +29,216 @@ var (
|
||||
CommonName: "leaf.example.com",
|
||||
}))
|
||||
|
||||
ecKey, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
|
||||
leafECC = intermediate.Issue(pki.Subject(pkix.Name{
|
||||
CommonName: "leaf.example.com",
|
||||
}), pki.PrivateKey(ecKey))
|
||||
|
||||
keyPair = tls.Certificate{
|
||||
Certificate: [][]byte{leaf.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
||||
PrivateKey: leaf.PrivateKey.(crypto.PrivateKey),
|
||||
Leaf: leaf.Certificate,
|
||||
}
|
||||
|
||||
keyPairECC = tls.Certificate{
|
||||
Certificate: [][]byte{leafECC.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
||||
PrivateKey: leafECC.PrivateKey.(crypto.PrivateKey),
|
||||
Leaf: leafECC.Certificate,
|
||||
}
|
||||
|
||||
keyPairs = []tls.Certificate{}
|
||||
|
||||
keyPairsOpenssl = []tls.Certificate{}
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
keyPairs = []tls.Certificate{keyPair, keyPairECC}
|
||||
|
||||
version, err := openssl.Openssl(nil, "version")
|
||||
|
||||
if err == nil {
|
||||
keyPairsOpenssl = append(keyPairsOpenssl, keyPair)
|
||||
}
|
||||
|
||||
if strings.HasPrefix(string(version), "OpenSSL 1.1") {
|
||||
openssl.SMIME = "cms"
|
||||
keyPairsOpenssl = append(keyPairsOpenssl, keyPairECC)
|
||||
}
|
||||
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestAuthEnrypt(t *testing.T) {
|
||||
|
||||
cms, err := New(keyPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, keypair := range keyPairs {
|
||||
cms, err := New(keypair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
plaintext := []byte("Hallo Welt!")
|
||||
plaintext := []byte("Hallo Welt!")
|
||||
|
||||
ciphertext, err := cms.AuthEncrypt(plaintext, []*x509.Certificate{leaf.Certificate})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ciphertext, err := cms.AuthEncrypt(plaintext, []*x509.Certificate{keypair.Leaf})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
plain, err := cms.AuthDecrypt(ciphertext)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
plain, err := cms.AuthDecrypt(ciphertext)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
if !bytes.Equal(plaintext, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnryptDecrypt(t *testing.T) {
|
||||
|
||||
cms, err := New(keyPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, keypair := range keyPairs {
|
||||
cms, err := New(keypair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
plaintext := []byte("Hallo Welt!")
|
||||
plaintext := []byte("Hallo Welt!")
|
||||
|
||||
ciphertext, err := cms.Encrypt(plaintext, []*x509.Certificate{leaf.Certificate})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ciphertext, err := cms.Encrypt(plaintext, []*x509.Certificate{keypair.Leaf})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
plain, err := cms.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
plain, err := cms.Decrypt(ciphertext)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(plaintext, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
if !bytes.Equal(plaintext, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignVerify(t *testing.T) {
|
||||
cms, err := New(keyPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cms.roots.AddCert(root.Certificate)
|
||||
for _, keypair := range keyPairs {
|
||||
cms, err := New(keypair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
msg := []byte("Hallo Welt!")
|
||||
cms.roots.AddCert(root.Certificate)
|
||||
|
||||
der, err := cms.Sign(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msg := []byte("Hallo Welt!")
|
||||
|
||||
_, err = cms.Verify(der)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
der, err := cms.Sign(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = cms.Verify(der)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncryptOpenSSL(t *testing.T) {
|
||||
message := []byte("Hallo Welt!")
|
||||
|
||||
der, err := openssl.Encrypt(message, leaf.Certificate, "-outform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, keypair := range keyPairsOpenssl {
|
||||
message := []byte("Hallo Welt!")
|
||||
|
||||
cms, err := New(keyPair)
|
||||
plain, err := cms.Decrypt(der)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
der, err := openssl.Encrypt(message, keypair.Leaf, "-outform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(message, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
cms, err := New(keypair)
|
||||
plain, err := cms.Decrypt(der)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(message, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecryptOpenSSL(t *testing.T) {
|
||||
message := []byte("Hallo Welt!")
|
||||
|
||||
cms, _ := New()
|
||||
ciphertext, err := cms.Encrypt(message, []*x509.Certificate{leaf.Certificate})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, keypair := range keyPairsOpenssl {
|
||||
message := []byte("Hallo Welt!")
|
||||
|
||||
plain, err := openssl.Decrypt(ciphertext, leaf.PrivateKey, "-inform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cms, _ := New()
|
||||
ciphertext, err := cms.Encrypt(message, []*x509.Certificate{keypair.Leaf})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(message, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
plain, err := openssl.Decrypt(ciphertext, keypair.PrivateKey, "-inform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(message, plain) {
|
||||
t.Fatal("Encryption and decryption are not inverse")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSignOpenSSL(t *testing.T) {
|
||||
message := []byte("Hallo Welt")
|
||||
|
||||
sig, err := openssl.SignDetached(message, leaf.Certificate, leaf.PrivateKey, []*x509.Certificate{intermediate.Certificate}, "-outform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
for _, keypair := range keyPairsOpenssl {
|
||||
message := []byte("Hallo Welt")
|
||||
|
||||
cms, err := New()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cms.roots.AddCert(root.Certificate)
|
||||
sig, err := openssl.SignDetached(message, keypair.Leaf, keypair.PrivateKey, []*x509.Certificate{intermediate.Certificate}, "-outform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = cms.Verify(sig)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
cms, err := New()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
cms.roots.AddCert(root.Certificate)
|
||||
|
||||
_, err = cms.Verify(sig)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerifyOpenSSL(t *testing.T) {
|
||||
cms, err := New(keyPair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cms.TimeStamp = true
|
||||
for _, keypair := range keyPairsOpenssl {
|
||||
cms, err := New(keypair)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
cms.roots.AddCert(root.Certificate)
|
||||
cms.TimeStamp = true
|
||||
|
||||
msg := []byte("Hallo Welt!")
|
||||
cms.roots.AddCert(root.Certificate)
|
||||
|
||||
der, err := cms.Sign(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
msg := []byte("Hallo Welt!")
|
||||
|
||||
sig, err := openssl.Verify(der, root.Certificate, "-inform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
der, err := cms.Sign(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(msg, sig) {
|
||||
t.Fatal("Signed message and message do not agree!")
|
||||
sig, err := openssl.Verify(der, root.Certificate, "-inform", "DER")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(msg, sig) {
|
||||
t.Fatal("Signed message and message do not agree!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
218
cms/protocol/ecdh.go
Normal file
218
cms/protocol/ecdh.go
Normal file
@ -0,0 +1,218 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/InfiniteLoopSpace/go_S-MIME/oid"
|
||||
)
|
||||
|
||||
var errUnsupported = errors.New("Unsupported hash function")
|
||||
|
||||
// ECDHsharedSecret computes shared secret with ephemeral static ECDH
|
||||
func ECDHsharedSecret(curve elliptic.Curve, priv []byte, pubX, pubY *big.Int) []byte {
|
||||
|
||||
x, _ := curve.ScalarMult(pubX, pubY, priv)
|
||||
|
||||
return x.Bytes()
|
||||
}
|
||||
|
||||
// ANSIx963KDF implents ANSI X9.63 key derivation function
|
||||
func ANSIx963KDF(sharedSecret, sharedInfo []byte, keyLen int, hash crypto.Hash) (key []byte, err error) {
|
||||
|
||||
ctr := make([]byte, 4)
|
||||
ctr[3] = 0x01
|
||||
if hash == 0 || !hash.Available() {
|
||||
return nil, errUnsupported
|
||||
}
|
||||
h := hash.New()
|
||||
|
||||
for i := 0; i < keyLen/hash.Size()+1; i++ {
|
||||
h.Reset()
|
||||
h.Write(sharedSecret)
|
||||
h.Write(ctr)
|
||||
h.Write(sharedInfo)
|
||||
key = append(key, h.Sum(nil)...)
|
||||
|
||||
// Increment counter
|
||||
for i := len(ctr) - 1; i >= 0; i-- {
|
||||
ctr[i]++
|
||||
if ctr[i] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return key[:keyLen], nil
|
||||
}
|
||||
|
||||
func encryptKeyECDH(key []byte, recipient *x509.Certificate) (kari KeyAgreeRecipientInfo, err error) {
|
||||
|
||||
keyWrapAlgorithm := oid.KeyWrap{KeyWrapAlgorithm: oid.AES128Wrap}
|
||||
keyEncryptionAlgorithm := oid.DHSinglePassstdDHsha256kdfscheme
|
||||
hash := oid.KDFHashAlgorithm[keyEncryptionAlgorithm.String()]
|
||||
|
||||
kari.UKM = make([]byte, 8)
|
||||
rand.Read(kari.UKM)
|
||||
|
||||
kari.Version = 3
|
||||
kari.Originator.OriginatorKey.Algorithm = pkix.AlgorithmIdentifier{Algorithm: oid.ECPublicKey}
|
||||
|
||||
// check recipient key
|
||||
|
||||
if recipient.PublicKeyAlgorithm != x509.ECDSA {
|
||||
err = errors.New("Recipient certficiate has wrong public key algorithm, expected ECDSA")
|
||||
return
|
||||
}
|
||||
|
||||
pubKey, ok := recipient.PublicKey.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
err = errors.New("Can not parse public key of recipient")
|
||||
return
|
||||
}
|
||||
|
||||
// genrate ephemeral public key and key encryption key
|
||||
|
||||
priv, x, y, err := elliptic.GenerateKey(pubKey.Curve, rand.Reader)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ephPubKey := elliptic.Marshal(pubKey.Curve, x, y)
|
||||
kari.Originator.OriginatorKey.PublicKey = asn1.BitString{Bytes: ephPubKey, BitLength: len(ephPubKey) * 8}
|
||||
|
||||
sharedSecret := ECDHsharedSecret(pubKey.Curve, priv, pubKey.X, pubKey.Y)
|
||||
|
||||
keyLenBigEnd := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(keyLenBigEnd, uint32(keyWrapAlgorithm.KeyLen())*8)
|
||||
sharedInfo := ECCCMSSharedInfo{KeyInfo: keyWrapAlgorithm.AlgorithmIdentifier(),
|
||||
SuppPubInfo: keyLenBigEnd,
|
||||
EntityUInfo: kari.UKM}
|
||||
|
||||
sharedInfoDER, err := asn1.Marshal(sharedInfo)
|
||||
|
||||
kek, err := ANSIx963KDF(sharedSecret, sharedInfoDER, keyWrapAlgorithm.KeyLen(), hash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// encrypt key
|
||||
|
||||
keyWrapAlgorithm.KEK = kek
|
||||
encKey, err := keyWrapAlgorithm.Wrap(key)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
keyWrapAlgorithmIdentifier, err := RawValue(keyWrapAlgorithm.AlgorithmIdentifier())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
kari.KeyEncryptionAlgorithm = pkix.AlgorithmIdentifier{Algorithm: keyEncryptionAlgorithm,
|
||||
Parameters: keyWrapAlgorithmIdentifier}
|
||||
|
||||
ias, err := NewIssuerAndSerialNumber(recipient)
|
||||
karID := KeyAgreeRecipientIdentifier{IAS: ias}
|
||||
|
||||
kari.RecipientEncryptedKeys = append(kari.RecipientEncryptedKeys, RecipientEncryptedKey{RID: karID, EncryptedKey: encKey})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ECCCMSSharedInfo ECC-CMS-SharedInfo ::= SEQUENCE {
|
||||
// keyInfo AlgorithmIdentifier,
|
||||
// entityUInfo [0] EXPLICIT OCTET STRING OPTIONAL,
|
||||
// suppPubInfo [2] EXPLICIT OCTET STRING }
|
||||
type ECCCMSSharedInfo struct {
|
||||
KeyInfo pkix.AlgorithmIdentifier
|
||||
EntityUInfo []byte `asn1:"optional,explicit,tag:0"`
|
||||
SuppPubInfo []byte `asn1:"explicit,tag:2"`
|
||||
}
|
||||
|
||||
func (kari *KeyAgreeRecipientInfo) decryptKey(keyPair tls.Certificate) (key []byte, err error) {
|
||||
|
||||
// check for ec key
|
||||
|
||||
if kari.Version != 3 {
|
||||
err = errors.New("Version not supported")
|
||||
return
|
||||
}
|
||||
|
||||
if !kari.Originator.OriginatorKey.Algorithm.Algorithm.Equal(oid.ECPublicKey) {
|
||||
err = errors.New("Orginator key algorithm not supported")
|
||||
return
|
||||
}
|
||||
|
||||
pubKey, ok := keyPair.Leaf.PublicKey.(*ecdsa.PublicKey)
|
||||
if !ok {
|
||||
err = errors.New("Can not parse public key of recipient")
|
||||
return
|
||||
}
|
||||
|
||||
x, y := elliptic.Unmarshal(pubKey.Curve, kari.Originator.OriginatorKey.PublicKey.Bytes)
|
||||
|
||||
// genrate ephemeral public key and key encryption key
|
||||
|
||||
priv := keyPair.PrivateKey.(*ecdsa.PrivateKey)
|
||||
|
||||
privateKeyBytes := keyPair.PrivateKey.(*ecdsa.PrivateKey).D.Bytes()
|
||||
paddedPrivateKey := make([]byte, (priv.Curve.Params().N.BitLen()+7)/8)
|
||||
copy(paddedPrivateKey[len(paddedPrivateKey)-len(privateKeyBytes):], privateKeyBytes)
|
||||
|
||||
sharedSecret := ECDHsharedSecret(pubKey.Curve, paddedPrivateKey, x, y)
|
||||
|
||||
hash, ok := oid.KDFHashAlgorithm[kari.KeyEncryptionAlgorithm.Algorithm.String()]
|
||||
if !ok {
|
||||
err = errors.New("Unsupported key derivation hash algorithm")
|
||||
return
|
||||
}
|
||||
|
||||
var keyWrapAlgorithmIdentifier pkix.AlgorithmIdentifier
|
||||
asn1.Unmarshal(kari.KeyEncryptionAlgorithm.Parameters.FullBytes, &keyWrapAlgorithmIdentifier)
|
||||
keyWrapAlgorithm := oid.KeyWrap{KeyWrapAlgorithm: keyWrapAlgorithmIdentifier.Algorithm}
|
||||
|
||||
//
|
||||
|
||||
keyLenBigEnd := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(keyLenBigEnd, uint32(keyWrapAlgorithm.KeyLen())*8)
|
||||
sharedInfo := ECCCMSSharedInfo{KeyInfo: keyWrapAlgorithmIdentifier,
|
||||
SuppPubInfo: keyLenBigEnd,
|
||||
EntityUInfo: kari.UKM}
|
||||
|
||||
sharedInfoDER, err := asn1.Marshal(sharedInfo)
|
||||
|
||||
kek, err := ANSIx963KDF(sharedSecret, sharedInfoDER, keyWrapAlgorithm.KeyLen(), hash)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
keyWrapAlgorithm.KEK = kek
|
||||
|
||||
// encrypt key
|
||||
|
||||
ias, err := NewIssuerAndSerialNumber(keyPair.Leaf)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range kari.RecipientEncryptedKeys {
|
||||
if kari.RecipientEncryptedKeys[i].RID.IAS.Equal(ias) {
|
||||
key, err = keyWrapAlgorithm.UnWrap(kari.RecipientEncryptedKeys[i].EncryptedKey)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = ErrNoKeyFound
|
||||
|
||||
return
|
||||
}
|
@ -58,7 +58,7 @@ func (ed *EnvelopedData) decryptKey(keyPair tls.Certificate) (key []byte, err er
|
||||
for i := range ed.RecipientInfos {
|
||||
|
||||
key, err = ed.RecipientInfos[i].decryptKey(keyPair)
|
||||
if key != nil {
|
||||
if key != nil || err != ErrNoKeyFound {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -33,8 +33,14 @@ type RecipientInfo struct {
|
||||
|
||||
func (recInfo *RecipientInfo) decryptKey(keyPair tls.Certificate) (key []byte, err error) {
|
||||
|
||||
return recInfo.KTRI.decryptKey(keyPair)
|
||||
key, err = recInfo.KTRI.decryptKey(keyPair)
|
||||
if key != nil {
|
||||
return
|
||||
}
|
||||
|
||||
key, err = recInfo.KARI.decryptKey(keyPair)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
//KeyTransRecipientInfo ::= SEQUENCE {
|
||||
@ -102,7 +108,7 @@ type RecipientIdentifier struct {
|
||||
}
|
||||
|
||||
// NewRecipientInfo creates RecipientInfo for giben recipient and key.
|
||||
func NewRecipientInfo(recipient *x509.Certificate, key []byte) RecipientInfo {
|
||||
func NewRecipientInfo(recipient *x509.Certificate, key []byte) (info RecipientInfo, err error) {
|
||||
version := 0 //issuerAndSerialNumber
|
||||
|
||||
rid := RecipientIdentifier{}
|
||||
@ -118,24 +124,35 @@ func NewRecipientInfo(recipient *x509.Certificate, key []byte) RecipientInfo {
|
||||
rid.SKI = recipient.SubjectKeyId
|
||||
}
|
||||
|
||||
kea := oid.PublicKeyAlgorithmToEncrytionAlgorithm[recipient.PublicKeyAlgorithm]
|
||||
if _, ok := oid.PublicKeyAlgorithmToEncrytionAlgorithm[recipient.PublicKeyAlgorithm]; !ok {
|
||||
log.Fatal("NewRecipientInfo: PublicKeyAlgorithm not supported")
|
||||
switch recipient.PublicKeyAlgorithm {
|
||||
case x509.RSA:
|
||||
var encrypted []byte
|
||||
encrypted, err = encryptKeyRSA(key, recipient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
info = RecipientInfo{
|
||||
KTRI: KeyTransRecipientInfo{
|
||||
Version: version,
|
||||
Rid: rid,
|
||||
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmRSA},
|
||||
EncryptedKey: encrypted,
|
||||
}}
|
||||
case x509.ECDSA:
|
||||
var kari KeyAgreeRecipientInfo
|
||||
kari, err = encryptKeyECDH(key, recipient)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
info = RecipientInfo{KARI: kari}
|
||||
default:
|
||||
err = errors.New("Public key algorithm not supported")
|
||||
}
|
||||
|
||||
encrypted, _ := encryptKey(key, recipient)
|
||||
|
||||
info := RecipientInfo{
|
||||
KTRI: KeyTransRecipientInfo{
|
||||
Version: version,
|
||||
Rid: rid,
|
||||
KeyEncryptionAlgorithm: kea,
|
||||
EncryptedKey: encrypted,
|
||||
}}
|
||||
return info
|
||||
return
|
||||
}
|
||||
|
||||
func encryptKey(key []byte, recipient *x509.Certificate) ([]byte, error) {
|
||||
func encryptKeyRSA(key []byte, recipient *x509.Certificate) ([]byte, error) {
|
||||
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
|
||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||
}
|
||||
|
@ -379,8 +379,12 @@ func (sd *SignedData) Verify(Opts x509.VerifyOptions, detached []byte) (chains [
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
err = cert.CheckSignature(signer.X509SignatureAlgorithm(), signedMessage, signer.Signature)
|
||||
var sigAlg x509.SignatureAlgorithm
|
||||
sigAlg, err = signer.X509SignatureAlgorithm()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = cert.CheckSignature(sigAlg, signedMessage, signer.Signature)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
asn "github.com/InfiniteLoopSpace/go_S-MIME/asn1"
|
||||
@ -83,13 +84,18 @@ func (si SignerInfo) Hash() (crypto.Hash, error) {
|
||||
|
||||
// X509SignatureAlgorithm gets the x509.SignatureAlgorithm that should be used
|
||||
// for verifying this SignerInfo's signature.
|
||||
func (si SignerInfo) X509SignatureAlgorithm() x509.SignatureAlgorithm {
|
||||
func (si SignerInfo) X509SignatureAlgorithm() (sigAlg x509.SignatureAlgorithm, err error) {
|
||||
var (
|
||||
sigOID = si.SignatureAlgorithm.Algorithm.String()
|
||||
digestOID = si.DigestAlgorithm.Algorithm.String()
|
||||
)
|
||||
sigAlg, ok := oid.SignatureAlgorithms[sigOID][digestOID]
|
||||
|
||||
return oid.SignatureAlgorithms[sigOID][digestOID]
|
||||
if !ok {
|
||||
err = fmt.Errorf("Signature algorithm with OID %s in combination with digest with OID %s not supported", sigOID, digestOID)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// GetContentTypeAttribute gets the signed ContentType attribute from the
|
||||
|
Reference in New Issue
Block a user