pax_global_header00006660000000000000000000000064147060256570014526gustar00rootroot0000000000000052 comment=c3ffd35533865875bd55b8fa55dc1aac2c5291ae golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/000077500000000000000000000000001470602565700216705ustar00rootroot00000000000000golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/.github/000077500000000000000000000000001470602565700232305ustar00rootroot00000000000000golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/.github/dependabot.yml000066400000000000000000000006601470602565700260620ustar00rootroot00000000000000# To get started with Dependabot version updates, you'll need to specify which # package ecosystems to update and where the package manifests are located. # Please see the documentation for all configuration options: # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: "gomod" directory: "/" schedule: interval: "weekly" golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/.github/workflows/000077500000000000000000000000001470602565700252655ustar00rootroot00000000000000golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/.github/workflows/ci.yml000066400000000000000000000013501470602565700264020ustar00rootroot00000000000000name: CI on: [push, pull_request] env: GODEBUG: x509sha1=1 jobs: test: name: Test strategy: matrix: go: ['1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: fetch-depth: 0 - uses: actions/setup-go@v2 with: go-version: ${{ matrix.go }} stable: false - name: Test env: # set this environment variable to true so tests can be run with the # sha1 algorithm. Without this set, tests fail because Go notes the # SHA1 algorithm as insecure GODEBUG: x509sha1=1 run: go vet . && go build . && go test -count=1 -covermode=count -coverprofile=coverage.out . golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/.gitignore000066400000000000000000000004121470602565700236550ustar00rootroot00000000000000# 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 golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/LICENSE000066400000000000000000000020701470602565700226740ustar00rootroot00000000000000The 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. golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/Makefile000066400000000000000000000004601470602565700233300ustar00rootroot00000000000000all: vet staticcheck test test: GODEBUG=x509sha1=1 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 golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/README.md000066400000000000000000000034211470602565700231470ustar00rootroot00000000000000# pkcs7 [![GoDoc](https://godoc.org/go.mozilla.org/pkcs7?status.svg)](https://godoc.org/go.mozilla.org/pkcs7) [![Build Status](https://github.com/mozilla-services/pkcs7/workflows/CI/badge.svg?branch=master&event=push)](https://github.com/mozilla-services/pkcs7/actions/workflows/ci.yml?query=branch%3Amaster+event%3Apush) 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) golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/ber.go000066400000000000000000000156361470602565700230020ustar00rootroot00000000000000package pkcs7 import ( "bytes" "errors" ) type asn1Object interface { EncodeTo(writer *bytes.Buffer) error } type asn1Structured struct { tagBytes []byte content []asn1Object } func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { //fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes) inner := new(bytes.Buffer) for _, obj := range s.content { err := obj.EncodeTo(inner) if err != nil { return err } } out.Write(s.tagBytes) encodeLength(out, inner.Len()) out.Write(inner.Bytes()) return nil } type asn1Primitive struct { tagBytes []byte length int content []byte } func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error { _, err := out.Write(p.tagBytes) if err != nil { return err } if err = encodeLength(out, p.length); err != nil { return err } //fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) //fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) out.Write(p.content) return nil } func ber2der(ber []byte) ([]byte, error) { if len(ber) == 0 { return nil, errors.New("ber2der: input ber is empty") } //fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) out := new(bytes.Buffer) obj, _, err := readObject(ber, 0) if err != nil { return nil, err } obj.EncodeTo(out) 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 l >= 0x80 && offset >= berLen { // if indefinite or multibyte length, we need to verify there is at least one more byte available // otherwise we need to be flexible here for length == 0 conditions // validation that the length is available is done after the length is correctly parsed return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } indefinite := false if l > 0x80 { numberOfBytes := (int)(l & 0x7F) if numberOfBytes > 4 { // int is only guaranteed to be 32bit return nil, 0, errors.New("ber2der: BER tag length too long") } if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F { return nil, 0, errors.New("ber2der: BER tag length is negative") } if offset + numberOfBytes > berLen { // == condition is not checked here, this allows for a more descreptive error when the parsed length is // compared with the remaining available bytes (`contentEnd > berLen`) return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } if (int)(ber[offset]) == 0x0 && (numberOfBytes == 1 || ber[offset+1] <= 0x7F) { // `numberOfBytes == 1` is an important conditional to avoid a potential out of bounds panic with `ber[offset+1]` 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++ } } else if l == 0x80 { indefinite = true } else { length = (int)(l) } if length < 0 { return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length") } //fmt.Printf("--> length : %d\n", length) contentEnd := offset + length if contentEnd > berLen { return nil, 0, errors.New("ber2der: BER tag length is more than available data") } debugprint("--> content start : %d\n", offset) debugprint("--> content end : %d\n", contentEnd) //debugprint("--> content : %x\n", ber[offset:contentEnd]) var obj asn1Object if indefinite && kind == 0 { return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding") } if kind == 0 { obj = asn1Primitive{ tagBytes: ber[tagStart:tagEnd], length: length, content: ber[offset:contentEnd], } } else { var subObjects []asn1Object for (offset < contentEnd) || indefinite { var subObj asn1Object var err error subObj, offset, err = readObject(ber, offset) if err != nil { return nil, 0, err } subObjects = append(subObjects, subObj) if indefinite { terminated, err := isIndefiniteTermination(ber, offset) if err != nil { return nil, 0, err } if terminated { break } } } obj = asn1Structured{ tagBytes: ber[tagStart:tagEnd], content: subObjects, } } // Apply indefinite form length with 0x0000 terminator. if indefinite { contentEnd = offset + 2 } return obj, contentEnd, nil } func isIndefiniteTermination(ber []byte, offset int) (bool, error) { if len(ber) - offset < 2 { return false, errors.New("ber2der: Invalid BER format") } return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil } func debugprint(format string, a ...interface{}) { //fmt.Printf(format, a) } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/ber_test.go000066400000000000000000000167651470602565700240450ustar00rootroot00000000000000package pkcs7 import ( "bytes" "encoding/asn1" "encoding/pem" "fmt" "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{}, "input ber is empty"}, {[]byte{0x30}, "cannot move offset forward, end of ber data reached"}, {[]byte{0x30, 0x08}, "BER tag length is more than available dat"}, {[]byte{0x30, 0x81}, "cannot move offset forward, end of ber data reached"}, {[]byte{0x30, 0x81, 0x00}, "BER tag length has leading zero"}, {[]byte{0x30, 0x85, 0x00}, "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, 0x1, 0x2}, "Invalid BER format"}, {[]byte{0x30, 0x80, 0x1, 0x2}, "BER tag length is more than available data"}, {[]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()) } } } func TestBer2Der_NestedMultipleIndefinite(t *testing.T) { // indefinite length fixture ber := []byte{0x30, 0x80, 0x30, 0x80, 0x02, 0x01, 0x01, 0x00, 0x00, 0x30, 0x80, 0x02, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00} expected := []byte{0x30, 0x0A, 0x30, 0x03, 0x02, 0x01, 0x01, 0x30, 0x03, 0x02, 0x01, 0x02} der, err := ber2der(ber) if err != nil { t.Fatalf("ber2der failed with error: %v", err) } if bytes.Compare(der, expected) != 0 { 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 { Nest1 struct { Number int } Nest2 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 TestVerifyIndefiniteLengthBer(t *testing.T) { decoded := mustDecodePEM([]byte(testPKCS7)) _, err := ber2der(decoded) if err != nil { t.Errorf("cannot parse indefinite length ber: %v", err) } } func mustDecodePEM(data []byte) []byte { var block *pem.Block block, rest := pem.Decode(data) if len(rest) != 0 { panic(fmt.Errorf("unexpected remaining PEM block during decode")) } return block.Bytes } const testPKCS7 = ` -----BEGIN PKCS7----- MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0B BwGggCSABIIDfXsiQWdlbnRBY3Rpb25PdmVycmlkZXMiOnsiQWdlbnRPdmVycmlk ZXMiOnsiRmlsZUV4aXN0c0JlaGF2aW9yIjoiT1ZFUldSSVRFIn19LCJBcHBsaWNh dGlvbklkIjoiZTA0NDIzZTQtN2E2Ny00ZjljLWIyOTEtOTllNjNjMWMyMTU4Iiwi QXBwbGljYXRpb25OYW1lIjoibWthbmlhLXhyZF9zYW0uY2R3c19lY2hvc2VydmVy IiwiRGVwbG95bWVudENyZWF0b3IiOiJ1c2VyIiwiRGVwbG95bWVudEdyb3VwSWQi OiJmYWI5MjEwZi1mNmM3LTQyODUtYWEyZC03Mzc2MGQ4ODE3NmEiLCJEZXBsb3lt ZW50R3JvdXBOYW1lIjoibWthbmlhLXhyZF9zYW0uY2R3c19lY2hvc2VydmVyX2Rn IiwiRGVwbG95bWVudElkIjoiZC1UREUxVTNXREEiLCJEZXBsb3ltZW50VHlwZSI6 IklOX1BMQUNFIiwiR2l0SHViQWNjZXNzVG9rZW4iOm51bGwsIkluc3RhbmNlR3Jv dXBJZCI6ImZhYjkyMTBmLWY2YzctNDI4NS1hYTJkLTczNzYwZDg4MTc2YSIsIlJl dmlzaW9uIjp7IkFwcFNwZWNDb250ZW50IjpudWxsLCJDb2RlQ29tbWl0UmV2aXNp b24iOm51bGwsIkdpdEh1YlJldmlzaW9uIjpudWxsLCJHaXRSZXZpc2lvbiI6bnVs bCwiUmV2aXNpb25UeXBlIjoiUzMiLCJTM1JldmlzaW9uIjp7IkJ1Y2tldCI6Im1r YW5pYS1jZHdzLWRlcGxveS1idWNrZXQiLCJCdW5kbGVUeXBlIjoiemlwIiwiRVRh ZyI6bnVsbCwiS2V5IjoieHJkOjpzYW0uY2R3czo6ZWNob3NlcnZlcjo6MTo6Lnpp cCIsIlZlcnNpb24iOm51bGx9fSwiUzNSZXZpc2lvbiI6eyJCdWNrZXQiOiJta2Fu aWEtY2R3cy1kZXBsb3ktYnVja2V0IiwiQnVuZGxlVHlwZSI6InppcCIsIkVUYWci Om51bGwsIktleSI6InhyZDo6c2FtLmNkd3M6OmVjaG9zZXJ2ZXI6OjE6Oi56aXAi LCJWZXJzaW9uIjpudWxsfSwiVGFyZ2V0UmV2aXNpb24iOm51bGx9AAAAAAAAoIAw ggWbMIIEg6ADAgECAhAGrjFMK45t2jcNHtjY1DjEMA0GCSqGSIb3DQEBCwUAMEYx CzAJBgNVBAYTAlVTMQ8wDQYDVQQKEwZBbWF6b24xFTATBgNVBAsTDFNlcnZlciBD QSAxQjEPMA0GA1UEAxMGQW1hem9uMB4XDTIwMTExMjAwMDAwMFoXDTIxMTAxNTIz NTk1OVowNDEyMDAGA1UEAxMpY29kZWRlcGxveS1zaWduZXItdXMtZWFzdC0yLmFt YXpvbmF3cy5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDit4f+ I4BSv4rBV/8bJ+f4KqBwTCt9iJeau/r9liQfMgj/C1M2E+aa++u8BtY/LQstB44v v6KqcaiOyWpkD9OsUty9qb4eNTPF2Y4jpNsi/Hfw0phsd9gLun2foppILmL4lZIG lBhTeEwv6qV4KbyXOG9abHOX32+jVFtM1rbzHNFvz90ysfZp16TBAi7IRKEZeXvd MvlJJMAJtAoblxiDIS3A1csY1G4XHYET8xIoCop3mqEZEtAxUUP2epdXXdhD2U0G 7alSRS54o91QW1Dp3A13lu1A1nds9CkWlPkDTpKSUG/qN5y5+6dCCGaydgL5krMs R79bCrR1sEKm5hi1AgMBAAGjggKVMIICkTAfBgNVHSMEGDAWgBRZpGYGUqB7lZI8 o5QHJ5Z0W/k90DAdBgNVHQ4EFgQUPF5qTbnTDYhmp7tGmmL/jTmLoHMwNAYDVR0R BC0wK4IpY29kZWRlcGxveS1zaWduZXItdXMtZWFzdC0yLmFtYXpvbmF3cy5jb20w DgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjA7 BgNVHR8ENDAyMDCgLqAshipodHRwOi8vY3JsLnNjYTFiLmFtYXpvbnRydXN0LmNv bS9zY2ExYi5jcmwwIAYDVR0gBBkwFzALBglghkgBhv1sAQIwCAYGZ4EMAQIBMHUG CCsGAQUFBwEBBGkwZzAtBggrBgEFBQcwAYYhaHR0cDovL29jc3Auc2NhMWIuYW1h em9udHJ1c3QuY29tMDYGCCsGAQUFBzAChipodHRwOi8vY3J0LnNjYTFiLmFtYXpv bnRydXN0LmNvbS9zY2ExYi5jcnQwDAYDVR0TAQH/BAIwADCCAQQGCisGAQQB1nkC BAIEgfUEgfIA8AB2APZclC/RdzAiFFQYCDCUVo7jTRMZM7/fDC8gC8xO8WTjAAAB dboejIcAAAQDAEcwRQIgeqoKXbST17TCEzM1BMWx/jjyVQVBIN3LG17U4OaV364C IQDPUSJZhJm7uqGea6+VwqeDe/vGuGSuJzkDwTIOeIXPaAB2AFzcQ5L+5qtFRLFe mtRW5hA3+9X6R9yhc5SyXub2xw7KAAABdboejNQAAAQDAEcwRQIgEKIAwwhjUcq2 iwzBAagdy+fTiKnBY1Yjf6wOeRpwXfMCIQC8wM3nxiWrGgIpdzzgDvFhZZTV3N81 JWcYAu+srIVOhTANBgkqhkiG9w0BAQsFAAOCAQEAer9kml53XFy4ZSVzCbdsIFYP Ohu7LDf5iffHBVZFnGOEVOmiPYYkNwi9R6EHIYaAs7G7GGLCp/6tdc+G4eF1j6wB IkmXZcxMTxk/87R+S+36yDLg1GBZvqttLfexj0TRVAfVLJc7FjLXAW2+wi7YyNe8 X17lWBwHxa1r5KgweJshGzYVUsgMTSx0aJ+93ZnqplBp9x+9DSQNqqNlBgxFANxs ux+dfpduyLd8VLqtlECGC07tYE4mBaAjMiNjCZRWMp8ya/Z6J/bJZ27IDGA4dXzm l9NNnlbuUDAenAByUqE+0b78J6EmmdAVf+N8siriMg02FdP3lAXJLE8tDeZp8AAA MYICIDCCAhwCAQEwWjBGMQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRUw EwYDVQQLEwxTZXJ2ZXIgQ0EgMUIxDzANBgNVBAMTBkFtYXpvbgIQBq4xTCuObdo3 DR7Y2NQ4xDANBglghkgBZQMEAgEFAKCBmDAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN AQcBMBwGCSqGSIb3DQEJBTEPFw0yMTA2MjQxOTU1MzFaMC0GCSqGSIb3DQEJNDEg MB4wDQYJYIZIAWUDBAIBBQChDQYJKoZIhvcNAQELBQAwLwYJKoZIhvcNAQkEMSIE IP7gMuT2H0/AhgPgj3Eo0NWCIdQOBjJO18coNKIaOnJYMA0GCSqGSIb3DQEBCwUA BIIBAJX+e87q0YvRon9/ENTvE0FoYMzYblID2Reek6L217ZlZ6pUuRsc4ghhJ5Yh WZeOCaLwi4mrnQ5/+DGKkJ4a/w5sqFTwtJIGIIAuDCn/uDm8kIDUVkbeznSOLoPA 67cxiqgIdqZ5pqUoid2YsDj20owrGDG4wUF6ZvhM9g/5va3CAhxqvTE2HwjhHTfz Cgl8Nlvalz7YxXEf2clFEiEVa1fVaGMl9pCyedAmTfd6hoivcpAsopvXfVaaaR2y iuZidpUfFhSk+Ls7TU/kB74ckfUGj5q/5HcKJgb/S+FYUV7eu0ewzTyW1uRl/d0U Tb7e7EjgDGJsjOTMdTrMfv8ho8kAAAAAAAA= -----END PKCS7----- ` golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/decrypt.go000066400000000000000000000121221470602565700236670ustar00rootroot00000000000000package 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{} } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/decrypt_test.go000066400000000000000000000051231470602565700247310ustar00rootroot00000000000000package 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) } } // echo -n "This is a test" > test.txt // openssl cms -encrypt -in test.txt cert.pem var EncryptedTestFixture = ` -----BEGIN PKCS7----- MIIBGgYJKoZIhvcNAQcDoIIBCzCCAQcCAQAxgcwwgckCAQAwMjApMRAwDgYDVQQK EwdBY21lIENvMRUwEwYDVQQDEwxFZGRhcmQgU3RhcmsCBQDL+CvWMA0GCSqGSIb3 DQEBAQUABIGAyFz7bfI2noUs4FpmYfztm1pVjGyB00p9x0H3gGHEYNXdqlq8VG8d iq36poWtEkatnwsOlURWZYECSi0g5IAL0U9sj82EN0xssZNaK0S5FTGnB3DPvYgt HJvcKq7YvNLKMh4oqd17C6GB4oXyEBDj0vZnL7SUoCAOAWELPeC8CTUwMwYJKoZI hvcNAQcBMBQGCCqGSIb3DQMHBAhEowTkot3a7oAQFD//J/IhFnk+JbkH7HZQFA== -----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-----` golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/encrypt.go000066400000000000000000000241511470602565700237060ustar00rootroot00000000000000package 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"` } 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 } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/encrypt_test.go000066400000000000000000000050431470602565700247440ustar00rootroot00000000000000package 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) } } } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/go.mod000066400000000000000000000000531470602565700227740ustar00rootroot00000000000000module github.com/digitorus/pkcs7 go 1.13 golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/pkcs7.go000066400000000000000000000235731470602565700232600ustar00rootroot00000000000000// Package pkcs7 implements parsing and generation of some PKCS#7 structures. package pkcs7 import ( "bytes" "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/ed25519" "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} OIDEncryptionAlgorithmEDDSA25519 = asn1.ObjectIdentifier{1, 3, 101, 112} // 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, x509.PureEd25519: return OIDDigestAlgorithmSHA512, nil } return nil, fmt.Errorf("pkcs7: cannot convert hash to oid, unknown hash algorithm") } // getOIDForEncryptionAlgorithm takes a private key or signer and // the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm func getOIDForEncryptionAlgorithm(keyOrSigner interface{}, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) { _, ok := keyOrSigner.(*dsa.PrivateKey) if ok { return OIDDigestAlgorithmDSA, nil } signer, ok := keyOrSigner.(crypto.Signer) if !ok { return nil, errors.New("pkcs7: key does not implement crypto.Signer") } switch signer.Public().(type) { case *rsa.PublicKey: switch { default: return OIDEncryptionAlgorithmRSA, nil case OIDDigestAlg.Equal(OIDEncryptionAlgorithmRSA): return OIDEncryptionAlgorithmRSA, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1): return OIDEncryptionAlgorithmRSASHA1, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256): return OIDEncryptionAlgorithmRSASHA256, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384): return OIDEncryptionAlgorithmRSASHA384, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512): return OIDEncryptionAlgorithmRSASHA512, nil } case *ecdsa.PublicKey: switch { case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1): return OIDDigestAlgorithmECDSASHA1, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256): return OIDDigestAlgorithmECDSASHA256, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384): return OIDDigestAlgorithmECDSASHA384, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512): return OIDDigestAlgorithmECDSASHA512, nil } case ed25519.PublicKey: return OIDEncryptionAlgorithmEDDSA25519, nil } return nil, fmt.Errorf("pkcs7: cannot convert encryption algorithm to oid, unknown key type %T", signer.Public()) } // 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 } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/pkcs7_test.go000066400000000000000000000475311470602565700243170ustar00rootroot00000000000000package pkcs7 import ( "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "math/big" "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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA1 } priv = &dsaPriv case x509.PureEd25519: _, priv, err = ed25519.GenerateKey(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 ed25519.PrivateKey: template.SignatureAlgorithm = x509.PureEd25519 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } } 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 } switch priv.(type) { case *rsa.PrivateKey: switch issuerKey := issuerKey.(type) { case *rsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey) case *ecdsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey) case ed25519.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey) case *dsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey) } case *ecdsa.PrivateKey: switch issuerKey := issuerKey.(type) { case *rsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey) case *ecdsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey) case ed25519.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey) case *dsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey) } case ed25519.PrivateKey: switch issuerKey := issuerKey.(type) { case *rsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(ed25519.PrivateKey).Public(), issuerKey) case *ecdsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(ed25519.PrivateKey).Public(), issuerKey) case ed25519.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(ed25519.PrivateKey).Public(), issuerKey) case *dsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(ed25519.PrivateKey).Public(), issuerKey) } 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 ed25519.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 } 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 } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/sign.go000066400000000000000000000351011470602565700231570ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/dsa" "crypto/ed25519" "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 SkipCertificates bool } 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. The signer can // either be a crypto.Signer or crypto.PrivateKey. func (sd *SignedData) AddSigner(ee *x509.Certificate, keyOrSigner interface{}, config SignerInfoConfig) error { var parents []*x509.Certificate return sd.AddSignerChain(ee, keyOrSigner, 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. The signer can be either a crypto.Signer or crypto.PrivateKey. func (sd *SignedData) AddSignerChain(ee *x509.Certificate, keyOrSigner interface{}, 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(keyOrSigner, 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, keyOrSigner, hash) if err != nil { return err } signerInfo := signerInfo{ AuthenticatedAttributes: finalAttrs, UnauthenticatedAttributes: finalUnsignedAttrs, DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid}, DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: encryptionOid}, IssuerAndSerialNumber: ias, EncryptedDigest: signature, Version: 1, } if !config.SkipCertificates { sd.certs = append(sd.certs, ee) if len(parents) > 0 { sd.certs = append(sd.certs, parents...) } } sd.sd.SignerInfos = append(sd.sd.SignerInfos, signerInfo) 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. The signer can be either a crypto.Signer or crypto.PrivateKey. func (sd *SignedData) SignWithoutAttr(ee *x509.Certificate, keyOrSigner interface{}, 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 := keyOrSigner.(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: signer, ok := keyOrSigner.(crypto.Signer) if !ok { return errors.New("pkcs7: private key does not implement crypto.Signer") } // special case for Ed25519, which hashes as part of the signing algorithm _, ok = signer.Public().(ed25519.PublicKey) if ok { signature, err = signer.Sign(rand.Reader, sd.data, crypto.Hash(0)) } else { signature, err = signer.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(keyOrSigner, sd.digestOid) } if err != nil { return err } signerInfo := 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, signerInfo) 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) } // SetContentType sets the content type of the SignedData. For example to specify the // content type of a time-stamp token according to RFC 3161 section 2.4.2. func (sd *SignedData) SetContentType(contentType asn1.ObjectIdentifier) { sd.sd.ContentInfo.ContentType = contentType } // 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, keyOrSigner interface{}, 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 := keyOrSigner.(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}) } signer, ok := keyOrSigner.(crypto.Signer) if !ok { return nil, errors.New("pkcs7: private key does not implement crypto.Signer") } // special case for Ed25519, which hashes as part of the signing algorithm _, ok = signer.Public().(ed25519.PublicKey) if ok { return signer.Sign(rand.Reader, attrBytes, crypto.Hash(0)) } return signer.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) } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/sign_test.go000066400000000000000000000312151470602565700242200ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/dsa" "crypto/x509" "encoding/asn1" "encoding/pem" "fmt" "io/ioutil" "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, x509.PureEd25519, } 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} { 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) } 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 TestSignWithoutAttributes(t *testing.T) { content := []byte("Hello World") sigalgs := []x509.SignatureAlgorithm{ x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA512WithRSA, x509.ECDSAWithSHA1, x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512, x509.PureEd25519, } 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 _, sigalgsigner := range sigalgs { signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", rootCert, sigalgsigner, false) if err != nil { t.Fatalf("test %s/%s: cannot generate signer cert: %s", sigalgroot, sigalgsigner, err) } for _, testDetach := range []bool{false, true} { toBeSigned, err := NewSignedData(content) if err != nil { t.Fatalf("test %s/%s: cannot initialize signed data: %s", sigalgroot, sigalgsigner, err) } // Set the digest to match the end entity cert signerDigest, _ := GetDigestOIDForSignatureAlgorithm(signerCert.Certificate.SignatureAlgorithm) toBeSigned.SetDigestAlgorithm(signerDigest) if err := toBeSigned.SignWithoutAttr(signerCert.Certificate, (*signerCert.PrivateKey).(crypto.Signer), SignerInfoConfig{}); err != nil { t.Fatalf("test %s/%s: cannot add signer: %s", sigalgroot, sigalgsigner, err) } if testDetach { toBeSigned.Detach() } signed, err := toBeSigned.Finish() if err != nil { t.Fatalf("test %s/%s: cannot finish signing data: %s", sigalgroot, sigalgsigner, err) } p7, err := Parse(signed) if err != nil { t.Fatalf("test %s/%s: cannot parse signed data: %s", sigalgroot, sigalgsigner, err) } if testDetach { p7.Content = content } if !bytes.Equal(content, p7.Content) { t.Errorf("test %s/%s: content was not found in the parsed data:\n\tExpected: %s\n\tActual: %s", sigalgroot, sigalgsigner, content, p7.Content) } if err := p7.VerifyWithChain(truststore); err != nil { t.Errorf("test %s/%s: cannot verify signed data: %s", sigalgroot, sigalgsigner, err) } if !signerDigest.Equal(p7.Signers[0].DigestAlgorithm.Algorithm) { t.Errorf("test %s/%s: expected digest algorithm %q but got %q", sigalgroot, sigalgsigner, signerDigest, p7.Signers[0].DigestAlgorithm.Algorithm) } } } } } 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 _, err = signedData.Finish() if err != nil { fmt.Printf("Cannot finish signing data: %s", err) } } func TestSetContentType(t *testing.T) { cert, err := createTestCertificate(x509.SHA256WithRSA) if err != nil { t.Fatalf("Cannot create test certificates: %s", err) } signedData, err := NewSignedData([]byte("Example data to be signed")) if err != nil { t.Fatalf("Cannot initialize signed data: %s", err) } idctTSTInfo := asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 16, 1, 4} signedData.SetContentType(idctTSTInfo) if err := signedData.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{}); err != nil { t.Fatalf("Cannot add signer: %s", err) } _, err = signedData.Finish() if err != nil { t.Fatalf("Cannot finish signing data: %s", err) } sd := signedData.GetSignedData() if !sd.ContentInfo.ContentType.Equal(idctTSTInfo) { t.Fatalf("Unexpected content type: %s", err) } } 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) } func TestSkipCertificates(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) } if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{ SkipCertificates: true, }); 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) } if len(p7.Certificates) > 0 { t.Fatalf("Got %d certificate(s), exected none", len(p7.Certificates)) } } // 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 } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/verify.go000066400000000000000000000301311470602565700235210ustar00rootroot00000000000000package pkcs7 import ( "crypto/subtle" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "time" ) // Verify is a wrapper around VerifyWithChain() that initializes an empty // trust store, effectively disabling certificate verification when validating // a signature. func (p7 *PKCS7) Verify() (err error) { return p7.VerifyWithChain(nil) } // VerifyWithChain checks the signatures of a PKCS7 object. // // If truststore is not nil, it also verifies the chain of trust of // the end-entity signer cert to one of the roots in the // truststore. When the PKCS7 object includes the signing time // authenticated attr it verifies the chain at that time and UTC now // otherwise. func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error) { intermediates := x509.NewCertPool() for _, cert := range(p7.Certificates) { intermediates.AddCert(cert) } opts := x509.VerifyOptions{ Roots: truststore, Intermediates: intermediates, } return p7.VerifyWithOpts(opts) } // VerifyWithChainAtTime checks the signatures of a PKCS7 object. // // If truststore is not nil, it also verifies the chain of trust of // the end-entity signer cert to a root in the truststore at // currentTime. It does not use the signing time authenticated // attribute. func (p7 *PKCS7) VerifyWithChainAtTime(truststore *x509.CertPool, currentTime time.Time) (err error) { intermediates := x509.NewCertPool() for _, cert := range(p7.Certificates) { intermediates.AddCert(cert) } opts := x509.VerifyOptions{ Roots: truststore, Intermediates: intermediates, CurrentTime: currentTime, } return p7.VerifyWithOpts(opts) } // VerifyWithOpts checks the signatures of a PKCS7 object. // // It accepts x509.VerifyOptions as a parameter. // This struct contains a root certificate pool, an intermedate certificate pool, // an optional list of EKUs, and an optional time that certificates should be // checked as being valid during. // If VerifyOpts.Roots is not nil it verifies the chain of trust of // the end-entity signer cert to one of the roots in the // truststore. When the PKCS7 object includes the signing time // authenticated attr it verifies the chain at that time and UTC now // otherwise. func (p7 *PKCS7) VerifyWithOpts(opts x509.VerifyOptions) (err error) { // if KeyUsage isn't set, default to ExtKeyUsageAny if opts.KeyUsages == nil { opts.KeyUsages = []x509.ExtKeyUsage{x509.ExtKeyUsageAny} } if len(p7.Signers) == 0 { return errors.New("pkcs7: Message has no signers") } // if opts.CurrentTime is not set, call verifySignature, // which will verify the leaf certificate with the current time if opts.CurrentTime.IsZero() { for _, signer := range p7.Signers { if err := verifySignature(p7, signer, opts); err != nil { return err } } return nil } // if opts.CurrentTime is set, call verifySignatureAtTime, // which will verify the leaf certificate with opts.CurrentTime for _, signer := range p7.Signers { if err := verifySignatureAtTime(p7, signer, opts); err != nil { return err } } return nil } func verifySignatureAtTime(p7 *PKCS7, signer signerInfo, opts x509.VerifyOptions) (err error) { signedData := p7.Content ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) if ee == nil { return errors.New("pkcs7: No certificate for signer") } if len(signer.AuthenticatedAttributes) > 0 { // TODO(fullsailor): First check the content type match var ( digest []byte signingTime time.Time ) err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest) if err != nil { return err } hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm) if err != nil { return err } h := hash.New() h.Write(p7.Content) computed := h.Sum(nil) if subtle.ConstantTimeCompare(digest, computed) != 1 { return &MessageDigestMismatchError{ ExpectedDigest: digest, ActualDigest: computed, } } signedData, err = marshalAttributes(signer.AuthenticatedAttributes) if err != nil { return err } err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime) if err == nil { // signing time found, performing validity check if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { return fmt.Errorf("pkcs7: signing time %q is outside of certificate validity %q to %q", signingTime.Format(time.RFC3339), ee.NotBefore.Format(time.RFC3339), ee.NotAfter.Format(time.RFC3339)) } } } if opts.Roots != nil { _, err = ee.Verify(opts) if err != nil { return fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err) } } sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm) if err != nil { return err } return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest) } func verifySignature(p7 *PKCS7, signer signerInfo, opts x509.VerifyOptions) (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.NotAfter.Format(time.RFC3339)) } } } if opts.Roots != nil { opts.CurrentTime = signingTime _, err = ee.Verify(opts) if err != nil { return fmt.Errorf("pkcs7: failed to verify certificate chain: %v", 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 } // 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()) } case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmEDDSA25519): return x509.PureEd25519, nil 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") } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/verify_test.go000066400000000000000000000732401470602565700245700ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "encoding/base64" "encoding/pem" "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 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) // verifies at the signingTime authenticated attr if err := p7.VerifyWithChain(certPool); err != nil { t.Errorf("Verify failed with error: %v", err) } // The chain has validity: // // EE: 2016-08-17 20:04:58 +0000 UTC 2021-08-16 20:04:58 +0000 UTC // Intermediate: 2015-03-17 23:52:42 +0000 UTC 2025-03-14 23:52:42 +0000 UTC // Root: 2015-03-17 22:53:57 +0000 UTC 2025-03-14 22:53:57 +0000 UTC validTime := time.Date(2021, 8, 16, 20, 0, 0, 0, time.UTC) if err = p7.VerifyWithChainAtTime(certPool, validTime); err != nil { t.Errorf("Verify at UTC now failed with error: %v", err) } expiredTime := time.Date(2030, time.January, 1, 0, 0, 0, 0, time.UTC) if err = p7.VerifyWithChainAtTime(certPool, expiredTime); err == nil { t.Errorf("Verify at expired time %s did not error", expiredTime) } notYetValidTime := time.Date(1999, time.July, 5, 0, 13, 0, 0, time.UTC) if err = p7.VerifyWithChainAtTime(certPool, notYetValidTime); err == nil { t.Errorf("Verify at not yet valid time %s did not error", notYetValidTime) } // 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") } opts := x509.VerifyOptions{ Roots: certPool, CurrentTime: mustParseTime("2017-02-23T09:06:16-05:00"), KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, } intermediates := x509.NewCertPool() for _, cert := range(p7.Certificates) { intermediates.AddCert(cert) } opts.Intermediates = intermediates chains, err := ee.Verify(opts) 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) } } func mustParseTime(s string) time.Time { t, err := time.Parse(time.RFC3339, s) if err != nil { panic(err) } return t } 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") } opts := x509.VerifyOptions{ Roots: truststore, CurrentTime: time.Now(), KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, } intermediates := x509.NewCertPool() for _, cert := range(p7.Certificates) { intermediates.AddCert(cert) } opts.Intermediates = intermediates chains, err := ee.Verify(opts) 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 } golang-github-digitorus-pkcs7-0.0~git20230818.3a137a8/verify_test_dsa.go000066400000000000000000000155631470602565700254230ustar00rootroot00000000000000// +build go1.11 go1.12 go1.13 go1.14 go1.15 package pkcs7 import ( "crypto/x509" "encoding/pem" "fmt" "io/ioutil" "os" "os/exec" "testing" ) func TestVerifyEC2(t *testing.T) { fixture := UnmarshalDSATestFixture(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 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-----`) type DSATestFixture struct { Input []byte Certificate *x509.Certificate } func UnmarshalDSATestFixture(testPEMBlock string) DSATestFixture { var result DSATestFixture 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) } } return result }