From 19f0397fe96f665fc4e522375fd68caafbe06996 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 26 Feb 2021 00:55:37 +0100 Subject: [PATCH] Remove the copy of mozilla/pkcs7 Apparently the existing library works out of the box, after all. We'll have to see how it works out continuing forward. --- scep/authority.go | 4 +- scep/pkcs7/.gitignore | 24 -- scep/pkcs7/.travis.yml | 10 - scep/pkcs7/LICENSE | 22 -- scep/pkcs7/Makefile | 20 -- scep/pkcs7/README.md | 69 ---- scep/pkcs7/ber.go | 251 ------------- scep/pkcs7/ber_test.go | 62 ---- scep/pkcs7/decrypt.go | 177 --------- scep/pkcs7/decrypt_test.go | 60 ---- scep/pkcs7/encrypt.go | 399 --------------------- scep/pkcs7/encrypt_test.go | 102 ------ scep/pkcs7/pkcs7.go | 291 --------------- scep/pkcs7/pkcs7_test.go | 326 ----------------- scep/pkcs7/sign.go | 429 ---------------------- scep/pkcs7/sign_test.go | 266 -------------- scep/pkcs7/verify.go | 264 -------------- scep/pkcs7/verify_test.go | 713 ------------------------------------- scep/scep.go | 4 +- 19 files changed, 6 insertions(+), 3487 deletions(-) delete mode 100644 scep/pkcs7/.gitignore delete mode 100644 scep/pkcs7/.travis.yml delete mode 100644 scep/pkcs7/LICENSE delete mode 100644 scep/pkcs7/Makefile delete mode 100644 scep/pkcs7/README.md delete mode 100644 scep/pkcs7/ber.go delete mode 100644 scep/pkcs7/ber_test.go delete mode 100644 scep/pkcs7/decrypt.go delete mode 100644 scep/pkcs7/decrypt_test.go delete mode 100644 scep/pkcs7/encrypt.go delete mode 100644 scep/pkcs7/encrypt_test.go delete mode 100644 scep/pkcs7/pkcs7.go delete mode 100644 scep/pkcs7/pkcs7_test.go delete mode 100644 scep/pkcs7/sign.go delete mode 100644 scep/pkcs7/sign_test.go delete mode 100644 scep/pkcs7/verify.go delete mode 100644 scep/pkcs7/verify_test.go diff --git a/scep/authority.go b/scep/authority.go index 244a6f92..864ecbba 100644 --- a/scep/authority.go +++ b/scep/authority.go @@ -18,7 +18,9 @@ import ( microx509util "github.com/micromdm/scep/crypto/x509util" microscep "github.com/micromdm/scep/scep" - "github.com/smallstep/certificates/scep/pkcs7" + //"github.com/smallstep/certificates/scep/pkcs7" + + "go.mozilla.org/pkcs7" "go.step.sm/crypto/x509util" ) diff --git a/scep/pkcs7/.gitignore b/scep/pkcs7/.gitignore deleted file mode 100644 index daf913b1..00000000 --- a/scep/pkcs7/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# 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/scep/pkcs7/.travis.yml b/scep/pkcs7/.travis.yml deleted file mode 100644 index eac4c176..00000000 --- a/scep/pkcs7/.travis.yml +++ /dev/null @@ -1,10 +0,0 @@ -language: go -go: - - "1.11" - - "1.12" - - "1.13" - - tip -before_install: - - make gettools -script: - - make diff --git a/scep/pkcs7/LICENSE b/scep/pkcs7/LICENSE deleted file mode 100644 index 75f32090..00000000 --- a/scep/pkcs7/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -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/scep/pkcs7/Makefile b/scep/pkcs7/Makefile deleted file mode 100644 index 47c73b86..00000000 --- a/scep/pkcs7/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -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/scep/pkcs7/README.md b/scep/pkcs7/README.md deleted file mode 100644 index bf37059c..00000000 --- a/scep/pkcs7/README.md +++ /dev/null @@ -1,69 +0,0 @@ -# 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/scep/pkcs7/ber.go b/scep/pkcs7/ber.go deleted file mode 100644 index 58525673..00000000 --- a/scep/pkcs7/ber.go +++ /dev/null @@ -1,251 +0,0 @@ -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/scep/pkcs7/ber_test.go b/scep/pkcs7/ber_test.go deleted file mode 100644 index fcb4b6a2..00000000 --- a/scep/pkcs7/ber_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package pkcs7 - -import ( - "bytes" - "encoding/asn1" - "strings" - "testing" -) - -func TestBer2Der(t *testing.T) { - // indefinite length fixture - ber := []byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00} - expected := []byte{0x30, 0x03, 0x02, 0x01, 0x01} - der, err := ber2der(ber) - if err != nil { - t.Fatalf("ber2der failed with error: %v", err) - } - if !bytes.Equal(der, expected) { - t.Errorf("ber2der result did not match.\n\tExpected: % X\n\tActual: % X", expected, der) - } - - if der2, err := ber2der(der); err != nil { - t.Errorf("ber2der on DER bytes failed with error: %v", err) - } else { - if !bytes.Equal(der, der2) { - t.Error("ber2der is not idempotent") - } - } - var thing struct { - Number int - } - rest, err := asn1.Unmarshal(der, &thing) - if err != nil { - t.Errorf("Cannot parse resulting DER because: %v", err) - } else if len(rest) > 0 { - t.Errorf("Resulting DER has trailing data: % X", rest) - } -} - -func TestBer2Der_Negatives(t *testing.T) { - fixtures := []struct { - Input []byte - ErrorContains string - }{ - {[]byte{0x30, 0x85}, "tag length too long"}, - {[]byte{0x30, 0x84, 0x80, 0x0, 0x0, 0x0}, "length is negative"}, - {[]byte{0x30, 0x82, 0x0, 0x1}, "length has leading zero"}, - {[]byte{0x30, 0x80, 0x1, 0x2}, "Invalid BER format"}, - {[]byte{0x30, 0x03, 0x01, 0x02}, "length is more than available data"}, - {[]byte{0x30}, "end of ber data reached"}, - } - - for _, fixture := range fixtures { - _, err := ber2der(fixture.Input) - if err == nil { - t.Errorf("No error thrown. Expected: %s", fixture.ErrorContains) - } - if !strings.Contains(err.Error(), fixture.ErrorContains) { - t.Errorf("Unexpected error thrown.\n\tExpected: /%s/\n\tActual: %s", fixture.ErrorContains, err.Error()) - } - } -} diff --git a/scep/pkcs7/decrypt.go b/scep/pkcs7/decrypt.go deleted file mode 100644 index 0d088d62..00000000 --- a/scep/pkcs7/decrypt.go +++ /dev/null @@ -1,177 +0,0 @@ -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, ¶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("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/scep/pkcs7/decrypt_test.go b/scep/pkcs7/decrypt_test.go deleted file mode 100644 index 06cc0f80..00000000 --- a/scep/pkcs7/decrypt_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package pkcs7 - -import ( - "bytes" - "testing" -) - -func TestDecrypt(t *testing.T) { - fixture := UnmarshalTestFixture(EncryptedTestFixture) - p7, err := Parse(fixture.Input) - if err != nil { - t.Fatal(err) - } - content, err := p7.Decrypt(fixture.Certificate, fixture.PrivateKey) - if err != nil { - t.Errorf("Cannot Decrypt with error: %v", err) - } - expected := []byte("This is a test") - if !bytes.Equal(content, expected) { - t.Errorf("Decrypted result does not match.\n\tExpected:%s\n\tActual:%s", expected, content) - } -} - -// Content is "This is a test" -var EncryptedTestFixture = ` ------BEGIN PKCS7----- -MIIBFwYJKoZIhvcNAQcDoIIBCDCCAQQCAQAxgcowgccCAQAwMjApMRAwDgYDVQQK -EwdBY21lIENvMRUwEwYDVQQDEwxFZGRhcmQgU3RhcmsCBQDL+CvWMAsGCSqGSIb3 -DQEBAQSBgKyP/5WlRTZD3dWMrLOX6QRNDrXEkQjhmToRwFZdY3LgUh25ZU0S/q4G -dHPV21Fv9lQD+q7l3vfeHw8M6Z1PKi9sHMVfxAkQpvaI96DTIT3YHtuLC1w3geCO -8eFWTq2qS4WChSuS/yhYosjA1kTkE0eLnVZcGw0z/WVuEZznkdyIMDIGCSqGSIb3 -DQEHATARBgUrDgMCBwQImpKsUyMPpQigEgQQRcWWrCRXqpD5Njs0GkJl+g== ------END PKCS7----- ------BEGIN CERTIFICATE----- -MIIB1jCCAUGgAwIBAgIFAMv4K9YwCwYJKoZIhvcNAQELMCkxEDAOBgNVBAoTB0Fj -bWUgQ28xFTATBgNVBAMTDEVkZGFyZCBTdGFyazAeFw0xNTA1MDYwMzU2NDBaFw0x -NjA1MDYwMzU2NDBaMCUxEDAOBgNVBAoTB0FjbWUgQ28xETAPBgNVBAMTCEpvbiBT -bm93MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK6NU0R0eiCYVquU4RcjKc -LzGfx0aa1lMr2TnLQUSeLFZHFxsyyMXXuMPig3HK4A7SGFHupO+/1H/sL4xpH5zg -8+Zg2r8xnnney7abxcuv0uATWSIeKlNnb1ZO1BAxFnESc3GtyOCr2dUwZHX5mRVP -+Zxp2ni5qHNraf3wE2VPIQIDAQABoxIwEDAOBgNVHQ8BAf8EBAMCAKAwCwYJKoZI -hvcNAQELA4GBAIr2F7wsqmEU/J/kLyrCgEVXgaV/sKZq4pPNnzS0tBYk8fkV3V18 -sBJyHKRLL/wFZASvzDcVGCplXyMdAOCyfd8jO3F9Ac/xdlz10RrHJT75hNu3a7/n -9KNwKhfN4A1CQv2x372oGjRhCW5bHNCWx4PIVeNzCyq/KZhyY9sxHE6f ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIICXgIBAAKBgQDK6NU0R0eiCYVquU4RcjKcLzGfx0aa1lMr2TnLQUSeLFZHFxsy -yMXXuMPig3HK4A7SGFHupO+/1H/sL4xpH5zg8+Zg2r8xnnney7abxcuv0uATWSIe -KlNnb1ZO1BAxFnESc3GtyOCr2dUwZHX5mRVP+Zxp2ni5qHNraf3wE2VPIQIDAQAB -AoGBALyvnSt7KUquDen7nXQtvJBudnf9KFPt//OjkdHHxNZNpoF/JCSqfQeoYkeu -MdAVYNLQGMiRifzZz4dDhA9xfUAuy7lcGQcMCxEQ1dwwuFaYkawbS0Tvy2PFlq2d -H5/HeDXU4EDJ3BZg0eYj2Bnkt1sJI35UKQSxblQ0MY2q0uFBAkEA5MMOogkgUx1C -67S1tFqMUSM8D0mZB0O5vOJZC5Gtt2Urju6vywge2ArExWRXlM2qGl8afFy2SgSv -Xk5eybcEiQJBAOMRwwbEoW5NYHuFFbSJyWll4n71CYuWuQOCzehDPyTb80WFZGLV -i91kFIjeERyq88eDE5xVB3ZuRiXqaShO/9kCQQCKOEkpInaDgZSjskZvuJ47kByD -6CYsO4GIXQMMeHML8ncFH7bb6AYq5ybJVb2NTU7QLFJmfeYuhvIm+xdOreRxAkEA -o5FC5Jg2FUfFzZSDmyZ6IONUsdF/i78KDV5nRv1R+hI6/oRlWNCtTNBv/lvBBd6b -dseUE9QoaQZsn5lpILEvmQJAZ0B+Or1rAYjnbjnUhdVZoy9kC4Zov+4UH3N/BtSy -KJRWUR0wTWfZBPZ5hAYZjTBEAFULaYCXlQKsODSp0M1aQA== ------END PRIVATE KEY-----` diff --git a/scep/pkcs7/encrypt.go b/scep/pkcs7/encrypt.go deleted file mode 100644 index da57ae64..00000000 --- a/scep/pkcs7/encrypt.go +++ /dev/null @@ -1,399 +0,0 @@ -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/scep/pkcs7/encrypt_test.go b/scep/pkcs7/encrypt_test.go deleted file mode 100644 index c64381e2..00000000 --- a/scep/pkcs7/encrypt_test.go +++ /dev/null @@ -1,102 +0,0 @@ -package pkcs7 - -import ( - "bytes" - "crypto/x509" - "testing" -) - -func TestEncrypt(t *testing.T) { - modes := []int{ - EncryptionAlgorithmDESCBC, - EncryptionAlgorithmAES128CBC, - EncryptionAlgorithmAES256CBC, - EncryptionAlgorithmAES128GCM, - EncryptionAlgorithmAES256GCM, - } - sigalgs := []x509.SignatureAlgorithm{ - x509.SHA1WithRSA, - x509.SHA256WithRSA, - x509.SHA512WithRSA, - } - for _, mode := range modes { - for _, sigalg := range sigalgs { - ContentEncryptionAlgorithm = mode - - plaintext := []byte("Hello Secret World!") - cert, err := createTestCertificate(sigalg) - if err != nil { - t.Fatal(err) - } - encrypted, err := Encrypt(plaintext, []*x509.Certificate{cert.Certificate}) - if err != nil { - t.Fatal(err) - } - p7, err := Parse(encrypted) - if err != nil { - t.Fatalf("cannot Parse encrypted result: %s", err) - } - result, err := p7.Decrypt(cert.Certificate, *cert.PrivateKey) - if err != nil { - t.Fatalf("cannot Decrypt encrypted result: %s", err) - } - if !bytes.Equal(plaintext, result) { - t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result) - } - } - } -} - -func TestEncryptUsingPSK(t *testing.T) { - modes := []int{ - EncryptionAlgorithmDESCBC, - EncryptionAlgorithmAES128GCM, - } - - for _, mode := range modes { - ContentEncryptionAlgorithm = mode - plaintext := []byte("Hello Secret World!") - var key []byte - - switch mode { - case EncryptionAlgorithmDESCBC: - key = []byte("64BitKey") - case EncryptionAlgorithmAES128GCM: - key = []byte("128BitKey4AESGCM") - } - ciphertext, err := EncryptUsingPSK(plaintext, key) - if err != nil { - t.Fatal(err) - } - - p7, _ := Parse(ciphertext) - result, err := p7.DecryptUsingPSK(key) - if err != nil { - t.Fatalf("cannot Decrypt encrypted result: %s", err) - } - if !bytes.Equal(plaintext, result) { - t.Errorf("encrypted data does not match plaintext:\n\tExpected: %s\n\tActual: %s", plaintext, result) - } - } -} - -func TestPad(t *testing.T) { - tests := []struct { - Original []byte - Expected []byte - BlockSize int - }{ - {[]byte{0x1, 0x2, 0x3, 0x10}, []byte{0x1, 0x2, 0x3, 0x10, 0x4, 0x4, 0x4, 0x4}, 8}, - {[]byte{0x1, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0}, []byte{0x1, 0x2, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8}, 8}, - } - for _, test := range tests { - padded, err := pad(test.Original, test.BlockSize) - if err != nil { - t.Errorf("pad encountered error: %s", err) - continue - } - if !bytes.Equal(test.Expected, padded) { - t.Errorf("pad results mismatch:\n\tExpected: %X\n\tActual: %X", test.Expected, padded) - } - } -} diff --git a/scep/pkcs7/pkcs7.go b/scep/pkcs7/pkcs7.go deleted file mode 100644 index ccc6cc6d..00000000 --- a/scep/pkcs7/pkcs7.go +++ /dev/null @@ -1,291 +0,0 @@ -// 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/scep/pkcs7/pkcs7_test.go b/scep/pkcs7/pkcs7_test.go deleted file mode 100644 index e743192d..00000000 --- a/scep/pkcs7/pkcs7_test.go +++ /dev/null @@ -1,326 +0,0 @@ -package pkcs7 - -import ( - "crypto" - "crypto/dsa" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/rsa" - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "fmt" - "log" - "math/big" - "os" - "time" -) - -var test1024Key, test2048Key, test3072Key, test4096Key *rsa.PrivateKey - -func init() { - test1024Key = &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: fromBase10("123024078101403810516614073341068864574068590522569345017786163424062310013967742924377390210586226651760719671658568413826602264886073432535341149584680111145880576802262550990305759285883150470245429547886689754596541046564560506544976611114898883158121012232676781340602508151730773214407220733898059285561"), - E: 65537, - }, - D: fromBase10("118892427340746627750435157989073921703209000249285930635312944544706203626114423392257295670807166199489096863209592887347935991101581502404113203993092422730000157893515953622392722273095289787303943046491132467130346663160540744582438810535626328230098940583296878135092036661410664695896115177534496784545"), - Primes: []*big.Int{ - fromBase10("12172745919282672373981903347443034348576729562395784527365032103134165674508405592530417723266847908118361582847315228810176708212888860333051929276459099"), - fromBase10("10106518193772789699356660087736308350857919389391620140340519320928952625438936098550728858345355053201610649202713962702543058578827268756755006576249339"), - }, - } - test1024Key.Precompute() - test2048Key = &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"), - E: 3, - }, - D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"), - Primes: []*big.Int{ - fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"), - fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"), - }, - } - test2048Key.Precompute() - test3072Key = &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: fromBase10("4799422180968749215324244710281712119910779465109490663934897082847293004098645365195947978124390029272750644394844443980065532911010718425428791498896288210928474905407341584968381379157418577471272697781778686372450913810019702928839200328075568223462554606149618941566459398862673532997592879359280754226882565483298027678735544377401276021471356093819491755877827249763065753555051973844057308627201762456191918852016986546071426986328720794061622370410645440235373576002278045257207695462423797272017386006110722769072206022723167102083033531426777518054025826800254337147514768377949097720074878744769255210076910190151785807232805749219196645305822228090875616900385866236956058984170647782567907618713309775105943700661530312800231153745705977436176908325539234432407050398510090070342851489496464612052853185583222422124535243967989533830816012180864309784486694786581956050902756173889941244024888811572094961378021"), - E: 65537, - }, - D: fromBase10("4068124900056380177006532461065648259352178312499768312132802353620854992915205894105621345694615110794369150964768050224096623567443679436821868510233726084582567244003894477723706516831312989564775159596496449435830457803384416702014837685962523313266832032687145914871879794104404800823188153886925022171560391765913739346955738372354826804228989767120353182641396181570533678315099748218734875742705419933837638038793286534641711407564379950728858267828581787483317040753987167237461567332386718574803231955771633274184646232632371006762852623964054645811527580417392163873708539175349637050049959954373319861427407953413018816604365474462455009323937599275324390953644555294418021286807661559165324810415569396577697316798600308544755741549699523972971375304826663847015905713096287495342701286542193782001358775773848824496321550110946106870685499577993864871847542645561943034990484973293461948058147956373115641615329"), - Primes: []*big.Int{ - fromBase10("2378529069722721185825622840841310902793949682948530343491428052737890236476884657507685118578733560141370511507721598189068683665232991988491561624429938984370132428230072355214627085652359350722926394699707232921674771664421591347888367477300909202851476404132163673865768760147403525700174918450753162242834161458300343282159799476695001920226357456953682236859505243928716782707623075239350380352265954107362618991716602898266999700316937680986690964564264877"), - fromBase10("2017811025336026464312837780072272578817919741496395062543647660689775637351085991504709917848745137013798005682591633910555599626950744674459976829106750083386168859581016361317479081273480343110649405858059581933773354781034946787147300862495438979895430001323443224335618577322449133208754541656374335100929456885995320929464029817626916719434010943205170760536768893924932021302887114400922813817969176636993508191950649313115712159241971065134077636674146073"), - }, - } - test3072Key.Precompute() - test4096Key = &rsa.PrivateKey{ - PublicKey: rsa.PublicKey{ - N: fromBase10("633335480064287130853997429184971616419051348693342219741748040433588285601270210251206421401040394238592139790962887290698043839174341843721930134010306454716566698330215646704263665452264344664385995704186692432827662862845900348526672531755932642433662686500295989783595767573119607065791980381547677840410600100715146047382485989885183858757974681241303484641390718944520330953604501686666386926996348457928415093305041429178744778762826377713889019740060910363468343855830206640274442887621960581569183233822878661711798998132931623726434336448716605363514220760343097572198620479297583609779817750646169845195672483600293522186340560792255595411601450766002877850696008003794520089358819042318331840490155176019070646738739580486357084733208876620846449161909966690602374519398451042362690200166144326179405976024265116931974936425064291406950542193873313447617169603706868220189295654943247311295475722243471700112334609817776430552541319671117235957754556272646031356496763094955985615723596562217985372503002989591679252640940571608314743271809251568670314461039035793703429977801961867815257832671786542212589906513979094156334941265621017752516999186481477500481433634914622735206243841674973785078408289183000133399026553"), - E: 65537, - }, - D: fromBase10("439373650557744155078930178606343279553665694488479749802070836418412881168612407941793966086633543867614175621952769177088930851151267623886678906158545451731745754402575409204816390946376103491325109185445659065122640946673660760274557781540431107937331701243915001777636528502669576801704352961341634812275635811512806966908648671988644114352046582195051714797831307925775689566757438907578527366568747104508496278929566712224252103563340770696548181508180254674236716995730292431858611476396845443056967589437890065663497768422598977743046882539288481002449571403783500529740184608873520856954837631427724158592309018382711485601884461168736465751756282510065053161144027097169985941910909130083273691945578478173708396726266170473745329617793866669307716920992380350270584929908460462802627239204245339385636926433446418108504614031393494119344916828744888432279343816084433424594432427362258172264834429525166677273382617457205387388293888430391895615438030066428745187333897518037597413369705720436392869403948934993623418405908467147848576977008003556716087129242155836114780890054057743164411952731290520995017097151300091841286806603044227906213832083363876549637037625314539090155417589796428888619937329669464810549362433"), - Primes: []*big.Int{ - fromBase10("25745433817240673759910623230144796182285844101796353869339294232644316274580053211056707671663014355388701931204078502829809738396303142990312095225333440050808647355535878394534263839500592870406002873182360027755750148248672968563366185348499498613479490545488025779331426515670185366021612402246813511722553210128074701620113404560399242413747318161403908617342170447610792422053460359960010544593668037305465806912471260799852789913123044326555978680190904164976511331681163576833618899773550873682147782263100803907156362439021929408298804955194748640633152519828940133338948391986823456836070708197320166146761"), - fromBase10("24599914864909676687852658457515103765368967514652318497893275892114442089314173678877914038802355565271545910572804267918959612739009937926962653912943833939518967731764560204997062096919833970670512726396663920955497151415639902788974842698619579886297871162402643104696160155894685518587660015182381685605752989716946154299190561137541792784125356553411300817844325739404126956793095254412123887617931225840421856505925283322918693259047428656823141903489964287619982295891439430302405252447010728112098326033634688757933930065610737780413018498561434074501822951716586796047404555397992425143397497639322075233073"), - }, - } - test4096Key.Precompute() -} - -func fromBase10(base10 string) *big.Int { - i, ok := new(big.Int).SetString(base10, 10) - if !ok { - panic("bad number: " + base10) - } - return i -} - -type certKeyPair struct { - Certificate *x509.Certificate - PrivateKey *crypto.PrivateKey -} - -func createTestCertificate(sigAlg x509.SignatureAlgorithm) (certKeyPair, error) { - signer, err := createTestCertificateByIssuer("Eddard Stark", nil, sigAlg, true) - if err != nil { - return certKeyPair{}, err - } - pair, err := createTestCertificateByIssuer("Jon Snow", signer, sigAlg, false) - if err != nil { - return certKeyPair{}, err - } - return *pair, nil -} - -func createTestCertificateByIssuer(name string, issuer *certKeyPair, sigAlg x509.SignatureAlgorithm, isCA bool) (*certKeyPair, error) { - var ( - err error - priv crypto.PrivateKey - derCert []byte - issuerCert *x509.Certificate - issuerKey crypto.PrivateKey - ) - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 32) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - return nil, err - } - - template := x509.Certificate{ - SerialNumber: serialNumber, - Subject: pkix.Name{ - CommonName: name, - Organization: []string{"Acme Co"}, - }, - NotBefore: time.Now().Add(-1 *time.Second), - NotAfter: time.Now().AddDate(1, 0, 0), - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}, - } - if issuer != nil { - issuerCert = issuer.Certificate - issuerKey = *issuer.PrivateKey - } - switch sigAlg { - case x509.SHA1WithRSA: - priv = test1024Key - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA1WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA1 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA1 - } - case x509.SHA256WithRSA: - priv = test2048Key - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA256WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA256 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA256 - } - case x509.SHA384WithRSA: - priv = test3072Key - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA384WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA384 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA256 - } - case x509.SHA512WithRSA: - priv = test4096Key - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA512WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA512 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA256 - } - case x509.ECDSAWithSHA1: - priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return nil, err - } - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA1WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA1 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA1 - } - case x509.ECDSAWithSHA256: - priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return nil, err - } - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA256WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA256 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA256 - } - case x509.ECDSAWithSHA384: - priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - if err != nil { - return nil, err - } - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA384WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA384 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA256 - } - case x509.ECDSAWithSHA512: - priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) - if err != nil { - return nil, err - } - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA512WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA512 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA256 - } - case x509.DSAWithSHA1: - var dsaPriv dsa.PrivateKey - params := &dsaPriv.Parameters - err = dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160) - if err != nil { - return nil, err - } - err = dsa.GenerateKey(&dsaPriv, rand.Reader) - if err != nil { - return nil, err - } - switch issuerKey.(type) { - case *rsa.PrivateKey: - template.SignatureAlgorithm = x509.SHA1WithRSA - case *ecdsa.PrivateKey: - template.SignatureAlgorithm = x509.ECDSAWithSHA1 - case *dsa.PrivateKey: - template.SignatureAlgorithm = x509.DSAWithSHA1 - } - priv = &dsaPriv - } - if isCA { - template.IsCA = true - template.KeyUsage |= x509.KeyUsageCertSign - template.BasicConstraintsValid = true - } - if issuer == nil { - // no issuer given,make this a self-signed root cert - issuerCert = &template - issuerKey = priv - } - - log.Println("creating cert", name, "issued by", issuerCert.Subject.CommonName, "with sigalg", sigAlg) - switch priv.(type) { - case *rsa.PrivateKey: - switch issuerKey.(type) { - case *rsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey.(*rsa.PrivateKey)) - case *ecdsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey.(*ecdsa.PrivateKey)) - case *dsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey.(*dsa.PrivateKey)) - } - case *ecdsa.PrivateKey: - switch issuerKey.(type) { - case *rsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey.(*rsa.PrivateKey)) - case *ecdsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey.(*ecdsa.PrivateKey)) - case *dsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey.(*dsa.PrivateKey)) - } - case *dsa.PrivateKey: - pub := &priv.(*dsa.PrivateKey).PublicKey - switch issuerKey := issuerKey.(type) { - case *rsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, pub, issuerKey) - case *ecdsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*dsa.PublicKey), issuerKey) - case *dsa.PrivateKey: - derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*dsa.PublicKey), issuerKey) - } - } - if err != nil { - return nil, err - } - if len(derCert) == 0 { - return nil, fmt.Errorf("no certificate created, probably due to wrong keys. types were %T and %T", priv, issuerKey) - } - cert, err := x509.ParseCertificate(derCert) - if err != nil { - return nil, err - } - pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) - return &certKeyPair{ - Certificate: cert, - PrivateKey: &priv, - }, nil -} - -type TestFixture struct { - Input []byte - Certificate *x509.Certificate - PrivateKey *rsa.PrivateKey -} - -func UnmarshalTestFixture(testPEMBlock string) TestFixture { - var result TestFixture - var derBlock *pem.Block - var pemBlock = []byte(testPEMBlock) - for { - derBlock, pemBlock = pem.Decode(pemBlock) - if derBlock == nil { - break - } - switch derBlock.Type { - case "PKCS7": - result.Input = derBlock.Bytes - case "CERTIFICATE": - result.Certificate, _ = x509.ParseCertificate(derBlock.Bytes) - case "PRIVATE KEY": - result.PrivateKey, _ = x509.ParsePKCS1PrivateKey(derBlock.Bytes) - } - } - - return result -} diff --git a/scep/pkcs7/sign.go b/scep/pkcs7/sign.go deleted file mode 100644 index addd7638..00000000 --- a/scep/pkcs7/sign.go +++ /dev/null @@ -1,429 +0,0 @@ -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/scep/pkcs7/sign_test.go b/scep/pkcs7/sign_test.go deleted file mode 100644 index 0ba6324d..00000000 --- a/scep/pkcs7/sign_test.go +++ /dev/null @@ -1,266 +0,0 @@ -package pkcs7 - -import ( - "bytes" - "crypto/dsa" - "crypto/x509" - "encoding/asn1" - "encoding/pem" - "fmt" - "io/ioutil" - "log" - "math/big" - "os" - "os/exec" - "testing" -) - -func TestSign(t *testing.T) { - content := []byte("Hello World") - sigalgs := []x509.SignatureAlgorithm{ - x509.SHA1WithRSA, - x509.SHA256WithRSA, - x509.SHA512WithRSA, - x509.ECDSAWithSHA1, - x509.ECDSAWithSHA256, - x509.ECDSAWithSHA384, - x509.ECDSAWithSHA512, - } - for _, sigalgroot := range sigalgs { - rootCert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, sigalgroot, true) - if err != nil { - t.Fatalf("test %s: cannot generate root cert: %s", sigalgroot, err) - } - truststore := x509.NewCertPool() - truststore.AddCert(rootCert.Certificate) - for _, sigalginter := range sigalgs { - interCert, err := createTestCertificateByIssuer("PKCS7 Test Intermediate Cert", rootCert, sigalginter, true) - if err != nil { - t.Fatalf("test %s/%s: cannot generate intermediate cert: %s", sigalgroot, sigalginter, err) - } - var parents []*x509.Certificate - parents = append(parents, interCert.Certificate) - for _, sigalgsigner := range sigalgs { - signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", interCert, sigalgsigner, false) - if err != nil { - t.Fatalf("test %s/%s/%s: cannot generate signer cert: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - for _, testDetach := range []bool{false, true} { - log.Printf("test %s/%s/%s detached %t\n", sigalgroot, sigalginter, sigalgsigner, testDetach) - toBeSigned, err := NewSignedData(content) - if err != nil { - t.Fatalf("test %s/%s/%s: cannot initialize signed data: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - - // Set the digest to match the end entity cert - signerDigest, _ := getDigestOIDForSignatureAlgorithm(signerCert.Certificate.SignatureAlgorithm) - toBeSigned.SetDigestAlgorithm(signerDigest) - - if err := toBeSigned.AddSignerChain(signerCert.Certificate, *signerCert.PrivateKey, parents, SignerInfoConfig{}); err != nil { - t.Fatalf("test %s/%s/%s: cannot add signer: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - if testDetach { - toBeSigned.Detach() - } - signed, err := toBeSigned.Finish() - if err != nil { - t.Fatalf("test %s/%s/%s: cannot finish signing data: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed}) - p7, err := Parse(signed) - if err != nil { - t.Fatalf("test %s/%s/%s: cannot parse signed data: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - if testDetach { - p7.Content = content - } - if !bytes.Equal(content, p7.Content) { - t.Errorf("test %s/%s/%s: content was not found in the parsed data:\n\tExpected: %s\n\tActual: %s", sigalgroot, sigalginter, sigalgsigner, content, p7.Content) - } - if err := p7.VerifyWithChain(truststore); err != nil { - t.Errorf("test %s/%s/%s: cannot verify signed data: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - if !signerDigest.Equal(p7.Signers[0].DigestAlgorithm.Algorithm) { - t.Errorf("test %s/%s/%s: expected digest algorithm %q but got %q", - sigalgroot, sigalginter, sigalgsigner, signerDigest, p7.Signers[0].DigestAlgorithm.Algorithm) - } - } - } - } - } -} - -func TestDSASignAndVerifyWithOpenSSL(t *testing.T) { - content := []byte("Hello World") - // write the content to a temp file - tmpContentFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_content") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpContentFile.Name(), content, 0755) - - block, _ := pem.Decode([]byte(dsaPublicCert)) - if block == nil { - t.Fatal("failed to parse certificate PEM") - } - signerCert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - t.Fatal("failed to parse certificate: " + err.Error()) - } - - // write the signer cert to a temp file - tmpSignerCertFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_signer") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpSignerCertFile.Name(), dsaPublicCert, 0755) - - priv := dsa.PrivateKey{ - PublicKey: dsa.PublicKey{Parameters: dsa.Parameters{P: fromHex("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7"), - Q: fromHex("9760508F15230BCCB292B982A2EB840BF0581CF5"), - G: fromHex("F7E1A085D69B3DDECBBCAB5C36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A"), - }, - }, - X: fromHex("7D6E1A3DD4019FD809669D8AB8DA73807CEF7EC1"), - } - toBeSigned, err := NewSignedData(content) - if err != nil { - t.Fatalf("test case: cannot initialize signed data: %s", err) - } - if err := toBeSigned.SignWithoutAttr(signerCert, &priv, SignerInfoConfig{}); err != nil { - t.Fatalf("Cannot add signer: %s", err) - } - toBeSigned.Detach() - signed, err := toBeSigned.Finish() - if err != nil { - t.Fatalf("test case: cannot finish signing data: %s", err) - } - - // write the signature to a temp file - tmpSignatureFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_signature") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpSignatureFile.Name(), pem.EncodeToMemory(&pem.Block{Type: "PKCS7", Bytes: signed}), 0755) - - // call openssl to verify the signature on the content using the root - opensslCMD := exec.Command("openssl", "smime", "-verify", "-noverify", - "-in", tmpSignatureFile.Name(), "-inform", "PEM", - "-content", tmpContentFile.Name()) - out, err := opensslCMD.CombinedOutput() - if err != nil { - t.Fatalf("test case: openssl command failed with %s: %s", err, out) - } - os.Remove(tmpSignatureFile.Name()) // clean up - os.Remove(tmpContentFile.Name()) // clean up - os.Remove(tmpSignerCertFile.Name()) // clean up -} - -func ExampleSignedData() { - // generate a signing cert or load a key pair - cert, err := createTestCertificate(x509.SHA256WithRSA) - if err != nil { - fmt.Printf("Cannot create test certificates: %s", err) - } - - // Initialize a SignedData struct with content to be signed - signedData, err := NewSignedData([]byte("Example data to be signed")) - if err != nil { - fmt.Printf("Cannot initialize signed data: %s", err) - } - - // Add the signing cert and private key - if err := signedData.AddSigner(cert.Certificate, cert.PrivateKey, SignerInfoConfig{}); err != nil { - fmt.Printf("Cannot add signer: %s", err) - } - - // Call Detach() is you want to remove content from the signature - // and generate an S/MIME detached signature - signedData.Detach() - - // Finish() to obtain the signature bytes - detachedSignature, err := signedData.Finish() - if err != nil { - fmt.Printf("Cannot finish signing data: %s", err) - } - pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: detachedSignature}) -} - -func TestUnmarshalSignedAttribute(t *testing.T) { - cert, err := createTestCertificate(x509.SHA512WithRSA) - if err != nil { - t.Fatal(err) - } - content := []byte("Hello World") - toBeSigned, err := NewSignedData(content) - if err != nil { - t.Fatalf("Cannot initialize signed data: %s", err) - } - oidTest := asn1.ObjectIdentifier{2, 3, 4, 5, 6, 7} - testValue := "TestValue" - if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{ - ExtraSignedAttributes: []Attribute{Attribute{Type: oidTest, Value: testValue}}, - }); err != nil { - t.Fatalf("Cannot add signer: %s", err) - } - signed, err := toBeSigned.Finish() - if err != nil { - t.Fatalf("Cannot finish signing data: %s", err) - } - p7, err := Parse(signed) - if err != nil { - t.Fatalf("Cannot parse signed data: %v", err) - } - var actual string - err = p7.UnmarshalSignedAttribute(oidTest, &actual) - if err != nil { - t.Fatalf("Cannot unmarshal test value: %s", err) - } - if testValue != actual { - t.Errorf("Attribute does not match test value\n\tExpected: %s\n\tActual: %s", testValue, actual) - } -} - -func TestDegenerateCertificate(t *testing.T) { - cert, err := createTestCertificate(x509.SHA1WithRSA) - if err != nil { - t.Fatal(err) - } - deg, err := DegenerateCertificate(cert.Certificate.Raw) - if err != nil { - t.Fatal(err) - } - testOpenSSLParse(t, deg) - pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: deg}) -} - -// writes the cert to a temporary file and tests that openssl can read it. -func testOpenSSLParse(t *testing.T, certBytes []byte) { - tmpCertFile, err := ioutil.TempFile("", "testCertificate") - if err != nil { - t.Fatal(err) - } - defer os.Remove(tmpCertFile.Name()) // clean up - - if _, err := tmpCertFile.Write(certBytes); err != nil { - t.Fatal(err) - } - - opensslCMD := exec.Command("openssl", "pkcs7", "-inform", "der", "-in", tmpCertFile.Name()) - _, err = opensslCMD.Output() - if err != nil { - t.Fatal(err) - } - - if err := tmpCertFile.Close(); err != nil { - t.Fatal(err) - } - -} -func fromHex(s string) *big.Int { - result, ok := new(big.Int).SetString(s, 16) - if !ok { - panic(s) - } - return result -} diff --git a/scep/pkcs7/verify.go b/scep/pkcs7/verify.go deleted file mode 100644 index c8ead236..00000000 --- a/scep/pkcs7/verify.go +++ /dev/null @@ -1,264 +0,0 @@ -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") -} diff --git a/scep/pkcs7/verify_test.go b/scep/pkcs7/verify_test.go deleted file mode 100644 index f80943b2..00000000 --- a/scep/pkcs7/verify_test.go +++ /dev/null @@ -1,713 +0,0 @@ -package pkcs7 - -import ( - "bytes" - "crypto/ecdsa" - "crypto/rsa" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "fmt" - "io/ioutil" - "os" - "os/exec" - "testing" - "time" -) - -func TestVerify(t *testing.T) { - fixture := UnmarshalTestFixture(SignedTestFixture) - p7, err := Parse(fixture.Input) - if err != nil { - t.Errorf("Parse encountered unexpected error: %v", err) - } - - if err := p7.Verify(); err != nil { - t.Errorf("Verify failed with error: %v", err) - } - expected := []byte("We the People") - if !bytes.Equal(p7.Content, expected) { - t.Errorf("Signed content does not match.\n\tExpected:%s\n\tActual:%s", expected, p7.Content) - - } -} - -var SignedTestFixture = ` ------BEGIN PKCS7----- -MIIDVgYJKoZIhvcNAQcCoIIDRzCCA0MCAQExCTAHBgUrDgMCGjAcBgkqhkiG9w0B -BwGgDwQNV2UgdGhlIFBlb3BsZaCCAdkwggHVMIIBQKADAgECAgRpuDctMAsGCSqG -SIb3DQEBCzApMRAwDgYDVQQKEwdBY21lIENvMRUwEwYDVQQDEwxFZGRhcmQgU3Rh -cmswHhcNMTUwNTA2MDQyNDQ4WhcNMTYwNTA2MDQyNDQ4WjAlMRAwDgYDVQQKEwdB -Y21lIENvMREwDwYDVQQDEwhKb24gU25vdzCBnzANBgkqhkiG9w0BAQEFAAOBjQAw -gYkCgYEAqr+tTF4mZP5rMwlXp1y+crRtFpuLXF1zvBZiYMfIvAHwo1ta8E1IcyEP -J1jIiKMcwbzeo6kAmZzIJRCTezq9jwXUsKbQTvcfOH9HmjUmXBRWFXZYoQs/OaaF -a45deHmwEeMQkuSWEtYiVKKZXtJOtflKIT3MryJEDiiItMkdybUCAwEAAaMSMBAw -DgYDVR0PAQH/BAQDAgCgMAsGCSqGSIb3DQEBCwOBgQDK1EweZWRL+f7Z+J0kVzY8 -zXptcBaV4Lf5wGZJLJVUgp33bpLNpT3yadS++XQJ+cvtW3wADQzBSTMduyOF8Zf+ -L7TjjrQ2+F2HbNbKUhBQKudxTfv9dJHdKbD+ngCCdQJYkIy2YexsoNG0C8nQkggy -axZd/J69xDVx6pui3Sj8sDGCATYwggEyAgEBMDEwKTEQMA4GA1UEChMHQWNtZSBD -bzEVMBMGA1UEAxMMRWRkYXJkIFN0YXJrAgRpuDctMAcGBSsOAwIaoGEwGAYJKoZI -hvcNAQkDMQsGCSqGSIb3DQEHATAgBgkqhkiG9w0BCQUxExcRMTUwNTA2MDAyNDQ4 -LTA0MDAwIwYJKoZIhvcNAQkEMRYEFG9D7gcTh9zfKiYNJ1lgB0yTh4sZMAsGCSqG -SIb3DQEBAQSBgFF3sGDU9PtXty/QMtpcFa35vvIOqmWQAIZt93XAskQOnBq4OloX -iL9Ct7t1m4pzjRm0o9nDkbaSLZe7HKASHdCqijroScGlI8M+alJ8drHSFv6ZIjnM -FIwIf0B2Lko6nh9/6mUXq7tbbIHa3Gd1JUVire/QFFtmgRXMbXYk8SIS ------END PKCS7----- ------BEGIN CERTIFICATE----- -MIIB1TCCAUCgAwIBAgIEabg3LTALBgkqhkiG9w0BAQswKTEQMA4GA1UEChMHQWNt -ZSBDbzEVMBMGA1UEAxMMRWRkYXJkIFN0YXJrMB4XDTE1MDUwNjA0MjQ0OFoXDTE2 -MDUwNjA0MjQ0OFowJTEQMA4GA1UEChMHQWNtZSBDbzERMA8GA1UEAxMISm9uIFNu -b3cwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKq/rUxeJmT+azMJV6dcvnK0 -bRabi1xdc7wWYmDHyLwB8KNbWvBNSHMhDydYyIijHMG83qOpAJmcyCUQk3s6vY8F -1LCm0E73Hzh/R5o1JlwUVhV2WKELPzmmhWuOXXh5sBHjEJLklhLWIlSimV7STrX5 -SiE9zK8iRA4oiLTJHcm1AgMBAAGjEjAQMA4GA1UdDwEB/wQEAwIAoDALBgkqhkiG -9w0BAQsDgYEAytRMHmVkS/n+2fidJFc2PM16bXAWleC3+cBmSSyVVIKd926SzaU9 -8mnUvvl0CfnL7Vt8AA0MwUkzHbsjhfGX/i+04460Nvhdh2zWylIQUCrncU37/XSR -3Smw/p4AgnUCWJCMtmHsbKDRtAvJ0JIIMmsWXfyevcQ1ceqbot0o/LA= ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIICXgIBAAKBgQCqv61MXiZk/mszCVenXL5ytG0Wm4tcXXO8FmJgx8i8AfCjW1rw -TUhzIQ8nWMiIoxzBvN6jqQCZnMglEJN7Or2PBdSwptBO9x84f0eaNSZcFFYVdlih -Cz85poVrjl14ebAR4xCS5JYS1iJUople0k61+UohPcyvIkQOKIi0yR3JtQIDAQAB -AoGBAIPLCR9N+IKxodq11lNXEaUFwMHXc1zqwP8no+2hpz3+nVfplqqubEJ4/PJY -5AgbJoIfnxVhyBXJXu7E+aD/OPneKZrgp58YvHKgGvvPyJg2gpC/1Fh0vQB0HNpI -1ZzIZUl8ZTUtVgtnCBUOh5JGI4bFokAqrT//Uvcfd+idgxqBAkEA1ZbP/Kseld14 -qbWmgmU5GCVxsZRxgR1j4lG3UVjH36KXMtRTm1atAam1uw3OEGa6Y3ANjpU52FaB -Hep5rkk4FQJBAMynMo1L1uiN5GP+KYLEF5kKRxK+FLjXR0ywnMh+gpGcZDcOae+J -+t1gLoWBIESH/Xt639T7smuSfrZSA9V0EyECQA8cvZiWDvLxmaEAXkipmtGPjKzQ -4PsOtkuEFqFl07aKDYKmLUg3aMROWrJidqsIabWxbvQgsNgSvs38EiH3wkUCQQCg -ndxb7piVXb9RBwm3OoU2tE1BlXMX+sVXmAkEhd2dwDsaxrI3sHf1xGXem5AimQRF -JBOFyaCnMotGNioSHY5hAkEAxyXcNixQ2RpLXJTQZtwnbk0XDcbgB+fBgXnv/4f3 -BCvcu85DqJeJyQv44Oe1qsXEX9BfcQIOVaoep35RPlKi9g== ------END PRIVATE KEY-----` - -func TestVerifyEC2(t *testing.T) { - fixture := UnmarshalTestFixture(EC2IdentityDocumentFixture) - p7, err := Parse(fixture.Input) - if err != nil { - t.Errorf("Parse encountered unexpected error: %v", err) - } - p7.Certificates = []*x509.Certificate{fixture.Certificate} - if err := p7.Verify(); err != nil { - t.Errorf("Verify failed with error: %v", err) - } -} - -var EC2IdentityDocumentFixture = ` ------BEGIN PKCS7----- -MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAaCA -JIAEggGmewogICJwcml2YXRlSXAiIDogIjE3Mi4zMC4wLjI1MiIsCiAgImRldnBh -eVByb2R1Y3RDb2RlcyIgOiBudWxsLAogICJhdmFpbGFiaWxpdHlab25lIiA6ICJ1 -cy1lYXN0LTFhIiwKICAidmVyc2lvbiIgOiAiMjAxMC0wOC0zMSIsCiAgImluc3Rh -bmNlSWQiIDogImktZjc5ZmU1NmMiLAogICJiaWxsaW5nUHJvZHVjdHMiIDogbnVs -bCwKICAiaW5zdGFuY2VUeXBlIiA6ICJ0Mi5taWNybyIsCiAgImFjY291bnRJZCIg -OiAiMTIxNjU5MDE0MzM0IiwKICAiaW1hZ2VJZCIgOiAiYW1pLWZjZTNjNjk2IiwK -ICAicGVuZGluZ1RpbWUiIDogIjIwMTYtMDQtMDhUMDM6MDE6MzhaIiwKICAiYXJj -aGl0ZWN0dXJlIiA6ICJ4ODZfNjQiLAogICJrZXJuZWxJZCIgOiBudWxsLAogICJy -YW1kaXNrSWQiIDogbnVsbCwKICAicmVnaW9uIiA6ICJ1cy1lYXN0LTEiCn0AAAAA -AAAxggEYMIIBFAIBATBpMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5n -dG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2Vi -IFNlcnZpY2VzIExMQwIJAJa6SNnlXhpnMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0B -CQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNjA0MDgwMzAxNDRaMCMG -CSqGSIb3DQEJBDEWBBTuUc28eBXmImAautC+wOjqcFCBVjAJBgcqhkjOOAQDBC8w -LQIVAKA54NxGHWWCz5InboDmY/GHs33nAhQ6O/ZI86NwjA9Vz3RNMUJrUPU5tAAA -AAAAAA== ------END PKCS7----- ------BEGIN CERTIFICATE----- -MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw -FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD -VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z -ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u -IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl -cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt/5e -ih5OO6kK/n1Lzllr7D8ZwtQP8fOEpp5E2ng+D6Ud1Z1gYipr58Kj3nssSNpI6bX3 -VyIQzK7wLclnd/YozqNNmgIyZecN7EglK9ITHJLP+x8FtUpt3QbyYXJdmVMegN6P -hviYt5JH/nYl4hh3Pa1HJdskgQIVALVJ3ER11+Ko4tP6nwvHwh6+ERYRAoGBAI1j -k+tkqMVHuAFcvAGKocTgsjJem6/5qomzJuKDmbJNu9Qxw3rAotXau8Qe+MBcJl/U -hhy1KHVpCGl9fueQ2s6IL0CaO/buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF -lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE/Gf -MNmP9CM5eovQOGx5ho8WqD+aTebs+k2tn92BBPqeZqpWRa5P/+jrdKml1qx4llHW -MXrs3IgIb6+hUIB+S8dz8/mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9+EUAH5mw -vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw -7HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K ------END CERTIFICATE-----` - -func TestVerifyAppStore(t *testing.T) { - fixture := UnmarshalTestFixture(AppStoreReceiptFixture) - p7, err := Parse(fixture.Input) - if err != nil { - t.Errorf("Parse encountered unexpected error: %v", err) - } - if err := p7.Verify(); err != nil { - t.Errorf("Verify failed with error: %v", err) - } -} - -var AppStoreReceiptFixture = ` ------BEGIN PKCS7----- -MIITtgYJKoZIhvcNAQcCoIITpzCCE6MCAQExCzAJBgUrDgMCGgUAMIIDVwYJKoZI -hvcNAQcBoIIDSASCA0QxggNAMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQEC -AQEEAwIBADALAgEDAgEBBAMMATEwCwIBCwIBAQQDAgEAMAsCAQ8CAQEEAwIBADAL -AgEQAgEBBAMCAQAwCwIBGQIBAQQDAgEDMAwCAQoCAQEEBBYCNCswDAIBDgIBAQQE -AgIAjTANAgENAgEBBAUCAwFgvTANAgETAgEBBAUMAzEuMDAOAgEJAgEBBAYCBFAy -NDcwGAIBAgIBAQQQDA5jb20uemhpaHUudGVzdDAYAgEEAgECBBCS+ZODNMHwT1Nz -gWYDXyWZMBsCAQACAQEEEwwRUHJvZHVjdGlvblNhbmRib3gwHAIBBQIBAQQU4nRh -YCEZx70Flzv7hvJRjJZckYIwHgIBDAIBAQQWFhQyMDE2LTA3LTIzVDA2OjIxOjEx -WjAeAgESAgEBBBYWFDIwMTMtMDgtMDFUMDc6MDA6MDBaMD0CAQYCAQEENbR21I+a -8+byMXo3NPRoDWQmSXQF2EcCeBoD4GaL//ZCRETp9rGFPSg1KekCP7Kr9HAqw09m -MEICAQcCAQEEOlVJozYYBdugybShbiiMsejDMNeCbZq6CrzGBwW6GBy+DGWxJI91 -Y3ouXN4TZUhuVvLvN1b0m5T3ggQwggFaAgERAgEBBIIBUDGCAUwwCwICBqwCAQEE -AhYAMAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgaz -AgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAM -AgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQEwDAICBq4CAQEEAwIBADAMAgIGrwIB -AQQDAgEAMAwCAgaxAgEBBAMCAQAwGwICBqcCAQEEEgwQMTAwMDAwMDIyNTMyNTkw -MTAbAgIGqQIBAQQSDBAxMDAwMDAwMjI1MzI1OTAxMB8CAgaoAgEBBBYWFDIwMTYt -MDctMjNUMDY6MjE6MTFaMB8CAgaqAgEBBBYWFDIwMTYtMDctMjNUMDY6MjE6MTFa -MCACAgamAgEBBBcMFWNvbS56aGlodS50ZXN0LnRlc3RfMaCCDmUwggV8MIIEZKAD -AgECAggO61eH554JjTANBgkqhkiG9w0BAQUFADCBljELMAkGA1UEBhMCVVMxEzAR -BgNVBAoMCkFwcGxlIEluYy4xLDAqBgNVBAsMI0FwcGxlIFdvcmxkd2lkZSBEZXZl -bG9wZXIgUmVsYXRpb25zMUQwQgYDVQQDDDtBcHBsZSBXb3JsZHdpZGUgRGV2ZWxv -cGVyIFJlbGF0aW9ucyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNTExMTMw -MjE1MDlaFw0yMzAyMDcyMTQ4NDdaMIGJMTcwNQYDVQQDDC5NYWMgQXBwIFN0b3Jl -IGFuZCBpVHVuZXMgU3RvcmUgUmVjZWlwdCBTaWduaW5nMSwwKgYDVQQLDCNBcHBs -ZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczETMBEGA1UECgwKQXBwbGUg -SW5jLjELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQClz4H9JaKBW9aH7SPaMxyO4iPApcQmyz3Gn+xKDVWG/6QC15fKOVRtfX+yVBid -xCxScY5ke4LOibpJ1gjltIhxzz9bRi7GxB24A6lYogQ+IXjV27fQjhKNg0xbKmg3 -k8LyvR7E0qEMSlhSqxLj7d0fmBWQNS3CzBLKjUiB91h4VGvojDE2H0oGDEdU8zeQ -uLKSiX1fpIVK4cCc4Lqku4KXY/Qrk8H9Pm/KwfU8qY9SGsAlCnYO3v6Z/v/Ca/Vb -XqxzUUkIVonMQ5DMjoEC0KCXtlyxoWlph5AQaCYmObgdEHOwCl3Fc9DfdjvYLdmI -HuPsB8/ijtDT+iZVge/iA0kjAgMBAAGjggHXMIIB0zA/BggrBgEFBQcBAQQzMDEw -LwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtd3dkcjA0 -MB0GA1UdDgQWBBSRpJz8xHa3n6CK9E31jzZd7SsEhTAMBgNVHRMBAf8EAjAAMB8G -A1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBHgYDVR0gBIIBFTCCAREw -ggENBgoqhkiG92NkBQYBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9u -IHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5j -ZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25k -aXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0 -aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3 -LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wDgYDVR0PAQH/BAQDAgeA -MBAGCiqGSIb3Y2QGCwEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQANphvTLj3jWysH -bkKWbNPojEMwgl/gXNGNvr0PvRr8JZLbjIXDgFnf4+LXLgUUrA3btrj+/DUufMut -F2uOfx/kd7mxZ5W0E16mGYZ2+FogledjjA9z/Ojtxh+umfhlSFyg4Cg6wBA3Lbmg -BDkfc7nIBf3y3n8aKipuKwH8oCBc2et9J6Yz+PWY4L5E27FMZ/xuCk/J4gao0pfz -p45rUaJahHVl0RYEYuPBX/UIqc9o2ZIAycGMs/iNAGS6WGDAfK+PdcppuVsq1h1o -bphC9UynNxmbzDscehlD86Ntv0hgBgw2kivs3hi1EdotI9CO/KBpnBcbnoB7OUdF -MGEvxxOoMIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjEL -MAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxl -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENB -MB4XDTEzMDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVT -MRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUg -RGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERl -dmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0 -U3rOfGOAYXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkV -CBmsqtsqMu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8 -V25nNYB2NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHl -d0WNUEi6Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1q -arunFjVg0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGj -gaYwgaMwHQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQF -MAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcw -JTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/ -BAQDAgGGMBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Z -viz1smwvj+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/N -w0Uwj6ODDc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJ -TleMa1s8Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1V -AKmuu0swruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur -+cmV6U/kTecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxR -pVzscYqCtGwPDBUfMIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQsw -CQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0Ew -HhcNMDYwNDI1MjE0MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzET -MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne -+Uts9QerIjAC6Bg++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjcz -y8QPTc4UadHJGXL1XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQ -Z48ItCD3y6wsIG9wtj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCS -C7EhFi501TwN22IWq6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINB -hzOKgbEwWOxaBDKMaLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIB -djAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9Bp -R5R2Cf70a40uQKb3R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ -CF4wggERBgNVHSAEggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcC -ARYeaHR0cHM6Ly93d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCB -thqBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFz -c3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk -IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5 -IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3 -DQEBBQUAA4IBAQBcNplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizU -sZAS2L70c5vu0mQPy3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJ -fBdAVhEedNO3iyM7R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr -1KIkIxH3oayPc4FgxhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltk -wGMzd/c6ByxW69oPIQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIq -xw8dtk2cXmPIS4AXUKqK1drk/NAJBzewdXUhMYIByzCCAccCAQEwgaMwgZYxCzAJ -BgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBX -b3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29y -bGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkCCA7rV4fnngmNMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEggEAasPtnide -NWyfUtewW9OSgcQA8pW+5tWMR0469cBPZR84uJa0gyfmPspySvbNOAwnrwzZHYLa -ujOxZLip4DUw4F5s3QwUa3y4BXpF4J+NSn9XNvxNtnT/GcEQtCuFwgJ0o3F0ilhv -MTHrwiwyx/vr+uNDqlORK8lfK+1qNp+A/kzh8eszMrn4JSeTh9ZYxLHE56WkTQGD -VZXl0gKgxSOmDrcp1eQxdlymzrPv9U60wUJ0bkPfrU9qZj3mJrmrkQk61JTe3j6/ -QfjfFBG9JG2mUmYQP1KQ3SypGHzDW8vngvsGu//tNU0NFfOqQu4bYU4VpQl0nPtD -4B85NkrgvQsWAQ== ------END PKCS7-----` - -func TestVerifyApkEcdsa(t *testing.T) { - fixture := UnmarshalTestFixture(ApkEcdsaFixture) - p7, err := Parse(fixture.Input) - if err != nil { - t.Errorf("Parse encountered unexpected error: %v", err) - } - p7.Content, err = base64.StdEncoding.DecodeString(ApkEcdsaContent) - if err != nil { - t.Errorf("Failed to decode base64 signature file: %v", err) - } - if err := p7.Verify(); err != nil { - t.Errorf("Verify failed with error: %v", err) - } -} - -var ApkEcdsaFixture = `-----BEGIN PKCS7----- -MIIDAgYJKoZIhvcNAQcCoIIC8zCCAu8CAQExDzANBglghkgBZQMEAgMFADALBgkq -hkiG9w0BBwGgggH3MIIB8zCCAVSgAwIBAgIJAOxXdFsvm3YiMAoGCCqGSM49BAME -MBIxEDAOBgNVBAMMB2VjLXA1MjEwHhcNMTYwMzMxMTUzMTIyWhcNNDMwODE3MTUz -MTIyWjASMRAwDgYDVQQDDAdlYy1wNTIxMIGbMBAGByqGSM49AgEGBSuBBAAjA4GG -AAQAYX95sSjPEQqgyLD04tNUyq9y/w8seblOpfqa/Amx6H4GFdrjGXX0YTfXKr9G -hAyIyQSnNrIg0zDlWQUbBPRW4CYBLFOg1pUn1NBhKFD4NtO1KWvYtNOYDegFjRCP -B0p+fEXDbq8QFDYvlh+NZUJ16+ih8XNIf1C29xuLEqN6oKOnAvajUDBOMB0GA1Ud -DgQWBBT/Ra3kz60gQ7tYk3byZckcLabt8TAfBgNVHSMEGDAWgBT/Ra3kz60gQ7tY -k3byZckcLabt8TAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAP39 -hYLsWk2H84oEw+HJqGGjexhqeD3vSO1mWhopripE/81oy3yV10puYoJe11xDSfcD -j2VfNCHazuXO3kSxGA/1AkIBLUJxp/WYbYzhBGKr6lcxczKI/wuMfkZ6vL+0EMJV -A/2uEoeqvnl7BsdkicyaOBNEADijuVdaPPIWzKClt9OaVxExgdAwgc0CAQEwHzAS -MRAwDgYDVQQDDAdlYy1wNTIxAgkA7Fd0Wy+bdiIwDQYJYIZIAWUDBAIDBQAwCgYI -KoZIzj0EAwQEgYswgYgCQgD1pVSNo7qTm9A6tpt3SU2yRa+xpJAnUbpZ+Gu36B71 -JnQBUzRgTGevniqHpyagi7b2zjWh1uvfz9FfrITUwGMddgJCAPjiBRcl7rKpxmZn -V1MvcJOX41xRSJu1wmBiYXqaJarL+gQ/Wl7RYsMtqLjmNColvLaHNxCaWOO/8nAE -Hg0OMA60 ------END PKCS7-----` - -var ApkEcdsaContent = `U2lnbmF0dXJlLVZlcnNpb246IDEuMA0KU0hBLTUxMi1EaWdlc3QtTWFuaWZlc3Q6IFAvVDRqSWtTMjQvNzFxeFE2WW1MeEtNdkRPUUF0WjUxR090dFRzUU9yemhHRQ0KIEpaUGVpWUtyUzZYY090bStYaWlFVC9uS2tYdWVtUVBwZ2RBRzFKUzFnPT0NCkNyZWF0ZWQtQnk6IDEuMCAoQW5kcm9pZCBTaWduQXBrKQ0KDQpOYW1lOiBBbmRyb2lkTWFuaWZlc3QueG1sDQpTSEEtNTEyLURpZ2VzdDogcm9NbWVQZmllYUNQSjFJK2VzMVpsYis0anB2UXowNHZqRWVpL2U0dkN1ald0VVVWSHEzMkNXDQogMUxsOHZiZGMzMCtRc1FlN29ibld4dmhLdXN2K3c1a2c9PQ0KDQpOYW1lOiByZXNvdXJjZXMuYXJzYw0KU0hBLTUxMi1EaWdlc3Q6IG5aYW1aUzlPZTRBRW41cEZaaCtoQ1JFT3krb1N6a3hHdU5YZU0wUFF6WGVBVlVQV3hSVzFPYQ0KIGVLbThRbXdmTmhhaS9HOEcwRUhIbHZEQWdlcy9HUGtBPT0NCg0KTmFtZTogY2xhc3Nlcy5kZXgNClNIQS01MTItRGlnZXN0OiBlbWlDQld2bkVSb0g2N2lCa3EwcUgrdm5tMkpaZDlMWUNEV051N3RNYzJ3bTRtV0dYSUVpWmcNCiBWZkVPV083MFRlZnFjUVhldkNtN2hQMnRpT0U3Y0w5UT09DQoNCg==` - -func TestVerifyFirefoxAddon(t *testing.T) { - fixture := UnmarshalTestFixture(FirefoxAddonFixture) - p7, err := Parse(fixture.Input) - if err != nil { - t.Errorf("Parse encountered unexpected error: %v", err) - } - p7.Content = FirefoxAddonContent - certPool := x509.NewCertPool() - certPool.AppendCertsFromPEM(FirefoxAddonRootCert) - if err := p7.VerifyWithChain(certPool); err != nil { - t.Errorf("Verify failed with error: %v", err) - } - // Verify the certificate chain to make sure the identified root - // is the one we expect - ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, p7.Signers[0].IssuerAndSerialNumber) - if ee == nil { - t.Errorf("No end-entity certificate found for signer") - } - signingTime, _ := time.Parse(time.RFC3339, "2017-02-23 09:06:16-05:00") - chains, err := verifyCertChain(ee, p7.Certificates, certPool, signingTime) - if err != nil { - t.Error(err) - } - if len(chains) != 1 { - t.Errorf("Expected to find one chain, but found %d", len(chains)) - } - if len(chains[0]) != 3 { - t.Errorf("Expected to find three certificates in chain, but found %d", len(chains[0])) - } - if chains[0][0].Subject.CommonName != "tabscope@xuldev.org" { - t.Errorf("Expected to find EE certificate with subject 'tabscope@xuldev.org', but found '%s'", chains[0][0].Subject.CommonName) - } - if chains[0][1].Subject.CommonName != "production-signing-ca.addons.mozilla.org" { - t.Errorf("Expected to find intermediate certificate with subject 'production-signing-ca.addons.mozilla.org', but found '%s'", chains[0][1].Subject.CommonName) - } - if chains[0][2].Subject.CommonName != "root-ca-production-amo" { - t.Errorf("Expected to find root certificate with subject 'root-ca-production-amo', but found '%s'", chains[0][2].Subject.CommonName) - } -} - -var FirefoxAddonContent = []byte(`Signature-Version: 1.0 -MD5-Digest-Manifest: KjRavc6/KNpuT1QLcB/Gsg== -SHA1-Digest-Manifest: 5Md5nUg+U7hQ/UfzV+xGKWOruVI= - -`) - -var FirefoxAddonFixture = ` ------BEGIN PKCS7----- -MIIQTAYJKoZIhvcNAQcCoIIQPTCCEDkCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3 -DQEHAaCCDL0wggW6MIIDoqADAgECAgYBVpobWVwwDQYJKoZIhvcNAQELBQAwgcUx -CzAJBgNVBAYTAlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYD -VQQLEyZNb3ppbGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTExMC8G -A1UEAxMocHJvZHVjdGlvbi1zaWduaW5nLWNhLmFkZG9ucy5tb3ppbGxhLm9yZzE0 -MDIGCSqGSIb3DQEJARYlc2VydmljZXMtb3BzK2FkZG9uc2lnbmluZ0Btb3ppbGxh -LmNvbTAeFw0xNjA4MTcyMDA0NThaFw0yMTA4MTYyMDA0NThaMHYxEzARBgNVBAsT -ClByb2R1Y3Rpb24xCzAJBgNVBAYTAlVTMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3 -MQ8wDQYDVQQKEwZBZGRvbnMxCzAJBgNVBAgTAkNBMRwwGgYDVQQDFBN0YWJzY29w -ZUB4dWxkZXYub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv6e0 -mPD8dt4J8HTNNq4ODns2DV6Weh1hllCIFvOeu1u3UrR03st0BMY8OXYwr/NvRVjg -bA8gRySWAL+XqLzbhtXNeNegAoxrF+3mYY5rJjsLj/FGI6P6OXjngqwgm9VTBl7m -jh/KXBSwYoUcavJo6cmk8sCFwoblyQiv+tsWaUCOI6zMzubNtIS+GFvET9y/VZMP -j6mk8O10wBgJF5MMtA19va3qXy7aCZ7DnZp1l3equd/L6t324TtXoqx6xWQKo6TM -I0mcTlKvm6TKegTGBCyGn3JRARoIJv4AW1qqgyaHXf9EoY2pKT8Avkri5++NuSJ6 -jtO4k/diBA2MZU20U0KGffYZNTxKDqd6XtI6y1tJPd/OWRFyU+mHntkcm9sar7L3 -nPKujHRox2re10ec1WBnJE3PjlAoesNjxzp+xs2mGGc8DX9NuWn+1uK9xmgGIIMl -OFfyQ4s0G6hKp5goFcrFZxmexu0ZahOs8vZf8xDBW7yR1zToQElOXHvrscM386os -kOF9IxQZfcCoPuNQVg1haCONNkx0oau3RQQlOSAZtC79b+rBjQ5JYfjRLYAworf2 -xQaprCh33TD1dTBrvzEbCGszgkN53Vqh5TFBjbU/NyldOkGvK8Xf6WhT5u+aftnV -lbuE2McAg6x1AlloUZq6PNTBpz7zypcIISnQ+y8CAwEAATANBgkqhkiG9w0BAQsF -AAOCAgEAIBoo2+OEYNCgP/IbUj9azaf/lde1q4AK/uTMoUeS5WcrXd8aqA0Y1qV7 -xUALgDQAExXgqcOMGu4mPMaoZDgwGI4Tj7XPJQq5Z5zYxpRf/Wtzae33T9BF6QPW -v5xiRYuol+FbEtqRHZqxDWtIrd1MWBy3wjO3pLPdzDM9jWh+HLxdGWThJszaZp3T -CqsOx+l9W0Q7qM5ioZpHStgXDfhw38Lg++kLnzcX9MqsjYyezdwE4krqW6hK3+4S -0LZE4dTgsy8JULkyAF3HrPWEXESnD7c4mx6owZe+BNDK5hsVM/obAqH7sJq/igbM -5N1l832p/ws8l5xKOr3qBWSzWn6u7ExvqG6Ckh0foJOVXvzGqvrXcoiBGV8S9Z7c -DghUvMt6b0pZ0ildRCHfTUz7eG3g4MhfbjupR7b+L9FWEJhcd/H0dxpw7SKYha/n -ePuRL7MXmbW8WLMqO/ImxzL8TPOB3pUg3nITfubV6gpPBmn+0nwbqYUmggJuwgvK -I2GpN2Ny6EErZy17EEgyhJygJZMj+UzQjC781xxsl3ljpYEqqwgRLIZBSBUD5dXj -XBuU24w162SeSyHZzkBbuv6lr52pqoZyFrG29DCHECgO9ZmNWgSpiWSkh+vExAG7 -wNs0y61t2HUG+BCMGPQ9sOzouyTfrnLVAWwzswGftFYQfoIBeJIwggb7MIIE46AD -AgECAgMQAAIwDQYJKoZIhvcNAQEMBQAwfTELMAkGA1UEBhMCVVMxHDAaBgNVBAoT -E01vemlsbGEgQ29ycG9yYXRpb24xLzAtBgNVBAsTJk1vemlsbGEgQU1PIFByb2R1 -Y3Rpb24gU2lnbmluZyBTZXJ2aWNlMR8wHQYDVQQDExZyb290LWNhLXByb2R1Y3Rp -b24tYW1vMB4XDTE1MDMxNzIzNTI0MloXDTI1MDMxNDIzNTI0MlowgcUxCzAJBgNV -BAYTAlVTMRwwGgYDVQQKExNNb3ppbGxhIENvcnBvcmF0aW9uMS8wLQYDVQQLEyZN -b3ppbGxhIEFNTyBQcm9kdWN0aW9uIFNpZ25pbmcgU2VydmljZTExMC8GA1UEAxMo -cHJvZHVjdGlvbi1zaWduaW5nLWNhLmFkZG9ucy5tb3ppbGxhLm9yZzE0MDIGCSqG -SIb3DQEJARYlc2VydmljZXMtb3BzK2FkZG9uc2lnbmluZ0Btb3ppbGxhLmNvbTCC -AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMLMM9m2HBLhCiO9mhljpehT -hxpzlCnxluzDZ51I/H7MvBbIvZBm9zSpHdffubSsak2qYE69d+ebTa/CK83WIosM -24/2Qp7n/GGaPJcCC4Y3JkrCsgA8+wV2MbFlKSv+qMdvI/sE3BPYDMCjVPMhHmIP -XaPWd42OoHpI8R3GGUtVnR3Hm76pa2+v6TwgeMiO8om+ogGufiyv6FNMZ5NuY1Z9 -aLNEvehnAzSfddQyki+6FJd7XkgZbP7pb1Kl8yYgiy4piBerJ9H09uPehffE3Ell -3cApQL3+0kjaUX4scMjuNQDMKziRZkYgJAM+qA9WA5Jn77AjerQBWQeEev1PWHYh -0IDlgS/a0bjKmVjNZYG6adrY/R5/whzWGFCIE1UfhPm6PdN0557qvF838C2RFHsI -KzV6KQf0chMjpa02tPaIctjVhnDQZZNKm2ZfLOt9kQ57Is/e6KxH7pYMit46+s99 -lYM7ZquvWbK19b1Ili/6S1BxSzd3wztgfN5jGsc+jCCYLm+AcVtfNKc8cFZHXKrB -CwhGmdbWDSBCicZNA7FKJpO3oIx26VPF2XUldA/T5Mh/POGLilK3t9m9qbjEyDp1 -EwoBToOR/aMrdnNYvSWp0g/GHMzSfJjjXyAqrZY2itam/IJd8r9FoRAzevPt/zTX -BET3INoiCDGRH0XrxUYtAgMGVTejggE5MIIBNTAMBgNVHRMEBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUdHxf -FKXipZLjs20GqIUdNkQXH4gwgagGA1UdIwSBoDCBnYAUs7zqWHSr4W54KrKrnCMe -qGMsl7ehgYGkfzB9MQswCQYDVQQGEwJVUzEcMBoGA1UEChMTTW96aWxsYSBDb3Jw -b3JhdGlvbjEvMC0GA1UECxMmTW96aWxsYSBBTU8gUHJvZHVjdGlvbiBTaWduaW5n -IFNlcnZpY2UxHzAdBgNVBAMTFnJvb3QtY2EtcHJvZHVjdGlvbi1hbW+CAQEwMwYJ -YIZIAYb4QgEEBCYWJGh0dHA6Ly9hZGRvbnMubW96aWxsYS5vcmcvY2EvY3JsLnBl -bTANBgkqhkiG9w0BAQwFAAOCAgEArde/fdjb7TE0eH7Ij7xU4JbcSyhY3cQhVYCw -Fg+Q/2pj+NAfazcjUuLWA0Y/YZs9HOx6j+ZAqO4C/xfMP4RDs9IypxvzHDU6SXgD -RK6uOKtS07HXLcXgFUBvJEQhbT/h5+IQOA4/GcpCshfD6iyiBBi+IocR+tnKPCuZ -T3m1t60Eja/MkPKG/Gx8vSodHvlTTsJ2GzjUEANveCZOnlAdp9fjTvFZny9qqnbg -sfVbuTqKndbCFW5QLXfkna6jBqMrY0+CpMYY2oJ5gwpHbE/7hhukjxGCTcpv7r/O -M53bb/DZnybDlLLepacljvz7DBA1O1FFtEhf9MR+vyvmBpniAyKQhqG2hsVGurE1 -nBcE+oteZWar2lMp6+etDAb9DRC+jZv0aEQs2o/qQwyD8AGquLgBsJq5Jz3gGxzn -4r3vGu2lV8VdzIm0C8sOFSWTmTZxQmJbF8xSsQBojnsvEah4DPER+eAt6qKolaWe -s4drJQjzFyC7HJn2VqalpCwbe9CdMB7eRqzeP6GujJBi80/gx0pAysUtuKKpH5IJ -WbXAOszfrjb3CaHafYZDnwPoOfj74ogFzjt2f54jwnU+ET/byfjZ7J8SLH316C1V -HrvFXcTzyMV4aRluVPjPg9x1G58hMIbeuT4GpwQUNdJ9uL8t65v0XwG2t6Y7jpRO -sFVxBtgxggNXMIIDUwIBATCB0DCBxTELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE01v -emlsbGEgQ29ycG9yYXRpb24xLzAtBgNVBAsTJk1vemlsbGEgQU1PIFByb2R1Y3Rp -b24gU2lnbmluZyBTZXJ2aWNlMTEwLwYDVQQDEyhwcm9kdWN0aW9uLXNpZ25pbmct -Y2EuYWRkb25zLm1vemlsbGEub3JnMTQwMgYJKoZIhvcNAQkBFiVzZXJ2aWNlcy1v -cHMrYWRkb25zaWduaW5nQG1vemlsbGEuY29tAgYBVpobWVwwCQYFKw4DAhoFAKBd -MBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTE2MDgx -NzIwMDQ1OFowIwYJKoZIhvcNAQkEMRYEFAxlGvNFSx+Jqj70haE8b7UZk+2GMA0G -CSqGSIb3DQEBAQUABIICADsDlrucYRgwq9o2QSsO6X6cRa5Zu6w+1n07PTIyc1zn -Pi1cgkkWZ0kZBHDrJ5CY33yRQPl6I1tHXaq7SkOSdOppKhpUmBiKZxQRAZR21QHk -R3v1XS+st/o0N+0btv3YoplUifLIwtH89oolxqlStChELu7FuOBretdhx/z12ytA -EhIIS53o/XjDL7XKJbQA02vzOtOC/Eq6p8BI7F3y6pvtmJIRkeGv+u6ssJa6g5q8 -74w8hHXaH94Z9+hDPqjNWlsXJHgPdAKiEjzDz9oLkvDyX4Pd8JMK5ILskirpG+hj -Q8jkTc5oYwyuSlBAUTGxW6ZbuOrtfVZvOVtRL/ixuiFiVlJ+JOQOxrtK19ukamsI -iacFlbLgiA7w0HCtm2DsT9aL67/1e4rJ0lv0MjnQYUMmKQy7g0Gd3+nQPU9pn+Lf -Z/UmSNWiJ8Csc/seDMyzT6jrzcGPfoSVaUowH0wGrI9If1snwcr+mMg7dWRGf1fm -y/dcVSzed0ax4LqDmike1EshU+51cKWWlnhyNHK4KH+0fNsBQ0c6clrFpGx9MPmV -YXie6C+LWkh5x12RU0sJt/SmSZV6q9VliIkX+yY3jBrC/pKgRahtcIyq46Da1E6K -lc15Euur3NfGow+nott0Z8XutpYdK/2vBKcIh9JOdkd+oe6pcIP6hnhHRp53wqmG ------END PKCS7-----` - -var FirefoxAddonRootCert = []byte(` ------BEGIN CERTIFICATE----- -MIIGYTCCBEmgAwIBAgIBATANBgkqhkiG9w0BAQwFADB9MQswCQYDVQQGEwJVUzEc -MBoGA1UEChMTTW96aWxsYSBDb3Jwb3JhdGlvbjEvMC0GA1UECxMmTW96aWxsYSBB -TU8gUHJvZHVjdGlvbiBTaWduaW5nIFNlcnZpY2UxHzAdBgNVBAMTFnJvb3QtY2Et -cHJvZHVjdGlvbi1hbW8wHhcNMTUwMzE3MjI1MzU3WhcNMjUwMzE0MjI1MzU3WjB9 -MQswCQYDVQQGEwJVUzEcMBoGA1UEChMTTW96aWxsYSBDb3Jwb3JhdGlvbjEvMC0G -A1UECxMmTW96aWxsYSBBTU8gUHJvZHVjdGlvbiBTaWduaW5nIFNlcnZpY2UxHzAd -BgNVBAMTFnJvb3QtY2EtcHJvZHVjdGlvbi1hbW8wggIgMA0GCSqGSIb3DQEBAQUA -A4ICDQAwggIIAoICAQC0u2HXXbrwy36+MPeKf5jgoASMfMNz7mJWBecJgvlTf4hH -JbLzMPsIUauzI9GEpLfHdZ6wzSyFOb4AM+D1mxAWhuZJ3MDAJOf3B1Rs6QorHrl8 -qqlNtPGqepnpNJcLo7JsSqqE3NUm72MgqIHRgTRsqUs+7LIPGe7262U+N/T0LPYV -Le4rZ2RDHoaZhYY7a9+49mHOI/g2YFB+9yZjE+XdplT2kBgA4P8db7i7I0tIi4b0 -B0N6y9MhL+CRZJyxdFe2wBykJX14LsheKsM1azHjZO56SKNrW8VAJTLkpRxCmsiT -r08fnPyDKmaeZ0BtsugicdipcZpXriIGmsZbI12q5yuwjSELdkDV6Uajo2n+2ws5 -uXrP342X71WiWhC/dF5dz1LKtjBdmUkxaQMOP/uhtXEKBrZo1ounDRQx1j7+SkQ4 -BEwjB3SEtr7XDWGOcOIkoJZWPACfBLC3PJCBWjTAyBlud0C5n3Cy9regAAnOIqI1 -t16GU2laRh7elJ7gPRNgQgwLXeZcFxw6wvyiEcmCjOEQ6PM8UQjthOsKlszMhlKw -vjyOGDoztkqSBy/v+Asx7OW2Q7rlVfKarL0mREZdSMfoy3zTgtMVCM0vhNl6zcvf -5HNNopoEdg5yuXo2chZ1p1J+q86b0G5yJRMeT2+iOVY2EQ37tHrqUURncCy4uwIB -A6OB7TCB6jAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSUBAf8E -DDAKBggrBgEFBQcDAzCBkgYDVR0jBIGKMIGHoYGBpH8wfTELMAkGA1UEBhMCVVMx -HDAaBgNVBAoTE01vemlsbGEgQ29ycG9yYXRpb24xLzAtBgNVBAsTJk1vemlsbGEg -QU1PIFByb2R1Y3Rpb24gU2lnbmluZyBTZXJ2aWNlMR8wHQYDVQQDExZyb290LWNh -LXByb2R1Y3Rpb24tYW1vggEBMB0GA1UdDgQWBBSzvOpYdKvhbngqsqucIx6oYyyX -tzANBgkqhkiG9w0BAQwFAAOCAgEAaNSRYAaECAePQFyfk12kl8UPLh8hBNidP2H6 -KT6O0vCVBjxmMrwr8Aqz6NL+TgdPmGRPDDLPDpDJTdWzdj7khAjxqWYhutACTew5 -eWEaAzyErbKQl+duKvtThhV2p6F6YHJ2vutu4KIciOMKB8dslIqIQr90IX2Usljq -8Ttdyf+GhUmazqLtoB0GOuESEqT4unX6X7vSGu1oLV20t7t5eCnMMYD67ZBn0YIU -/cm/+pan66hHrja+NeDGF8wabJxdqKItCS3p3GN1zUGuJKrLykxqbOp/21byAGog -Z1amhz6NHUcfE6jki7sM7LHjPostU5ZWs3PEfVVgha9fZUhOrIDsyXEpCWVa3481 -LlAq3GiUMKZ5DVRh9/Nvm4NwrTfB3QkQQJCwfXvO9pwnPKtISYkZUqhEqvXk5nBg -QCkDSLDjXTx39naBBGIVIqBtKKuVTla9enngdq692xX/CgO6QJVrwpqdGjebj5P8 -5fNZPABzTezG3Uls5Vp+4iIWVAEDkK23cUj3c/HhE+Oo7kxfUeu5Y1ZV3qr61+6t -ZARKjbu1TuYQHf0fs+GwID8zeLc2zJL7UzcHFwwQ6Nda9OJN4uPAuC/BKaIpxCLL -26b24/tRam4SJjqpiq20lynhUrmTtt6hbG3E1Hpy3bmkt2DYnuMFwEx2gfXNcnbT -wNuvFqc= ------END CERTIFICATE-----`) - -// sign a document with openssl and verify the signature with pkcs7. -// this uses a chain of root, intermediate and signer cert, where the -// intermediate is added to the certs but the root isn't. -func TestSignWithOpenSSLAndVerify(t *testing.T) { - content := []byte(` -A ship in port is safe, -but that's not what ships are built for. --- Grace Hopper`) - // write the content to a temp file - tmpContentFile, err := ioutil.TempFile("", "TestSignWithOpenSSLAndVerify_content") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpContentFile.Name(), content, 0755) - sigalgs := []x509.SignatureAlgorithm{ - x509.SHA1WithRSA, - x509.SHA256WithRSA, - x509.SHA512WithRSA, - x509.ECDSAWithSHA1, - x509.ECDSAWithSHA256, - x509.ECDSAWithSHA384, - x509.ECDSAWithSHA512, - } - for _, sigalgroot := range sigalgs { - rootCert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, sigalgroot, true) - if err != nil { - t.Fatalf("test %s: cannot generate root cert: %s", sigalgroot, err) - } - truststore := x509.NewCertPool() - truststore.AddCert(rootCert.Certificate) - for _, sigalginter := range sigalgs { - interCert, err := createTestCertificateByIssuer("PKCS7 Test Intermediate Cert", rootCert, sigalginter, true) - if err != nil { - t.Fatalf("test %s/%s: cannot generate intermediate cert: %s", sigalgroot, sigalginter, err) - } - // write the intermediate cert to a temp file - tmpInterCertFile, err := ioutil.TempFile("", "TestSignWithOpenSSLAndVerify_intermediate") - if err != nil { - t.Fatal(err) - } - fd, err := os.OpenFile(tmpInterCertFile.Name(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - t.Fatal(err) - } - pem.Encode(fd, &pem.Block{Type: "CERTIFICATE", Bytes: interCert.Certificate.Raw}) - fd.Close() - for _, sigalgsigner := range sigalgs { - signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", interCert, sigalgsigner, false) - if err != nil { - t.Fatalf("test %s/%s/%s: cannot generate signer cert: %s", sigalgroot, sigalginter, sigalgsigner, err) - } - - // write the signer cert to a temp file - tmpSignerCertFile, err := ioutil.TempFile("", "TestSignWithOpenSSLAndVerify_signer") - if err != nil { - t.Fatal(err) - } - fd, err = os.OpenFile(tmpSignerCertFile.Name(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - t.Fatal(err) - } - pem.Encode(fd, &pem.Block{Type: "CERTIFICATE", Bytes: signerCert.Certificate.Raw}) - fd.Close() - - // write the signer key to a temp file - tmpSignerKeyFile, err := ioutil.TempFile("", "TestSignWithOpenSSLAndVerify_key") - if err != nil { - t.Fatal(err) - } - fd, err = os.OpenFile(tmpSignerKeyFile.Name(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755) - if err != nil { - t.Fatal(err) - } - var derKey []byte - priv := *signerCert.PrivateKey - switch priv := priv.(type) { - case *rsa.PrivateKey: - derKey = x509.MarshalPKCS1PrivateKey(priv) - pem.Encode(fd, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: derKey}) - case *ecdsa.PrivateKey: - derKey, err = x509.MarshalECPrivateKey(priv) - if err != nil { - t.Fatal(err) - } - pem.Encode(fd, &pem.Block{Type: "EC PRIVATE KEY", Bytes: derKey}) - } - fd.Close() - - // write the root cert to a temp file - tmpSignedFile, err := ioutil.TempFile("", "TestSignWithOpenSSLAndVerify_signature") - if err != nil { - t.Fatal(err) - } - // call openssl to sign the content - opensslCMD := exec.Command("openssl", "smime", "-sign", "-nodetach", - "-in", tmpContentFile.Name(), "-out", tmpSignedFile.Name(), - "-signer", tmpSignerCertFile.Name(), "-inkey", tmpSignerKeyFile.Name(), - "-certfile", tmpInterCertFile.Name(), "-outform", "PEM") - out, err := opensslCMD.CombinedOutput() - if err != nil { - t.Fatalf("test %s/%s/%s: openssl command failed with %s: %s", sigalgroot, sigalginter, sigalgsigner, err, out) - } - - // verify the signed content - pemSignature, err := ioutil.ReadFile(tmpSignedFile.Name()) - if err != nil { - t.Fatal(err) - } - derBlock, _ := pem.Decode(pemSignature) - if derBlock == nil { - break - } - p7, err := Parse(derBlock.Bytes) - if err != nil { - t.Fatalf("Parse encountered unexpected error: %v", err) - } - if err := p7.VerifyWithChain(truststore); err != nil { - t.Fatalf("Verify failed with error: %v", err) - } - // Verify the certificate chain to make sure the identified root - // is the one we expect - ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, p7.Signers[0].IssuerAndSerialNumber) - if ee == nil { - t.Fatalf("No end-entity certificate found for signer") - } - chains, err := verifyCertChain(ee, p7.Certificates, truststore, time.Now()) - if err != nil { - t.Fatal(err) - } - if len(chains) != 1 { - t.Fatalf("Expected to find one chain, but found %d", len(chains)) - } - if len(chains[0]) != 3 { - t.Fatalf("Expected to find three certificates in chain, but found %d", len(chains[0])) - } - if chains[0][0].Subject.CommonName != "PKCS7 Test Signer Cert" { - t.Fatalf("Expected to find EE certificate with subject 'PKCS7 Test Signer Cert', but found '%s'", chains[0][0].Subject.CommonName) - } - if chains[0][1].Subject.CommonName != "PKCS7 Test Intermediate Cert" { - t.Fatalf("Expected to find intermediate certificate with subject 'PKCS7 Test Intermediate Cert', but found '%s'", chains[0][1].Subject.CommonName) - } - if chains[0][2].Subject.CommonName != "PKCS7 Test Root CA" { - t.Fatalf("Expected to find root certificate with subject 'PKCS7 Test Root CA', but found '%s'", chains[0][2].Subject.CommonName) - } - os.Remove(tmpSignerCertFile.Name()) // clean up - os.Remove(tmpSignerKeyFile.Name()) // clean up - } - os.Remove(tmpInterCertFile.Name()) // clean up - } - } - os.Remove(tmpContentFile.Name()) // clean up -} - -func TestDSASignWithOpenSSLAndVerify(t *testing.T) { - content := []byte(` -A ship in port is safe, -but that's not what ships are built for. --- Grace Hopper`) - // write the content to a temp file - tmpContentFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_content") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpContentFile.Name(), content, 0755) - - // write the signer cert to a temp file - tmpSignerCertFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_signer") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpSignerCertFile.Name(), dsaPublicCert, 0755) - - // write the signer key to a temp file - tmpSignerKeyFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_key") - if err != nil { - t.Fatal(err) - } - ioutil.WriteFile(tmpSignerKeyFile.Name(), dsaPrivateKey, 0755) - - tmpSignedFile, err := ioutil.TempFile("", "TestDSASignWithOpenSSLAndVerify_signature") - if err != nil { - t.Fatal(err) - } - // call openssl to sign the content - opensslCMD := exec.Command("openssl", "smime", "-sign", "-nodetach", "-md", "sha1", - "-in", tmpContentFile.Name(), "-out", tmpSignedFile.Name(), - "-signer", tmpSignerCertFile.Name(), "-inkey", tmpSignerKeyFile.Name(), - "-certfile", tmpSignerCertFile.Name(), "-outform", "PEM") - out, err := opensslCMD.CombinedOutput() - if err != nil { - t.Fatalf("openssl command failed with %s: %s", err, out) - } - - // verify the signed content - pemSignature, err := ioutil.ReadFile(tmpSignedFile.Name()) - if err != nil { - t.Fatal(err) - } - fmt.Printf("%s\n", pemSignature) - derBlock, _ := pem.Decode(pemSignature) - if derBlock == nil { - t.Fatalf("failed to read DER block from signature PEM %s", tmpSignedFile.Name()) - } - p7, err := Parse(derBlock.Bytes) - if err != nil { - t.Fatalf("Parse encountered unexpected error: %v", err) - } - if err := p7.Verify(); err != nil { - t.Fatalf("Verify failed with error: %v", err) - } - os.Remove(tmpSignerCertFile.Name()) // clean up - os.Remove(tmpSignerKeyFile.Name()) // clean up - os.Remove(tmpContentFile.Name()) // clean up -} - -var dsaPrivateKey = []byte(`-----BEGIN PRIVATE KEY----- -MIIBSwIBADCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdS -PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVCl -pJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith -1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7L -vKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3 -zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImo -g9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoEFgIUfW4aPdQBn9gJZp2KuNpzgHzvfsE= ------END PRIVATE KEY-----`) - -var dsaPublicCert = []byte(`-----BEGIN CERTIFICATE----- -MIIDOjCCAvWgAwIBAgIEPCY/UDANBglghkgBZQMEAwIFADBsMRAwDgYDVQQGEwdV -bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD -VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du -MB4XDTE4MTAyMjEzNDMwN1oXDTQ2MDMwOTEzNDMwN1owbDEQMA4GA1UEBhMHVW5r -bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE -ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC -AbgwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADD -Hj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gE -exAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/Ii -Axmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4 -V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozI -puE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4Vrl -nwaSi2ZegHtVJWQBTDv+z0kqA4GFAAKBgQDCriMPbEVBoRK4SOUeFwg7+VRf4TTp -rcOQC9IVVoCjXzuWEGrp3ZI7YWJSpFnSch4lk29RH8O0HpI/NOzKnOBtnKr782pt -1k/bJVMH9EaLd6MKnAVjrCDMYBB0MhebZ8QHY2elZZCWoqDYAcIDOsEx+m4NLErT -ypPnjS5M0jm1PKMhMB8wHQYDVR0OBBYEFC0Yt5XdM0Kc95IX8NQ8XRssGPx7MA0G -CWCGSAFlAwQDAgUAAzAAMC0CFQCIgQtrZZ9hdZG1ROhR5hc8nYEmbgIUAIlgC688 -qzy/7yePTlhlpj+ahMM= ------END CERTIFICATE-----`) diff --git a/scep/scep.go b/scep/scep.go index bc46cce7..6a636aee 100644 --- a/scep/scep.go +++ b/scep/scep.go @@ -6,7 +6,9 @@ import ( microscep "github.com/micromdm/scep/scep" - "github.com/smallstep/certificates/scep/pkcs7" + //"github.com/smallstep/certificates/scep/pkcs7" + + "go.mozilla.org/pkcs7" ) // SCEP OIDs