summaryrefslogtreecommitdiff
path: root/vendor/go.mozilla.org/pkcs7
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.mozilla.org/pkcs7')
-rw-r--r--vendor/go.mozilla.org/pkcs7/.gitignore24
-rw-r--r--vendor/go.mozilla.org/pkcs7/.travis.yml10
-rw-r--r--vendor/go.mozilla.org/pkcs7/LICENSE22
-rw-r--r--vendor/go.mozilla.org/pkcs7/Makefile20
-rw-r--r--vendor/go.mozilla.org/pkcs7/README.md69
-rw-r--r--vendor/go.mozilla.org/pkcs7/ber.go251
-rw-r--r--vendor/go.mozilla.org/pkcs7/decrypt.go177
-rw-r--r--vendor/go.mozilla.org/pkcs7/encrypt.go399
-rw-r--r--vendor/go.mozilla.org/pkcs7/go.mod3
-rw-r--r--vendor/go.mozilla.org/pkcs7/pkcs7.go291
-rw-r--r--vendor/go.mozilla.org/pkcs7/sign.go429
-rw-r--r--vendor/go.mozilla.org/pkcs7/verify.go264
12 files changed, 1959 insertions, 0 deletions
diff --git a/vendor/go.mozilla.org/pkcs7/.gitignore b/vendor/go.mozilla.org/pkcs7/.gitignore
new file mode 100644
index 000000000..daf913b1b
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/.gitignore
@@ -0,0 +1,24 @@
+# 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
diff --git a/vendor/go.mozilla.org/pkcs7/.travis.yml b/vendor/go.mozilla.org/pkcs7/.travis.yml
new file mode 100644
index 000000000..eac4c1762
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/.travis.yml
@@ -0,0 +1,10 @@
+language: go
+go:
+ - "1.11"
+ - "1.12"
+ - "1.13"
+ - tip
+before_install:
+ - make gettools
+script:
+ - make
diff --git a/vendor/go.mozilla.org/pkcs7/LICENSE b/vendor/go.mozilla.org/pkcs7/LICENSE
new file mode 100644
index 000000000..75f320908
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/LICENSE
@@ -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.
+
diff --git a/vendor/go.mozilla.org/pkcs7/Makefile b/vendor/go.mozilla.org/pkcs7/Makefile
new file mode 100644
index 000000000..47c73b868
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/Makefile
@@ -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
diff --git a/vendor/go.mozilla.org/pkcs7/README.md b/vendor/go.mozilla.org/pkcs7/README.md
new file mode 100644
index 000000000..bf37059c5
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/README.md
@@ -0,0 +1,69 @@
+# pkcs7
+
+[![GoDoc](https://godoc.org/go.mozilla.org/pkcs7?status.svg)](https://godoc.org/go.mozilla.org/pkcs7)
+[![Build Status](https://travis-ci.org/mozilla-services/pkcs7.svg?branch=master)](https://travis-ci.org/mozilla-services/pkcs7)
+
+pkcs7 implements parsing and creating signed and enveloped messages.
+
+```go
+package main
+
+import (
+ "bytes"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+ "os"
+
+ "go.mozilla.org/pkcs7"
+)
+
+func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateKey) (signed []byte, err error) {
+ toBeSigned, err := NewSignedData(content)
+ if err != nil {
+ err = fmt.Errorf("Cannot initialize signed data: %s", err)
+ return
+ }
+ if err = toBeSigned.AddSigner(cert, privkey, SignerInfoConfig{}); err != nil {
+ err = fmt.Errorf("Cannot add signer: %s", err)
+ return
+ }
+
+ // Detach signature, omit if you want an embedded signature
+ toBeSigned.Detach()
+
+ signed, err = toBeSigned.Finish()
+ if err != nil {
+ err = fmt.Errorf("Cannot finish signing data: %s", err)
+ return
+ }
+
+ // Verify the signature
+ pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed})
+ p7, err := pkcs7.Parse(signed)
+ if err != nil {
+ err = fmt.Errorf("Cannot parse our signed data: %s", err)
+ return
+ }
+
+ // since the signature was detached, reattach the content here
+ p7.Content = content
+
+ if bytes.Compare(content, p7.Content) != 0 {
+ err = fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content)
+ return
+ }
+ if err = p7.Verify(); err != nil {
+ err = fmt.Errorf("Cannot verify our signed data: %s", err)
+ return
+ }
+
+ return signed, nil
+}
+```
+
+
+
+## Credits
+This is a fork of [fullsailor/pkcs7](https://github.com/fullsailor/pkcs7)
diff --git a/vendor/go.mozilla.org/pkcs7/ber.go b/vendor/go.mozilla.org/pkcs7/ber.go
new file mode 100644
index 000000000..585256739
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/ber.go
@@ -0,0 +1,251 @@
+package pkcs7
+
+import (
+ "bytes"
+ "errors"
+)
+
+var encodeIndent = 0
+
+type asn1Object interface {
+ EncodeTo(writer *bytes.Buffer) error
+}
+
+type asn1Structured struct {
+ tagBytes []byte
+ content []asn1Object
+}
+
+func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
+ //fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
+ encodeIndent++
+ inner := new(bytes.Buffer)
+ for _, obj := range s.content {
+ err := obj.EncodeTo(inner)
+ if err != nil {
+ return err
+ }
+ }
+ encodeIndent--
+ 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")
+ }
+ hack := 0
+ 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 {
+ // find length by searching content
+ markerIndex := bytes.LastIndex(ber[offset:], []byte{0x0, 0x0})
+ if markerIndex == -1 {
+ return nil, 0, errors.New("ber2der: Invalid BER format")
+ }
+ length = markerIndex
+ hack = 2
+ debugprint("--> (compute length) marker found at offset: %d\n", markerIndex+offset)
+ } 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 kind == 0 {
+ obj = asn1Primitive{
+ tagBytes: ber[tagStart:tagEnd],
+ length: length,
+ content: ber[offset:contentEnd],
+ }
+ } else {
+ var subObjects []asn1Object
+ for offset < contentEnd {
+ var subObj asn1Object
+ var err error
+ subObj, offset, err = readObject(ber[:contentEnd], offset)
+ if err != nil {
+ return nil, 0, err
+ }
+ subObjects = append(subObjects, subObj)
+ }
+ obj = asn1Structured{
+ tagBytes: ber[tagStart:tagEnd],
+ content: subObjects,
+ }
+ }
+
+ return obj, contentEnd + hack, nil
+}
+
+func debugprint(format string, a ...interface{}) {
+ //fmt.Printf(format, a)
+}
diff --git a/vendor/go.mozilla.org/pkcs7/decrypt.go b/vendor/go.mozilla.org/pkcs7/decrypt.go
new file mode 100644
index 000000000..0d088d628
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/decrypt.go
@@ -0,0 +1,177 @@
+package pkcs7
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "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")
+
+// 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 *rsa.PrivateKey:
+ var contentKey []byte
+ contentKey, err := rsa.DecryptPKCS1v15(rand.Reader, pkey, recipient.EncryptedKey)
+ if err != nil {
+ return nil, err
+ }
+ return data.EncryptedContentInfo.decrypt(contentKey)
+ }
+ return nil, ErrUnsupportedAlgorithm
+}
+
+// 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) {
+ fmt.Printf("Unsupported Content Encryption Algorithm: %s\n", alg)
+ 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, &params)
+ 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("invalid blocklen %d", blocklen)
+ }
+ if len(data)%blocklen != 0 || len(data) == 0 {
+ return nil, fmt.Errorf("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("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{}
+}
diff --git a/vendor/go.mozilla.org/pkcs7/encrypt.go b/vendor/go.mozilla.org/pkcs7/encrypt.go
new file mode 100644
index 000000000..da57ae643
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/encrypt.go
@@ -0,0 +1,399 @@
+package pkcs7
+
+import (
+ "bytes"
+ "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,explicit"`
+}
+
+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")
+
+// 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 = EncryptionAlgorithmAES128GCM
+//
+// 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 {
+ encrypted, err := encryptKey(key, recipient)
+ if err != nil {
+ return nil, err
+ }
+ ias, err := cert2issuerAndSerial(recipient)
+ if err != nil {
+ return nil, err
+ }
+ info := recipientInfo{
+ Version: 0,
+ IssuerAndSerialNumber: ias,
+ KeyEncryptionAlgorithm: pkix.AlgorithmIdentifier{
+ Algorithm: OIDEncryptionAlgorithmRSA,
+ },
+ 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)
+}
+
+// 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 {
+ asn1Content, _ := asn1.Marshal(content)
+ return asn1.RawValue{Tag: 0, Class: 2, Bytes: asn1Content, IsCompound: true}
+}
+
+func encryptKey(key []byte, recipient *x509.Certificate) ([]byte, error) {
+ if pub := recipient.PublicKey.(*rsa.PublicKey); pub != nil {
+ return rsa.EncryptPKCS1v15(rand.Reader, pub, key)
+ }
+ return nil, ErrUnsupportedAlgorithm
+}
+
+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
+}
diff --git a/vendor/go.mozilla.org/pkcs7/go.mod b/vendor/go.mozilla.org/pkcs7/go.mod
new file mode 100644
index 000000000..10ddff325
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/go.mod
@@ -0,0 +1,3 @@
+module go.mozilla.org/pkcs7
+
+go 1.11
diff --git a/vendor/go.mozilla.org/pkcs7/pkcs7.go b/vendor/go.mozilla.org/pkcs7/pkcs7.go
new file mode 100644
index 000000000..ccc6cc6df
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/pkcs7.go
@@ -0,0 +1,291 @@
+// 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"
+
+ _ "crypto/sha1" // for crypto.SHA1
+)
+
+// 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 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}
+
+ 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
+ OIDEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+ OIDEncryptionAlgorithmRSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+ OIDEncryptionAlgorithmRSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+ OIDEncryptionAlgorithmRSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+ OIDEncryptionAlgorithmRSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+
+ 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}
+
+ // Encryption Algorithms
+ OIDEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7}
+ OIDEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7}
+ OIDEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42}
+ OIDEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6}
+ OIDEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2}
+ OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46}
+)
+
+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 private key type of the signer and
+// the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm
+func getOIDForEncryptionAlgorithm(pkey crypto.PrivateKey, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) {
+ switch pkey.(type) {
+ case *rsa.PrivateKey:
+ 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:
+ 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:
+ return OIDDigestAlgorithmDSA, nil
+ }
+ 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
+}
+
+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
+ }
+
+ return x509.ParseCertificates(val.Bytes)
+}
+
+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
+}
diff --git a/vendor/go.mozilla.org/pkcs7/sign.go b/vendor/go.mozilla.org/pkcs7/sign.go
new file mode 100644
index 000000000..addd76383
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/sign.go
@@ -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)
+}
diff --git a/vendor/go.mozilla.org/pkcs7/verify.go b/vendor/go.mozilla.org/pkcs7/verify.go
new file mode 100644
index 000000000..c8ead2362
--- /dev/null
+++ b/vendor/go.mozilla.org/pkcs7/verify.go
@@ -0,0 +1,264 @@
+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 root in the truststore.
+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
+}
+
+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 fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q",
+ signingTime.Format(time.RFC3339),
+ ee.NotBefore.Format(time.RFC3339),
+ ee.NotBefore.Format(time.RFC3339))
+ }
+ }
+ }
+ 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 {
+ if _, err = asn1.Unmarshal(compound.Bytes, &content); err != nil {
+ return nil, err
+ }
+ } 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):
+ return x509.SHA1WithRSA, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256):
+ return x509.SHA256WithRSA, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384):
+ return x509.SHA384WithRSA, nil
+ case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512):
+ 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")
+}