mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-10-30 10:12:35 +00:00
Add underlining support for the PKI Enterprise SCEP work (#29604)
This commit is contained in:
@@ -62,59 +62,10 @@ var (
|
|||||||
endWildRegex = labelRegex + `\*`
|
endWildRegex = labelRegex + `\*`
|
||||||
middleWildRegex = labelRegex + `\*` + labelRegex
|
middleWildRegex = labelRegex + `\*` + labelRegex
|
||||||
leftWildLabelRegex = regexp.MustCompile(`^(` + allWildRegex + `|` + startWildRegex + `|` + endWildRegex + `|` + middleWildRegex + `)$`)
|
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 {
|
func doesPublicKeyAlgoMatchSignatureAlgo(pubKey x509.PublicKeyAlgorithm, algo x509.SignatureAlgorithm) bool {
|
||||||
for _, detail := range signatureAlgorithmDetails {
|
return issuing.DoesPublicKeyAlgoMatchSignatureAlgo(pubKey, algo)
|
||||||
if detail.algo == algo {
|
|
||||||
return pubKey == detail.pubKeyAlgo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getFormat(data *framework.FieldData) string {
|
func getFormat(data *framework.FieldData) string {
|
||||||
|
|||||||
162
builtin/logical/pki/issuing/signing_utils.go
Normal file
162
builtin/logical/pki/issuing/signing_utils.go
Normal 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)
|
||||||
|
}
|
||||||
18
builtin/logical/pki/parsing/asn1.go
Normal file
18
builtin/logical/pki/parsing/asn1.go
Normal 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
|
||||||
|
}
|
||||||
52
builtin/logical/pki/parsing/asn1_test.go
Normal file
52
builtin/logical/pki/parsing/asn1_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,15 +52,40 @@ func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error) {
|
|||||||
return data.EncryptedContentInfo.decrypt(key)
|
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) {
|
func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) {
|
||||||
alg := eci.ContentEncryptionAlgorithm.Algorithm
|
alg := eci.ContentEncryptionAlgorithm.Algorithm
|
||||||
if !alg.Equal(OIDEncryptionAlgorithmDESCBC) &&
|
if _, err := encryptedAlgoOidToConstant(alg); err != nil {
|
||||||
!alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC) &&
|
return nil, err
|
||||||
!alg.Equal(OIDEncryptionAlgorithmAES256CBC) &&
|
|
||||||
!alg.Equal(OIDEncryptionAlgorithmAES128CBC) &&
|
|
||||||
!alg.Equal(OIDEncryptionAlgorithmAES128GCM) &&
|
|
||||||
!alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
|
|
||||||
return nil, ErrUnsupportedAlgorithm
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncryptedContent can either be constructed of multple OCTET STRINGs
|
// EncryptedContent can either be constructed of multple OCTET STRINGs
|
||||||
|
|||||||
@@ -55,6 +55,9 @@ const (
|
|||||||
|
|
||||||
// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
|
// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
|
||||||
EncryptionAlgorithmAES256GCM
|
EncryptionAlgorithmAES256GCM
|
||||||
|
|
||||||
|
// EncryptionAlgorithmDESEDE3CBC is the 3DES CBC encryption algorithm (currently only supported on decrypt)
|
||||||
|
EncryptionAlgorithmDESEDE3CBC
|
||||||
)
|
)
|
||||||
|
|
||||||
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
|
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
|
||||||
@@ -77,10 +80,10 @@ type aesGCMParameters struct {
|
|||||||
ICVLen int
|
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 keyLen int
|
||||||
var algID asn1.ObjectIdentifier
|
var algID asn1.ObjectIdentifier
|
||||||
switch ContentEncryptionAlgorithm {
|
switch algo {
|
||||||
case EncryptionAlgorithmAES128GCM:
|
case EncryptionAlgorithmAES128GCM:
|
||||||
keyLen = 16
|
keyLen = 16
|
||||||
algID = OIDEncryptionAlgorithmAES128GCM
|
algID = OIDEncryptionAlgorithmAES128GCM
|
||||||
@@ -88,7 +91,7 @@ func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
|
|||||||
keyLen = 32
|
keyLen = 32
|
||||||
algID = OIDEncryptionAlgorithmAES256GCM
|
algID = OIDEncryptionAlgorithmAES256GCM
|
||||||
default:
|
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 {
|
if key == nil {
|
||||||
// Create AES key
|
// Create AES key
|
||||||
@@ -147,10 +150,23 @@ func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
|
|||||||
return key, &eci, nil
|
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 {
|
if key == nil {
|
||||||
// Create DES key
|
// Create our key
|
||||||
key = make([]byte, 8)
|
key = make([]byte, keyLen)
|
||||||
|
|
||||||
_, err := rand.Read(key)
|
_, err := rand.Read(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -166,10 +182,21 @@ func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Encrypt padded content
|
// Encrypt padded content
|
||||||
block, err := des.NewCipher(key)
|
var block cipher.Block
|
||||||
|
switch algo {
|
||||||
|
case EncryptionAlgorithmDESCBC:
|
||||||
|
block, err = des.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
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)
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
plaintext, err := pad(content, mode.BlockSize())
|
plaintext, err := pad(content, mode.BlockSize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -182,7 +209,7 @@ func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
|
|||||||
eci := encryptedContentInfo{
|
eci := encryptedContentInfo{
|
||||||
ContentType: OIDData,
|
ContentType: OIDData,
|
||||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||||
Algorithm: OIDEncryptionAlgorithmDESCBC,
|
Algorithm: algID,
|
||||||
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||||
},
|
},
|
||||||
EncryptedContent: marshalEncryptedContent(cyphertext),
|
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||||
@@ -191,10 +218,10 @@ func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
|
|||||||
return key, &eci, nil
|
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 keyLen int
|
||||||
var algID asn1.ObjectIdentifier
|
var algID asn1.ObjectIdentifier
|
||||||
switch ContentEncryptionAlgorithm {
|
switch algo {
|
||||||
case EncryptionAlgorithmAES128CBC:
|
case EncryptionAlgorithmAES128CBC:
|
||||||
keyLen = 16
|
keyLen = 16
|
||||||
algID = OIDEncryptionAlgorithmAES128CBC
|
algID = OIDEncryptionAlgorithmAES128CBC
|
||||||
@@ -202,7 +229,7 @@ func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, e
|
|||||||
keyLen = 32
|
keyLen = 32
|
||||||
algID = OIDEncryptionAlgorithmAES256CBC
|
algID = OIDEncryptionAlgorithmAES256CBC
|
||||||
default:
|
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 {
|
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
|
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
||||||
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
|
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 eci *encryptedContentInfo
|
||||||
var key []byte
|
var key []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
// Apply chosen symmetric encryption method
|
// Apply chosen symmetric encryption method
|
||||||
switch ContentEncryptionAlgorithm {
|
switch algo {
|
||||||
case EncryptionAlgorithmDESCBC:
|
case EncryptionAlgorithmDESCBC:
|
||||||
key, eci, err = encryptDESCBC(content, nil)
|
fallthrough
|
||||||
|
case EncryptionAlgorithmDESEDE3CBC:
|
||||||
|
key, eci, err = encryptDESCBC(content, nil, algo)
|
||||||
case EncryptionAlgorithmAES128CBC:
|
case EncryptionAlgorithmAES128CBC:
|
||||||
fallthrough
|
fallthrough
|
||||||
case EncryptionAlgorithmAES256CBC:
|
case EncryptionAlgorithmAES256CBC:
|
||||||
key, eci, err = encryptAESCBC(content, nil)
|
key, eci, err = encryptAESCBC(content, nil, algo)
|
||||||
case EncryptionAlgorithmAES128GCM:
|
case EncryptionAlgorithmAES128GCM:
|
||||||
fallthrough
|
fallthrough
|
||||||
case EncryptionAlgorithmAES256GCM:
|
case EncryptionAlgorithmAES256GCM:
|
||||||
key, eci, err = encryptAESGCM(content, nil)
|
key, eci, err = encryptAESGCM(content, nil, algo)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
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,
|
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
|
||||||
// encrypted using caller provided pre-shared secret.
|
// encrypted using caller provided pre-shared secret.
|
||||||
func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
|
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 eci *encryptedContentInfo
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -338,14 +393,16 @@ func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply chosen symmetric encryption method
|
// Apply chosen symmetric encryption method
|
||||||
switch ContentEncryptionAlgorithm {
|
switch algo {
|
||||||
case EncryptionAlgorithmDESCBC:
|
case EncryptionAlgorithmDESCBC:
|
||||||
_, eci, err = encryptDESCBC(content, key)
|
fallthrough
|
||||||
|
case EncryptionAlgorithmDESEDE3CBC:
|
||||||
|
_, eci, err = encryptDESCBC(content, key, algo)
|
||||||
|
|
||||||
case EncryptionAlgorithmAES128GCM:
|
case EncryptionAlgorithmAES128GCM:
|
||||||
fallthrough
|
fallthrough
|
||||||
case EncryptionAlgorithmAES256GCM:
|
case EncryptionAlgorithmAES256GCM:
|
||||||
_, eci, err = encryptAESGCM(content, key)
|
_, eci, err = encryptAESGCM(content, key, algo)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
func TestEncrypt(t *testing.T) {
|
func TestEncrypt(t *testing.T) {
|
||||||
modes := []int{
|
modes := []int{
|
||||||
EncryptionAlgorithmDESCBC,
|
EncryptionAlgorithmDESCBC,
|
||||||
|
EncryptionAlgorithmDESEDE3CBC,
|
||||||
EncryptionAlgorithmAES128CBC,
|
EncryptionAlgorithmAES128CBC,
|
||||||
EncryptionAlgorithmAES256CBC,
|
EncryptionAlgorithmAES256CBC,
|
||||||
EncryptionAlgorithmAES128GCM,
|
EncryptionAlgorithmAES128GCM,
|
||||||
@@ -49,7 +50,9 @@ func TestEncrypt(t *testing.T) {
|
|||||||
func TestEncryptUsingPSK(t *testing.T) {
|
func TestEncryptUsingPSK(t *testing.T) {
|
||||||
modes := []int{
|
modes := []int{
|
||||||
EncryptionAlgorithmDESCBC,
|
EncryptionAlgorithmDESCBC,
|
||||||
|
EncryptionAlgorithmDESEDE3CBC,
|
||||||
EncryptionAlgorithmAES128GCM,
|
EncryptionAlgorithmAES128GCM,
|
||||||
|
EncryptionAlgorithmAES256GCM,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, mode := range modes {
|
for _, mode := range modes {
|
||||||
@@ -60,9 +63,16 @@ func TestEncryptUsingPSK(t *testing.T) {
|
|||||||
switch mode {
|
switch mode {
|
||||||
case EncryptionAlgorithmDESCBC:
|
case EncryptionAlgorithmDESCBC:
|
||||||
key = []byte("64BitKey")
|
key = []byte("64BitKey")
|
||||||
|
case EncryptionAlgorithmDESEDE3CBC:
|
||||||
|
key = []byte("192BitKeyForMoreSecurity")
|
||||||
case EncryptionAlgorithmAES128GCM:
|
case EncryptionAlgorithmAES128GCM:
|
||||||
key = []byte("128BitKey4AESGCM")
|
key = []byte("128BitKey4AESGCM")
|
||||||
|
case EncryptionAlgorithmAES256GCM:
|
||||||
|
key = []byte("256BitKey4AESGCM256BitKey4AESGCM")
|
||||||
|
default:
|
||||||
|
t.Errorf("unsupported mode %d", mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
ciphertext, err := EncryptUsingPSK(plaintext, key)
|
ciphertext, err := EncryptUsingPSK(plaintext, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|||||||
@@ -81,6 +81,10 @@ var (
|
|||||||
OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46}
|
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) {
|
func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) {
|
||||||
switch {
|
switch {
|
||||||
case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1),
|
case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1),
|
||||||
|
|||||||
Reference in New Issue
Block a user