Add underlining support for the PKI Enterprise SCEP work (#29604)

This commit is contained in:
Steven Clark
2025-02-13 10:54:18 -05:00
committed by GitHub
parent fe576994a4
commit ce8094fb6c
8 changed files with 356 additions and 77 deletions

View File

@@ -62,59 +62,10 @@ var (
endWildRegex = labelRegex + `\*`
middleWildRegex = labelRegex + `\*` + labelRegex
leftWildLabelRegex = regexp.MustCompile(`^(` + allWildRegex + `|` + startWildRegex + `|` + endWildRegex + `|` + middleWildRegex + `)$`)
// Cloned from https://github.com/golang/go/blob/82c713feb05da594567631972082af2fcba0ee4f/src/crypto/x509/x509.go#L327-L379
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
signatureAlgorithmDetails = []struct {
algo x509.SignatureAlgorithm
name string
oid asn1.ObjectIdentifier
pubKeyAlgo x509.PublicKeyAlgorithm
hash crypto.Hash
}{
{x509.MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, x509.RSA, crypto.Hash(0) /* no value for MD2 */},
{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, x509.RSA, crypto.MD5},
{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, x509.RSA, crypto.SHA1},
{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, x509.RSA, crypto.SHA256},
{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, x509.RSA, crypto.SHA384},
{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, x509.RSA, crypto.SHA512},
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA256},
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA384},
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, x509.RSA, crypto.SHA512},
{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, x509.DSA, crypto.SHA1},
{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, x509.DSA, crypto.SHA256},
{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, x509.ECDSA, crypto.SHA1},
{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, x509.ECDSA, crypto.SHA256},
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
{x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */},
}
)
func doesPublicKeyAlgoMatchSignatureAlgo(pubKey x509.PublicKeyAlgorithm, algo x509.SignatureAlgorithm) bool {
for _, detail := range signatureAlgorithmDetails {
if detail.algo == algo {
return pubKey == detail.pubKeyAlgo
}
}
return false
return issuing.DoesPublicKeyAlgoMatchSignatureAlgo(pubKey, algo)
}
func getFormat(data *framework.FieldData) string {

View File

@@ -0,0 +1,162 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package issuing
import (
"crypto"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
)
// DER encoded RSA PSS parameters for the
// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
// The parameters contain the following values:
// - hashAlgorithm contains the associated hash identifier with NULL parameters
// - maskGenAlgorithm always contains the default mgf1SHA1 identifier
// - saltLength contains the length of the associated hash
// - trailerField always contains the default trailerFieldBC value
var (
pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}}
pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}}
pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}}
)
var (
emptyRawValue = asn1.RawValue{}
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
signatureAlgorithmDetails = []struct {
algo x509.SignatureAlgorithm
name string
oid asn1.ObjectIdentifier
params asn1.RawValue
pubKeyAlgo x509.PublicKeyAlgorithm
hash crypto.Hash
isRSAPSS bool
}{
{x509.MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, x509.RSA, crypto.MD5, false},
{x509.SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, x509.RSA, crypto.SHA1, false},
{x509.SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, x509.RSA, crypto.SHA1, false},
{x509.SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, x509.RSA, crypto.SHA256, false},
{x509.SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, x509.RSA, crypto.SHA384, false},
{x509.SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, x509.RSA, crypto.SHA512, false},
{x509.SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, x509.RSA, crypto.SHA256, true},
{x509.SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, x509.RSA, crypto.SHA384, true},
{x509.SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, x509.RSA, crypto.SHA512, true},
{x509.DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, x509.DSA, crypto.SHA1, false},
{x509.DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, x509.DSA, crypto.SHA256, false},
{x509.ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, x509.ECDSA, crypto.SHA1, false},
{x509.ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, x509.ECDSA, crypto.SHA256, false},
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, x509.ECDSA, crypto.SHA384, false},
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, x509.ECDSA, crypto.SHA512, false},
{x509.PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */, false},
}
)
// SigningParamsForKey returns the signature algorithm and its Algorithm
// Identifier to use for signing, based on the key type. If sigAlgo is not zero
// then it overrides the default.
// This function is copied from crypto/x509/x509.go in the Go standard library.
func SigningParamsForKey(key crypto.Signer, sigAlgo x509.SignatureAlgorithm) (x509.SignatureAlgorithm, pkix.AlgorithmIdentifier, error) {
var ai pkix.AlgorithmIdentifier
var pubType x509.PublicKeyAlgorithm
var defaultAlgo x509.SignatureAlgorithm
switch pub := key.Public().(type) {
case *rsa.PublicKey:
pubType = x509.RSA
defaultAlgo = x509.SHA256WithRSA
case *ecdsa.PublicKey:
pubType = x509.ECDSA
switch pub.Curve {
case elliptic.P224(), elliptic.P256():
defaultAlgo = x509.ECDSAWithSHA256
case elliptic.P384():
defaultAlgo = x509.ECDSAWithSHA384
case elliptic.P521():
defaultAlgo = x509.ECDSAWithSHA512
default:
return 0, ai, errors.New("x509: unsupported elliptic curve")
}
case ed25519.PublicKey:
pubType = x509.Ed25519
defaultAlgo = x509.PureEd25519
default:
return 0, ai, errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
}
if sigAlgo == 0 {
sigAlgo = defaultAlgo
}
for _, details := range signatureAlgorithmDetails {
if details.algo == sigAlgo {
if details.pubKeyAlgo != pubType {
return 0, ai, errors.New("x509: requested SignatureAlgorithm does not match private key type")
}
if details.hash == crypto.MD5 {
return 0, ai, errors.New("x509: signing with MD5 is not supported")
}
return sigAlgo, pkix.AlgorithmIdentifier{
Algorithm: details.oid,
Parameters: details.params,
}, nil
}
}
return 0, ai, errors.New("x509: unknown SignatureAlgorithm")
}
func DoesPublicKeyAlgoMatchSignatureAlgo(pubKey x509.PublicKeyAlgorithm, algo x509.SignatureAlgorithm) bool {
for _, detail := range signatureAlgorithmDetails {
if detail.algo == algo {
return pubKey == detail.pubKeyAlgo
}
}
return false
}
func IsRSAPSS(algo x509.SignatureAlgorithm) bool {
for _, details := range signatureAlgorithmDetails {
if details.algo == algo {
return details.isRSAPSS
}
}
return false
}
func HashFunc(algo x509.SignatureAlgorithm) crypto.Hash {
for _, details := range signatureAlgorithmDetails {
if details.algo == algo {
return details.hash
}
}
return crypto.Hash(0)
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package parsing
import "encoding/asn1"
// Asn1UnmarshallNoTrailing is a wrapper around asn1.Unmarshal that ensures there
// is no trailing data in the input returning an error if there is.
func Asn1UnmarshallNoTrailing(b []byte, val any) error {
rest, err := asn1.Unmarshal(b, val)
if err != nil {
return err
} else if len(rest) != 0 {
return asn1.SyntaxError{Msg: "trailing data"}
}
return nil
}

View File

@@ -0,0 +1,52 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package parsing
import (
"testing"
"github.com/google/certificate-transparency-go/asn1"
"github.com/stretchr/testify/require"
)
// TestAsn1UnmarshallNoTrailing tests the Asn1UnmarshallNoTrailing function returns
// errors as we expect if the input is not marshalled correctly or there is trailing
// data.
func TestAsn1UnmarshallNoTrailing(t *testing.T) {
stringToMarshal := "a string"
marshal, err := asn1.Marshal(stringToMarshal)
require.NoError(t, err, "marshal failed")
var myTestString string
type args struct {
b []byte
val any
}
tests := []struct {
name string
args args
wantErr bool
}{
{"happy-path", args{marshal, &myTestString}, false},
{"bad-marshalling", args{[]byte("incorrect"), &myTestString}, true},
{"trailing-data", args{append(marshal, []byte("\n")...), &myTestString}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
myTestString = ""
err := Asn1UnmarshallNoTrailing(tt.args.b, tt.args.val)
if (err != nil) != tt.wantErr {
t.Errorf("Asn1UnmarshallNoTrailing() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.wantErr {
if myTestString != stringToMarshal {
t.Errorf("Asn1UnmarshallNoTrailing() = %v, want %v", myTestString, stringToMarshal)
}
}
})
}
}

View File

@@ -52,15 +52,40 @@ func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error) {
return data.EncryptedContentInfo.decrypt(key)
}
func (p7 *PKCS7) GetEncryptionAlgo() (int, error) {
data, ok := p7.raw.(envelopedData)
if !ok {
return -1, ErrNotEncryptedContent
}
alg := data.EncryptedContentInfo.ContentEncryptionAlgorithm.Algorithm
return encryptedAlgoOidToConstant(alg)
}
// convert the Encrypted Algorithm OID to our internal constants for Encryption Algorithms
func encryptedAlgoOidToConstant(alg asn1.ObjectIdentifier) (int, error) {
switch {
case alg.Equal(OIDEncryptionAlgorithmDESCBC):
return EncryptionAlgorithmDESCBC, nil
case alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC):
return EncryptionAlgorithmDESEDE3CBC, nil
case alg.Equal(OIDEncryptionAlgorithmAES128CBC):
return EncryptionAlgorithmAES128CBC, nil
case alg.Equal(OIDEncryptionAlgorithmAES256CBC):
return EncryptionAlgorithmAES256CBC, nil
case alg.Equal(OIDEncryptionAlgorithmAES128GCM):
return EncryptionAlgorithmAES128GCM, nil
case alg.Equal(OIDEncryptionAlgorithmAES256GCM):
return EncryptionAlgorithmAES256GCM, nil
default:
return -1, ErrUnsupportedAlgorithm
}
}
func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
alg := eci.ContentEncryptionAlgorithm.Algorithm
if !alg.Equal(OIDEncryptionAlgorithmDESCBC) &&
!alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC) &&
!alg.Equal(OIDEncryptionAlgorithmAES256CBC) &&
!alg.Equal(OIDEncryptionAlgorithmAES128CBC) &&
!alg.Equal(OIDEncryptionAlgorithmAES128GCM) &&
!alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
return nil, ErrUnsupportedAlgorithm
if _, err := encryptedAlgoOidToConstant(alg); err != nil {
return nil, err
}
// EncryptedContent can either be constructed of multple OCTET STRINGs

