mirror of
https://github.com/containers/skopeo.git
synced 2025-09-04 16:20:23 +00:00
fix(deps): update module github.com/containers/ocicrypt to v1.2.1
Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
2
vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go
generated
vendored
2
vendor/github.com/containers/ocicrypt/keywrap/pkcs7/keywrapper_pkcs7.go
generated
vendored
@@ -25,7 +25,7 @@ import (
|
||||
"github.com/containers/ocicrypt/config"
|
||||
"github.com/containers/ocicrypt/keywrap"
|
||||
"github.com/containers/ocicrypt/utils"
|
||||
"go.mozilla.org/pkcs7"
|
||||
"github.com/smallstep/pkcs7"
|
||||
)
|
||||
|
||||
type pkcs7KeyWrapper struct {
|
||||
|
28
vendor/github.com/smallstep/pkcs7/.gitignore
generated
vendored
Normal file
28
vendor/github.com/smallstep/pkcs7/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
# Development
|
||||
.envrc
|
||||
coverage.out
|
22
vendor/github.com/smallstep/pkcs7/LICENSE
generated
vendored
Normal file
22
vendor/github.com/smallstep/pkcs7/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Andrew Smith
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
20
vendor/github.com/smallstep/pkcs7/Makefile
generated
vendored
Normal file
20
vendor/github.com/smallstep/pkcs7/Makefile
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
all: vet staticcheck test
|
||||
|
||||
test:
|
||||
go test -covermode=count -coverprofile=coverage.out .
|
||||
|
||||
showcoverage: test
|
||||
go tool cover -html=coverage.out
|
||||
|
||||
vet:
|
||||
go vet .
|
||||
|
||||
lint:
|
||||
golint .
|
||||
|
||||
staticcheck:
|
||||
staticcheck .
|
||||
|
||||
gettools:
|
||||
go get -u honnef.co/go/tools/...
|
||||
go get -u golang.org/x/lint/golint
|
63
vendor/github.com/smallstep/pkcs7/README.md
generated
vendored
Normal file
63
vendor/github.com/smallstep/pkcs7/README.md
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
# pkcs7
|
||||
|
||||
[](https://pkg.go.dev/github.com/smallstep/pkcs7)
|
||||
[](https://github.com/smallstep/pkcs7/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush)
|
||||
|
||||
pkcs7 implements parsing and creating signed and enveloped messages.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/smallstep/pkcs7"
|
||||
)
|
||||
|
||||
func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateKey) (signed []byte, err error) {
|
||||
toBeSigned, err := NewSignedData(content)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot initialize signed data: %w", err)
|
||||
}
|
||||
if err = toBeSigned.AddSigner(cert, privkey, SignerInfoConfig{}); err != nil {
|
||||
return fmt.Errorf("Cannot add signer: %w", err)
|
||||
}
|
||||
|
||||
// Detach signature, omit if you want an embedded signature
|
||||
toBeSigned.Detach()
|
||||
|
||||
signed, err = toBeSigned.Finish()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot finish signing data: %w", err)
|
||||
}
|
||||
|
||||
// Verify the signature
|
||||
pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed})
|
||||
p7, err := pkcs7.Parse(signed)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot parse our signed data: %w", err)
|
||||
}
|
||||
|
||||
// since the signature was detached, reattach the content here
|
||||
p7.Content = content
|
||||
|
||||
if bytes.Compare(content, p7.Content) != 0 {
|
||||
return fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content)
|
||||
}
|
||||
if err = p7.Verify(); err != nil {
|
||||
return fmt.Errorf("Cannot verify our signed data: %w", err)
|
||||
}
|
||||
|
||||
return signed, nil
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
This is a fork of [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) which, itself, was a fork of [fullsailor/pkcs7](https://github.com/fullsailor/pkcs7).
|
266
vendor/github.com/smallstep/pkcs7/ber.go
generated
vendored
Normal file
266
vendor/github.com/smallstep/pkcs7/ber.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type asn1Object interface {
|
||||
EncodeTo(writer *bytes.Buffer) error
|
||||
}
|
||||
|
||||
type asn1Structured struct {
|
||||
tagBytes []byte
|
||||
content []asn1Object
|
||||
}
|
||||
|
||||
func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
|
||||
inner := new(bytes.Buffer)
|
||||
for _, obj := range s.content {
|
||||
err := obj.EncodeTo(inner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
out.Write(s.tagBytes)
|
||||
encodeLength(out, inner.Len())
|
||||
out.Write(inner.Bytes())
|
||||
return nil
|
||||
}
|
||||
|
||||
type asn1Primitive struct {
|
||||
tagBytes []byte
|
||||
length int
|
||||
content []byte
|
||||
}
|
||||
|
||||
func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error {
|
||||
_, err := out.Write(p.tagBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = encodeLength(out, p.length); err != nil {
|
||||
return err
|
||||
}
|
||||
// fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length)
|
||||
// fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content))
|
||||
out.Write(p.content)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ber2der(ber []byte) ([]byte, error) {
|
||||
if len(ber) == 0 {
|
||||
return nil, errors.New("ber2der: input ber is empty")
|
||||
}
|
||||
// fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber))
|
||||
out := new(bytes.Buffer)
|
||||
|
||||
obj, _, err := readObject(ber, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
obj.EncodeTo(out)
|
||||
|
||||
// if offset < len(ber) {
|
||||
// return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber))
|
||||
// }
|
||||
|
||||
return out.Bytes(), nil
|
||||
}
|
||||
|
||||
// encodes lengths that are longer than 127 into string of bytes
|
||||
func marshalLongLength(out *bytes.Buffer, i int) (err error) {
|
||||
n := lengthLength(i)
|
||||
|
||||
for ; n > 0; n-- {
|
||||
err = out.WriteByte(byte(i >> uint((n-1)*8)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// computes the byte length of an encoded length value
|
||||
func lengthLength(i int) (numBytes int) {
|
||||
numBytes = 1
|
||||
for i > 255 {
|
||||
numBytes++
|
||||
i >>= 8
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// encodes the length in DER format
|
||||
// If the length fits in 7 bits, the value is encoded directly.
|
||||
//
|
||||
// Otherwise, the number of bytes to encode the length is first determined.
|
||||
// This number is likely to be 4 or less for a 32bit length. This number is
|
||||
// added to 0x80. The length is encoded in big endian encoding follow after
|
||||
//
|
||||
// Examples:
|
||||
// length | byte 1 | bytes n
|
||||
// 0 | 0x00 | -
|
||||
// 120 | 0x78 | -
|
||||
// 200 | 0x81 | 0xC8
|
||||
// 500 | 0x82 | 0x01 0xF4
|
||||
//
|
||||
func encodeLength(out *bytes.Buffer, length int) (err error) {
|
||||
if length >= 128 {
|
||||
l := lengthLength(length)
|
||||
err = out.WriteByte(0x80 | byte(l))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = marshalLongLength(out, length)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
err = out.WriteByte(byte(length))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readObject(ber []byte, offset int) (asn1Object, int, error) {
|
||||
berLen := len(ber)
|
||||
if offset >= berLen {
|
||||
return nil, 0, errors.New("ber2der: offset is after end of ber data")
|
||||
}
|
||||
tagStart := offset
|
||||
b := ber[offset]
|
||||
offset++
|
||||
if offset >= berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
tag := b & 0x1F // last 5 bits
|
||||
if tag == 0x1F {
|
||||
tag = 0
|
||||
for ber[offset] >= 0x80 {
|
||||
tag = tag*128 + ber[offset] - 0x80
|
||||
offset++
|
||||
if offset > berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
}
|
||||
// jvehent 20170227: this doesn't appear to be used anywhere...
|
||||
// tag = tag*128 + ber[offset] - 0x80
|
||||
offset++
|
||||
if offset > berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
}
|
||||
tagEnd := offset
|
||||
|
||||
kind := b & 0x20
|
||||
if kind == 0 {
|
||||
debugprint("--> Primitive\n")
|
||||
} else {
|
||||
debugprint("--> Constructed\n")
|
||||
}
|
||||
// read length
|
||||
var length int
|
||||
l := ber[offset]
|
||||
offset++
|
||||
if offset > berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
indefinite := false
|
||||
if l > 0x80 {
|
||||
numberOfBytes := (int)(l & 0x7F)
|
||||
if numberOfBytes > 4 { // int is only guaranteed to be 32bit
|
||||
return nil, 0, errors.New("ber2der: BER tag length too long")
|
||||
}
|
||||
if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
|
||||
return nil, 0, errors.New("ber2der: BER tag length is negative")
|
||||
}
|
||||
if (int)(ber[offset]) == 0x0 {
|
||||
return nil, 0, errors.New("ber2der: BER tag length has leading zero")
|
||||
}
|
||||
debugprint("--> (compute length) indicator byte: %x\n", l)
|
||||
debugprint("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes])
|
||||
for i := 0; i < numberOfBytes; i++ {
|
||||
length = length*256 + (int)(ber[offset])
|
||||
offset++
|
||||
if offset > berLen {
|
||||
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
|
||||
}
|
||||
}
|
||||
} else if l == 0x80 {
|
||||
indefinite = true
|
||||
} else {
|
||||
length = (int)(l)
|
||||
}
|
||||
if length < 0 {
|
||||
return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length")
|
||||
}
|
||||
// fmt.Printf("--> length : %d\n", length)
|
||||
contentEnd := offset + length
|
||||
if contentEnd > len(ber) {
|
||||
return nil, 0, errors.New("ber2der: BER tag length is more than available data")
|
||||
}
|
||||
debugprint("--> content start : %d\n", offset)
|
||||
debugprint("--> content end : %d\n", contentEnd)
|
||||
debugprint("--> content : % X\n", ber[offset:contentEnd])
|
||||
var obj asn1Object
|
||||
if indefinite && kind == 0 {
|
||||
return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
|
||||
}
|
||||
if kind == 0 {
|
||||
obj = asn1Primitive{
|
||||
tagBytes: ber[tagStart:tagEnd],
|
||||
length: length,
|
||||
content: ber[offset:contentEnd],
|
||||
}
|
||||
} else {
|
||||
var subObjects []asn1Object
|
||||
for (offset < contentEnd) || indefinite {
|
||||
var subObj asn1Object
|
||||
var err error
|
||||
subObj, offset, err = readObject(ber, offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
subObjects = append(subObjects, subObj)
|
||||
|
||||
if indefinite {
|
||||
terminated, err := isIndefiniteTermination(ber, offset)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if terminated {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
obj = asn1Structured{
|
||||
tagBytes: ber[tagStart:tagEnd],
|
||||
content: subObjects,
|
||||
}
|
||||
}
|
||||
|
||||
// Apply indefinite form length with 0x0000 terminator.
|
||||
if indefinite {
|
||||
contentEnd = offset + 2
|
||||
}
|
||||
|
||||
return obj, contentEnd, nil
|
||||
}
|
||||
|
||||
func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
|
||||
if len(ber)-offset < 2 {
|
||||
return false, errors.New("ber2der: Invalid BER format")
|
||||
}
|
||||
|
||||
return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
|
||||
}
|
||||
|
||||
func debugprint(format string, a ...interface{}) {
|
||||
// fmt.Printf(format, a)
|
||||
}
|
233
vendor/github.com/smallstep/pkcs7/decrypt.go
generated
vendored
Normal file
233
vendor/github.com/smallstep/pkcs7/decrypt.go
generated
vendored
Normal file
@@ -0,0 +1,233 @@
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed
|
||||
var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported")
|
||||
|
||||
// ErrUnsupportedAsymmetricEncryptionAlgorithm is returned when attempting to use an unknown asymmetric encryption algorithm
|
||||
var ErrUnsupportedAsymmetricEncryptionAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA PKCS#1 v1.5 and RSA OAEP are supported")
|
||||
|
||||
// ErrUnsupportedKeyType is returned when attempting to encrypting keys using a key that's not an RSA key
|
||||
var ErrUnsupportedKeyType = errors.New("pkcs7: only RSA keys are supported")
|
||||
|
||||
// ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data
|
||||
var ErrNotEncryptedContent = errors.New("pkcs7: content data is a decryptable data type")
|
||||
|
||||
// Decrypt decrypts encrypted content info for recipient cert and private key
|
||||
func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pkey crypto.PrivateKey) ([]byte, error) {
|
||||
data, ok := p7.raw.(envelopedData)
|
||||
if !ok {
|
||||
return nil, ErrNotEncryptedContent
|
||||
}
|
||||
recipient := selectRecipientForCertificate(data.RecipientInfos, cert)
|
||||
if recipient.EncryptedKey == nil {
|
||||
return nil, errors.New("pkcs7: no enveloped recipient for provided certificate")
|
||||
}
|
||||
switch pkey := pkey.(type) {
|
||||
case crypto.Decrypter:
|
||||
var opts crypto.DecrypterOpts
|
||||
switch algorithm := recipient.KeyEncryptionAlgorithm.Algorithm; {
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP):
|
||||
hashFunc, err := getHashFuncForKeyEncryptionAlgorithm(recipient.KeyEncryptionAlgorithm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts = &rsa.OAEPOptions{Hash: hashFunc}
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSA):
|
||||
opts = &rsa.PKCS1v15DecryptOptions{}
|
||||
default:
|
||||
return nil, ErrUnsupportedAsymmetricEncryptionAlgorithm
|
||||
}
|
||||
contentKey, err := pkey.Decrypt(rand.Reader, recipient.EncryptedKey, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data.EncryptedContentInfo.decrypt(contentKey)
|
||||
}
|
||||
return nil, ErrUnsupportedAlgorithm
|
||||
}
|
||||
|
||||
// RFC 4055, 4.1
|
||||
// The current ASN.1 parser does not support non-integer defaults so the 'default:' tags here do nothing.
|
||||
type rsaOAEPAlgorithmParameters struct {
|
||||
HashFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:0,default:sha1Identifier"`
|
||||
MaskGenFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:1,default:mgf1SHA1Identifier"`
|
||||
PSourceFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:2,default:pSpecifiedEmptyIdentifier"`
|
||||
}
|
||||
|
||||
func getHashFuncForKeyEncryptionAlgorithm(keyEncryptionAlgorithm pkix.AlgorithmIdentifier) (crypto.Hash, error) {
|
||||
invalidHashFunc := crypto.Hash(0)
|
||||
params := &rsaOAEPAlgorithmParameters{
|
||||
HashFunc: pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA1}, // set default hash algorithm to SHA1
|
||||
}
|
||||
var rest []byte
|
||||
rest, err := asn1.Unmarshal(keyEncryptionAlgorithm.Parameters.FullBytes, params)
|
||||
if err != nil {
|
||||
return invalidHashFunc, fmt.Errorf("pkcs7: failed unmarshaling key encryption algorithm parameters: %v", err)
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
return invalidHashFunc, errors.New("pkcs7: trailing data after RSA OAEP parameters")
|
||||
}
|
||||
|
||||
switch {
|
||||
case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA1):
|
||||
return crypto.SHA1, nil
|
||||
case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA224):
|
||||
return crypto.SHA224, nil
|
||||
case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA256):
|
||||
return crypto.SHA256, nil
|
||||
case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA384):
|
||||
return crypto.SHA384, nil
|
||||
case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA512):
|
||||
return crypto.SHA512, nil
|
||||
default:
|
||||
return invalidHashFunc, errors.New("pkcs7: unsupported hash function for RSA OAEP")
|
||||
}
|
||||
}
|
||||
|
||||
// DecryptUsingPSK decrypts encrypted data using caller provided
|
||||
// pre-shared secret
|
||||
func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error) {
|
||||
data, ok := p7.raw.(encryptedData)
|
||||
if !ok {
|
||||
return nil, ErrNotEncryptedContent
|
||||
}
|
||||
return data.EncryptedContentInfo.decrypt(key)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// EncryptedContent can either be constructed of multple OCTET STRINGs
|
||||
// or _be_ a tagged OCTET STRING
|
||||
var cyphertext []byte
|
||||
if eci.EncryptedContent.IsCompound {
|
||||
// Complex case to concat all of the children OCTET STRINGs
|
||||
var buf bytes.Buffer
|
||||
cypherbytes := eci.EncryptedContent.Bytes
|
||||
for {
|
||||
var part []byte
|
||||
cypherbytes, _ = asn1.Unmarshal(cypherbytes, &part)
|
||||
buf.Write(part)
|
||||
if cypherbytes == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
cyphertext = buf.Bytes()
|
||||
} else {
|
||||
// Simple case, the bytes _are_ the cyphertext
|
||||
cyphertext = eci.EncryptedContent.Bytes
|
||||
}
|
||||
|
||||
var block cipher.Block
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case alg.Equal(OIDEncryptionAlgorithmDESCBC):
|
||||
block, err = des.NewCipher(key)
|
||||
case alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC):
|
||||
block, err = des.NewTripleDESCipher(key)
|
||||
case alg.Equal(OIDEncryptionAlgorithmAES256CBC), alg.Equal(OIDEncryptionAlgorithmAES256GCM):
|
||||
fallthrough
|
||||
case alg.Equal(OIDEncryptionAlgorithmAES128GCM), alg.Equal(OIDEncryptionAlgorithmAES128CBC):
|
||||
block, err = aes.NewCipher(key)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if alg.Equal(OIDEncryptionAlgorithmAES128GCM) || alg.Equal(OIDEncryptionAlgorithmAES256GCM) {
|
||||
params := aesGCMParameters{}
|
||||
paramBytes := eci.ContentEncryptionAlgorithm.Parameters.Bytes
|
||||
|
||||
_, err := asn1.Unmarshal(paramBytes, ¶ms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(params.Nonce) != gcm.NonceSize() {
|
||||
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
|
||||
}
|
||||
if params.ICVLen != gcm.Overhead() {
|
||||
return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect")
|
||||
}
|
||||
|
||||
plaintext, err := gcm.Open(nil, params.Nonce, cyphertext, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
iv := eci.ContentEncryptionAlgorithm.Parameters.Bytes
|
||||
if len(iv) != block.BlockSize() {
|
||||
return nil, errors.New("pkcs7: encryption algorithm parameters are malformed")
|
||||
}
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
plaintext := make([]byte, len(cyphertext))
|
||||
mode.CryptBlocks(plaintext, cyphertext)
|
||||
if plaintext, err = unpad(plaintext, mode.BlockSize()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return plaintext, nil
|
||||
}
|
||||
|
||||
func unpad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen < 1 {
|
||||
return nil, fmt.Errorf("pkcs7: invalid blocklen %d", blocklen)
|
||||
}
|
||||
if len(data)%blocklen != 0 || len(data) == 0 {
|
||||
return nil, fmt.Errorf("pkcs7: invalid data len %d", len(data))
|
||||
}
|
||||
|
||||
// the last byte is the length of padding
|
||||
padlen := int(data[len(data)-1])
|
||||
|
||||
// check padding integrity, all bytes should be the same
|
||||
pad := data[len(data)-padlen:]
|
||||
for _, padbyte := range pad {
|
||||
if padbyte != byte(padlen) {
|
||||
return nil, errors.New("pkcs7: invalid padding")
|
||||
}
|
||||
}
|
||||
|
||||
return data[:len(data)-padlen], nil
|
||||
}
|
||||
|
||||
func selectRecipientForCertificate(recipients []recipientInfo, cert *x509.Certificate) recipientInfo {
|
||||
for _, recp := range recipients {
|
||||
if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) {
|
||||
return recp
|
||||
}
|
||||
}
|
||||
return recipientInfo{}
|
||||
}
|
475
vendor/github.com/smallstep/pkcs7/encrypt.go
generated
vendored
Normal file
475
vendor/github.com/smallstep/pkcs7/encrypt.go
generated
vendored
Normal file
@@ -0,0 +1,475 @@
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type envelopedData struct {
|
||||
Version int
|
||||
RecipientInfos []recipientInfo `asn1:"set"`
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type encryptedData struct {
|
||||
Version int
|
||||
EncryptedContentInfo encryptedContentInfo
|
||||
}
|
||||
|
||||
type recipientInfo struct {
|
||||
Version int
|
||||
IssuerAndSerialNumber issuerAndSerial
|
||||
KeyEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedKey []byte
|
||||
}
|
||||
|
||||
type encryptedContentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
ContentEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedContent asn1.RawValue `asn1:"tag:0,optional"`
|
||||
}
|
||||
|
||||
const (
|
||||
// EncryptionAlgorithmDESCBC is the DES CBC encryption algorithm
|
||||
EncryptionAlgorithmDESCBC = iota
|
||||
|
||||
// EncryptionAlgorithmAES128CBC is the AES 128 bits with CBC encryption algorithm
|
||||
// Avoid this algorithm unless required for interoperability; use AES GCM instead.
|
||||
EncryptionAlgorithmAES128CBC
|
||||
|
||||
// EncryptionAlgorithmAES256CBC is the AES 256 bits with CBC encryption algorithm
|
||||
// Avoid this algorithm unless required for interoperability; use AES GCM instead.
|
||||
EncryptionAlgorithmAES256CBC
|
||||
|
||||
// EncryptionAlgorithmAES128GCM is the AES 128 bits with GCM encryption algorithm
|
||||
EncryptionAlgorithmAES128GCM
|
||||
|
||||
// EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm
|
||||
EncryptionAlgorithmAES256GCM
|
||||
)
|
||||
|
||||
// ContentEncryptionAlgorithm determines the algorithm used to encrypt the
|
||||
// plaintext message. Change the value of this variable to change which
|
||||
// algorithm is used in the Encrypt() function.
|
||||
var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC
|
||||
|
||||
// ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt
|
||||
// content with an unsupported algorithm.
|
||||
var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, and AES-GCM supported")
|
||||
|
||||
// KeyEncryptionAlgorithm determines the algorithm used to encrypt a
|
||||
// content key. Change the value of this variable to change which
|
||||
// algorithm is used in the Encrypt() function.
|
||||
var KeyEncryptionAlgorithm = OIDEncryptionAlgorithmRSA
|
||||
|
||||
// ErrUnsupportedKeyEncryptionAlgorithm is returned when an
|
||||
// unsupported key encryption algorithm OID is provided.
|
||||
var ErrUnsupportedKeyEncryptionAlgorithm = errors.New("pkcs7: unsupported key encryption algorithm provided")
|
||||
|
||||
// KeyEncryptionHash determines the crypto.Hash algorithm to use
|
||||
// when encrypting a content key. Change the value of this variable
|
||||
// to change which algorithm is used in the Encrypt() function.
|
||||
var KeyEncryptionHash = crypto.SHA256
|
||||
|
||||
// ErrUnsupportedKeyEncryptionHash is returned when an
|
||||
// unsupported key encryption hash is provided.
|
||||
var ErrUnsupportedKeyEncryptionHash = errors.New("pkcs7: unsupported key encryption hash provided")
|
||||
|
||||
// ErrPSKNotProvided is returned when attempting to encrypt
|
||||
// using a PSK without actually providing the PSK.
|
||||
var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided")
|
||||
|
||||
const nonceSize = 12
|
||||
|
||||
type aesGCMParameters struct {
|
||||
Nonce []byte `asn1:"tag:4"`
|
||||
ICVLen int
|
||||
}
|
||||
|
||||
func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||
var keyLen int
|
||||
var algID asn1.ObjectIdentifier
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmAES128GCM:
|
||||
keyLen = 16
|
||||
algID = OIDEncryptionAlgorithmAES128GCM
|
||||
case EncryptionAlgorithmAES256GCM:
|
||||
keyLen = 32
|
||||
algID = OIDEncryptionAlgorithmAES256GCM
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESGCM: %d", ContentEncryptionAlgorithm)
|
||||
}
|
||||
if key == nil {
|
||||
// Create AES key
|
||||
key = make([]byte, keyLen)
|
||||
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create nonce
|
||||
nonce := make([]byte, nonceSize)
|
||||
|
||||
_, err := rand.Read(nonce)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Encrypt content
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
gcm, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ciphertext := gcm.Seal(nil, nonce, content, nil)
|
||||
|
||||
// Prepare ASN.1 Encrypted Content Info
|
||||
paramSeq := aesGCMParameters{
|
||||
Nonce: nonce,
|
||||
ICVLen: gcm.Overhead(),
|
||||
}
|
||||
|
||||
paramBytes, err := asn1.Marshal(paramSeq)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
eci := encryptedContentInfo{
|
||||
ContentType: OIDData,
|
||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: algID,
|
||||
Parameters: asn1.RawValue{
|
||||
Tag: asn1.TagSequence,
|
||||
Bytes: paramBytes,
|
||||
},
|
||||
},
|
||||
EncryptedContent: marshalEncryptedContent(ciphertext),
|
||||
}
|
||||
|
||||
return key, &eci, nil
|
||||
}
|
||||
|
||||
func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||
if key == nil {
|
||||
// Create DES key
|
||||
key = make([]byte, 8)
|
||||
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create CBC IV
|
||||
iv := make([]byte, des.BlockSize)
|
||||
_, err := rand.Read(iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Encrypt padded content
|
||||
block, err := des.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
plaintext, err := pad(content, mode.BlockSize())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cyphertext := make([]byte, len(plaintext))
|
||||
mode.CryptBlocks(cyphertext, plaintext)
|
||||
|
||||
// Prepare ASN.1 Encrypted Content Info
|
||||
eci := encryptedContentInfo{
|
||||
ContentType: OIDData,
|
||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: OIDEncryptionAlgorithmDESCBC,
|
||||
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||
},
|
||||
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||
}
|
||||
|
||||
return key, &eci, nil
|
||||
}
|
||||
|
||||
func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) {
|
||||
var keyLen int
|
||||
var algID asn1.ObjectIdentifier
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmAES128CBC:
|
||||
keyLen = 16
|
||||
algID = OIDEncryptionAlgorithmAES128CBC
|
||||
case EncryptionAlgorithmAES256CBC:
|
||||
keyLen = 32
|
||||
algID = OIDEncryptionAlgorithmAES256CBC
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESCBC: %d", ContentEncryptionAlgorithm)
|
||||
}
|
||||
|
||||
if key == nil {
|
||||
// Create AES key
|
||||
key = make([]byte, keyLen)
|
||||
|
||||
_, err := rand.Read(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Create CBC IV
|
||||
iv := make([]byte, aes.BlockSize)
|
||||
_, err := rand.Read(iv)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Encrypt padded content
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
mode := cipher.NewCBCEncrypter(block, iv)
|
||||
plaintext, err := pad(content, mode.BlockSize())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cyphertext := make([]byte, len(plaintext))
|
||||
mode.CryptBlocks(cyphertext, plaintext)
|
||||
|
||||
// Prepare ASN.1 Encrypted Content Info
|
||||
eci := encryptedContentInfo{
|
||||
ContentType: OIDData,
|
||||
ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{
|
||||
Algorithm: algID,
|
||||
Parameters: asn1.RawValue{Tag: 4, Bytes: iv},
|
||||
},
|
||||
EncryptedContent: marshalEncryptedContent(cyphertext),
|
||||
}
|
||||
|
||||
return key, &eci, nil
|
||||
}
|
||||
|
||||
// Encrypt creates and returns an envelope data PKCS7 structure with encrypted
|
||||
// recipient keys for each recipient public key.
|
||||
//
|
||||
// The algorithm used to perform encryption is determined by the current value
|
||||
// of the global ContentEncryptionAlgorithm package variable. By default, the
|
||||
// value is EncryptionAlgorithmDESCBC. To use a different algorithm, change the
|
||||
// value before calling Encrypt(). For example:
|
||||
//
|
||||
// ContentEncryptionAlgorithm = EncryptionAlgorithmAES256GCM
|
||||
//
|
||||
// TODO(fullsailor): Add support for encrypting content with other algorithms
|
||||
func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) {
|
||||
var eci *encryptedContentInfo
|
||||
var key []byte
|
||||
var err error
|
||||
|
||||
// Apply chosen symmetric encryption method
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmDESCBC:
|
||||
key, eci, err = encryptDESCBC(content, nil)
|
||||
case EncryptionAlgorithmAES128CBC:
|
||||
fallthrough
|
||||
case EncryptionAlgorithmAES256CBC:
|
||||
key, eci, err = encryptAESCBC(content, nil)
|
||||
case EncryptionAlgorithmAES128GCM:
|
||||
fallthrough
|
||||
case EncryptionAlgorithmAES256GCM:
|
||||
key, eci, err = encryptAESGCM(content, nil)
|
||||
|
||||
default:
|
||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare each recipient's encrypted cipher key
|
||||
recipientInfos := make([]recipientInfo, len(recipients))
|
||||
for i, recipient := range recipients {
|
||||
algorithm := KeyEncryptionAlgorithm
|
||||
hash := KeyEncryptionHash
|
||||
var kea pkix.AlgorithmIdentifier
|
||||
switch {
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP):
|
||||
parameters, err := getParametersForKeyEncryptionAlgorithm(algorithm, hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get parameters for key encryption: %v", err)
|
||||
}
|
||||
kea = pkix.AlgorithmIdentifier{
|
||||
Algorithm: algorithm,
|
||||
Parameters: parameters,
|
||||
}
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSA):
|
||||
kea = pkix.AlgorithmIdentifier{
|
||||
Algorithm: algorithm,
|
||||
}
|
||||
default:
|
||||
return nil, ErrUnsupportedKeyEncryptionAlgorithm
|
||||
}
|
||||
encrypted, err := encryptKey(key, recipient, algorithm, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ias, err := cert2issuerAndSerial(recipient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info := recipientInfo{
|
||||
Version: 0,
|
||||
IssuerAndSerialNumber: ias,
|
||||
KeyEncryptionAlgorithm: kea,
|
||||
EncryptedKey: encrypted,
|
||||
}
|
||||
recipientInfos[i] = info
|
||||
}
|
||||
|
||||
// Prepare envelope content
|
||||
envelope := envelopedData{
|
||||
EncryptedContentInfo: *eci,
|
||||
Version: 0,
|
||||
RecipientInfos: recipientInfos,
|
||||
}
|
||||
innerContent, err := asn1.Marshal(envelope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare outer payload structure
|
||||
wrapper := contentInfo{
|
||||
ContentType: OIDEnvelopedData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||
}
|
||||
|
||||
return asn1.Marshal(wrapper)
|
||||
}
|
||||
|
||||
func getParametersForKeyEncryptionAlgorithm(algorithm asn1.ObjectIdentifier, hash crypto.Hash) (asn1.RawValue, error) {
|
||||
if !algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP) {
|
||||
return asn1.RawValue{}, nil // return empty; not used
|
||||
}
|
||||
|
||||
params := rsaOAEPAlgorithmParameters{}
|
||||
switch hash {
|
||||
case crypto.SHA1:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA1}
|
||||
case crypto.SHA224:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA224}
|
||||
case crypto.SHA256:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA256}
|
||||
case crypto.SHA384:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA384}
|
||||
case crypto.SHA512:
|
||||
params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA512}
|
||||
default:
|
||||
return asn1.RawValue{}, ErrUnsupportedAlgorithm
|
||||
}
|
||||
|
||||
b, err := asn1.Marshal(params)
|
||||
if err != nil {
|
||||
return asn1.RawValue{}, fmt.Errorf("failed marshaling key encryption parameters: %v", err)
|
||||
}
|
||||
|
||||
return asn1.RawValue{
|
||||
FullBytes: b,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EncryptUsingPSK creates and returns an encrypted data PKCS7 structure,
|
||||
// encrypted using caller provided pre-shared secret.
|
||||
func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) {
|
||||
var eci *encryptedContentInfo
|
||||
var err error
|
||||
|
||||
if key == nil {
|
||||
return nil, ErrPSKNotProvided
|
||||
}
|
||||
|
||||
// Apply chosen symmetric encryption method
|
||||
switch ContentEncryptionAlgorithm {
|
||||
case EncryptionAlgorithmDESCBC:
|
||||
_, eci, err = encryptDESCBC(content, key)
|
||||
|
||||
case EncryptionAlgorithmAES128GCM:
|
||||
fallthrough
|
||||
case EncryptionAlgorithmAES256GCM:
|
||||
_, eci, err = encryptAESGCM(content, key)
|
||||
|
||||
default:
|
||||
return nil, ErrUnsupportedEncryptionAlgorithm
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare encrypted-data content
|
||||
ed := encryptedData{
|
||||
Version: 0,
|
||||
EncryptedContentInfo: *eci,
|
||||
}
|
||||
innerContent, err := asn1.Marshal(ed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare outer payload structure
|
||||
wrapper := contentInfo{
|
||||
ContentType: OIDEncryptedData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent},
|
||||
}
|
||||
|
||||
return asn1.Marshal(wrapper)
|
||||
}
|
||||
|
||||
func marshalEncryptedContent(content []byte) asn1.RawValue {
|
||||
return asn1.RawValue{Bytes: content, Class: 2, IsCompound: false}
|
||||
}
|
||||
|
||||
func encryptKey(key []byte, recipient *x509.Certificate, algorithm asn1.ObjectIdentifier, hash crypto.Hash) ([]byte, error) {
|
||||
pub, ok := recipient.PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
return nil, ErrUnsupportedKeyType
|
||||
}
|
||||
|
||||
switch {
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSA):
|
||||
return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
|
||||
case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP):
|
||||
return rsa.EncryptOAEP(hash.New(), rand.Reader, pub, key, nil)
|
||||
default:
|
||||
return nil, ErrUnsupportedKeyEncryptionAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
func pad(data []byte, blocklen int) ([]byte, error) {
|
||||
if blocklen < 1 {
|
||||
return nil, fmt.Errorf("invalid blocklen %d", blocklen)
|
||||
}
|
||||
padlen := blocklen - (len(data) % blocklen)
|
||||
if padlen == 0 {
|
||||
padlen = blocklen
|
||||
}
|
||||
pad := bytes.Repeat([]byte{byte(padlen)}, padlen)
|
||||
return append(data, pad...), nil
|
||||
}
|
14
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/debug.go
generated
vendored
Normal file
14
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/debug.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package legacyx509
|
||||
|
||||
import "fmt"
|
||||
|
||||
// legacyGodebugSetting is a type mimicking Go's internal godebug package
|
||||
// settings, which are used to enable / disable certain functionalities at
|
||||
// build time.
|
||||
type legacyGodebugSetting int
|
||||
|
||||
func (s legacyGodebugSetting) Value() string {
|
||||
return fmt.Sprintf("%d", s)
|
||||
}
|
||||
|
||||
func (s legacyGodebugSetting) IncNonDefault() {}
|
14
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/doc.go
generated
vendored
Normal file
14
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/doc.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Package legacyx509 is a copy of certain parts of Go's crypto/x509 package.
|
||||
It is based on Go 1.23, and has just the parts copied over required for
|
||||
parsing X509 certificates.
|
||||
|
||||
The primary reason this copy exists is to keep support for parsing PKCS7
|
||||
messages containing Simple Certificate Enrolment Protocol (SCEP) requests
|
||||
from Windows devices. Go 1.23 made a change marking certificates with a
|
||||
critical authority key identifier as invalid, which is mandated by RFC 5280,
|
||||
but apparently Windows marks those specific certificates as such, resulting
|
||||
in those SCEP requests failing from being parsed correctly.
|
||||
*/
|
||||
|
||||
package legacyx509
|
377
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/oid.go
generated
vendored
Normal file
377
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/oid.go
generated
vendored
Normal file
@@ -0,0 +1,377 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package legacyx509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"math"
|
||||
"math/big"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
errInvalidOID = errors.New("invalid oid")
|
||||
)
|
||||
|
||||
// An OID represents an ASN.1 OBJECT IDENTIFIER.
|
||||
type OID struct {
|
||||
der []byte
|
||||
}
|
||||
|
||||
// ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots.
|
||||
func ParseOID(oid string) (OID, error) {
|
||||
var o OID
|
||||
return o, o.unmarshalOIDText(oid)
|
||||
}
|
||||
|
||||
func newOIDFromDER(der []byte) (OID, bool) {
|
||||
if len(der) == 0 || der[len(der)-1]&0x80 != 0 {
|
||||
return OID{}, false
|
||||
}
|
||||
|
||||
start := 0
|
||||
for i, v := range der {
|
||||
// ITU-T X.690, section 8.19.2:
|
||||
// The subidentifier shall be encoded in the fewest possible octets,
|
||||
// that is, the leading octet of the subidentifier shall not have the value 0x80.
|
||||
if i == start && v == 0x80 {
|
||||
return OID{}, false
|
||||
}
|
||||
if v&0x80 == 0 {
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
return OID{der}, true
|
||||
}
|
||||
|
||||
// OIDFromInts creates a new OID using ints, each integer is a separate component.
|
||||
func OIDFromInts(oid []uint64) (OID, error) {
|
||||
if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) {
|
||||
return OID{}, errInvalidOID
|
||||
}
|
||||
|
||||
length := base128IntLength(oid[0]*40 + oid[1])
|
||||
for _, v := range oid[2:] {
|
||||
length += base128IntLength(v)
|
||||
}
|
||||
|
||||
der := make([]byte, 0, length)
|
||||
der = appendBase128Int(der, oid[0]*40+oid[1])
|
||||
for _, v := range oid[2:] {
|
||||
der = appendBase128Int(der, v)
|
||||
}
|
||||
return OID{der}, nil
|
||||
}
|
||||
|
||||
func base128IntLength(n uint64) int {
|
||||
if n == 0 {
|
||||
return 1
|
||||
}
|
||||
return (bits.Len64(n) + 6) / 7
|
||||
}
|
||||
|
||||
func appendBase128Int(dst []byte, n uint64) []byte {
|
||||
for i := base128IntLength(n) - 1; i >= 0; i-- {
|
||||
o := byte(n >> uint(i*7))
|
||||
o &= 0x7f
|
||||
if i != 0 {
|
||||
o |= 0x80
|
||||
}
|
||||
dst = append(dst, o)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func base128BigIntLength(n *big.Int) int {
|
||||
if n.Cmp(big.NewInt(0)) == 0 {
|
||||
return 1
|
||||
}
|
||||
return (n.BitLen() + 6) / 7
|
||||
}
|
||||
|
||||
func appendBase128BigInt(dst []byte, n *big.Int) []byte {
|
||||
if n.Cmp(big.NewInt(0)) == 0 {
|
||||
return append(dst, 0)
|
||||
}
|
||||
|
||||
for i := base128BigIntLength(n) - 1; i >= 0; i-- {
|
||||
o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0])
|
||||
o &= 0x7f
|
||||
if i != 0 {
|
||||
o |= 0x80
|
||||
}
|
||||
dst = append(dst, o)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// AppendText implements [encoding.TextAppender]
|
||||
func (o OID) AppendText(b []byte) ([]byte, error) {
|
||||
return append(b, o.String()...), nil
|
||||
}
|
||||
|
||||
// MarshalText implements [encoding.TextMarshaler]
|
||||
func (o OID) MarshalText() ([]byte, error) {
|
||||
return o.AppendText(nil)
|
||||
}
|
||||
|
||||
// UnmarshalText implements [encoding.TextUnmarshaler]
|
||||
func (o *OID) UnmarshalText(text []byte) error {
|
||||
return o.unmarshalOIDText(string(text))
|
||||
}
|
||||
|
||||
// cutString slices s around the first instance of sep,
|
||||
// returning the text before and after sep.
|
||||
// The found result reports whether sep appears in s.
|
||||
// If sep does not appear in s, cut returns s, "", false.
|
||||
func cutString(s, sep string) (before, after string, found bool) {
|
||||
if i := strings.Index(s, sep); i >= 0 {
|
||||
return s[:i], s[i+len(sep):], true
|
||||
}
|
||||
return s, "", false
|
||||
}
|
||||
|
||||
func (o *OID) unmarshalOIDText(oid string) error {
|
||||
// (*big.Int).SetString allows +/- signs, but we don't want
|
||||
// to allow them in the string representation of Object Identifier, so
|
||||
// reject such encodings.
|
||||
for _, c := range oid {
|
||||
isDigit := c >= '0' && c <= '9'
|
||||
if !isDigit && c != '.' {
|
||||
return errInvalidOID
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
firstNum string
|
||||
secondNum string
|
||||
)
|
||||
|
||||
var nextComponentExists bool
|
||||
firstNum, oid, nextComponentExists = cutString(oid, ".")
|
||||
if !nextComponentExists {
|
||||
return errInvalidOID
|
||||
}
|
||||
secondNum, oid, nextComponentExists = cutString(oid, ".")
|
||||
|
||||
var (
|
||||
first = big.NewInt(0)
|
||||
second = big.NewInt(0)
|
||||
)
|
||||
|
||||
if _, ok := first.SetString(firstNum, 10); !ok {
|
||||
return errInvalidOID
|
||||
}
|
||||
if _, ok := second.SetString(secondNum, 10); !ok {
|
||||
return errInvalidOID
|
||||
}
|
||||
|
||||
if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) {
|
||||
return errInvalidOID
|
||||
}
|
||||
|
||||
firstComponent := first.Mul(first, big.NewInt(40))
|
||||
firstComponent.Add(firstComponent, second)
|
||||
|
||||
der := appendBase128BigInt(make([]byte, 0, 32), firstComponent)
|
||||
|
||||
for nextComponentExists {
|
||||
var strNum string
|
||||
strNum, oid, nextComponentExists = cutString(oid, ".")
|
||||
b, ok := big.NewInt(0).SetString(strNum, 10)
|
||||
if !ok {
|
||||
return errInvalidOID
|
||||
}
|
||||
der = appendBase128BigInt(der, b)
|
||||
}
|
||||
|
||||
o.der = der
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendBinary implements [encoding.BinaryAppender]
|
||||
func (o OID) AppendBinary(b []byte) ([]byte, error) {
|
||||
return append(b, o.der...), nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements [encoding.BinaryMarshaler]
|
||||
func (o OID) MarshalBinary() ([]byte, error) {
|
||||
return o.AppendBinary(nil)
|
||||
}
|
||||
|
||||
// cloneBytes returns a copy of b[:len(b)].
|
||||
// The result may have additional unused capacity.
|
||||
// Clone(nil) returns nil.
|
||||
func cloneBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
return append([]byte{}, b...)
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements [encoding.BinaryUnmarshaler]
|
||||
func (o *OID) UnmarshalBinary(b []byte) error {
|
||||
oid, ok := newOIDFromDER(cloneBytes(b))
|
||||
if !ok {
|
||||
return errInvalidOID
|
||||
}
|
||||
*o = oid
|
||||
return nil
|
||||
}
|
||||
|
||||
// Equal returns true when oid and other represents the same Object Identifier.
|
||||
func (oid OID) Equal(other OID) bool {
|
||||
// There is only one possible DER encoding of
|
||||
// each unique Object Identifier.
|
||||
return bytes.Equal(oid.der, other.der)
|
||||
}
|
||||
|
||||
func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) {
|
||||
offset = initOffset
|
||||
var ret64 int64
|
||||
for shifted := 0; offset < len(bytes); shifted++ {
|
||||
// 5 * 7 bits per byte == 35 bits of data
|
||||
// Thus the representation is either non-minimal or too large for an int32
|
||||
if shifted == 5 {
|
||||
failed = true
|
||||
return
|
||||
}
|
||||
ret64 <<= 7
|
||||
b := bytes[offset]
|
||||
// integers should be minimally encoded, so the leading octet should
|
||||
// never be 0x80
|
||||
if shifted == 0 && b == 0x80 {
|
||||
failed = true
|
||||
return
|
||||
}
|
||||
ret64 |= int64(b & 0x7f)
|
||||
offset++
|
||||
if b&0x80 == 0 {
|
||||
ret = int(ret64)
|
||||
// Ensure that the returned value fits in an int on all platforms
|
||||
if ret64 > math.MaxInt32 {
|
||||
failed = true
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
failed = true
|
||||
return
|
||||
}
|
||||
|
||||
// EqualASN1OID returns whether an OID equals an asn1.ObjectIdentifier. If
|
||||
// asn1.ObjectIdentifier cannot represent the OID specified by oid, because
|
||||
// a component of OID requires more than 31 bits, it returns false.
|
||||
func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool {
|
||||
if len(other) < 2 {
|
||||
return false
|
||||
}
|
||||
v, offset, failed := parseBase128Int(oid.der, 0)
|
||||
if failed {
|
||||
// This should never happen, since we've already parsed the OID,
|
||||
// but just in case.
|
||||
return false
|
||||
}
|
||||
if v < 80 {
|
||||
a, b := v/40, v%40
|
||||
if other[0] != a || other[1] != b {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
a, b := 2, v-80
|
||||
if other[0] != a || other[1] != b {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
i := 2
|
||||
for ; offset < len(oid.der); i++ {
|
||||
v, offset, failed = parseBase128Int(oid.der, offset)
|
||||
if failed {
|
||||
// Again, shouldn't happen, since we've already parsed
|
||||
// the OID, but better safe than sorry.
|
||||
return false
|
||||
}
|
||||
if i >= len(other) || v != other[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return i == len(other)
|
||||
}
|
||||
|
||||
// Strings returns the string representation of the Object Identifier.
|
||||
func (oid OID) String() string {
|
||||
var b strings.Builder
|
||||
b.Grow(32)
|
||||
const (
|
||||
valSize = 64 // size in bits of val.
|
||||
bitsPerByte = 7
|
||||
maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1
|
||||
)
|
||||
var (
|
||||
start = 0
|
||||
val = uint64(0)
|
||||
numBuf = make([]byte, 0, 21)
|
||||
bigVal *big.Int
|
||||
overflow bool
|
||||
)
|
||||
for i, v := range oid.der {
|
||||
curVal := v & 0x7F
|
||||
valEnd := v&0x80 == 0
|
||||
if valEnd {
|
||||
if start != 0 {
|
||||
b.WriteByte('.')
|
||||
}
|
||||
}
|
||||
if !overflow && val > maxValSafeShift {
|
||||
if bigVal == nil {
|
||||
bigVal = new(big.Int)
|
||||
}
|
||||
bigVal = bigVal.SetUint64(val)
|
||||
overflow = true
|
||||
}
|
||||
if overflow {
|
||||
bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal)))
|
||||
if valEnd {
|
||||
if start == 0 {
|
||||
b.WriteString("2.")
|
||||
bigVal = bigVal.Sub(bigVal, big.NewInt(80))
|
||||
}
|
||||
numBuf = bigVal.Append(numBuf, 10)
|
||||
b.Write(numBuf)
|
||||
numBuf = numBuf[:0]
|
||||
val = 0
|
||||
start = i + 1
|
||||
overflow = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
val <<= bitsPerByte
|
||||
val |= uint64(curVal)
|
||||
if valEnd {
|
||||
if start == 0 {
|
||||
if val < 80 {
|
||||
b.Write(strconv.AppendUint(numBuf, val/40, 10))
|
||||
b.WriteByte('.')
|
||||
b.Write(strconv.AppendUint(numBuf, val%40, 10))
|
||||
} else {
|
||||
b.WriteString("2.")
|
||||
b.Write(strconv.AppendUint(numBuf, val-80, 10))
|
||||
}
|
||||
} else {
|
||||
b.Write(strconv.AppendUint(numBuf, val, 10))
|
||||
}
|
||||
val = 0
|
||||
start = i + 1
|
||||
}
|
||||
}
|
||||
return b.String()
|
||||
}
|
1027
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/parser.go
generated
vendored
Normal file
1027
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/parser.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
15
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/pkcs1.go
generated
vendored
Normal file
15
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/pkcs1.go
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2011 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package legacyx509
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key.
|
||||
type pkcs1PublicKey struct {
|
||||
N *big.Int
|
||||
E int
|
||||
}
|
193
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/verify.go
generated
vendored
Normal file
193
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/verify.go
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
||||
package legacyx509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// rfc2821Mailbox represents a “mailbox” (which is an email address to most
|
||||
// people) by breaking it into the “local” (i.e. before the '@') and “domain”
|
||||
// parts.
|
||||
type rfc2821Mailbox struct {
|
||||
local, domain string
|
||||
}
|
||||
|
||||
// parseRFC2821Mailbox parses an email address into local and domain parts,
|
||||
// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280,
|
||||
// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The
|
||||
// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”.
|
||||
func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
|
||||
if len(in) == 0 {
|
||||
return mailbox, false
|
||||
}
|
||||
|
||||
localPartBytes := make([]byte, 0, len(in)/2)
|
||||
|
||||
if in[0] == '"' {
|
||||
// Quoted-string = DQUOTE *qcontent DQUOTE
|
||||
// non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127
|
||||
// qcontent = qtext / quoted-pair
|
||||
// qtext = non-whitespace-control /
|
||||
// %d33 / %d35-91 / %d93-126
|
||||
// quoted-pair = ("\" text) / obs-qp
|
||||
// text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text
|
||||
//
|
||||
// (Names beginning with “obs-” are the obsolete syntax from RFC 2822,
|
||||
// Section 4. Since it has been 16 years, we no longer accept that.)
|
||||
in = in[1:]
|
||||
QuotedString:
|
||||
for {
|
||||
if len(in) == 0 {
|
||||
return mailbox, false
|
||||
}
|
||||
c := in[0]
|
||||
in = in[1:]
|
||||
|
||||
switch {
|
||||
case c == '"':
|
||||
break QuotedString
|
||||
|
||||
case c == '\\':
|
||||
// quoted-pair
|
||||
if len(in) == 0 {
|
||||
return mailbox, false
|
||||
}
|
||||
if in[0] == 11 ||
|
||||
in[0] == 12 ||
|
||||
(1 <= in[0] && in[0] <= 9) ||
|
||||
(14 <= in[0] && in[0] <= 127) {
|
||||
localPartBytes = append(localPartBytes, in[0])
|
||||
in = in[1:]
|
||||
} else {
|
||||
return mailbox, false
|
||||
}
|
||||
|
||||
case c == 11 ||
|
||||
c == 12 ||
|
||||
// Space (char 32) is not allowed based on the
|
||||
// BNF, but RFC 3696 gives an example that
|
||||
// assumes that it is. Several “verified”
|
||||
// errata continue to argue about this point.
|
||||
// We choose to accept it.
|
||||
c == 32 ||
|
||||
c == 33 ||
|
||||
c == 127 ||
|
||||
(1 <= c && c <= 8) ||
|
||||
(14 <= c && c <= 31) ||
|
||||
(35 <= c && c <= 91) ||
|
||||
(93 <= c && c <= 126):
|
||||
// qtext
|
||||
localPartBytes = append(localPartBytes, c)
|
||||
|
||||
default:
|
||||
return mailbox, false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Atom ("." Atom)*
|
||||
NextChar:
|
||||
for len(in) > 0 {
|
||||
// atext from RFC 2822, Section 3.2.4
|
||||
c := in[0]
|
||||
|
||||
switch {
|
||||
case c == '\\':
|
||||
// Examples given in RFC 3696 suggest that
|
||||
// escaped characters can appear outside of a
|
||||
// quoted string. Several “verified” errata
|
||||
// continue to argue the point. We choose to
|
||||
// accept it.
|
||||
in = in[1:]
|
||||
if len(in) == 0 {
|
||||
return mailbox, false
|
||||
}
|
||||
fallthrough
|
||||
|
||||
case ('0' <= c && c <= '9') ||
|
||||
('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
c == '!' || c == '#' || c == '$' || c == '%' ||
|
||||
c == '&' || c == '\'' || c == '*' || c == '+' ||
|
||||
c == '-' || c == '/' || c == '=' || c == '?' ||
|
||||
c == '^' || c == '_' || c == '`' || c == '{' ||
|
||||
c == '|' || c == '}' || c == '~' || c == '.':
|
||||
localPartBytes = append(localPartBytes, in[0])
|
||||
in = in[1:]
|
||||
|
||||
default:
|
||||
break NextChar
|
||||
}
|
||||
}
|
||||
|
||||
if len(localPartBytes) == 0 {
|
||||
return mailbox, false
|
||||
}
|
||||
|
||||
// From RFC 3696, Section 3:
|
||||
// “period (".") may also appear, but may not be used to start
|
||||
// or end the local part, nor may two or more consecutive
|
||||
// periods appear.”
|
||||
twoDots := []byte{'.', '.'}
|
||||
if localPartBytes[0] == '.' ||
|
||||
localPartBytes[len(localPartBytes)-1] == '.' ||
|
||||
bytes.Contains(localPartBytes, twoDots) {
|
||||
return mailbox, false
|
||||
}
|
||||
}
|
||||
|
||||
if len(in) == 0 || in[0] != '@' {
|
||||
return mailbox, false
|
||||
}
|
||||
in = in[1:]
|
||||
|
||||
// The RFC species a format for domains, but that's known to be
|
||||
// violated in practice so we accept that anything after an '@' is the
|
||||
// domain part.
|
||||
if _, ok := domainToReverseLabels(in); !ok {
|
||||
return mailbox, false
|
||||
}
|
||||
|
||||
mailbox.local = string(localPartBytes)
|
||||
mailbox.domain = in
|
||||
return mailbox, true
|
||||
}
|
||||
|
||||
// domainToReverseLabels converts a textual domain name like foo.example.com to
|
||||
// the list of labels in reverse order, e.g. ["com", "example", "foo"].
|
||||
func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
|
||||
for len(domain) > 0 {
|
||||
if i := strings.LastIndexByte(domain, '.'); i == -1 {
|
||||
reverseLabels = append(reverseLabels, domain)
|
||||
domain = ""
|
||||
} else {
|
||||
reverseLabels = append(reverseLabels, domain[i+1:])
|
||||
domain = domain[:i]
|
||||
if i == 0 { // domain == ""
|
||||
// domain is prefixed with an empty label, append an empty
|
||||
// string to reverseLabels to indicate this.
|
||||
reverseLabels = append(reverseLabels, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
|
||||
// An empty label at the end indicates an absolute value.
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for _, label := range reverseLabels {
|
||||
if len(label) == 0 {
|
||||
// Empty labels are otherwise invalid.
|
||||
return nil, false
|
||||
}
|
||||
|
||||
for _, c := range label {
|
||||
if c < 33 || c > 126 {
|
||||
// Invalid character.
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return reverseLabels, true
|
||||
}
|
488
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/x509.go
generated
vendored
Normal file
488
vendor/github.com/smallstep/pkcs7/internal/legacy/x509/x509.go
generated
vendored
Normal file
@@ -0,0 +1,488 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package x509 implements a subset of the X.509 standard.
|
||||
//
|
||||
// It allows parsing and generating certificates, certificate signing
|
||||
// requests, certificate revocation lists, and encoded public and private keys.
|
||||
// It provides a certificate verifier, complete with a chain builder.
|
||||
//
|
||||
// The package targets the X.509 technical profile defined by the IETF (RFC
|
||||
// 2459/3280/5280), and as further restricted by the CA/Browser Forum Baseline
|
||||
// Requirements. There is minimal support for features outside of these
|
||||
// profiles, as the primary goal of the package is to provide compatibility
|
||||
// with the publicly trusted TLS certificate ecosystem and its policies and
|
||||
// constraints.
|
||||
//
|
||||
// On macOS and Windows, certificate verification is handled by system APIs, but
|
||||
// the package aims to apply consistent validation rules across operating
|
||||
// systems.
|
||||
package legacyx509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/elliptic"
|
||||
stdx509 "crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"unicode"
|
||||
|
||||
// Explicitly import these for their crypto.RegisterHash init side-effects.
|
||||
// Keep these as blank imports, even if they're imported above.
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
)
|
||||
|
||||
type publicKeyInfo struct {
|
||||
Raw asn1.RawContent
|
||||
Algorithm pkix.AlgorithmIdentifier
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
|
||||
type SignatureAlgorithm int
|
||||
|
||||
const (
|
||||
UnknownSignatureAlgorithm SignatureAlgorithm = iota
|
||||
|
||||
MD2WithRSA // Unsupported.
|
||||
MD5WithRSA // Only supported for signing, not verification.
|
||||
SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
|
||||
SHA256WithRSA
|
||||
SHA384WithRSA
|
||||
SHA512WithRSA
|
||||
DSAWithSHA1 // Unsupported.
|
||||
DSAWithSHA256 // Unsupported.
|
||||
ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
|
||||
ECDSAWithSHA256
|
||||
ECDSAWithSHA384
|
||||
ECDSAWithSHA512
|
||||
SHA256WithRSAPSS
|
||||
SHA384WithRSAPSS
|
||||
SHA512WithRSAPSS
|
||||
PureEd25519
|
||||
)
|
||||
|
||||
func (algo SignatureAlgorithm) String() string {
|
||||
for _, details := range signatureAlgorithmDetails {
|
||||
if details.algo == algo {
|
||||
return details.name
|
||||
}
|
||||
}
|
||||
return strconv.Itoa(int(algo))
|
||||
}
|
||||
|
||||
type PublicKeyAlgorithm int
|
||||
|
||||
const (
|
||||
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
|
||||
RSA
|
||||
DSA // Only supported for parsing.
|
||||
ECDSA
|
||||
Ed25519
|
||||
)
|
||||
|
||||
var publicKeyAlgoName = [...]string{
|
||||
RSA: "RSA",
|
||||
DSA: "DSA",
|
||||
ECDSA: "ECDSA",
|
||||
Ed25519: "Ed25519",
|
||||
}
|
||||
|
||||
func (algo PublicKeyAlgorithm) String() string {
|
||||
if 0 < algo && int(algo) < len(publicKeyAlgoName) {
|
||||
return publicKeyAlgoName[algo]
|
||||
}
|
||||
return strconv.Itoa(int(algo))
|
||||
}
|
||||
|
||||
// OIDs for signature algorithms
|
||||
//
|
||||
// pkcs-1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
|
||||
//
|
||||
// RFC 3279 2.2.1 RSA Signature Algorithms
|
||||
//
|
||||
// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
|
||||
//
|
||||
// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
|
||||
//
|
||||
// dsaWithSha1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
|
||||
//
|
||||
// RFC 3279 2.2.3 ECDSA Signature Algorithm
|
||||
//
|
||||
// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) member-body(2) us(840) ansi-x962(10045)
|
||||
// signatures(4) ecdsa-with-SHA1(1)}
|
||||
//
|
||||
// RFC 4055 5 PKCS #1 Version 1.5
|
||||
//
|
||||
// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
|
||||
//
|
||||
// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
|
||||
//
|
||||
// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
|
||||
//
|
||||
// RFC 5758 3.1 DSA Signature Algorithms
|
||||
//
|
||||
// dsaWithSha256 OBJECT IDENTIFIER ::= {
|
||||
// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
|
||||
// csor(3) algorithms(4) id-dsa-with-sha2(3) 2}
|
||||
//
|
||||
// RFC 5758 3.2 ECDSA Signature Algorithm
|
||||
//
|
||||
// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
|
||||
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
|
||||
//
|
||||
// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
|
||||
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
|
||||
//
|
||||
// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
|
||||
// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
|
||||
//
|
||||
// RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers
|
||||
//
|
||||
// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
|
||||
var (
|
||||
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}
|
||||
|
||||
oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
||||
oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
||||
oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
||||
|
||||
oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
|
||||
|
||||
// oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
|
||||
// but it's specified by ISO. Microsoft's makecert.exe has been known
|
||||
// to produce certificates with this OID.
|
||||
oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
|
||||
)
|
||||
|
||||
var signatureAlgorithmDetails = []struct {
|
||||
algo SignatureAlgorithm
|
||||
name string
|
||||
oid asn1.ObjectIdentifier
|
||||
params asn1.RawValue
|
||||
pubKeyAlgo PublicKeyAlgorithm
|
||||
hash crypto.Hash
|
||||
isRSAPSS bool
|
||||
}{
|
||||
{MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false},
|
||||
{SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
|
||||
{SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false},
|
||||
{SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false},
|
||||
{SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false},
|
||||
{SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false},
|
||||
{SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true},
|
||||
{SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true},
|
||||
{SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true},
|
||||
{DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false},
|
||||
{DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false},
|
||||
{ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false},
|
||||
{ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false},
|
||||
{ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false},
|
||||
{ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false},
|
||||
{PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false},
|
||||
}
|
||||
|
||||
var emptyRawValue = asn1.RawValue{}
|
||||
|
||||
// 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}}
|
||||
)
|
||||
|
||||
// pssParameters reflects the parameters in an AlgorithmIdentifier that
|
||||
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
|
||||
type pssParameters struct {
|
||||
// The following three fields are not marked as
|
||||
// optional because the default values specify SHA-1,
|
||||
// which is no longer suitable for use in signatures.
|
||||
Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
|
||||
MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
|
||||
SaltLength int `asn1:"explicit,tag:2"`
|
||||
TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
|
||||
}
|
||||
|
||||
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) stdx509.SignatureAlgorithm {
|
||||
if ai.Algorithm.Equal(oidSignatureEd25519) {
|
||||
// RFC 8410, Section 3
|
||||
// > For all of the OIDs, the parameters MUST be absent.
|
||||
if len(ai.Parameters.FullBytes) != 0 {
|
||||
return stdx509.UnknownSignatureAlgorithm
|
||||
}
|
||||
}
|
||||
|
||||
if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
|
||||
for _, details := range signatureAlgorithmDetails {
|
||||
if ai.Algorithm.Equal(details.oid) {
|
||||
return stdx509.SignatureAlgorithm(details.algo)
|
||||
}
|
||||
}
|
||||
return stdx509.UnknownSignatureAlgorithm
|
||||
}
|
||||
|
||||
// RSA PSS is special because it encodes important parameters
|
||||
// in the Parameters.
|
||||
|
||||
var params pssParameters
|
||||
if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil {
|
||||
return stdx509.UnknownSignatureAlgorithm
|
||||
}
|
||||
|
||||
var mgf1HashFunc pkix.AlgorithmIdentifier
|
||||
if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
|
||||
return stdx509.UnknownSignatureAlgorithm
|
||||
}
|
||||
|
||||
// PSS is greatly overburdened with options. This code forces them into
|
||||
// three buckets by requiring that the MGF1 hash function always match the
|
||||
// message hash function (as recommended in RFC 3447, Section 8.1), that the
|
||||
// salt length matches the hash length, and that the trailer field has the
|
||||
// default value.
|
||||
if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) ||
|
||||
!params.MGF.Algorithm.Equal(oidMGF1) ||
|
||||
!mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
|
||||
(len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) ||
|
||||
params.TrailerField != 1 {
|
||||
return stdx509.UnknownSignatureAlgorithm
|
||||
}
|
||||
|
||||
switch {
|
||||
case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
|
||||
return stdx509.SHA256WithRSAPSS
|
||||
case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
|
||||
return stdx509.SHA384WithRSAPSS
|
||||
case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
|
||||
return stdx509.SHA512WithRSAPSS
|
||||
}
|
||||
|
||||
return stdx509.UnknownSignatureAlgorithm
|
||||
}
|
||||
|
||||
var (
|
||||
// RFC 3279, 2.3 Public Key Algorithms
|
||||
//
|
||||
// pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
|
||||
// rsadsi(113549) pkcs(1) 1 }
|
||||
//
|
||||
// rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
|
||||
//
|
||||
// id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
|
||||
// x9-57(10040) x9cm(4) 1 }
|
||||
oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
|
||||
oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
||||
// RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters
|
||||
//
|
||||
// id-ecPublicKey OBJECT IDENTIFIER ::= {
|
||||
// iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
|
||||
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
|
||||
// RFC 8410, Section 3
|
||||
//
|
||||
// id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 }
|
||||
// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
|
||||
oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110}
|
||||
oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
|
||||
)
|
||||
|
||||
// getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm
|
||||
// identifier for public key types supported in certificates and CSRs. Marshal
|
||||
// and Parse functions may support a different set of public key types.
|
||||
func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) stdx509.PublicKeyAlgorithm {
|
||||
switch {
|
||||
case oid.Equal(oidPublicKeyRSA):
|
||||
return stdx509.RSA
|
||||
case oid.Equal(oidPublicKeyDSA):
|
||||
return stdx509.DSA
|
||||
case oid.Equal(oidPublicKeyECDSA):
|
||||
return stdx509.ECDSA
|
||||
case oid.Equal(oidPublicKeyEd25519):
|
||||
return stdx509.Ed25519
|
||||
}
|
||||
return stdx509.UnknownPublicKeyAlgorithm
|
||||
}
|
||||
|
||||
// RFC 5480, 2.1.1.1. Named Curve
|
||||
//
|
||||
// secp224r1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
|
||||
//
|
||||
// secp256r1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
|
||||
// prime(1) 7 }
|
||||
//
|
||||
// secp384r1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) identified-organization(3) certicom(132) curve(0) 34 }
|
||||
//
|
||||
// secp521r1 OBJECT IDENTIFIER ::= {
|
||||
// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
|
||||
//
|
||||
// NB: secp256r1 is equivalent to prime256v1
|
||||
var (
|
||||
oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
|
||||
oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
||||
oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
||||
oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
||||
)
|
||||
|
||||
func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
|
||||
switch {
|
||||
case oid.Equal(oidNamedCurveP224):
|
||||
return elliptic.P224()
|
||||
case oid.Equal(oidNamedCurveP256):
|
||||
return elliptic.P256()
|
||||
case oid.Equal(oidNamedCurveP384):
|
||||
return elliptic.P384()
|
||||
case oid.Equal(oidNamedCurveP521):
|
||||
return elliptic.P521()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// KeyUsage represents the set of actions that are valid for a given key. It's
|
||||
// a bitmap of the KeyUsage* constants.
|
||||
type KeyUsage int
|
||||
|
||||
const (
|
||||
KeyUsageDigitalSignature KeyUsage = 1 << iota
|
||||
KeyUsageContentCommitment
|
||||
KeyUsageKeyEncipherment
|
||||
KeyUsageDataEncipherment
|
||||
KeyUsageKeyAgreement
|
||||
KeyUsageCertSign
|
||||
KeyUsageCRLSign
|
||||
KeyUsageEncipherOnly
|
||||
KeyUsageDecipherOnly
|
||||
)
|
||||
|
||||
// RFC 5280, 4.2.1.12 Extended Key Usage
|
||||
//
|
||||
// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
|
||||
//
|
||||
// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
|
||||
//
|
||||
// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
|
||||
// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
|
||||
// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
|
||||
// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
|
||||
// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
|
||||
// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
|
||||
var (
|
||||
oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
|
||||
oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
|
||||
oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
|
||||
oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
|
||||
oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
|
||||
oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
|
||||
oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
|
||||
oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
|
||||
oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
|
||||
oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
|
||||
oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
|
||||
oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
|
||||
oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22}
|
||||
oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1}
|
||||
)
|
||||
|
||||
// ExtKeyUsage represents an extended set of actions that are valid for a given key.
|
||||
// Each of the ExtKeyUsage* constants define a unique action.
|
||||
type ExtKeyUsage int
|
||||
|
||||
const (
|
||||
ExtKeyUsageAny ExtKeyUsage = iota
|
||||
ExtKeyUsageServerAuth
|
||||
ExtKeyUsageClientAuth
|
||||
ExtKeyUsageCodeSigning
|
||||
ExtKeyUsageEmailProtection
|
||||
ExtKeyUsageIPSECEndSystem
|
||||
ExtKeyUsageIPSECTunnel
|
||||
ExtKeyUsageIPSECUser
|
||||
ExtKeyUsageTimeStamping
|
||||
ExtKeyUsageOCSPSigning
|
||||
ExtKeyUsageMicrosoftServerGatedCrypto
|
||||
ExtKeyUsageNetscapeServerGatedCrypto
|
||||
ExtKeyUsageMicrosoftCommercialCodeSigning
|
||||
ExtKeyUsageMicrosoftKernelCodeSigning
|
||||
)
|
||||
|
||||
// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
|
||||
var extKeyUsageOIDs = []struct {
|
||||
extKeyUsage ExtKeyUsage
|
||||
oid asn1.ObjectIdentifier
|
||||
}{
|
||||
{ExtKeyUsageAny, oidExtKeyUsageAny},
|
||||
{ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
|
||||
{ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
|
||||
{ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
|
||||
{ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
|
||||
{ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem},
|
||||
{ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel},
|
||||
{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
|
||||
{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
|
||||
{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
|
||||
{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
|
||||
{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
|
||||
{ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning},
|
||||
{ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning},
|
||||
}
|
||||
|
||||
func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
|
||||
for _, pair := range extKeyUsageOIDs {
|
||||
if oid.Equal(pair.oid) {
|
||||
return pair.extKeyUsage, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
nameTypeEmail = 1
|
||||
nameTypeDNS = 2
|
||||
nameTypeURI = 6
|
||||
nameTypeIP = 7
|
||||
)
|
||||
|
||||
var (
|
||||
oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
|
||||
)
|
||||
|
||||
var (
|
||||
oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1}
|
||||
oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}
|
||||
)
|
||||
|
||||
func isIA5String(s string) error {
|
||||
for _, r := range s {
|
||||
// Per RFC5280 "IA5String is limited to the set of ASCII characters"
|
||||
if r > unicode.MaxASCII {
|
||||
return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
346
vendor/github.com/smallstep/pkcs7/pkcs7.go
generated
vendored
Normal file
346
vendor/github.com/smallstep/pkcs7/pkcs7.go
generated
vendored
Normal file
@@ -0,0 +1,346 @@
|
||||
// Package pkcs7 implements parsing and generation of some PKCS#7 structures.
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
_ "crypto/sha1" // for crypto.SHA1
|
||||
|
||||
legacyx509 "github.com/smallstep/pkcs7/internal/legacy/x509"
|
||||
)
|
||||
|
||||
// PKCS7 Represents a PKCS7 structure
|
||||
type PKCS7 struct {
|
||||
Content []byte
|
||||
Certificates []*x509.Certificate
|
||||
CRLs []pkix.CertificateList
|
||||
Signers []signerInfo
|
||||
raw interface{}
|
||||
}
|
||||
|
||||
type contentInfo struct {
|
||||
ContentType asn1.ObjectIdentifier
|
||||
Content asn1.RawValue `asn1:"explicit,optional,tag:0"`
|
||||
}
|
||||
|
||||
// ErrUnsupportedContentType is returned when a PKCS7 content type is not supported.
|
||||
// Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2),
|
||||
// and Enveloped Data are supported (1.2.840.113549.1.7.3)
|
||||
var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type")
|
||||
|
||||
type unsignedData []byte
|
||||
|
||||
var (
|
||||
// Signed Data OIDs
|
||||
OIDData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1}
|
||||
OIDSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2}
|
||||
OIDEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3}
|
||||
OIDEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6}
|
||||
OIDAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3}
|
||||
OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4}
|
||||
OIDAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5}
|
||||
|
||||
// Digest Algorithms
|
||||
OIDDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26}
|
||||
OIDDigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
|
||||
OIDDigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
|
||||
OIDDigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
|
||||
OIDDigestAlgorithmSHA224 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 4}
|
||||
|
||||
OIDDigestAlgorithmDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
|
||||
OIDDigestAlgorithmDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
|
||||
|
||||
OIDDigestAlgorithmECDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
|
||||
OIDDigestAlgorithmECDSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
|
||||
OIDDigestAlgorithmECDSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
|
||||
OIDDigestAlgorithmECDSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
|
||||
|
||||
// Signature Algorithms
|
||||
OIDEncryptionAlgorithmRSAMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} // see https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.4
|
||||
OIDEncryptionAlgorithmRSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} // ditto
|
||||
OIDEncryptionAlgorithmRSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} // ditto
|
||||
OIDEncryptionAlgorithmRSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} // ditto
|
||||
OIDEncryptionAlgorithmRSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} // ditto
|
||||
OIDEncryptionAlgorithmRSASHA224 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 14} // ditto
|
||||
|
||||
OIDEncryptionAlgorithmECDSAP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
|
||||
OIDEncryptionAlgorithmECDSAP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
|
||||
OIDEncryptionAlgorithmECDSAP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
|
||||
|
||||
// Asymmetric Encryption Algorithms
|
||||
OIDEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} // see https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.2
|
||||
OIDEncryptionAlgorithmRSAESOAEP = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 7} // see https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.1
|
||||
|
||||
// Symmetric Encryption Algorithms
|
||||
OIDEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7} // see https://www.rfc-editor.org/rfc/rfc8018.html#appendix-B.2.1
|
||||
OIDEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7} // see https://www.rfc-editor.org/rfc/rfc8018.html#appendix-B.2.2
|
||||
OIDEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42} // see https://www.rfc-editor.org/rfc/rfc3565.html#section-4.1
|
||||
OIDEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6} // see https://www.rfc-editor.org/rfc/rfc5084.html#section-3.2
|
||||
OIDEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2} // see https://www.rfc-editor.org/rfc/rfc8018.html#appendix-B.2.5
|
||||
OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46} // see https://www.rfc-editor.org/rfc/rfc5084.html#section-3.2
|
||||
)
|
||||
|
||||
func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) {
|
||||
switch {
|
||||
case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1),
|
||||
oid.Equal(OIDDigestAlgorithmDSA), oid.Equal(OIDDigestAlgorithmDSASHA1),
|
||||
oid.Equal(OIDEncryptionAlgorithmRSA):
|
||||
return crypto.SHA1, nil
|
||||
case oid.Equal(OIDDigestAlgorithmSHA256), oid.Equal(OIDDigestAlgorithmECDSASHA256):
|
||||
return crypto.SHA256, nil
|
||||
case oid.Equal(OIDDigestAlgorithmSHA384), oid.Equal(OIDDigestAlgorithmECDSASHA384):
|
||||
return crypto.SHA384, nil
|
||||
case oid.Equal(OIDDigestAlgorithmSHA512), oid.Equal(OIDDigestAlgorithmECDSASHA512):
|
||||
return crypto.SHA512, nil
|
||||
}
|
||||
return crypto.Hash(0), ErrUnsupportedAlgorithm
|
||||
}
|
||||
|
||||
// getDigestOIDForSignatureAlgorithm takes an x509.SignatureAlgorithm
|
||||
// and returns the corresponding OID digest algorithm
|
||||
func getDigestOIDForSignatureAlgorithm(digestAlg x509.SignatureAlgorithm) (asn1.ObjectIdentifier, error) {
|
||||
switch digestAlg {
|
||||
case x509.SHA1WithRSA, x509.ECDSAWithSHA1:
|
||||
return OIDDigestAlgorithmSHA1, nil
|
||||
case x509.SHA256WithRSA, x509.ECDSAWithSHA256:
|
||||
return OIDDigestAlgorithmSHA256, nil
|
||||
case x509.SHA384WithRSA, x509.ECDSAWithSHA384:
|
||||
return OIDDigestAlgorithmSHA384, nil
|
||||
case x509.SHA512WithRSA, x509.ECDSAWithSHA512:
|
||||
return OIDDigestAlgorithmSHA512, nil
|
||||
}
|
||||
return nil, fmt.Errorf("pkcs7: cannot convert hash to oid, unknown hash algorithm")
|
||||
}
|
||||
|
||||
// getOIDForEncryptionAlgorithm takes the public or private key type of the signer and
|
||||
// the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm
|
||||
func getOIDForEncryptionAlgorithm(pkey interface{}, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) {
|
||||
switch k := pkey.(type) {
|
||||
case *rsa.PrivateKey, *rsa.PublicKey:
|
||||
switch {
|
||||
default:
|
||||
return OIDEncryptionAlgorithmRSA, nil
|
||||
case OIDDigestAlg.Equal(OIDEncryptionAlgorithmRSA):
|
||||
return OIDEncryptionAlgorithmRSA, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1):
|
||||
return OIDEncryptionAlgorithmRSASHA1, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256):
|
||||
return OIDEncryptionAlgorithmRSASHA256, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384):
|
||||
return OIDEncryptionAlgorithmRSASHA384, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512):
|
||||
return OIDEncryptionAlgorithmRSASHA512, nil
|
||||
}
|
||||
case *ecdsa.PrivateKey, *ecdsa.PublicKey:
|
||||
switch {
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1):
|
||||
return OIDDigestAlgorithmECDSASHA1, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256):
|
||||
return OIDDigestAlgorithmECDSASHA256, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384):
|
||||
return OIDDigestAlgorithmECDSASHA384, nil
|
||||
case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512):
|
||||
return OIDDigestAlgorithmECDSASHA512, nil
|
||||
}
|
||||
case *dsa.PrivateKey, *dsa.PublicKey:
|
||||
return OIDDigestAlgorithmDSA, nil
|
||||
case crypto.Signer:
|
||||
// This generic case is here to cover types from other packages. It
|
||||
// was specifically added to handle the private keyRSA type in the
|
||||
// github.com/go-piv/piv-go/piv package.
|
||||
return getOIDForEncryptionAlgorithm(k.Public(), OIDDigestAlg)
|
||||
}
|
||||
return nil, fmt.Errorf("pkcs7: cannot convert encryption algorithm to oid, unknown private key type %T", pkey)
|
||||
|
||||
}
|
||||
|
||||
// Parse decodes a DER encoded PKCS7 package
|
||||
func Parse(data []byte) (p7 *PKCS7, err error) {
|
||||
if len(data) == 0 {
|
||||
return nil, errors.New("pkcs7: input data is empty")
|
||||
}
|
||||
var info contentInfo
|
||||
der, err := ber2der(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rest, err := asn1.Unmarshal(der, &info)
|
||||
if len(rest) > 0 {
|
||||
err = asn1.SyntaxError{Msg: "trailing data"}
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Printf("--> Content Type: %s", info.ContentType)
|
||||
switch {
|
||||
case info.ContentType.Equal(OIDSignedData):
|
||||
return parseSignedData(info.Content.Bytes)
|
||||
case info.ContentType.Equal(OIDEnvelopedData):
|
||||
return parseEnvelopedData(info.Content.Bytes)
|
||||
case info.ContentType.Equal(OIDEncryptedData):
|
||||
return parseEncryptedData(info.Content.Bytes)
|
||||
}
|
||||
return nil, ErrUnsupportedContentType
|
||||
}
|
||||
|
||||
func parseEnvelopedData(data []byte) (*PKCS7, error) {
|
||||
var ed envelopedData
|
||||
if _, err := asn1.Unmarshal(data, &ed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PKCS7{
|
||||
raw: ed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseEncryptedData(data []byte) (*PKCS7, error) {
|
||||
var ed encryptedData
|
||||
if _, err := asn1.Unmarshal(data, &ed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &PKCS7{
|
||||
raw: ed,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetFallbackLegacyX509CertificateParserEnabled enables parsing certificates
|
||||
// embedded in a PKCS7 message using the logic from crypto/x509 from before
|
||||
// Go 1.23. Go 1.23 introduced a breaking change in case a certificate contains
|
||||
// a critical authority key identifier, which is the correct thing to do based
|
||||
// on RFC 5280, but it breaks Windows devices performing the Simple Certificate
|
||||
// Enrolment Protocol (SCEP), as the certificates embedded in those requests
|
||||
// apparently have authority key identifier extensions marked critical.
|
||||
//
|
||||
// See https://go-review.googlesource.com/c/go/+/562341 for the change in the
|
||||
// Go source.
|
||||
//
|
||||
// When [SetFallbackLegacyX509CertificateParserEnabled] is called with true, it
|
||||
// enables parsing using the legacy crypto/x509 certificate parser. It'll first
|
||||
// try to parse the certificates using the regular Go crypto/x509 package, but
|
||||
// if it fails on the above case, it'll retry parsing the certificates using a
|
||||
// copy of the crypto/x509 package based on Go 1.23, but skips checking the
|
||||
// authority key identifier extension being critical or not.
|
||||
func SetFallbackLegacyX509CertificateParserEnabled(v bool) {
|
||||
legacyX509CertificateParser.Lock()
|
||||
legacyX509CertificateParser.enabled = v
|
||||
legacyX509CertificateParser.Unlock()
|
||||
}
|
||||
|
||||
var legacyX509CertificateParser struct {
|
||||
sync.RWMutex
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func isLegacyX509ParserEnabled() bool {
|
||||
legacyX509CertificateParser.RLock()
|
||||
defer legacyX509CertificateParser.RUnlock()
|
||||
return legacyX509CertificateParser.enabled
|
||||
}
|
||||
|
||||
func (raw rawCertificates) Parse() ([]*x509.Certificate, error) {
|
||||
if len(raw.Raw) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var val asn1.RawValue
|
||||
if _, err := asn1.Unmarshal(raw.Raw, &val); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certificates, err := x509.ParseCertificates(val.Bytes)
|
||||
if err != nil && err.Error() == "x509: authority key identifier incorrectly marked critical" {
|
||||
if isLegacyX509ParserEnabled() {
|
||||
certificates, err = legacyx509.ParseCertificates(val.Bytes)
|
||||
}
|
||||
}
|
||||
|
||||
return certificates, err
|
||||
}
|
||||
|
||||
func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool {
|
||||
return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Equal(cert.RawIssuer, ias.IssuerName.FullBytes)
|
||||
}
|
||||
|
||||
// Attribute represents a key value pair attribute. Value must be marshalable byte
|
||||
// `encoding/asn1`
|
||||
type Attribute struct {
|
||||
Type asn1.ObjectIdentifier
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
type attributes struct {
|
||||
types []asn1.ObjectIdentifier
|
||||
values []interface{}
|
||||
}
|
||||
|
||||
// Add adds the attribute, maintaining insertion order
|
||||
func (attrs *attributes) Add(attrType asn1.ObjectIdentifier, value interface{}) {
|
||||
attrs.types = append(attrs.types, attrType)
|
||||
attrs.values = append(attrs.values, value)
|
||||
}
|
||||
|
||||
type sortableAttribute struct {
|
||||
SortKey []byte
|
||||
Attribute attribute
|
||||
}
|
||||
|
||||
type attributeSet []sortableAttribute
|
||||
|
||||
func (sa attributeSet) Len() int {
|
||||
return len(sa)
|
||||
}
|
||||
|
||||
func (sa attributeSet) Less(i, j int) bool {
|
||||
return bytes.Compare(sa[i].SortKey, sa[j].SortKey) < 0
|
||||
}
|
||||
|
||||
func (sa attributeSet) Swap(i, j int) {
|
||||
sa[i], sa[j] = sa[j], sa[i]
|
||||
}
|
||||
|
||||
func (sa attributeSet) Attributes() []attribute {
|
||||
attrs := make([]attribute, len(sa))
|
||||
for i, attr := range sa {
|
||||
attrs[i] = attr.Attribute
|
||||
}
|
||||
return attrs
|
||||
}
|
||||
|
||||
func (attrs *attributes) ForMarshalling() ([]attribute, error) {
|
||||
sortables := make(attributeSet, len(attrs.types))
|
||||
for i := range sortables {
|
||||
attrType := attrs.types[i]
|
||||
attrValue := attrs.values[i]
|
||||
asn1Value, err := asn1.Marshal(attrValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
attr := attribute{
|
||||
Type: attrType,
|
||||
Value: asn1.RawValue{Tag: 17, IsCompound: true, Bytes: asn1Value}, // 17 == SET tag
|
||||
}
|
||||
encoded, err := asn1.Marshal(attr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sortables[i] = sortableAttribute{
|
||||
SortKey: encoded,
|
||||
Attribute: attr,
|
||||
}
|
||||
}
|
||||
sort.Sort(sortables)
|
||||
return sortables.Attributes(), nil
|
||||
}
|
429
vendor/github.com/smallstep/pkcs7/sign.go
generated
vendored
Normal file
429
vendor/github.com/smallstep/pkcs7/sign.go
generated
vendored
Normal file
@@ -0,0 +1,429 @@
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SignedData is an opaque data structure for creating signed data payloads
|
||||
type SignedData struct {
|
||||
sd signedData
|
||||
certs []*x509.Certificate
|
||||
data, messageDigest []byte
|
||||
digestOid asn1.ObjectIdentifier
|
||||
encryptionOid asn1.ObjectIdentifier
|
||||
}
|
||||
|
||||
// NewSignedData takes data and initializes a PKCS7 SignedData struct that is
|
||||
// ready to be signed via AddSigner. The digest algorithm is set to SHA1 by default
|
||||
// and can be changed by calling SetDigestAlgorithm.
|
||||
func NewSignedData(data []byte) (*SignedData, error) {
|
||||
content, err := asn1.Marshal(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ci := contentInfo{
|
||||
ContentType: OIDData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
|
||||
}
|
||||
sd := signedData{
|
||||
ContentInfo: ci,
|
||||
Version: 1,
|
||||
}
|
||||
return &SignedData{sd: sd, data: data, digestOid: OIDDigestAlgorithmSHA1}, nil
|
||||
}
|
||||
|
||||
// SignerInfoConfig are optional values to include when adding a signer
|
||||
type SignerInfoConfig struct {
|
||||
ExtraSignedAttributes []Attribute
|
||||
ExtraUnsignedAttributes []Attribute
|
||||
}
|
||||
|
||||
type signedData struct {
|
||||
Version int `asn1:"default:1"`
|
||||
DigestAlgorithmIdentifiers []pkix.AlgorithmIdentifier `asn1:"set"`
|
||||
ContentInfo contentInfo
|
||||
Certificates rawCertificates `asn1:"optional,tag:0"`
|
||||
CRLs []pkix.CertificateList `asn1:"optional,tag:1"`
|
||||
SignerInfos []signerInfo `asn1:"set"`
|
||||
}
|
||||
|
||||
type signerInfo struct {
|
||||
Version int `asn1:"default:1"`
|
||||
IssuerAndSerialNumber issuerAndSerial
|
||||
DigestAlgorithm pkix.AlgorithmIdentifier
|
||||
AuthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:0"`
|
||||
DigestEncryptionAlgorithm pkix.AlgorithmIdentifier
|
||||
EncryptedDigest []byte
|
||||
UnauthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:1"`
|
||||
}
|
||||
|
||||
type attribute struct {
|
||||
Type asn1.ObjectIdentifier
|
||||
Value asn1.RawValue `asn1:"set"`
|
||||
}
|
||||
|
||||
func marshalAttributes(attrs []attribute) ([]byte, error) {
|
||||
encodedAttributes, err := asn1.Marshal(struct {
|
||||
A []attribute `asn1:"set"`
|
||||
}{A: attrs})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Remove the leading sequence octets
|
||||
var raw asn1.RawValue
|
||||
asn1.Unmarshal(encodedAttributes, &raw)
|
||||
return raw.Bytes, nil
|
||||
}
|
||||
|
||||
type rawCertificates struct {
|
||||
Raw asn1.RawContent
|
||||
}
|
||||
|
||||
type issuerAndSerial struct {
|
||||
IssuerName asn1.RawValue
|
||||
SerialNumber *big.Int
|
||||
}
|
||||
|
||||
// SetDigestAlgorithm sets the digest algorithm to be used in the signing process.
|
||||
//
|
||||
// This should be called before adding signers
|
||||
func (sd *SignedData) SetDigestAlgorithm(d asn1.ObjectIdentifier) {
|
||||
sd.digestOid = d
|
||||
}
|
||||
|
||||
// SetEncryptionAlgorithm sets the encryption algorithm to be used in the signing process.
|
||||
//
|
||||
// This should be called before adding signers
|
||||
func (sd *SignedData) SetEncryptionAlgorithm(d asn1.ObjectIdentifier) {
|
||||
sd.encryptionOid = d
|
||||
}
|
||||
|
||||
// AddSigner is a wrapper around AddSignerChain() that adds a signer without any parent.
|
||||
func (sd *SignedData) AddSigner(ee *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error {
|
||||
var parents []*x509.Certificate
|
||||
return sd.AddSignerChain(ee, pkey, parents, config)
|
||||
}
|
||||
|
||||
// AddSignerChain signs attributes about the content and adds certificates
|
||||
// and signers infos to the Signed Data. The certificate and private key
|
||||
// of the end-entity signer are used to issue the signature, and any
|
||||
// parent of that end-entity that need to be added to the list of
|
||||
// certifications can be specified in the parents slice.
|
||||
//
|
||||
// The signature algorithm used to hash the data is the one of the end-entity
|
||||
// certificate.
|
||||
func (sd *SignedData) AddSignerChain(ee *x509.Certificate, pkey crypto.PrivateKey, parents []*x509.Certificate, config SignerInfoConfig) error {
|
||||
// Following RFC 2315, 9.2 SignerInfo type, the distinguished name of
|
||||
// the issuer of the end-entity signer is stored in the issuerAndSerialNumber
|
||||
// section of the SignedData.SignerInfo, alongside the serial number of
|
||||
// the end-entity.
|
||||
var ias issuerAndSerial
|
||||
ias.SerialNumber = ee.SerialNumber
|
||||
if len(parents) == 0 {
|
||||
// no parent, the issuer is the end-entity cert itself
|
||||
ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer}
|
||||
} else {
|
||||
err := verifyPartialChain(ee, parents)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// the first parent is the issuer
|
||||
ias.IssuerName = asn1.RawValue{FullBytes: parents[0].RawSubject}
|
||||
}
|
||||
sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers,
|
||||
pkix.AlgorithmIdentifier{Algorithm: sd.digestOid},
|
||||
)
|
||||
hash, err := getHashForOID(sd.digestOid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := hash.New()
|
||||
h.Write(sd.data)
|
||||
sd.messageDigest = h.Sum(nil)
|
||||
encryptionOid, err := getOIDForEncryptionAlgorithm(pkey, sd.digestOid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attrs := &attributes{}
|
||||
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
|
||||
attrs.Add(OIDAttributeMessageDigest, sd.messageDigest)
|
||||
attrs.Add(OIDAttributeSigningTime, time.Now().UTC())
|
||||
for _, attr := range config.ExtraSignedAttributes {
|
||||
attrs.Add(attr.Type, attr.Value)
|
||||
}
|
||||
finalAttrs, err := attrs.ForMarshalling()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unsignedAttrs := &attributes{}
|
||||
for _, attr := range config.ExtraUnsignedAttributes {
|
||||
unsignedAttrs.Add(attr.Type, attr.Value)
|
||||
}
|
||||
finalUnsignedAttrs, err := unsignedAttrs.ForMarshalling()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// create signature of signed attributes
|
||||
signature, err := signAttributes(finalAttrs, pkey, hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signer := signerInfo{
|
||||
AuthenticatedAttributes: finalAttrs,
|
||||
UnauthenticatedAttributes: finalUnsignedAttrs,
|
||||
DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid},
|
||||
DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: encryptionOid},
|
||||
IssuerAndSerialNumber: ias,
|
||||
EncryptedDigest: signature,
|
||||
Version: 1,
|
||||
}
|
||||
sd.certs = append(sd.certs, ee)
|
||||
if len(parents) > 0 {
|
||||
sd.certs = append(sd.certs, parents...)
|
||||
}
|
||||
sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignWithoutAttr issues a signature on the content of the pkcs7 SignedData.
|
||||
// Unlike AddSigner/AddSignerChain, it calculates the digest on the data alone
|
||||
// and does not include any signed attributes like timestamp and so on.
|
||||
//
|
||||
// This function is needed to sign old Android APKs, something you probably
|
||||
// shouldn't do unless you're maintaining backward compatibility for old
|
||||
// applications.
|
||||
func (sd *SignedData) SignWithoutAttr(ee *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error {
|
||||
var signature []byte
|
||||
sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers, pkix.AlgorithmIdentifier{Algorithm: sd.digestOid})
|
||||
hash, err := getHashForOID(sd.digestOid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := hash.New()
|
||||
h.Write(sd.data)
|
||||
sd.messageDigest = h.Sum(nil)
|
||||
switch pkey := pkey.(type) {
|
||||
case *dsa.PrivateKey:
|
||||
// dsa doesn't implement crypto.Signer so we make a special case
|
||||
// https://github.com/golang/go/issues/27889
|
||||
r, s, err := dsa.Sign(rand.Reader, pkey, sd.messageDigest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signature, err = asn1.Marshal(dsaSignature{r, s})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
key, ok := pkey.(crypto.Signer)
|
||||
if !ok {
|
||||
return errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||
}
|
||||
signature, err = key.Sign(rand.Reader, sd.messageDigest, hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
var ias issuerAndSerial
|
||||
ias.SerialNumber = ee.SerialNumber
|
||||
// no parent, the issue is the end-entity cert itself
|
||||
ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer}
|
||||
if sd.encryptionOid == nil {
|
||||
// if the encryption algorithm wasn't set by SetEncryptionAlgorithm,
|
||||
// infer it from the digest algorithm
|
||||
sd.encryptionOid, err = getOIDForEncryptionAlgorithm(pkey, sd.digestOid)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signer := signerInfo{
|
||||
DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid},
|
||||
DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.encryptionOid},
|
||||
IssuerAndSerialNumber: ias,
|
||||
EncryptedDigest: signature,
|
||||
Version: 1,
|
||||
}
|
||||
// create signature of signed attributes
|
||||
sd.certs = append(sd.certs, ee)
|
||||
sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (si *signerInfo) SetUnauthenticatedAttributes(extraUnsignedAttrs []Attribute) error {
|
||||
unsignedAttrs := &attributes{}
|
||||
for _, attr := range extraUnsignedAttrs {
|
||||
unsignedAttrs.Add(attr.Type, attr.Value)
|
||||
}
|
||||
finalUnsignedAttrs, err := unsignedAttrs.ForMarshalling()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
si.UnauthenticatedAttributes = finalUnsignedAttrs
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddCertificate adds the certificate to the payload. Useful for parent certificates
|
||||
func (sd *SignedData) AddCertificate(cert *x509.Certificate) {
|
||||
sd.certs = append(sd.certs, cert)
|
||||
}
|
||||
|
||||
// Detach removes content from the signed data struct to make it a detached signature.
|
||||
// This must be called right before Finish()
|
||||
func (sd *SignedData) Detach() {
|
||||
sd.sd.ContentInfo = contentInfo{ContentType: OIDData}
|
||||
}
|
||||
|
||||
// GetSignedData returns the private Signed Data
|
||||
func (sd *SignedData) GetSignedData() *signedData {
|
||||
return &sd.sd
|
||||
}
|
||||
|
||||
// Finish marshals the content and its signers
|
||||
func (sd *SignedData) Finish() ([]byte, error) {
|
||||
sd.sd.Certificates = marshalCertificates(sd.certs)
|
||||
inner, err := asn1.Marshal(sd.sd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outer := contentInfo{
|
||||
ContentType: OIDSignedData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: inner, IsCompound: true},
|
||||
}
|
||||
return asn1.Marshal(outer)
|
||||
}
|
||||
|
||||
// RemoveAuthenticatedAttributes removes authenticated attributes from signedData
|
||||
// similar to OpenSSL's PKCS7_NOATTR or -noattr flags
|
||||
func (sd *SignedData) RemoveAuthenticatedAttributes() {
|
||||
for i := range sd.sd.SignerInfos {
|
||||
sd.sd.SignerInfos[i].AuthenticatedAttributes = nil
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveUnauthenticatedAttributes removes unauthenticated attributes from signedData
|
||||
func (sd *SignedData) RemoveUnauthenticatedAttributes() {
|
||||
for i := range sd.sd.SignerInfos {
|
||||
sd.sd.SignerInfos[i].UnauthenticatedAttributes = nil
|
||||
}
|
||||
}
|
||||
|
||||
// verifyPartialChain checks that a given cert is issued by the first parent in the list,
|
||||
// then continue down the path. It doesn't require the last parent to be a root CA,
|
||||
// or to be trusted in any truststore. It simply verifies that the chain provided, albeit
|
||||
// partial, makes sense.
|
||||
func verifyPartialChain(cert *x509.Certificate, parents []*x509.Certificate) error {
|
||||
if len(parents) == 0 {
|
||||
return fmt.Errorf("pkcs7: zero parents provided to verify the signature of certificate %q", cert.Subject.CommonName)
|
||||
}
|
||||
err := cert.CheckSignatureFrom(parents[0])
|
||||
if err != nil {
|
||||
return fmt.Errorf("pkcs7: certificate signature from parent is invalid: %v", err)
|
||||
}
|
||||
if len(parents) == 1 {
|
||||
// there is no more parent to check, return
|
||||
return nil
|
||||
}
|
||||
return verifyPartialChain(parents[0], parents[1:])
|
||||
}
|
||||
|
||||
func cert2issuerAndSerial(cert *x509.Certificate) (issuerAndSerial, error) {
|
||||
var ias issuerAndSerial
|
||||
// The issuer RDNSequence has to match exactly the sequence in the certificate
|
||||
// We cannot use cert.Issuer.ToRDNSequence() here since it mangles the sequence
|
||||
ias.IssuerName = asn1.RawValue{FullBytes: cert.RawIssuer}
|
||||
ias.SerialNumber = cert.SerialNumber
|
||||
|
||||
return ias, nil
|
||||
}
|
||||
|
||||
// signs the DER encoded form of the attributes with the private key
|
||||
func signAttributes(attrs []attribute, pkey crypto.PrivateKey, digestAlg crypto.Hash) ([]byte, error) {
|
||||
attrBytes, err := marshalAttributes(attrs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
h := digestAlg.New()
|
||||
h.Write(attrBytes)
|
||||
hash := h.Sum(nil)
|
||||
|
||||
// dsa doesn't implement crypto.Signer so we make a special case
|
||||
// https://github.com/golang/go/issues/27889
|
||||
switch pkey := pkey.(type) {
|
||||
case *dsa.PrivateKey:
|
||||
r, s, err := dsa.Sign(rand.Reader, pkey, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return asn1.Marshal(dsaSignature{r, s})
|
||||
}
|
||||
|
||||
key, ok := pkey.(crypto.Signer)
|
||||
if !ok {
|
||||
return nil, errors.New("pkcs7: private key does not implement crypto.Signer")
|
||||
}
|
||||
return key.Sign(rand.Reader, hash, digestAlg)
|
||||
}
|
||||
|
||||
type dsaSignature struct {
|
||||
R, S *big.Int
|
||||
}
|
||||
|
||||
// concats and wraps the certificates in the RawValue structure
|
||||
func marshalCertificates(certs []*x509.Certificate) rawCertificates {
|
||||
var buf bytes.Buffer
|
||||
for _, cert := range certs {
|
||||
buf.Write(cert.Raw)
|
||||
}
|
||||
rawCerts, _ := marshalCertificateBytes(buf.Bytes())
|
||||
return rawCerts
|
||||
}
|
||||
|
||||
// Even though, the tag & length are stripped out during marshalling the
|
||||
// RawContent, we have to encode it into the RawContent. If its missing,
|
||||
// then `asn1.Marshal()` will strip out the certificate wrapper instead.
|
||||
func marshalCertificateBytes(certs []byte) (rawCertificates, error) {
|
||||
var val = asn1.RawValue{Bytes: certs, Class: 2, Tag: 0, IsCompound: true}
|
||||
b, err := asn1.Marshal(val)
|
||||
if err != nil {
|
||||
return rawCertificates{}, err
|
||||
}
|
||||
return rawCertificates{Raw: b}, nil
|
||||
}
|
||||
|
||||
// DegenerateCertificate creates a signed data structure containing only the
|
||||
// provided certificate or certificate chain.
|
||||
func DegenerateCertificate(cert []byte) ([]byte, error) {
|
||||
rawCert, err := marshalCertificateBytes(cert)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
emptyContent := contentInfo{ContentType: OIDData}
|
||||
sd := signedData{
|
||||
Version: 1,
|
||||
ContentInfo: emptyContent,
|
||||
Certificates: rawCert,
|
||||
CRLs: []pkix.CertificateList{},
|
||||
}
|
||||
content, err := asn1.Marshal(sd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signedContent := contentInfo{
|
||||
ContentType: OIDSignedData,
|
||||
Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true},
|
||||
}
|
||||
return asn1.Marshal(signedContent)
|
||||
}
|
365
vendor/github.com/smallstep/pkcs7/verify.go
generated
vendored
Normal file
365
vendor/github.com/smallstep/pkcs7/verify.go
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
package pkcs7
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Verify is a wrapper around VerifyWithChain() that initializes an empty
|
||||
// trust store, effectively disabling certificate verification when validating
|
||||
// a signature.
|
||||
func (p7 *PKCS7) Verify() (err error) {
|
||||
return p7.VerifyWithChain(nil)
|
||||
}
|
||||
|
||||
// VerifyWithChain checks the signatures of a PKCS7 object.
|
||||
//
|
||||
// If truststore is not nil, it also verifies the chain of trust of
|
||||
// the end-entity signer cert to one of the roots in the
|
||||
// truststore. When the PKCS7 object includes the signing time
|
||||
// authenticated attr verifies the chain at that time and UTC now
|
||||
// otherwise.
|
||||
func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error) {
|
||||
if len(p7.Signers) == 0 {
|
||||
return errors.New("pkcs7: Message has no signers")
|
||||
}
|
||||
for _, signer := range p7.Signers {
|
||||
if err := verifySignature(p7, signer, truststore); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// VerifyWithChainAtTime checks the signatures of a PKCS7 object.
|
||||
//
|
||||
// If truststore is not nil, it also verifies the chain of trust of
|
||||
// the end-entity signer cert to a root in the truststore at
|
||||
// currentTime. It does not use the signing time authenticated
|
||||
// attribute.
|
||||
func (p7 *PKCS7) VerifyWithChainAtTime(truststore *x509.CertPool, currentTime time.Time) (err error) {
|
||||
if len(p7.Signers) == 0 {
|
||||
return errors.New("pkcs7: Message has no signers")
|
||||
}
|
||||
for _, signer := range p7.Signers {
|
||||
if err := verifySignatureAtTime(p7, signer, truststore, currentTime); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SigningTimeNotValidError is returned when the signing time attribute
|
||||
// falls outside of the signer certificate validity.
|
||||
type SigningTimeNotValidError struct {
|
||||
SigningTime time.Time
|
||||
NotBefore time.Time // NotBefore of signer
|
||||
NotAfter time.Time // NotAfter of signer
|
||||
}
|
||||
|
||||
func (e *SigningTimeNotValidError) Error() string {
|
||||
return fmt.Sprintf("pkcs7: signing time %q is outside of certificate validity %q to %q",
|
||||
e.SigningTime.Format(time.RFC3339),
|
||||
e.NotBefore.Format(time.RFC3339),
|
||||
e.NotAfter.Format(time.RFC3339))
|
||||
}
|
||||
|
||||
func verifySignatureAtTime(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool, currentTime time.Time) (err error) {
|
||||
signedData := p7.Content
|
||||
ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
||||
if ee == nil {
|
||||
return errors.New("pkcs7: No certificate for signer")
|
||||
}
|
||||
if len(signer.AuthenticatedAttributes) > 0 {
|
||||
// TODO(fullsailor): First check the content type match
|
||||
var (
|
||||
digest []byte
|
||||
signingTime time.Time
|
||||
)
|
||||
err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := hash.New()
|
||||
h.Write(p7.Content)
|
||||
computed := h.Sum(nil)
|
||||
if subtle.ConstantTimeCompare(digest, computed) != 1 {
|
||||
return &MessageDigestMismatchError{
|
||||
ExpectedDigest: digest,
|
||||
ActualDigest: computed,
|
||||
}
|
||||
}
|
||||
signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
|
||||
if err == nil {
|
||||
// signing time found, performing validity check
|
||||
if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) {
|
||||
return &SigningTimeNotValidError{
|
||||
SigningTime: signingTime,
|
||||
NotBefore: ee.NotBefore,
|
||||
NotAfter: ee.NotAfter,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if truststore != nil {
|
||||
_, err = verifyCertChain(ee, p7.Certificates, truststore, currentTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
|
||||
}
|
||||
|
||||
func verifySignature(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool) (err error) {
|
||||
signedData := p7.Content
|
||||
ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
||||
if ee == nil {
|
||||
return errors.New("pkcs7: No certificate for signer")
|
||||
}
|
||||
signingTime := time.Now().UTC()
|
||||
if len(signer.AuthenticatedAttributes) > 0 {
|
||||
// TODO(fullsailor): First check the content type match
|
||||
var digest []byte
|
||||
err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h := hash.New()
|
||||
h.Write(p7.Content)
|
||||
computed := h.Sum(nil)
|
||||
if subtle.ConstantTimeCompare(digest, computed) != 1 {
|
||||
return &MessageDigestMismatchError{
|
||||
ExpectedDigest: digest,
|
||||
ActualDigest: computed,
|
||||
}
|
||||
}
|
||||
signedData, err = marshalAttributes(signer.AuthenticatedAttributes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime)
|
||||
if err == nil {
|
||||
// signing time found, performing validity check
|
||||
if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) {
|
||||
return &SigningTimeNotValidError{
|
||||
SigningTime: signingTime,
|
||||
NotBefore: ee.NotBefore,
|
||||
NotAfter: ee.NotAfter,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if truststore != nil {
|
||||
_, err = verifyCertChain(ee, p7.Certificates, truststore, signingTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest)
|
||||
}
|
||||
|
||||
// GetOnlySigner returns an x509.Certificate for the first signer of the signed
|
||||
// data payload. If there are more or less than one signer, nil is returned
|
||||
func (p7 *PKCS7) GetOnlySigner() *x509.Certificate {
|
||||
if len(p7.Signers) != 1 {
|
||||
return nil
|
||||
}
|
||||
signer := p7.Signers[0]
|
||||
return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber)
|
||||
}
|
||||
|
||||
// UnmarshalSignedAttribute decodes a single attribute from the signer info
|
||||
func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error {
|
||||
sd, ok := p7.raw.(signedData)
|
||||
if !ok {
|
||||
return errors.New("pkcs7: payload is not signedData content")
|
||||
}
|
||||
if len(sd.SignerInfos) < 1 {
|
||||
return errors.New("pkcs7: payload has no signers")
|
||||
}
|
||||
attributes := sd.SignerInfos[0].AuthenticatedAttributes
|
||||
return unmarshalAttribute(attributes, attributeType, out)
|
||||
}
|
||||
|
||||
func parseSignedData(data []byte) (*PKCS7, error) {
|
||||
var sd signedData
|
||||
asn1.Unmarshal(data, &sd)
|
||||
certs, err := sd.Certificates.Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// fmt.Printf("--> Signed Data Version %d\n", sd.Version)
|
||||
|
||||
var compound asn1.RawValue
|
||||
var content unsignedData
|
||||
|
||||
// The Content.Bytes maybe empty on PKI responses.
|
||||
if len(sd.ContentInfo.Content.Bytes) > 0 {
|
||||
if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Compound octet string
|
||||
if compound.IsCompound {
|
||||
if compound.Tag == 4 {
|
||||
for len(compound.Bytes) > 0 {
|
||||
var cdata asn1.RawValue
|
||||
if _, err = asn1.Unmarshal(compound.Bytes, &cdata); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
content = append(content, cdata.Bytes...)
|
||||
compound.Bytes = compound.Bytes[len(cdata.FullBytes):]
|
||||
}
|
||||
} else {
|
||||
content = compound.Bytes
|
||||
}
|
||||
} else {
|
||||
// assuming this is tag 04
|
||||
content = compound.Bytes
|
||||
}
|
||||
return &PKCS7{
|
||||
Content: content,
|
||||
Certificates: certs,
|
||||
CRLs: sd.CRLs,
|
||||
Signers: sd.SignerInfos,
|
||||
raw: sd}, nil
|
||||
}
|
||||
|
||||
// verifyCertChain takes an end-entity certs, a list of potential intermediates and a
|
||||
// truststore, and built all potential chains between the EE and a trusted root.
|
||||
//
|
||||
// When verifying chains that may have expired, currentTime can be set to a past date
|
||||
// to allow the verification to pass. If unset, currentTime is set to the current UTC time.
|
||||
func verifyCertChain(ee *x509.Certificate, certs []*x509.Certificate, truststore *x509.CertPool, currentTime time.Time) (chains [][]*x509.Certificate, err error) {
|
||||
intermediates := x509.NewCertPool()
|
||||
for _, intermediate := range certs {
|
||||
intermediates.AddCert(intermediate)
|
||||
}
|
||||
verifyOptions := x509.VerifyOptions{
|
||||
Roots: truststore,
|
||||
Intermediates: intermediates,
|
||||
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
|
||||
CurrentTime: currentTime,
|
||||
}
|
||||
chains, err = ee.Verify(verifyOptions)
|
||||
if err != nil {
|
||||
return chains, fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// MessageDigestMismatchError is returned when the signer data digest does not
|
||||
// match the computed digest for the contained content
|
||||
type MessageDigestMismatchError struct {
|
||||
ExpectedDigest []byte
|
||||
ActualDigest []byte
|
||||
}
|
||||
|
||||
func (err *MessageDigestMismatchError) Error() string {
|
||||
return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest)
|
||||
}
|
||||
|
||||
func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) {
|
||||
switch {
|
||||
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1):
|
||||
return x509.ECDSAWithSHA1, nil
|
||||
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256):
|
||||
return x509.ECDSAWithSHA256, nil
|
||||
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384):
|
||||
return x509.ECDSAWithSHA384, nil
|
||||
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512):
|
||||
return x509.ECDSAWithSHA512, nil
|
||||
case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA),
|
||||
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1),
|
||||
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256),
|
||||
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384),
|
||||
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512):
|
||||
switch {
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1):
|
||||
return x509.SHA1WithRSA, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256):
|
||||
return x509.SHA256WithRSA, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384):
|
||||
return x509.SHA384WithRSA, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512):
|
||||
return x509.SHA512WithRSA, nil
|
||||
default:
|
||||
return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
|
||||
digest.Algorithm.String(), digestEncryption.Algorithm.String())
|
||||
}
|
||||
case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA),
|
||||
digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1):
|
||||
switch {
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
|
||||
return x509.DSAWithSHA1, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
|
||||
return x509.DSAWithSHA256, nil
|
||||
default:
|
||||
return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
|
||||
digest.Algorithm.String(), digestEncryption.Algorithm.String())
|
||||
}
|
||||
case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256),
|
||||
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384),
|
||||
digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521):
|
||||
switch {
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1):
|
||||
return x509.ECDSAWithSHA1, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
|
||||
return x509.ECDSAWithSHA256, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
|
||||
return x509.ECDSAWithSHA384, nil
|
||||
case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
|
||||
return x509.ECDSAWithSHA512, nil
|
||||
default:
|
||||
return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q",
|
||||
digest.Algorithm.String(), digestEncryption.Algorithm.String())
|
||||
}
|
||||
default:
|
||||
return -1, fmt.Errorf("pkcs7: unsupported algorithm %q",
|
||||
digestEncryption.Algorithm.String())
|
||||
}
|
||||
}
|
||||
|
||||
func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate {
|
||||
for _, cert := range certs {
|
||||
if isCertMatchForIssuerAndSerial(cert, ias) {
|
||||
return cert
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error {
|
||||
for _, attr := range attrs {
|
||||
if attr.Type.Equal(attributeType) {
|
||||
_, err := asn1.Unmarshal(attr.Value.Bytes, out)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return errors.New("pkcs7: attribute type not in attributes")
|
||||
}
|
Reference in New Issue
Block a user