Added support for RSASSA-PSS and RSAES-OAEP.
This commit is contained in:
parent
5f34d82562
commit
3f58f9a4b2
@ -14,12 +14,14 @@ It consists of the following packages
|
|||||||
- smime Secure/Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 [rfc5751-bis-12](https://tools.ietf.org/html/draft-ietf-lamps-rfc5751-bis-12) [![GoDoc](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/smime?status.svg)](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/smime)
|
- smime Secure/Multipurpose Internet Mail Extensions (S/MIME) Version 4.0 [rfc5751-bis-12](https://tools.ietf.org/html/draft-ietf-lamps-rfc5751-bis-12) [![GoDoc](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/smime?status.svg)](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/smime)
|
||||||
- timestamp<sup>[5]</sup> - Time-Stamp Protocol (TSP) [rfc3161](https://tools.ietf.org/html/rfc3161) [![GoDoc](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/timestamp?status.svg)](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/timestamp)
|
- timestamp<sup>[5]</sup> - Time-Stamp Protocol (TSP) [rfc3161](https://tools.ietf.org/html/rfc3161) [![GoDoc](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/timestamp?status.svg)](https://godoc.org/github.com/InfiniteLoopSpace/go_S-MIME/timestamp)
|
||||||
|
|
||||||
It supports enveloped data with AES in CBC mode. Decryption also works with (3)DES. Authenticated-Enveloped-Data Content Type is also supported with AES-GCM and ChaCha20-Poly1305.
|
It supports enveloped data with AES in CBC mode. Decryption also works with (3)DES. Authenticated-Enveloped-Data Content Type is also supported with AES-GCM and ChaCha20-Poly1305. Also RSAES-OAEP and RSASSA-PSS is supported.
|
||||||
|
|
||||||
This is covered in
|
This is covered in
|
||||||
- Cryptographic Message Syntax (CMS) Authenticated-Enveloped-Data Content Type [rfc5083](https://tools.ietf.org/html/rfc5083)
|
- Cryptographic Message Syntax (CMS) Authenticated-Enveloped-Data Content Type [rfc5083](https://tools.ietf.org/html/rfc5083)
|
||||||
- Using ChaCha20-Poly1305 Authenticated Encryption in the Cryptographic Message Syntax (CMS) [rfc8103](https://tools.ietf.org/html/rfc8103)
|
- Using ChaCha20-Poly1305 Authenticated Encryption in the Cryptographic Message Syntax (CMS) [rfc8103](https://tools.ietf.org/html/rfc8103)
|
||||||
- Using AES-CCM and AES-GCM Authenticated Encryption in the Cryptographic Message Syntax (CMS) [rfc5084](https://tools.ietf.org/html/rfc5084)
|
- Using AES-CCM and AES-GCM Authenticated Encryption in the Cryptographic Message Syntax (CMS) [rfc5084](https://tools.ietf.org/html/rfc5084)
|
||||||
|
- Use of the RSASSA-PSS Signature Algorithm in Cryptographic Message Syntax (CMS) [rfc4056](https://tools.ietf.org/html/rfc4056)
|
||||||
|
- Use of the RSAES-OAEP Key Transport Algorithm in the Cryptographic Message Syntax (CMS) [rfc3560](https://tools.ietf.org/html/rfc3560)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@ -53,8 +55,6 @@ plaintext, _ := SMIME.Verify(signedMsg)
|
|||||||
|
|
||||||
## Todo
|
## Todo
|
||||||
|
|
||||||
- Add S/MIME capabilities attributes
|
|
||||||
- Add ECDH for encryption and decryption
|
|
||||||
- Testing
|
- Testing
|
||||||
|
|
||||||
|
|
||||||
|
19
cms/cms.go
19
cms/cms.go
@ -23,6 +23,7 @@ type CMS struct {
|
|||||||
TimeStampServer string
|
TimeStampServer string
|
||||||
TimeStamp bool
|
TimeStamp bool
|
||||||
keyPairs []tls.Certificate
|
keyPairs []tls.Certificate
|
||||||
|
signedAttrs []protocol.Attribute
|
||||||
}
|
}
|
||||||
|
|
||||||
// New create a new instance of CMS with given keyPairs.
|
// New create a new instance of CMS with given keyPairs.
|
||||||
@ -54,6 +55,19 @@ func New(cert ...tls.Certificate) (cms *CMS, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddAttribute adds a attribute to signedAttrs which will be used for signing
|
||||||
|
func (cms *CMS) AddAttribute(attrType asn1.ObjectIdentifier, val interface{}) (err error) {
|
||||||
|
|
||||||
|
attr, err := protocol.NewAttribute(attrType, val)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cms.signedAttrs = append(cms.signedAttrs, attr)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Encrypt encrypts data for the recipients and returns DER-encoded ASN.1 ContentInfo.
|
// Encrypt encrypts data for the recipients and returns DER-encoded ASN.1 ContentInfo.
|
||||||
func (cms *CMS) Encrypt(data []byte, recipients []*x509.Certificate) (der []byte, err error) {
|
func (cms *CMS) Encrypt(data []byte, recipients []*x509.Certificate) (der []byte, err error) {
|
||||||
|
|
||||||
@ -160,7 +174,10 @@ func (cms *CMS) Sign(data []byte, detachedSignature ...bool) (der []byte, err er
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := range cms.keyPairs {
|
for i := range cms.keyPairs {
|
||||||
sd.AddSignerInfo(cms.keyPairs[i])
|
err = sd.AddSignerInfo(cms.keyPairs[i], cms.signedAttrs)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cms.TimeStamp {
|
if cms.TimeStamp {
|
||||||
|
@ -29,50 +29,78 @@ var (
|
|||||||
CommonName: "leaf.example.com",
|
CommonName: "leaf.example.com",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
leafPSS = intermediate.Issue(pki.Subject(pkix.Name{
|
||||||
|
CommonName: "leaf.example.com",
|
||||||
|
}), pki.SignatureAlgorithm(x509.SHA256WithRSAPSS))
|
||||||
|
|
||||||
ecKey, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
ecKey, _ = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||||
|
|
||||||
leafECC = intermediate.Issue(pki.Subject(pkix.Name{
|
leafECC = intermediate.Issue(pki.Subject(pkix.Name{
|
||||||
CommonName: "leaf.example.com",
|
CommonName: "leaf.example.com",
|
||||||
}), pki.PrivateKey(ecKey))
|
}), pki.PrivateKey(ecKey))
|
||||||
|
|
||||||
keyPair = tls.Certificate{
|
keyPairRSA = tls.Certificate{
|
||||||
Certificate: [][]byte{leaf.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
Certificate: [][]byte{leaf.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
||||||
PrivateKey: leaf.PrivateKey.(crypto.PrivateKey),
|
PrivateKey: leaf.PrivateKey.(crypto.PrivateKey),
|
||||||
Leaf: leaf.Certificate,
|
Leaf: leaf.Certificate,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyPairRSAPSS = tls.Certificate{
|
||||||
|
Certificate: [][]byte{leafPSS.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
||||||
|
PrivateKey: leafPSS.PrivateKey.(crypto.PrivateKey),
|
||||||
|
Leaf: leafPSS.Certificate,
|
||||||
|
}
|
||||||
|
|
||||||
keyPairECC = tls.Certificate{
|
keyPairECC = tls.Certificate{
|
||||||
Certificate: [][]byte{leafECC.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
Certificate: [][]byte{leafECC.Certificate.Raw, intermediate.Certificate.Raw, root.Certificate.Raw},
|
||||||
PrivateKey: leafECC.PrivateKey.(crypto.PrivateKey),
|
PrivateKey: leafECC.PrivateKey.(crypto.PrivateKey),
|
||||||
Leaf: leafECC.Certificate,
|
Leaf: leafECC.Certificate,
|
||||||
}
|
}
|
||||||
|
|
||||||
keyPairs = []tls.Certificate{}
|
keypair tls.Certificate
|
||||||
|
|
||||||
keyPairsOpenssl = []tls.Certificate{}
|
skipOpenssl = false
|
||||||
|
|
||||||
|
opensslSignOpts = []string{"-outform", "DER"}
|
||||||
|
|
||||||
|
opensslEncOpts = []string{"-outform", "DER"}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
|
// Test RSA
|
||||||
keyPairs = []tls.Certificate{keyPair, keyPairECC}
|
keypair = keyPairRSA
|
||||||
|
|
||||||
version, err := openssl.Openssl(nil, "version")
|
version, err := openssl.Openssl(nil, "version")
|
||||||
|
if err != nil {
|
||||||
if err == nil {
|
skipOpenssl = true
|
||||||
keyPairsOpenssl = append(keyPairsOpenssl, keyPair)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.Run()
|
||||||
|
|
||||||
|
// Test RSA PSS OAEP
|
||||||
|
keypair = keyPairRSAPSS
|
||||||
|
|
||||||
if strings.HasPrefix(string(version), "OpenSSL 1.1") {
|
if strings.HasPrefix(string(version), "OpenSSL 1.1") {
|
||||||
openssl.SMIME = "cms"
|
openssl.SMIME = "cms"
|
||||||
keyPairsOpenssl = append(keyPairsOpenssl, keyPairECC)
|
} else {
|
||||||
|
skipOpenssl = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opensslSignOpts = append(opensslSignOpts, "-keyopt", "rsa_padding_mode:pss")
|
||||||
|
opensslEncOpts = append(opensslEncOpts, "-keyopt", "rsa_padding_mode:oaep")
|
||||||
|
|
||||||
|
m.Run()
|
||||||
|
opensslSignOpts = []string{"-outform", "DER"}
|
||||||
|
opensslEncOpts = []string{"-outform", "DER"}
|
||||||
|
|
||||||
|
// Test ECDDSA
|
||||||
|
keypair = keyPairECC
|
||||||
|
|
||||||
m.Run()
|
m.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAuthEnrypt(t *testing.T) {
|
func TestAuthEnrypt(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairs {
|
|
||||||
cms, err := New(keypair)
|
cms, err := New(keypair)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@ -94,11 +122,9 @@ func TestAuthEnrypt(t *testing.T) {
|
|||||||
t.Fatal("Encryption and decryption are not inverse")
|
t.Fatal("Encryption and decryption are not inverse")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestEnryptDecrypt(t *testing.T) {
|
func TestEnryptDecrypt(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairs {
|
|
||||||
cms, err := New(keypair)
|
cms, err := New(keypair)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@ -119,12 +145,11 @@ func TestEnryptDecrypt(t *testing.T) {
|
|||||||
if !bytes.Equal(plaintext, plain) {
|
if !bytes.Equal(plaintext, plain) {
|
||||||
t.Fatal("Encryption and decryption are not inverse")
|
t.Fatal("Encryption and decryption are not inverse")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSignVerify(t *testing.T) {
|
func TestSignVerify(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairs {
|
|
||||||
cms, err := New(keypair)
|
cms, err := New(keypair)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@ -144,14 +169,16 @@ func TestSignVerify(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestEncryptOpenSSL(t *testing.T) {
|
func TestEncryptOpenSSL(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairsOpenssl {
|
if skipOpenssl {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
message := []byte("Hallo Welt!")
|
message := []byte("Hallo Welt!")
|
||||||
|
|
||||||
der, err := openssl.Encrypt(message, keypair.Leaf, "-outform", "DER")
|
der, err := openssl.Encrypt(message, keypair.Leaf, opensslEncOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -165,12 +192,15 @@ func TestEncryptOpenSSL(t *testing.T) {
|
|||||||
if !bytes.Equal(message, plain) {
|
if !bytes.Equal(message, plain) {
|
||||||
t.Fatal("Encryption and decryption are not inverse")
|
t.Fatal("Encryption and decryption are not inverse")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDecryptOpenSSL(t *testing.T) {
|
func TestDecryptOpenSSL(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairsOpenssl {
|
if skipOpenssl {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
message := []byte("Hallo Welt!")
|
message := []byte("Hallo Welt!")
|
||||||
|
|
||||||
cms, _ := New()
|
cms, _ := New()
|
||||||
@ -187,15 +217,18 @@ func TestDecryptOpenSSL(t *testing.T) {
|
|||||||
if !bytes.Equal(message, plain) {
|
if !bytes.Equal(message, plain) {
|
||||||
t.Fatal("Encryption and decryption are not inverse")
|
t.Fatal("Encryption and decryption are not inverse")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSignOpenSSL(t *testing.T) {
|
func TestSignOpenSSL(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairsOpenssl {
|
if skipOpenssl {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
message := []byte("Hallo Welt")
|
message := []byte("Hallo Welt")
|
||||||
|
|
||||||
sig, err := openssl.SignDetached(message, keypair.Leaf, keypair.PrivateKey, []*x509.Certificate{intermediate.Certificate}, "-outform", "DER")
|
sig, err := openssl.SignDetached(message, keypair.Leaf, keypair.PrivateKey, []*x509.Certificate{intermediate.Certificate}, opensslSignOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
@ -211,11 +244,13 @@ func TestSignOpenSSL(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyOpenSSL(t *testing.T) {
|
func TestVerifyOpenSSL(t *testing.T) {
|
||||||
|
|
||||||
for _, keypair := range keyPairsOpenssl {
|
if skipOpenssl {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
cms, err := New(keypair)
|
cms, err := New(keypair)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
@ -241,4 +276,3 @@ func TestVerifyOpenSSL(t *testing.T) {
|
|||||||
t.Fatal("Signed message and message do not agree!")
|
t.Fatal("Signed message and message do not agree!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
183
cms/protocol/pssoaep.go
Normal file
183
cms/protocol/pssoaep.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
oid "github.com/InfiniteLoopSpace/go_S-MIME/oid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type pssParameters struct {
|
||||||
|
Hash pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:0"`
|
||||||
|
MGF pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:1"`
|
||||||
|
SaltLength int `asn1:"optional,explicit,tag:2"`
|
||||||
|
TrailerField int `asn1:"optional,explicit,tag:3"` //,default:1"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
|
||||||
|
|
||||||
|
func newpssParameters(hash ...crypto.Hash) (param pssParameters, err error) {
|
||||||
|
|
||||||
|
// SHA1 is default value
|
||||||
|
if len(hash) == 1 && hash[0] == crypto.SHA1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var h asn1.ObjectIdentifier
|
||||||
|
|
||||||
|
if len(hash) == 0 {
|
||||||
|
h = oid.DigestAlgorithmSHA1
|
||||||
|
param.SaltLength = 20
|
||||||
|
param.TrailerField = 1
|
||||||
|
} else {
|
||||||
|
var ok bool
|
||||||
|
h, ok = oid.HashToDigestAlgorithm[hash[0]]
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("Unsupported hashfunction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hRV, err := RawValue(pkix.AlgorithmIdentifier{Algorithm: h})
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
param.Hash = pkix.AlgorithmIdentifier{Algorithm: h}
|
||||||
|
|
||||||
|
param.MGF = pkix.AlgorithmIdentifier{Algorithm: oidMGF1, Parameters: hRV}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is needed because CheckSignature uses PSSSaltLengthEqualsHash, if PSSSaltLengthAuto is used this code is not needed
|
||||||
|
func verfiyRSAPSS(cert x509.Certificate, signatureAlgorithm pkix.AlgorithmIdentifier, signedMessage, signature []byte) (err error) {
|
||||||
|
|
||||||
|
param, err := newpssParameters()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = asn1.Unmarshal(signatureAlgorithm.Parameters.FullBytes, ¶m)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !param.MGF.Algorithm.Equal(oidMGF1) {
|
||||||
|
err = errors.New("Mask generator funktion not supported; only MGF1 is supported")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hash := oid.DigestAlgorithmToHash[param.Hash.Algorithm.String()]
|
||||||
|
|
||||||
|
pssOpts := rsa.PSSOptions{SaltLength: param.SaltLength, Hash: hash}
|
||||||
|
|
||||||
|
h := hash.New()
|
||||||
|
h.Write(signedMessage)
|
||||||
|
digest := h.Sum(nil)
|
||||||
|
|
||||||
|
err = rsa.VerifyPSS(cert.PublicKey.(*rsa.PublicKey), hash, digest, signature, &pssOpts)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPSS(hash crypto.Hash, pub *rsa.PublicKey) (signatureAlgorithm pkix.AlgorithmIdentifier, opts *rsa.PSSOptions, err error) {
|
||||||
|
|
||||||
|
opts = &rsa.PSSOptions{Hash: hash}
|
||||||
|
|
||||||
|
pssParam, err := newpssParameters(hash)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pssParam.SaltLength = (pub.N.BitLen()+7)/8 - 2 - hash.Size() // https://golang.org/src/crypto/rsa/pss.go?s=6982:7095#L239
|
||||||
|
|
||||||
|
paramRV, err := RawValue(pssParam)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
signatureAlgorithm = pkix.AlgorithmIdentifier{Algorithm: oid.SignatureAlgorithmRSASSAPSS, Parameters: paramRV}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSAESOAEPparams ::= SEQUENCE {
|
||||||
|
// hashFunc [0] AlgorithmIdentifier DEFAULT sha1Identifier,
|
||||||
|
// maskGenFunc [1] AlgorithmIdentifier DEFAULT mgf1SHA1Identifier,
|
||||||
|
// pSourceFunc [2] AlgorithmIdentifier DEFAULT
|
||||||
|
// pSpecifiedEmptyIdentifier }
|
||||||
|
type RSAESOAEPparams struct {
|
||||||
|
HashFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:0"`
|
||||||
|
MaskGenFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:1"`
|
||||||
|
PSourceFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:2"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var oidpSpecified = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 9}
|
||||||
|
|
||||||
|
func newRSAESOAEPparams(hash ...crypto.Hash) (param RSAESOAEPparams, err error) {
|
||||||
|
|
||||||
|
// SHA1 is default value
|
||||||
|
if len(hash) == 1 && hash[0] == crypto.SHA1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
nullOctetString, err := RawValue([]byte{})
|
||||||
|
|
||||||
|
var h asn1.ObjectIdentifier
|
||||||
|
|
||||||
|
if len(hash) == 0 {
|
||||||
|
h = oid.DigestAlgorithmSHA1
|
||||||
|
} else {
|
||||||
|
var ok bool
|
||||||
|
h, ok = oid.HashToDigestAlgorithm[hash[0]]
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("Unsupported hashfunction")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hRV, err := RawValue(pkix.AlgorithmIdentifier{Algorithm: h})
|
||||||
|
|
||||||
|
param = RSAESOAEPparams{pkix.AlgorithmIdentifier{Algorithm: h, Parameters: asn1.NullRawValue},
|
||||||
|
pkix.AlgorithmIdentifier{Algorithm: oidMGF1, Parameters: hRV},
|
||||||
|
pkix.AlgorithmIdentifier{Algorithm: oidpSpecified, Parameters: nullOctetString}}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRSAESOAEPparams(param []byte) (opts *rsa.OAEPOptions, err error) {
|
||||||
|
var oaepOpts RSAESOAEPparams
|
||||||
|
oaepOpts, err = newRSAESOAEPparams()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = asn1.Unmarshal(param, &oaepOpts)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
opts = &rsa.OAEPOptions{Hash: oid.DigestAlgorithmToHash[oaepOpts.HashFunc.Algorithm.String()], Label: []byte{}}
|
||||||
|
|
||||||
|
if !oaepOpts.MaskGenFunc.Algorithm.Equal(oidMGF1) {
|
||||||
|
err = errors.New("Unsupported mask generation funktion" + oaepOpts.MaskGenFunc.Algorithm.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !oaepOpts.PSourceFunc.Algorithm.Equal(oidpSpecified) {
|
||||||
|
err = errors.New("Unsupported p source funktion" + oaepOpts.PSourceFunc.Algorithm.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRSAPSS(cert *x509.Certificate) bool {
|
||||||
|
switch cert.SignatureAlgorithm {
|
||||||
|
case x509.SHA256WithRSAPSS, x509.SHA384WithRSAPSS, x509.SHA512WithRSAPSS:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
@ -10,7 +10,6 @@ import (
|
|||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -34,7 +33,7 @@ type RecipientInfo struct {
|
|||||||
func (recInfo *RecipientInfo) decryptKey(keyPair tls.Certificate) (key []byte, err error) {
|
func (recInfo *RecipientInfo) decryptKey(keyPair tls.Certificate) (key []byte, err error) {
|
||||||
|
|
||||||
key, err = recInfo.KTRI.decryptKey(keyPair)
|
key, err = recInfo.KTRI.decryptKey(keyPair)
|
||||||
if key != nil {
|
if key != nil || (err != nil && err != ErrUnsupported) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +63,23 @@ func (ktri *KeyTransRecipientInfo) decryptKey(keyPair tls.Certificate) (key []by
|
|||||||
|
|
||||||
ski := keyPair.Leaf.SubjectKeyId
|
ski := keyPair.Leaf.SubjectKeyId
|
||||||
|
|
||||||
|
certPubAlg := oid.PublicKeyAlgorithmToEncrytionAlgorithm[keyPair.Leaf.PublicKeyAlgorithm].Algorithm
|
||||||
|
|
||||||
|
var decOpts crypto.DecrypterOpts
|
||||||
|
pkcs15CertwithOAEP := false
|
||||||
|
|
||||||
|
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(oid.EncryptionAlgorithmRSAESOAEP) {
|
||||||
|
|
||||||
|
if certPubAlg.Equal(oid.EncryptionAlgorithmRSA) {
|
||||||
|
pkcs15CertwithOAEP = true
|
||||||
|
}
|
||||||
|
|
||||||
|
decOpts, err = parseRSAESOAEPparams(ktri.KeyEncryptionAlgorithm.Parameters.FullBytes)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//version is the syntax version number. If the SignerIdentifier is
|
//version is the syntax version number. If the SignerIdentifier is
|
||||||
//the CHOICE issuerAndSerialNumber, then the version MUST be 1. If
|
//the CHOICE issuerAndSerialNumber, then the version MUST be 1. If
|
||||||
//the SignerIdentifier is subjectKeyIdentifier, then the version
|
//the SignerIdentifier is subjectKeyIdentifier, then the version
|
||||||
@ -71,28 +87,25 @@ func (ktri *KeyTransRecipientInfo) decryptKey(keyPair tls.Certificate) (key []by
|
|||||||
switch ktri.Version {
|
switch ktri.Version {
|
||||||
case 0:
|
case 0:
|
||||||
if ias.Equal(ktri.Rid.IAS) {
|
if ias.Equal(ktri.Rid.IAS) {
|
||||||
alg := oid.PublicKeyAlgorithmToEncrytionAlgorithm[keyPair.Leaf.PublicKeyAlgorithm].Algorithm
|
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(certPubAlg) || pkcs15CertwithOAEP {
|
||||||
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(alg) {
|
|
||||||
|
|
||||||
decrypter := keyPair.PrivateKey.(crypto.Decrypter)
|
decrypter := keyPair.PrivateKey.(crypto.Decrypter)
|
||||||
return decrypter.Decrypt(rand.Reader, ktri.EncryptedKey, nil)
|
return decrypter.Decrypt(rand.Reader, ktri.EncryptedKey, decOpts)
|
||||||
|
|
||||||
}
|
}
|
||||||
log.Println("Key encrytion algorithm not matching")
|
log.Println("Key encrytion algorithm not matching")
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
if bytes.Equal(ski, ktri.Rid.SKI) {
|
if bytes.Equal(ski, ktri.Rid.SKI) {
|
||||||
alg := oid.PublicKeyAlgorithmToEncrytionAlgorithm[keyPair.Leaf.PublicKeyAlgorithm].Algorithm
|
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(certPubAlg) || pkcs15CertwithOAEP {
|
||||||
if ktri.KeyEncryptionAlgorithm.Algorithm.Equal(alg) {
|
|
||||||
if alg.Equal(oid.EncryptionAlgorithmRSA) {
|
decrypter := keyPair.PrivateKey.(crypto.Decrypter)
|
||||||
return rsa.DecryptPKCS1v15(rand.Reader, keyPair.PrivateKey.(*rsa.PrivateKey), ktri.EncryptedKey)
|
return decrypter.Decrypt(rand.Reader, ktri.EncryptedKey, decOpts)
|
||||||
}
|
|
||||||
log.Println("Unsupported key encrytion algorithm")
|
|
||||||
}
|
}
|
||||||
log.Println("Key encrytion algorithm not matching")
|
log.Println("Key encrytion algorithm not matching")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fmt.Println(ktri.Version)
|
|
||||||
return nil, ErrUnsupported
|
return nil, ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,35 +122,15 @@ type RecipientIdentifier struct {
|
|||||||
|
|
||||||
// NewRecipientInfo creates RecipientInfo for giben recipient and key.
|
// NewRecipientInfo creates RecipientInfo for giben recipient and key.
|
||||||
func NewRecipientInfo(recipient *x509.Certificate, key []byte) (info RecipientInfo, err error) {
|
func NewRecipientInfo(recipient *x509.Certificate, key []byte) (info RecipientInfo, err error) {
|
||||||
version := 0 //issuerAndSerialNumber
|
|
||||||
|
|
||||||
rid := RecipientIdentifier{}
|
|
||||||
|
|
||||||
switch version {
|
|
||||||
case 0:
|
|
||||||
ias, err := NewIssuerAndSerialNumber(recipient)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
rid.IAS = ias
|
|
||||||
case 2:
|
|
||||||
rid.SKI = recipient.SubjectKeyId
|
|
||||||
}
|
|
||||||
|
|
||||||
switch recipient.PublicKeyAlgorithm {
|
switch recipient.PublicKeyAlgorithm {
|
||||||
case x509.RSA:
|
case x509.RSA:
|
||||||
var encrypted []byte
|
var ktri KeyTransRecipientInfo
|
||||||
encrypted, err = encryptKeyRSA(key, recipient)
|
ktri, err = encryptKeyRSA(key, recipient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
info = RecipientInfo{
|
info = RecipientInfo{KTRI: ktri}
|
||||||
KTRI: KeyTransRecipientInfo{
|
|
||||||
Version: version,
|
|
||||||
Rid: rid,
|
|
||||||
KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmRSA},
|
|
||||||
EncryptedKey: encrypted,
|
|
||||||
}}
|
|
||||||
case x509.ECDSA:
|
case x509.ECDSA:
|
||||||
var kari KeyAgreeRecipientInfo
|
var kari KeyAgreeRecipientInfo
|
||||||
kari, err = encryptKeyECDH(key, recipient)
|
kari, err = encryptKeyECDH(key, recipient)
|
||||||
@ -152,11 +145,47 @@ func NewRecipientInfo(recipient *x509.Certificate, key []byte) (info RecipientIn
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func encryptKeyRSA(key []byte, recipient *x509.Certificate) ([]byte, error) {
|
func encryptKeyRSA(key []byte, recipient *x509.Certificate) (ktri KeyTransRecipientInfo, err error) {
|
||||||
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
|
ktri.Version = 0 //issuerAndSerialNumber
|
||||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
|
||||||
|
switch ktri.Version {
|
||||||
|
case 0:
|
||||||
|
ias, err := NewIssuerAndSerialNumber(recipient)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
return nil, ErrUnsupportedAlgorithm
|
ktri.Rid.IAS = ias
|
||||||
|
case 2:
|
||||||
|
ktri.Rid.SKI = recipient.SubjectKeyId
|
||||||
|
}
|
||||||
|
|
||||||
|
if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
|
||||||
|
|
||||||
|
if isRSAPSS(recipient) {
|
||||||
|
hash := crypto.SHA256
|
||||||
|
var oaepparam RSAESOAEPparams
|
||||||
|
oaepparam, err = newRSAESOAEPparams(hash)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var oaepparamRV asn1.RawValue
|
||||||
|
oaepparamRV, err = RawValue(oaepparam)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ktri.KeyEncryptionAlgorithm = pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmRSAESOAEP, Parameters: oaepparamRV}
|
||||||
|
h := hash.New()
|
||||||
|
ktri.EncryptedKey, err = rsa.EncryptOAEP(h, rand.Reader, pub, key, nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ktri.KeyEncryptionAlgorithm = pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmRSA}
|
||||||
|
ktri.EncryptedKey, err = rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ErrUnsupportedAlgorithm
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrUnsupportedAlgorithm is returned if the algorithm is unsupported.
|
// ErrUnsupportedAlgorithm is returned if the algorithm is unsupported.
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
@ -106,7 +107,7 @@ func NewSignedData(eci EncapsulatedContentInfo) (*SignedData, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// AddSignerInfo adds a SignerInfo to the SignedData.
|
// AddSignerInfo adds a SignerInfo to the SignedData.
|
||||||
func (sd *SignedData) AddSignerInfo(keypPair tls.Certificate) (err error) {
|
func (sd *SignedData) AddSignerInfo(keypPair tls.Certificate, attrs []Attribute) (err error) {
|
||||||
|
|
||||||
for _, cert := range keypPair.Certificate {
|
for _, cert := range keypPair.Certificate {
|
||||||
if err = sd.AddCertificate(cert); err != nil {
|
if err = sd.AddCertificate(cert); err != nil {
|
||||||
@ -125,8 +126,13 @@ func (sd *SignedData) AddSignerInfo(keypPair tls.Certificate) (err error) {
|
|||||||
|
|
||||||
sid := SignerIdentifier{ias, nil}
|
sid := SignerIdentifier{ias, nil}
|
||||||
|
|
||||||
|
var signerOpts crypto.SignerOpts
|
||||||
digestAlgorithm := digestAlgorithmForPublicKey(cert.PublicKey)
|
digestAlgorithm := digestAlgorithmForPublicKey(cert.PublicKey)
|
||||||
signatureAlgorithm, ok := oid.PublicKeyAlgorithmToSignatureAlgorithm[keypPair.Leaf.PublicKeyAlgorithm]
|
signatureAlgorithm, ok := oid.PublicKeyAlgorithmToSignatureAlgorithm[keypPair.Leaf.PublicKeyAlgorithm]
|
||||||
|
if isRSAPSS(cert) {
|
||||||
|
h := oid.DigestAlgorithmToHash[digestAlgorithm.Algorithm.String()]
|
||||||
|
signatureAlgorithm, signerOpts, err = newPSS(h, cert.PublicKey.(*rsa.PublicKey))
|
||||||
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return errors.New("unsupported certificate public key algorithm")
|
return errors.New("unsupported certificate public key algorithm")
|
||||||
}
|
}
|
||||||
@ -155,6 +161,11 @@ func (sd *SignedData) AddSignerInfo(keypPair tls.Certificate) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !isRSAPSS(cert) {
|
||||||
|
signerOpts = hash
|
||||||
|
}
|
||||||
|
|
||||||
md := hash.New()
|
md := hash.New()
|
||||||
if _, err = md.Write(content); err != nil {
|
if _, err = md.Write(content); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -174,6 +185,7 @@ func (sd *SignedData) AddSignerInfo(keypPair tls.Certificate) (err error) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
si.SignedAttrs = append(si.SignedAttrs, mdAttr, ctAttr, sTAttr)
|
si.SignedAttrs = append(si.SignedAttrs, mdAttr, ctAttr, sTAttr)
|
||||||
|
si.SignedAttrs = append(si.SignedAttrs, attrs...)
|
||||||
|
|
||||||
sm, err := asn.MarshalWithParams(si.SignedAttrs, `set`)
|
sm, err := asn.MarshalWithParams(si.SignedAttrs, `set`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -184,7 +196,7 @@ func (sd *SignedData) AddSignerInfo(keypPair tls.Certificate) (err error) {
|
|||||||
if _, errr := smd.Write(sm); errr != nil {
|
if _, errr := smd.Write(sm); errr != nil {
|
||||||
return errr
|
return errr
|
||||||
}
|
}
|
||||||
if si.Signature, err = signer.Sign(rand.Reader, smd.Sum(nil), hash); err != nil {
|
if si.Signature, err = signer.Sign(rand.Reader, smd.Sum(nil), signerOpts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,7 +396,11 @@ func (sd *SignedData) Verify(Opts x509.VerifyOptions, detached []byte) (chains [
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
switch signer.SignatureAlgorithm.Algorithm.String() {
|
||||||
|
case oid.SignatureAlgorithmRSASSAPSS.String():
|
||||||
|
default:
|
||||||
err = cert.CheckSignature(sigAlg, signedMessage, signer.Signature)
|
err = cert.CheckSignature(sigAlg, signedMessage, signer.Signature)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ var (
|
|||||||
// Signature Algorithm OIDs
|
// Signature Algorithm OIDs
|
||||||
var (
|
var (
|
||||||
SignatureAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
SignatureAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||||
|
SignatureAlgorithmRSASSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
|
||||||
SignatureAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
SignatureAlgorithmECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||||
SignatureAlgorithmECDSAwithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
SignatureAlgorithmECDSAwithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||||
SignatureAlgorithmECDSAwithSHA224 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 1}
|
SignatureAlgorithmECDSAwithSHA224 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 1}
|
||||||
@ -40,6 +41,7 @@ var (
|
|||||||
// Public Key Encryption OIDs
|
// Public Key Encryption OIDs
|
||||||
var (
|
var (
|
||||||
EncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
EncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||||
|
EncryptionAlgorithmRSAESOAEP = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 7}
|
||||||
)
|
)
|
||||||
|
|
||||||
// Digest Algorithm OIDs
|
// Digest Algorithm OIDs
|
||||||
@ -133,6 +135,11 @@ var SignatureAlgorithms = map[string]map[string]x509.SignatureAlgorithm{
|
|||||||
DigestAlgorithmSHA384.String(): x509.SHA384WithRSA,
|
DigestAlgorithmSHA384.String(): x509.SHA384WithRSA,
|
||||||
DigestAlgorithmSHA512.String(): x509.SHA512WithRSA,
|
DigestAlgorithmSHA512.String(): x509.SHA512WithRSA,
|
||||||
},
|
},
|
||||||
|
SignatureAlgorithmRSASSAPSS.String(): map[string]x509.SignatureAlgorithm{
|
||||||
|
DigestAlgorithmSHA256.String(): x509.SHA256WithRSAPSS,
|
||||||
|
DigestAlgorithmSHA384.String(): x509.SHA384WithRSAPSS,
|
||||||
|
DigestAlgorithmSHA512.String(): x509.SHA512WithRSAPSS,
|
||||||
|
},
|
||||||
SignatureAlgorithmECDSA.String(): map[string]x509.SignatureAlgorithm{
|
SignatureAlgorithmECDSA.String(): map[string]x509.SignatureAlgorithm{
|
||||||
DigestAlgorithmSHA1.String(): x509.ECDSAWithSHA1,
|
DigestAlgorithmSHA1.String(): x509.ECDSAWithSHA1,
|
||||||
DigestAlgorithmSHA256.String(): x509.ECDSAWithSHA256,
|
DigestAlgorithmSHA256.String(): x509.ECDSAWithSHA256,
|
||||||
|
@ -25,8 +25,15 @@ func Encrypt(in []byte, cert *x509.Certificate, opts ...string) (der []byte, err
|
|||||||
pem.Encode(tmpKey, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
pem.Encode(tmpKey, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
|
||||||
|
|
||||||
param := []string{SMIME, "-encrypt", "-aes128"}
|
param := []string{SMIME, "-encrypt", "-aes128"}
|
||||||
|
if SMIME == "smime" {
|
||||||
|
// For smime arguments can not be passed after the keyfile
|
||||||
param = append(param, opts...)
|
param = append(param, opts...)
|
||||||
param = append(param, tmpKey.Name())
|
param = append(param, tmpKey.Name())
|
||||||
|
} else {
|
||||||
|
// Keyots have to be passed after the key
|
||||||
|
param = append(param, "-recip", tmpKey.Name())
|
||||||
|
param = append(param, opts...)
|
||||||
|
}
|
||||||
der, err = openssl(in, param...)
|
der, err = openssl(in, param...)
|
||||||
|
|
||||||
return
|
return
|
||||||
@ -76,9 +83,8 @@ func SignDetached(in []byte, cert *x509.Certificate, key crypto.PrivateKey, inte
|
|||||||
pem.Encode(tmpInterm, &pem.Block{Type: "CERTIFICATE", Bytes: i.Raw})
|
pem.Encode(tmpInterm, &pem.Block{Type: "CERTIFICATE", Bytes: i.Raw})
|
||||||
}
|
}
|
||||||
|
|
||||||
param := []string{SMIME, "-sign", "-nodetach"}
|
param := []string{SMIME, "-sign", "-nodetach", "-signer", tmpCert.Name(), "-inkey", tmpKey.Name(), "-certfile", tmpInterm.Name()}
|
||||||
param = append(param, opts...)
|
param = append(param, opts...)
|
||||||
param = append(param, []string{"-signer", tmpCert.Name(), "-inkey", tmpKey.Name(), "-certfile", tmpInterm.Name()}...)
|
|
||||||
plain, err = openssl(in, param...)
|
plain, err = openssl(in, param...)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
@ -22,6 +22,7 @@ type configuration struct {
|
|||||||
subject *pkix.Name
|
subject *pkix.Name
|
||||||
issuer *Identity
|
issuer *Identity
|
||||||
nextSN *int64
|
nextSN *int64
|
||||||
|
signatureAlgrotim x509.SignatureAlgorithm
|
||||||
priv *crypto.Signer
|
priv *crypto.Signer
|
||||||
isCA bool
|
isCA bool
|
||||||
notBefore *time.Time
|
notBefore *time.Time
|
||||||
@ -33,6 +34,7 @@ type configuration struct {
|
|||||||
func (c *configuration) generate() *Identity {
|
func (c *configuration) generate() *Identity {
|
||||||
templ := &x509.Certificate{
|
templ := &x509.Certificate{
|
||||||
Subject: c.getSubject(),
|
Subject: c.getSubject(),
|
||||||
|
SignatureAlgorithm: c.signatureAlgrotim,
|
||||||
IsCA: c.isCA,
|
IsCA: c.isCA,
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
NotAfter: c.getNotAfter(),
|
NotAfter: c.getNotAfter(),
|
||||||
@ -195,6 +197,13 @@ func PrivateKey(value crypto.Signer) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignatureAlgorithm is an Option for setting the signature algorithm.
|
||||||
|
func SignatureAlgorithm(value x509.SignatureAlgorithm) Option {
|
||||||
|
return func(c *configuration) {
|
||||||
|
c.signatureAlgrotim = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Issuer is an Option for setting the identity's issuer.
|
// Issuer is an Option for setting the identity's issuer.
|
||||||
func Issuer(value *Identity) Option {
|
func Issuer(value *Identity) Option {
|
||||||
return func(c *configuration) {
|
return func(c *configuration) {
|
||||||
|
@ -6,11 +6,15 @@ package smime
|
|||||||
import (
|
import (
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"crypto/x509/pkix"
|
||||||
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/InfiniteLoopSpace/go_S-MIME/oid"
|
||||||
|
|
||||||
"github.com/InfiniteLoopSpace/go_S-MIME/b64"
|
"github.com/InfiniteLoopSpace/go_S-MIME/b64"
|
||||||
|
|
||||||
cms "github.com/InfiniteLoopSpace/go_S-MIME/cms"
|
cms "github.com/InfiniteLoopSpace/go_S-MIME/cms"
|
||||||
@ -23,6 +27,26 @@ type SMIME struct {
|
|||||||
CMS *cms.CMS
|
CMS *cms.CMS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var oidsmimeCapabilities = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 15}
|
||||||
|
|
||||||
|
//SMIMECapability ::= SEQUENCE {
|
||||||
|
//capabilityID OBJECT IDENTIFIER,
|
||||||
|
//parameters ANY DEFINED BY capabilityID OPTIONAL }
|
||||||
|
|
||||||
|
//SMIMECapabilities ::= SEQUENCE OF SMIMECapability
|
||||||
|
|
||||||
|
func (smime *SMIME) addSMIMECapabilitesAttr() (err error) {
|
||||||
|
|
||||||
|
var smimeCapabilities []pkix.AlgorithmIdentifier
|
||||||
|
|
||||||
|
smimeCapabilities = append(smimeCapabilities, pkix.AlgorithmIdentifier{Algorithm: oid.EncryptionAlgorithmAES128CBC})
|
||||||
|
smimeCapabilities = append(smimeCapabilities, pkix.AlgorithmIdentifier{Algorithm: oid.AEADChaCha20Poly1305})
|
||||||
|
|
||||||
|
err = smime.CMS.AddAttribute(oidsmimeCapabilities, smimeCapabilities)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// New create a new instance of SMIME with given keyPairs.
|
// New create a new instance of SMIME with given keyPairs.
|
||||||
func New(keyPair ...tls.Certificate) (smime *SMIME, err error) {
|
func New(keyPair ...tls.Certificate) (smime *SMIME, err error) {
|
||||||
CMS, err := cms.New(keyPair...)
|
CMS, err := cms.New(keyPair...)
|
||||||
@ -31,6 +55,10 @@ func New(keyPair ...tls.Certificate) (smime *SMIME, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
smime = &SMIME{CMS}
|
smime = &SMIME{CMS}
|
||||||
|
err = smime.addSMIMECapabilitesAttr()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user