View File

@@ -55,6 +55,9 @@ const (
// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
EncryptionAlgorithmAES256GCM
// EncryptionAlgorithmDESEDE3CBC is the 3DES CBC encryption algorithm (currently only supported on decrypt)
EncryptionAlgorithmDESEDE3CBC
)
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
@@ -77,10 +80,10 @@ type aesGCMParameters struct {
ICVLen int
}
func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
func encryptAESGCM(content []byte, key []byte, algo int) ([]byte, *encryptedContentInfo, error) {
var keyLen int
var algID asn1.ObjectIdentifier
switch ContentEncryptionAlgorithm {
switch algo {
case EncryptionAlgorithmAES128GCM:
keyLen = 16
algID = OIDEncryptionAlgorithmAES128GCM
@@ -88,7 +91,7 @@ func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
keyLen = 32
algID = OIDEncryptionAlgorithmAES256GCM
default:
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESGCM: %d", ContentEncryptionAlgorithm)
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESGCM: %d", algo)
}
if key == nil {
// Create AES key
@@ -147,10 +150,23 @@ func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
return key, &eci, nil
}
func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
func encryptDESCBC(content []byte, key []byte, algo int) ([]byte, *encryptedContentInfo, error) {
var keyLen int
var algID asn1.ObjectIdentifier
switch algo {
case EncryptionAlgorithmDESCBC:
keyLen = 8
algID = OIDEncryptionAlgorithmDESCBC
case EncryptionAlgorithmDESEDE3CBC:
keyLen = 24
algID = OIDEncryptionAlgorithmDESEDE3CBC
default:
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptDESCBC: %d", algo)
}
if key == nil {
// Create DES key
key = make([]byte, 8)
// Create our key
key = make([]byte, keyLen)
_, err := rand.Read(key)
if err != nil {
@@ -166,9 +182,20 @@ func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
}
// Encrypt padded content
block, err := des.NewCipher(key)
if err != nil {
return nil, nil, err
var block cipher.Block
switch algo {
case EncryptionAlgorithmDESCBC:
block, err = des.NewCipher(key)
if err != nil {
return nil, nil, err
}
case EncryptionAlgorithmDESEDE3CBC:
block, err = des.NewTripleDESCipher(key)
if err != nil {
return nil, nil, err
}
default:
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptDESCBC: %d", algo)
}
mode := cipher.NewCBCEncrypter(block, iv)
plaintext, err := pad(content, mode.BlockSize())
@@ -182,7 +209,7 @@ func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
eci := encryptedContentInfo{
ContentType: OIDData,
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
Algorithm: OIDEncryptionAlgorithmDESCBC,
Algorithm: algID,
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
},
EncryptedContent: marshalEncryptedContent(cyphertext),
@@ -191,10 +218,10 @@ func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
return key, &eci, nil
}
func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
func encryptAESCBC(content []byte, key []byte, algo int) ([]byte, *encryptedContentInfo, error) {
var keyLen int
var algID asn1.ObjectIdentifier
switch ContentEncryptionAlgorithm {
switch algo {
case EncryptionAlgorithmAES128CBC:
keyLen = 16
algID = OIDEncryptionAlgorithmAES128CBC
@@ -202,7 +229,7 @@ func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
keyLen = 32
algID = OIDEncryptionAlgorithmAES256CBC
default:
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESCBC: %d", ContentEncryptionAlgorithm)
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESCBC: %d", algo)
}
if key == nil {
@@ -260,22 +287,38 @@ func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
//
// TODO(fullsailor): Add support for encrypting content with other algorithms
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
return EncryptWithAlgo(content, recipients, ContentEncryptionAlgorithm)
}
// EncryptWithAlgo creates and returns an envelope data PKCS7 structure with encrypted
// recipient keys for each recipient public key using the specified algorithm.
//
// The algorithm must be one of the supported encryption algorithms:
// - EncryptionAlgorithmDESCBC
// - EncryptionAlgorithmDESEDE3CBC
// - EncryptionAlgorithmAES128CBC
// - EncryptionAlgorithmAES256CBC
// - EncryptionAlgorithmAES128GCM
// - EncryptionAlgorithmAES256GCM
func EncryptWithAlgo(content []byte, recipients []*x509.Certificate, algo int) ([]byte, error) {
var eci *encryptedContentInfo
var key []byte
var err error
// Apply chosen symmetric encryption method
switch ContentEncryptionAlgorithm {
switch algo {
case EncryptionAlgorithmDESCBC:
key, eci, err = encryptDESCBC(content, nil)
fallthrough
case EncryptionAlgorithmDESEDE3CBC:
key, eci, err = encryptDESCBC(content, nil, algo)
case EncryptionAlgorithmAES128CBC:
fallthrough
case EncryptionAlgorithmAES256CBC:
key, eci, err = encryptAESCBC(content, nil)
key, eci, err = encryptAESCBC(content, nil, algo)
case EncryptionAlgorithmAES128GCM:
fallthrough
case EncryptionAlgorithmAES256GCM:
key, eci, err = encryptAESGCM(content, nil)
key, eci, err = encryptAESGCM(content, nil, algo)
default:
return nil, ErrUnsupportedEncryptionAlgorithm
@@ -330,6 +373,18 @@ func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
// encrypted using caller provided pre-shared secret.
func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
return EncryptUsingPSKWithAlgo(content, key, ContentEncryptionAlgorithm)
}
// EncryptUsingPSKWithAlgo creates and returns an encrypted data PKCS7 structure,
// encrypted using caller provided pre-shared secret with the specified algorithm.
//
// The algorithm must be one of the supported encryption algorithms:
// - EncryptionAlgorithmDESCBC
// - EncryptionAlgorithmDESEDE3CBC
// - EncryptionAlgorithmAES128GCM
// - EncryptionAlgorithmAES256GCM
func EncryptUsingPSKWithAlgo(content []byte, key []byte, algo int) ([]byte, error) {
var eci *encryptedContentInfo
var err error
@@ -338,14 +393,16 @@ func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
}
// Apply chosen symmetric encryption method
switch ContentEncryptionAlgorithm {
switch algo {
case EncryptionAlgorithmDESCBC:
_, eci, err = encryptDESCBC(content, key)
fallthrough
case EncryptionAlgorithmDESEDE3CBC:
_, eci, err = encryptDESCBC(content, key, algo)
case EncryptionAlgorithmAES128GCM:
fallthrough
case EncryptionAlgorithmAES256GCM:
_, eci, err = encryptAESGCM(content, key)
_, eci, err = encryptAESGCM(content, key, algo)
default:
return nil, ErrUnsupportedEncryptionAlgorithm

View File

@@ -9,6 +9,7 @@ import (
func TestEncrypt(t *testing.T) {
modes := []int{
EncryptionAlgorithmDESCBC,
EncryptionAlgorithmDESEDE3CBC,
EncryptionAlgorithmAES128CBC,
EncryptionAlgorithmAES256CBC,
EncryptionAlgorithmAES128GCM,
@@ -49,7 +50,9 @@ func TestEncrypt(t *testing.T) {
func TestEncryptUsingPSK(t *testing.T) {
modes := []int{
EncryptionAlgorithmDESCBC,
EncryptionAlgorithmDESEDE3CBC,
EncryptionAlgorithmAES128GCM,
EncryptionAlgorithmAES256GCM,
}
for _, mode := range modes {
@@ -60,9 +63,16 @@ func TestEncryptUsingPSK(t *testing.T) {
switch mode {
case EncryptionAlgorithmDESCBC:
key = []byte("64BitKey")
case EncryptionAlgorithmDESEDE3CBC:
key = []byte("192BitKeyForMoreSecurity")
case EncryptionAlgorithmAES128GCM:
key = []byte("128BitKey4AESGCM")
case EncryptionAlgorithmAES256GCM:
key = []byte("256BitKey4AESGCM256BitKey4AESGCM")
default:
t.Errorf("unsupported mode %d", mode)
}
ciphertext, err := EncryptUsingPSK(plaintext, key)
if err != nil {
t.Fatal(err)

View File

@@ -81,6 +81,10 @@ var (
OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46}
)
func GetHashForDigestAlgorithm(digestAlg asn1.ObjectIdentifier) (crypto.Hash, error) {
return getHashForOID(digestAlg)
}
func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) {
switch {
case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1),