pax_global_header00006660000000000000000000000064147536264120014524gustar00rootroot0000000000000052 comment=84613357c7f2c2e116a62f93034417fd40ef9265 pkcs7-0.2.1/000077500000000000000000000000001475362641200125535ustar00rootroot00000000000000pkcs7-0.2.1/.github/000077500000000000000000000000001475362641200141135ustar00rootroot00000000000000pkcs7-0.2.1/.github/PULL_REQUEST_TEMPLATE000066400000000000000000000010771475362641200173220ustar00rootroot00000000000000 #### Name of feature: #### Pain or issue this feature alleviates: #### Why is this important to the project (if not answered above): #### Is there documentation on how to use this feature? If so, where? #### In what environments or workflows is this feature supported? #### In what environments or workflows is this feature explicitly NOT supported (if any)? #### Supporting links/other PRs/issues: 💔Thank you! pkcs7-0.2.1/.github/dependabot.yml000066400000000000000000000007701475362641200167470ustar00rootroot00000000000000# 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" # See documentation for possible values directory: "/" # Location of package manifests schedule: interval: "weekly" pkcs7-0.2.1/.github/workflows/000077500000000000000000000000001475362641200161505ustar00rootroot00000000000000pkcs7-0.2.1/.github/workflows/ci.yml000066400000000000000000000010361475362641200172660ustar00rootroot00000000000000name: CI on: [push, pull_request] jobs: test: name: Test strategy: matrix: go: ['1.14', '1.15', '1.16', '1.21', '1.22', '1.23'] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-go@v4 with: go-version: ${{ matrix.go }} - name: Test run: go vet . && go build . && go test -count=1 -covermode=count -coverprofile=coverage.out . env: GODEBUG: x509sha1=1 # enable SHA1; it's used in the older fixtures pkcs7-0.2.1/.github/workflows/code-scan-cron.yml000066400000000000000000000002271475362641200214670ustar00rootroot00000000000000name: Code Scan Cron on: schedule: - cron: '0 0 * * SUN' jobs: code-scan: uses: smallstep/workflows/.github/workflows/code-scan.yml@main pkcs7-0.2.1/.github/workflows/dependabot-auto-merge.yml000066400000000000000000000011301475362641200230360ustar00rootroot00000000000000name: Dependabot auto-merge on: pull_request permissions: contents: write pull-requests: write jobs: dependabot: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} steps: - name: Dependabot metadata id: metadata uses: dependabot/fetch-metadata@v1.1.1 with: github-token: "${{ secrets.GITHUB_TOKEN }}" - name: Enable auto-merge for Dependabot PRs run: gh pr merge --auto --merge "$PR_URL" env: PR_URL: ${{github.event.pull_request.html_url}} GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} pkcs7-0.2.1/.gitignore000066400000000000000000000004541475362641200145460ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof # Development .envrc coverage.outpkcs7-0.2.1/LICENSE000066400000000000000000000020701475362641200135570ustar00rootroot00000000000000The 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. pkcs7-0.2.1/Makefile000066400000000000000000000004351475362641200142150ustar00rootroot00000000000000all: vet staticcheck test test: go test -covermode=count -coverprofile=coverage.out . showcoverage: test go tool cover -html=coverage.out vet: go vet . lint: golint . staticcheck: staticcheck . gettools: go get -u honnef.co/go/tools/... go get -u golang.org/x/lint/golint pkcs7-0.2.1/README.md000066400000000000000000000035251475362641200140370ustar00rootroot00000000000000# pkcs7 [![Go Reference](https://pkg.go.dev/badge/github.com/smallstep/pkcs7.svg)](https://pkg.go.dev/github.com/smallstep/pkcs7) [![Build Status](https://github.com/smallstep/pkcs7/workflows/CI/badge.svg?query=branch%3Amain+event%3Apush)](https://github.com/smallstep/pkcs7/actions/workflows/ci.yml?query=branch%3Amain+event%3Apush) pkcs7 implements parsing and creating signed and enveloped messages. ```go package main import ( "bytes" "crypto/rsa" "crypto/x509" "encoding/pem" "fmt" "os" "github.com/smallstep/pkcs7" ) func SignAndDetach(content []byte, cert *x509.Certificate, privkey *rsa.PrivateKey) (signed []byte, err error) { toBeSigned, err := NewSignedData(content) if err != nil { return fmt.Errorf("Cannot initialize signed data: %w", err) } if err = toBeSigned.AddSigner(cert, privkey, SignerInfoConfig{}); err != nil { return fmt.Errorf("Cannot add signer: %w", err) } // Detach signature, omit if you want an embedded signature toBeSigned.Detach() signed, err = toBeSigned.Finish() if err != nil { return fmt.Errorf("Cannot finish signing data: %w", err) } // Verify the signature pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed}) p7, err := pkcs7.Parse(signed) if err != nil { return fmt.Errorf("Cannot parse our signed data: %w", err) } // since the signature was detached, reattach the content here p7.Content = content if bytes.Compare(content, p7.Content) != 0 { return fmt.Errorf("Our content was not in the parsed data:\n\tExpected: %s\n\tActual: %s", content, p7.Content) } if err = p7.Verify(); err != nil { return fmt.Errorf("Cannot verify our signed data: %w", err) } return signed, nil } ``` ## Credits This is a fork of [mozilla-services/pkcs7](https://github.com/mozilla-services/pkcs7) which, itself, was a fork of [fullsailor/pkcs7](https://github.com/fullsailor/pkcs7). pkcs7-0.2.1/ber.go000066400000000000000000000145401475362641200136560ustar00rootroot00000000000000package pkcs7 import ( "bytes" "errors" ) type asn1Object interface { EncodeTo(writer *bytes.Buffer) error } type asn1Structured struct { tagBytes []byte content []asn1Object } func (s asn1Structured) EncodeTo(out *bytes.Buffer) error { inner := new(bytes.Buffer) for _, obj := range s.content { err := obj.EncodeTo(inner) if err != nil { return err } } out.Write(s.tagBytes) encodeLength(out, inner.Len()) out.Write(inner.Bytes()) return nil } type asn1Primitive struct { tagBytes []byte length int content []byte } func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error { _, err := out.Write(p.tagBytes) if err != nil { return err } if err = encodeLength(out, p.length); err != nil { return err } // fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length) // fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content)) out.Write(p.content) return nil } func ber2der(ber []byte) ([]byte, error) { if len(ber) == 0 { return nil, errors.New("ber2der: input ber is empty") } // fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber)) out := new(bytes.Buffer) obj, _, err := readObject(ber, 0) if err != nil { return nil, err } obj.EncodeTo(out) // if offset < len(ber) { // return nil, fmt.Errorf("ber2der: Content longer than expected. Got %d, expected %d", offset, len(ber)) // } return out.Bytes(), nil } // encodes lengths that are longer than 127 into string of bytes func marshalLongLength(out *bytes.Buffer, i int) (err error) { n := lengthLength(i) for ; n > 0; n-- { err = out.WriteByte(byte(i >> uint((n-1)*8))) if err != nil { return } } return nil } // computes the byte length of an encoded length value func lengthLength(i int) (numBytes int) { numBytes = 1 for i > 255 { numBytes++ i >>= 8 } return } // encodes the length in DER format // If the length fits in 7 bits, the value is encoded directly. // // Otherwise, the number of bytes to encode the length is first determined. // This number is likely to be 4 or less for a 32bit length. This number is // added to 0x80. The length is encoded in big endian encoding follow after // // Examples: // length | byte 1 | bytes n // 0 | 0x00 | - // 120 | 0x78 | - // 200 | 0x81 | 0xC8 // 500 | 0x82 | 0x01 0xF4 // func encodeLength(out *bytes.Buffer, length int) (err error) { if length >= 128 { l := lengthLength(length) err = out.WriteByte(0x80 | byte(l)) if err != nil { return } err = marshalLongLength(out, length) if err != nil { return } } else { err = out.WriteByte(byte(length)) if err != nil { return } } return } func readObject(ber []byte, offset int) (asn1Object, int, error) { berLen := len(ber) if offset >= berLen { return nil, 0, errors.New("ber2der: offset is after end of ber data") } tagStart := offset b := ber[offset] offset++ if offset >= berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } tag := b & 0x1F // last 5 bits if tag == 0x1F { tag = 0 for ber[offset] >= 0x80 { tag = tag*128 + ber[offset] - 0x80 offset++ if offset > berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } } // jvehent 20170227: this doesn't appear to be used anywhere... // tag = tag*128 + ber[offset] - 0x80 offset++ if offset > berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } } tagEnd := offset kind := b & 0x20 if kind == 0 { debugprint("--> Primitive\n") } else { debugprint("--> Constructed\n") } // read length var length int l := ber[offset] offset++ if offset > berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } indefinite := false if l > 0x80 { numberOfBytes := (int)(l & 0x7F) if numberOfBytes > 4 { // int is only guaranteed to be 32bit return nil, 0, errors.New("ber2der: BER tag length too long") } if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F { return nil, 0, errors.New("ber2der: BER tag length is negative") } if (int)(ber[offset]) == 0x0 { return nil, 0, errors.New("ber2der: BER tag length has leading zero") } debugprint("--> (compute length) indicator byte: %x\n", l) debugprint("--> (compute length) length bytes: % X\n", ber[offset:offset+numberOfBytes]) for i := 0; i < numberOfBytes; i++ { length = length*256 + (int)(ber[offset]) offset++ if offset > berLen { return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached") } } } else if l == 0x80 { indefinite = true } else { length = (int)(l) } if length < 0 { return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length") } // fmt.Printf("--> length : %d\n", length) contentEnd := offset + length if contentEnd > len(ber) { return nil, 0, errors.New("ber2der: BER tag length is more than available data") } debugprint("--> content start : %d\n", offset) debugprint("--> content end : %d\n", contentEnd) debugprint("--> content : % X\n", ber[offset:contentEnd]) var obj asn1Object if indefinite && kind == 0 { return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding") } if kind == 0 { obj = asn1Primitive{ tagBytes: ber[tagStart:tagEnd], length: length, content: ber[offset:contentEnd], } } else { var subObjects []asn1Object for (offset < contentEnd) || indefinite { var subObj asn1Object var err error subObj, offset, err = readObject(ber, offset) if err != nil { return nil, 0, err } subObjects = append(subObjects, subObj) if indefinite { terminated, err := isIndefiniteTermination(ber, offset) if err != nil { return nil, 0, err } if terminated { break } } } obj = asn1Structured{ tagBytes: ber[tagStart:tagEnd], content: subObjects, } } // Apply indefinite form length with 0x0000 terminator. if indefinite { contentEnd = offset + 2 } return obj, contentEnd, nil } func isIndefiniteTermination(ber []byte, offset int) (bool, error) { if len(ber)-offset < 2 { return false, errors.New("ber2der: Invalid BER format") } return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil } func debugprint(format string, a ...interface{}) { // fmt.Printf(format, a) } pkcs7-0.2.1/ber_test.go000066400000000000000000000162551475362641200147220ustar00rootroot00000000000000package 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{0x30, 0x85}, "tag length too long"}, {[]byte{0x30, 0x84, 0x80, 0x0, 0x0, 0x0}, "length is negative"}, {[]byte{0x30, 0x82, 0x0, 0x1}, "length has leading zero"}, {[]byte{0x30, 0x80, 0x1, 0x2, 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----- ` pkcs7-0.2.1/decrypt.go000066400000000000000000000171421475362641200145610ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/aes" "crypto/cipher" "crypto/des" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" ) // ErrUnsupportedAlgorithm tells you when our quick dev assumptions have failed var ErrUnsupportedAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA, DES, DES-EDE3, AES-256-CBC and AES-128-GCM supported") // ErrUnsupportedAsymmetricEncryptionAlgorithm is returned when attempting to use an unknown asymmetric encryption algorithm var ErrUnsupportedAsymmetricEncryptionAlgorithm = errors.New("pkcs7: cannot decrypt data: only RSA PKCS#1 v1.5 and RSA OAEP are supported") // ErrUnsupportedKeyType is returned when attempting to encrypting keys using a key that's not an RSA key var ErrUnsupportedKeyType = errors.New("pkcs7: only RSA keys are supported") // ErrNotEncryptedContent is returned when attempting to Decrypt data that is not encrypted data var ErrNotEncryptedContent = errors.New("pkcs7: content data is a decryptable data type") // Decrypt decrypts encrypted content info for recipient cert and private key func (p7 *PKCS7) Decrypt(cert *x509.Certificate, pkey crypto.PrivateKey) ([]byte, error) { data, ok := p7.raw.(envelopedData) if !ok { return nil, ErrNotEncryptedContent } recipient := selectRecipientForCertificate(data.RecipientInfos, cert) if recipient.EncryptedKey == nil { return nil, errors.New("pkcs7: no enveloped recipient for provided certificate") } switch pkey := pkey.(type) { case crypto.Decrypter: var opts crypto.DecrypterOpts switch algorithm := recipient.KeyEncryptionAlgorithm.Algorithm; { case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP): hashFunc, err := getHashFuncForKeyEncryptionAlgorithm(recipient.KeyEncryptionAlgorithm) if err != nil { return nil, err } opts = &rsa.OAEPOptions{Hash: hashFunc} case algorithm.Equal(OIDEncryptionAlgorithmRSA): opts = &rsa.PKCS1v15DecryptOptions{} default: return nil, ErrUnsupportedAsymmetricEncryptionAlgorithm } contentKey, err := pkey.Decrypt(rand.Reader, recipient.EncryptedKey, opts) if err != nil { return nil, err } return data.EncryptedContentInfo.decrypt(contentKey) } return nil, ErrUnsupportedAlgorithm } // RFC 4055, 4.1 // The current ASN.1 parser does not support non-integer defaults so the 'default:' tags here do nothing. type rsaOAEPAlgorithmParameters struct { HashFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:0,default:sha1Identifier"` MaskGenFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:1,default:mgf1SHA1Identifier"` PSourceFunc pkix.AlgorithmIdentifier `asn1:"optional,explicit,tag:2,default:pSpecifiedEmptyIdentifier"` } func getHashFuncForKeyEncryptionAlgorithm(keyEncryptionAlgorithm pkix.AlgorithmIdentifier) (crypto.Hash, error) { invalidHashFunc := crypto.Hash(0) params := &rsaOAEPAlgorithmParameters{ HashFunc: pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA1}, // set default hash algorithm to SHA1 } var rest []byte rest, err := asn1.Unmarshal(keyEncryptionAlgorithm.Parameters.FullBytes, params) if err != nil { return invalidHashFunc, fmt.Errorf("pkcs7: failed unmarshaling key encryption algorithm parameters: %v", err) } if len(rest) != 0 { return invalidHashFunc, errors.New("pkcs7: trailing data after RSA OAEP parameters") } switch { case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA1): return crypto.SHA1, nil case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA224): return crypto.SHA224, nil case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA256): return crypto.SHA256, nil case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA384): return crypto.SHA384, nil case params.HashFunc.Algorithm.Equal(OIDDigestAlgorithmSHA512): return crypto.SHA512, nil default: return invalidHashFunc, errors.New("pkcs7: unsupported hash function for RSA OAEP") } } // DecryptUsingPSK decrypts encrypted data using caller provided // pre-shared secret func (p7 *PKCS7) DecryptUsingPSK(key []byte) ([]byte, error) { data, ok := p7.raw.(encryptedData) if !ok { return nil, ErrNotEncryptedContent } return data.EncryptedContentInfo.decrypt(key) } func (eci encryptedContentInfo) decrypt(key []byte) ([]byte, error) { alg := eci.ContentEncryptionAlgorithm.Algorithm if !alg.Equal(OIDEncryptionAlgorithmDESCBC) && !alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC) && !alg.Equal(OIDEncryptionAlgorithmAES256CBC) && !alg.Equal(OIDEncryptionAlgorithmAES128CBC) && !alg.Equal(OIDEncryptionAlgorithmAES128GCM) && !alg.Equal(OIDEncryptionAlgorithmAES256GCM) { return nil, ErrUnsupportedAlgorithm } // EncryptedContent can either be constructed of multple OCTET STRINGs // or _be_ a tagged OCTET STRING var cyphertext []byte if eci.EncryptedContent.IsCompound { // Complex case to concat all of the children OCTET STRINGs var buf bytes.Buffer cypherbytes := eci.EncryptedContent.Bytes for { var part []byte cypherbytes, _ = asn1.Unmarshal(cypherbytes, &part) buf.Write(part) if cypherbytes == nil { break } } cyphertext = buf.Bytes() } else { // Simple case, the bytes _are_ the cyphertext cyphertext = eci.EncryptedContent.Bytes } var block cipher.Block var err error switch { case alg.Equal(OIDEncryptionAlgorithmDESCBC): block, err = des.NewCipher(key) case alg.Equal(OIDEncryptionAlgorithmDESEDE3CBC): block, err = des.NewTripleDESCipher(key) case alg.Equal(OIDEncryptionAlgorithmAES256CBC), alg.Equal(OIDEncryptionAlgorithmAES256GCM): fallthrough case alg.Equal(OIDEncryptionAlgorithmAES128GCM), alg.Equal(OIDEncryptionAlgorithmAES128CBC): block, err = aes.NewCipher(key) } if err != nil { return nil, err } if alg.Equal(OIDEncryptionAlgorithmAES128GCM) || alg.Equal(OIDEncryptionAlgorithmAES256GCM) { params := aesGCMParameters{} paramBytes := eci.ContentEncryptionAlgorithm.Parameters.Bytes _, err := asn1.Unmarshal(paramBytes, ¶ms) if err != nil { return nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, err } if len(params.Nonce) != gcm.NonceSize() { return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect") } if params.ICVLen != gcm.Overhead() { return nil, errors.New("pkcs7: encryption algorithm parameters are incorrect") } plaintext, err := gcm.Open(nil, params.Nonce, cyphertext, nil) if err != nil { return nil, err } return plaintext, nil } iv := eci.ContentEncryptionAlgorithm.Parameters.Bytes if len(iv) != block.BlockSize() { return nil, errors.New("pkcs7: encryption algorithm parameters are malformed") } mode := cipher.NewCBCDecrypter(block, iv) plaintext := make([]byte, len(cyphertext)) mode.CryptBlocks(plaintext, cyphertext) if plaintext, err = unpad(plaintext, mode.BlockSize()); err != nil { return nil, err } return plaintext, nil } func unpad(data []byte, blocklen int) ([]byte, error) { if blocklen < 1 { return nil, fmt.Errorf("pkcs7: invalid blocklen %d", blocklen) } if len(data)%blocklen != 0 || len(data) == 0 { return nil, fmt.Errorf("pkcs7: invalid data len %d", len(data)) } // the last byte is the length of padding padlen := int(data[len(data)-1]) // check padding integrity, all bytes should be the same pad := data[len(data)-padlen:] for _, padbyte := range pad { if padbyte != byte(padlen) { return nil, errors.New("pkcs7: invalid padding") } } return data[:len(data)-padlen], nil } func selectRecipientForCertificate(recipients []recipientInfo, cert *x509.Certificate) recipientInfo { for _, recp := range recipients { if isCertMatchForIssuerAndSerial(cert, recp.IssuerAndSerialNumber) { return recp } } return recipientInfo{} } pkcs7-0.2.1/decrypt_test.go000066400000000000000000000352501475362641200156200ustar00rootroot00000000000000package pkcs7 import ( "bytes" "testing" ) func TestDecrypt(t *testing.T) { tests := []struct { name string fixture string expected string }{ { name: "rsa-pkcs-#1-v1.5/1", fixture: EncryptedTestFixture, expected: "This is a test", }, { name: "rsa-pkcs-#1-v1.5/2", fixture: RSAPKCS1v15EncryptedTestFixture, expected: "This is a test", }, { name: "rsa-oaep-sha1", fixture: RSAOAEPSHA1EncryptedTestFixture, expected: "This is a test", }, { name: "rsa-oaep-sha256", fixture: RSAOAEPSHA256EncryptedTestFixture, expected: "This is a test", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fixture := UnmarshalTestFixture(tt.fixture) 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) } if !bytes.Equal(content, []byte(tt.expected)) { t.Errorf("decrypted result does not match.\n\tExpected:%s\n\tActual:%s", []byte(tt.expected), content) } }) } } // TODO: use `embed` (after upping Go to at least 1.16), so that // it's easier to work with the files used to generate the below // test fixtures. // 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 RSA 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 RSA PRIVATE KEY-----` // - Generate new private key using openssl genrsa -out key.pem 2048 // - Create a self-signed certificate for key.pem using // openssl req -x509 -key key.pem -out certificate.pem // - Create a file with the data to be encrypted using // echo -n "This is a test" > test.txt // - Generate PKCS #7 enveloped data encrypted using AES using // openssl smime -encrypt -in test.txt -aes256 -outform pem certificate.pem var RSAPKCS1v15EncryptedTestFixture = ` -----BEGIN PKCS7----- MIIBwgYJKoZIhvcNAQcDoIIBszCCAa8CAQAxggFqMIIBZgIBADBOMDYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlUZXN0IENlcnQC FCoCAvxWlBvVDwodj5frshHwg0GSMA0GCSqGSIb3DQEBAQUABIIBABvjuG8mbhW6 SQkYvyfs3S8BQxQJwl1I/wLckEB8YClEItw4ZCsDXVodJpAtQ+fiQPRpQLMksD22 IXVxdRrAV2/Nzl1g8vLa1ae3zh9pQsEOf0pTzVIChB3WgQegOkpu88i6Vp/TNzUp fYezUTVRgHC7cJMOciYMLVxgKRdjLVZeyaqKY6zU1OgKy0/JQpfRk6rlTyMltMDY 2mjywc/lP9GCNfMxpSpj/CpN+2YKYxKOdht3dpO5e13WWzhYmz7oUeLRN4AC9M4N Cfa8qYh3ipJauxCT4qeBIIDidHSA9iP8h3Ro3d+7q9Imf1UjJvuDmc8A8UlFdTRE r4tg/TnnVeAwPAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQ1Az0LE0/4y9NjXZ7 JSh3X4AQD6BD9BghuxT99dPWWkyRlw== -----END PKCS7----- -----BEGIN CERTIFICATE----- MIIDTTCCAjWgAwIBAgIUKgIC/FaUG9UPCh2Pl+uyEfCDQZIwDQYJKoZIhvcNAQEL BQAwNjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAoM CVRlc3QgQ2VydDAeFw0yMTAyMTAxNjIwMDBaFw0yMTAzMTIxNjIwMDBaMDYxCzAJ BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlUZXN0IENl cnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS+Nd7wSgX6j6xLCZd SdwAq8BWlbruuFEf6VYvZ5FBzIOeTwFketD1tJie8tq9sEv8V8sFYlZruM4mA12G jxSse5rwVTf6TomQChEuvW+l6dB4N7EQ6EtZ1bmBKUk0jhqmrHTgT8YbyBKZ/2t+ UqkcvmHIPBMUEHwEOqGjj+RsRb69qYZYWTbtUjBbEt2PBk2noVtd7yyqvtPUl/p0 LAhL9oAsZTgL4LiZaOo9NGV6AkJWYQJuONOXSkx34Sn6V7xLPLhD/FDv8q3X9WuP dc00rlLDWpa2zn8dI3MNK+Q8KTi643f3MpfOiE0xuj13Hwp2QkfsgLdoER3OTFEK UmedAgMBAAGjUzBRMB0GA1UdDgQWBBRaaQq4a4U1xwlriTHnfBq8X5ctvDAfBgNV HSMEGDAWgBRaaQq4a4U1xwlriTHnfBq8X5ctvDAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBCwUAA4IBAQDFURgxrMBCmMVZFR9+jlCAK9T/tH3tX4d2iIVaj1Aj dw0wDAO20QPM/ZHlPM+l8yMT8ACY5ZHp6neRcaz9qmNeYAeGVu5twIo30LfRWDoY rfL3gIHeUXQCdxwJMh3z14WNdxPBoPXerw9LT1J97Dg81e/b+Za/vdRfqNIKbADj yoP7LBNaX/r83/SsGGbtW618sar+27wWRlGeZvFq8hwh+qyj3S7wtY7wx5weR7eZ S9K/MB9npTbIjDUidByTIhpk0hS55s1jF6U0wlmV0oUmC4wBIebyo1cL/CMPRv+a z/D9/ZvUoaotiATRWSKLCmxapcmGbMxhHHYWYWtzPCt1 -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA0vjXe8EoF+o+sSwmXUncAKvAVpW67rhRH+lWL2eRQcyDnk8B ZHrQ9bSYnvLavbBL/FfLBWJWa7jOJgNdho8UrHua8FU3+k6JkAoRLr1vpenQeDex EOhLWdW5gSlJNI4apqx04E/GG8gSmf9rflKpHL5hyDwTFBB8BDqho4/kbEW+vamG WFk27VIwWxLdjwZNp6FbXe8sqr7T1Jf6dCwIS/aALGU4C+C4mWjqPTRlegJCVmEC bjjTl0pMd+Ep+le8Szy4Q/xQ7/Kt1/Vrj3XNNK5Sw1qWts5/HSNzDSvkPCk4uuN3 9zKXzohNMbo9dx8KdkJH7IC3aBEdzkxRClJnnQIDAQABAoIBAF8IKoCbbIUBRkYm ng1tpMVEmHooLjE0I47dW64019Cs4Cjia70oOZJETG9k87V4gXHk1hXRyx3w/CNR ZsKjFuvvLcbOjE2bLQoODtlgCbfRz88nPwJfsPmBdXNB9rDOxiCIFImqRZHkGMT3 siMP9w90jrVUoj9qgYKiKodz3LAMFLnc6QkuAPRdEEI14bxRCcc3w2nKcCbj8Yye qKDbWVqp36kWBYcWgD2vzRcBOjJ3mRvTwflEg8HXbU88ANlGf7QQ1YhB9ueAE9Eg E18BMoa8cjon+xH2OvH+PlOZkbCLojoFtlUSh99eApp51+DCTKwQfqeg5ufdwm5G vyci9X0CgYEA+tFy8dqGOlmHDRUg3lW68dA1zkm15WAZoj7NvCGvTQyfoeH3Syoo CNKJqJkGHVWksCbTnORGVLDsz+l5a2BJY3L0xiDxpciIomZO18/IGJ4K5X4tm10i 330jUMO/22BXgNzBLU8gIyQLIu45NgOugtfwFKrCvYER4m0/peXWtB8CgYEA11Sm mC9V3mwceUuHWgqxsZpxrTQEDTAOhrGiIl5ZtoD7moMpu9MOo3qGd8W4dNbQwONq RxDigTQWv9oxqqDTYQjoZRSo1zYYgn9K17V5v4P1pzFMVBJnK1ElciWObt9l2g4O B/+SWQncwShHhfwJPrYmVQGgb3fETfZiiGvyTMMCgYEAxf4MtKqCBxGhMEybc6dN OZHYx40cT4M6+P6GvZoBndr3MH0GD4mprL01+adCUmnG5V7g8RqqAjTf24g8Vuzd Qen/G1/qIapZYYlNd8MH+5bWly6xpdExtCY+eITtsKkuqgSZYcDyZ4sOV3aiJudl HNiFJmtd6uY2Tf1bnwP+JpUCgYA4aup3Rze1Xhgbw6lD8zdZdEDCg7VoCyZTLilv 3c6dna/ObP07Q/I67PhcW0aX/kyVrUAEPK1L8uze+Xk33oljjCTvjvkp4feMAXQH jnnGrvlnA+iewm+bjthDzwlBjXCvMC2G9PRQNeBMD5Sly0JU1v62GQYDDps1Xg+0 9Kt4ZwKBgF8995suzG285txhAnlbKJpXB67f20s0DpBb4QdB+1PuizuyWWxPYAcu J1h1Q5Z6frEwd4ye/bcpReEScPXOKEB+1b3TWGCWNC2jhfChtZSH1Y3Z3mL0SfwT n9txBjxLOx1G83OQYY3J6Bnwkn5/whXGdMlfOR963adQNweQuatB -----END RSA PRIVATE KEY-----` // - Generate new private key using openssl genrsa -out key.pem 2048 // - Create a self-signed certificate for key.pem using // openssl req -x509 -key key.pem -out certificate.pem // - Create a file with the data to be encrypted using // echo -n "This is a test" > test.txt // - Generate PKCS #7 enveloped data encrypted using AES using // openssl cms -encrypt -in test.txt -outform pem -recip certificate.pem -aes256 -keyopt rsa_padding_mode:oaep // - Change the CMS header to the PKCS7 header. var RSAOAEPSHA1EncryptedTestFixture = ` -----BEGIN PKCS7----- MIIBwgYJKoZIhvcNAQcDoIIBszCCAa8CAQAxggFqMIIBZgIBADBOMDYxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlUZXN0IENlcnQC FCoCAvxWlBvVDwodj5frshHwg0GSMA0GCSqGSIb3DQEBBzAABIIBAJk/va3ss8Rc 1hs7V7uo4XwrV+VVJMQtSnAwp2YihMtSPj3hiS6ZbhoadrK5tGersZZLiz25Wr9u qMc5D6EpCeo6dr4Fy4JJvBb6dox1X5jzA4G2m1gKv+J+KthWLBEuBKKYYeVIayr4 qiqyPW1re0yEREMapXfBHdzcYAHCa+sSomkYpMAHCqHd04uk8lznIE8mt/p3dJQx QqFtYQ1YHeXFTEoVFnumVjyWwFX2fMgjSkdA34v/xDQc2HP81QMC45f5HOVbPk/Z EmOBSvoUL9VQWKMwxS2RGDQKAZMbYOn948TI0DyairG5BQzHFC3OWUlp/DpVJoIA c40TpDjW1bAwPAYJKoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQSHiMHMNoG+HSC12p ym5+dYAQ4qvztP5U0tRnA7ezUef7Fg== -----END PKCS7----- -----BEGIN CERTIFICATE----- MIIDTTCCAjWgAwIBAgIUKgIC/FaUG9UPCh2Pl+uyEfCDQZIwDQYJKoZIhvcNAQEL BQAwNjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAoM CVRlc3QgQ2VydDAeFw0yMTAyMTAxNjIwMDBaFw0yMTAzMTIxNjIwMDBaMDYxCzAJ BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMRIwEAYDVQQKDAlUZXN0IENl cnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS+Nd7wSgX6j6xLCZd SdwAq8BWlbruuFEf6VYvZ5FBzIOeTwFketD1tJie8tq9sEv8V8sFYlZruM4mA12G jxSse5rwVTf6TomQChEuvW+l6dB4N7EQ6EtZ1bmBKUk0jhqmrHTgT8YbyBKZ/2t+ UqkcvmHIPBMUEHwEOqGjj+RsRb69qYZYWTbtUjBbEt2PBk2noVtd7yyqvtPUl/p0 LAhL9oAsZTgL4LiZaOo9NGV6AkJWYQJuONOXSkx34Sn6V7xLPLhD/FDv8q3X9WuP dc00rlLDWpa2zn8dI3MNK+Q8KTi643f3MpfOiE0xuj13Hwp2QkfsgLdoER3OTFEK UmedAgMBAAGjUzBRMB0GA1UdDgQWBBRaaQq4a4U1xwlriTHnfBq8X5ctvDAfBgNV HSMEGDAWgBRaaQq4a4U1xwlriTHnfBq8X5ctvDAPBgNVHRMBAf8EBTADAQH/MA0G CSqGSIb3DQEBCwUAA4IBAQDFURgxrMBCmMVZFR9+jlCAK9T/tH3tX4d2iIVaj1Aj dw0wDAO20QPM/ZHlPM+l8yMT8ACY5ZHp6neRcaz9qmNeYAeGVu5twIo30LfRWDoY rfL3gIHeUXQCdxwJMh3z14WNdxPBoPXerw9LT1J97Dg81e/b+Za/vdRfqNIKbADj yoP7LBNaX/r83/SsGGbtW618sar+27wWRlGeZvFq8hwh+qyj3S7wtY7wx5weR7eZ S9K/MB9npTbIjDUidByTIhpk0hS55s1jF6U0wlmV0oUmC4wBIebyo1cL/CMPRv+a z/D9/ZvUoaotiATRWSKLCmxapcmGbMxhHHYWYWtzPCt1 -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA0vjXe8EoF+o+sSwmXUncAKvAVpW67rhRH+lWL2eRQcyDnk8B ZHrQ9bSYnvLavbBL/FfLBWJWa7jOJgNdho8UrHua8FU3+k6JkAoRLr1vpenQeDex EOhLWdW5gSlJNI4apqx04E/GG8gSmf9rflKpHL5hyDwTFBB8BDqho4/kbEW+vamG WFk27VIwWxLdjwZNp6FbXe8sqr7T1Jf6dCwIS/aALGU4C+C4mWjqPTRlegJCVmEC bjjTl0pMd+Ep+le8Szy4Q/xQ7/Kt1/Vrj3XNNK5Sw1qWts5/HSNzDSvkPCk4uuN3 9zKXzohNMbo9dx8KdkJH7IC3aBEdzkxRClJnnQIDAQABAoIBAF8IKoCbbIUBRkYm ng1tpMVEmHooLjE0I47dW64019Cs4Cjia70oOZJETG9k87V4gXHk1hXRyx3w/CNR ZsKjFuvvLcbOjE2bLQoODtlgCbfRz88nPwJfsPmBdXNB9rDOxiCIFImqRZHkGMT3 siMP9w90jrVUoj9qgYKiKodz3LAMFLnc6QkuAPRdEEI14bxRCcc3w2nKcCbj8Yye qKDbWVqp36kWBYcWgD2vzRcBOjJ3mRvTwflEg8HXbU88ANlGf7QQ1YhB9ueAE9Eg E18BMoa8cjon+xH2OvH+PlOZkbCLojoFtlUSh99eApp51+DCTKwQfqeg5ufdwm5G vyci9X0CgYEA+tFy8dqGOlmHDRUg3lW68dA1zkm15WAZoj7NvCGvTQyfoeH3Syoo CNKJqJkGHVWksCbTnORGVLDsz+l5a2BJY3L0xiDxpciIomZO18/IGJ4K5X4tm10i 330jUMO/22BXgNzBLU8gIyQLIu45NgOugtfwFKrCvYER4m0/peXWtB8CgYEA11Sm mC9V3mwceUuHWgqxsZpxrTQEDTAOhrGiIl5ZtoD7moMpu9MOo3qGd8W4dNbQwONq RxDigTQWv9oxqqDTYQjoZRSo1zYYgn9K17V5v4P1pzFMVBJnK1ElciWObt9l2g4O B/+SWQncwShHhfwJPrYmVQGgb3fETfZiiGvyTMMCgYEAxf4MtKqCBxGhMEybc6dN OZHYx40cT4M6+P6GvZoBndr3MH0GD4mprL01+adCUmnG5V7g8RqqAjTf24g8Vuzd Qen/G1/qIapZYYlNd8MH+5bWly6xpdExtCY+eITtsKkuqgSZYcDyZ4sOV3aiJudl HNiFJmtd6uY2Tf1bnwP+JpUCgYA4aup3Rze1Xhgbw6lD8zdZdEDCg7VoCyZTLilv 3c6dna/ObP07Q/I67PhcW0aX/kyVrUAEPK1L8uze+Xk33oljjCTvjvkp4feMAXQH jnnGrvlnA+iewm+bjthDzwlBjXCvMC2G9PRQNeBMD5Sly0JU1v62GQYDDps1Xg+0 9Kt4ZwKBgF8995suzG285txhAnlbKJpXB67f20s0DpBb4QdB+1PuizuyWWxPYAcu J1h1Q5Z6frEwd4ye/bcpReEScPXOKEB+1b3TWGCWNC2jhfChtZSH1Y3Z3mL0SfwT n9txBjxLOx1G83OQYY3J6Bnwkn5/whXGdMlfOR963adQNweQuatB -----END RSA PRIVATE KEY-----` var RSAOAEPSHA256EncryptedTestFixture = ` -----BEGIN PKCS7----- MIIBtgYJKoZIhvcNAQcDoIIBpzCCAaMCAQAxggFeMIIBWgIBADAxMCkxEDAOBgNV BAoTB0FjbWUgQ28xFTATBgNVBAMTDEVkZGFyZCBTdGFyawIEItzA4TAeBgkqhkiG 9w0BAQcwEaAPMA0GCWCGSAFlAwQCAQUABIIBAFI8WCPbFK8sEkWFZKtcla39k0DA HL+iS16Is+6lKFpanTq1L1DUYfdNJe1raRy/0aHV7sOnugIXyMo5daKOqyJlcgr/ UR9iTu1mUADX+F3W/IeIIBrsFI73PsW30yk8uazjCGOh79TAmwjLSUMy/IV1LNKf mZEzfyaB8EEx1br7kW4tQ+DjW2VqMzKdVxNgzhrTR+VLiBkuGVGsdSEfFkJAYfhp 4kcqzsE+VZ93v0wnB7g0r9GckBox0OWeYHsldkOQPA6OrGL/54MxxcOdh0mh0i2l azux8yBteKsUJG9y+J78DFBwZtOsy4u2Rat895K31GDew3sgHofeeFNHA8kwPAYJ KoZIhvcNAQcBMB0GCWCGSAFlAwQBKgQQ4bmABhs/EKBtcfYEwHk2wIAQuA3tdOYV oKGnb5jFQi17VA== -----END PKCS7----- -----BEGIN CERTIFICATE----- MIIDETCCAfmgAwIBAgIEItzA4TANBgkqhkiG9w0BAQsFADApMRAwDgYDVQQKEwdB Y21lIENvMRUwEwYDVQQDEwxFZGRhcmQgU3RhcmswHhcNMjEwMjIzMTIxODQ2WhcN MjIwMjIzMTIxODQ3WjAlMRAwDgYDVQQKEwdBY21lIENvMREwDwYDVQQDEwhKb24g U25vdzCCAR8wDQYJKoZIhvcNAQEBBQADggEMADCCAQcCggEAcWPIQrIZColwlCsn ZK7ULUEkZHtvMOCaLaHA4laqLuJOeQxAyWpL1m11w3GpFeBwPEdrThoG8b04xaPB CuO9MPTvYqWqT1Eq0UWgbEjpZGmiLOjmIeBS8GaajDQVVRLYLlVEfwt+GNqUvZEa x7OqvnBoQ2aJZFk+5xsuXkhLzwx4NBAatdYbuh5j5iN69ASJzjaiYNq3Ct1PvsJN ZZ2w98rAmbCjqkVJrN5/yFink6l15s9lyidrdDUl8Ig5gPatBpvsNG14d5c4bVD+ DJc0vpZ8fYSuW480mwlAeUV8DAxv7jTEKguDJgOAT3HknzMgCBY3USxsvyu4G29r 4jmEbQIBA6NIMEYwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwME MB8GA1UdIwQYMBaAFOy+qIFIokwb/0GSIt4DOBOXMd5vMA0GCSqGSIb3DQEBCwUA A4IBAQA8F85MhBw5QxwrwRluL4waSXpxdRNpkN2K59eEqTUc+5lFLhinvX9WwkvR ToBiRpvX50GtCWZ/r5Lx2UxTyh3vKsgjhkXcvm6pvVVfqyz5pNQv3v2Q838xM98+ 15srGU9uU71McPZ5MmkmfHfgBaz5CCfUcsroJJ19pebaSARkRnb0bR36voXUbtwM F89PLjXUYLxSaWcOpRQ1ju0Kq7K3MDqauPzzl3HtrpGkCsoHMfb5o/HYNj+Pmxfl l3QH5xhOzVdioaGwE4SkY5Z5szZ8n+qi/Zd59PBCOpLoXvcB9WRTMmYkxmDOVcwI pQfViIYaatHkjbS/2C/Cx0hfb/6S -----END CERTIFICATE----- -----BEGIN RSA PRIVATE KEY----- MIIEnwIBAAKCAQBxY8hCshkKiXCUKydkrtQtQSRke28w4JotocDiVqou4k55DEDJ akvWbXXDcakV4HA8R2tOGgbxvTjFo8EK470w9O9ipapPUSrRRaBsSOlkaaIs6OYh 4FLwZpqMNBVVEtguVUR/C34Y2pS9kRrHs6q+cGhDZolkWT7nGy5eSEvPDHg0EBq1 1hu6HmPmI3r0BInONqJg2rcK3U++wk1lnbD3ysCZsKOqRUms3n/IWKeTqXXmz2XK J2t0NSXwiDmA9q0Gm+w0bXh3lzhtUP4MlzS+lnx9hK5bjzSbCUB5RXwMDG/uNMQq C4MmA4BPceSfMyAIFjdRLGy/K7gbb2viOYRtAgEDAoIBAEuX2tchZgcGSw1yGkMf OB4rbZhSSiCVvB5r1ew5xsnsNFCy1ducMo7zo9ehG2Pq9X2E8jQRWfZ+JdkX1gdC fiCjSkHDxt+LceDZFZ2F8O2bwXNF7sFAN0rvEbLNY44MkB7jgv9c/rs8YykLZy/N HH71mteZsO2Q1JoSHumFh99cwWHFhLxYh64qFeeH6Gqx6AM2YVBWHgs7OuKOvc8y zUbf8xftPht1kMwwDR1XySiEYtBtn74JflK3DcT8oxOuCZBuX6sMJHKbVP41zDj+ FJZBmpAvNfCEYJUr1Hg+DpMLqLUg+D6v5vpliburbk9LxcKFZyyZ9QVe7GoqMLBu eGsCgYEAummUj4MMKWJC2mv5rj/dt2pj2/B2HtP2RLypai4et1/Ru9nNk8cjMLzC qXz6/RLuJ7/eD7asFS3y7EqxKxEmW0G8tTHjnzR/3wnpVipuWnwCDGU032HJVd13 LMe51GH97qLzuDZjMCz+VlbCNdSslMgWWK0XmRnN7Yqxvh6ao2kCgYEAm7fTRBhF JtKcaJ7d8BQb9l8BNHfjayYOMq5CxoCyxa2pGBv/Mrnxv73Twp9Z/MP0ue5M5nZt GMovpP5cGdJLQ2w5p4H3opcuWeYW9Yyru2EyCEAI/hD/Td3QVP0ukc19BDuPl5Wg eIFs218uiVOU4pw3w+Et5B1PZ/F+ZLr5LGUCgYB8RmMKV11w7CyRnVEe1T56Ru09 Svlp4qQt0xucHr8k6ovSkTO32hd10yxw/fyot0lv1T61JHK4yUydhyDHYMQ81n3O IUJqIv/qBpuOxvQ8UqwIQ3iU69uOk6TIhSaNlqlJwffQJEIgHf7kOdbOjchjMA7l yLpmETPzscvUFGcXmwKBgGfP4i1lg283EvBp6Uq4EqQ/ViL6l5zECXce1y8Ady5z xhASqiHRS9UpN9cU5qiCoyae3e75nhCGym3+6BE23Nede8UBT8G6HuaZZKOzHSeW IVrVW1QLVN6T4DioybaI/gLSX7pjwFBWSJI/dFuNDexoJS1AyUK+NO/2VEMnUMhD AoGAOsdn3Prnh/mjC95vraHCLap0bRBSexMdx77ImHgtFUUcSaT8DJHs+NZw1RdM SZA0J+zVQ8q7B11jIgz5hMz+chedwoRjTL7a8VRTKHFmmBH0zlEuV7L79w6HkRCQ VRg10GUN6heGLv0aOHbPdobcuVDH4sgOqpT1QnOuce34sQs= -----END RSA PRIVATE KEY-----` pkcs7-0.2.1/encrypt.go000066400000000000000000000315421475362641200145730ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/aes" "crypto/cipher" "crypto/des" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" ) type envelopedData struct { Version int RecipientInfos []recipientInfo `asn1:"set"` EncryptedContentInfo encryptedContentInfo } type encryptedData struct { Version int EncryptedContentInfo encryptedContentInfo } type recipientInfo struct { Version int IssuerAndSerialNumber issuerAndSerial KeyEncryptionAlgorithm pkix.AlgorithmIdentifier EncryptedKey []byte } type encryptedContentInfo struct { ContentType asn1.ObjectIdentifier ContentEncryptionAlgorithm pkix.AlgorithmIdentifier EncryptedContent asn1.RawValue `asn1:"tag:0,optional"` } const ( // EncryptionAlgorithmDESCBC is the DES CBC encryption algorithm EncryptionAlgorithmDESCBC = iota // EncryptionAlgorithmAES128CBC is the AES 128 bits with CBC encryption algorithm // Avoid this algorithm unless required for interoperability; use AES GCM instead. EncryptionAlgorithmAES128CBC // EncryptionAlgorithmAES256CBC is the AES 256 bits with CBC encryption algorithm // Avoid this algorithm unless required for interoperability; use AES GCM instead. EncryptionAlgorithmAES256CBC // EncryptionAlgorithmAES128GCM is the AES 128 bits with GCM encryption algorithm EncryptionAlgorithmAES128GCM // EncryptionAlgorithmAES256GCM is the AES 256 bits with GCM encryption algorithm EncryptionAlgorithmAES256GCM ) // ContentEncryptionAlgorithm determines the algorithm used to encrypt the // plaintext message. Change the value of this variable to change which // algorithm is used in the Encrypt() function. var ContentEncryptionAlgorithm = EncryptionAlgorithmDESCBC // ErrUnsupportedEncryptionAlgorithm is returned when attempting to encrypt // content with an unsupported algorithm. var ErrUnsupportedEncryptionAlgorithm = errors.New("pkcs7: cannot encrypt content: only DES-CBC, AES-CBC, and AES-GCM supported") // KeyEncryptionAlgorithm determines the algorithm used to encrypt a // content key. Change the value of this variable to change which // algorithm is used in the Encrypt() function. var KeyEncryptionAlgorithm = OIDEncryptionAlgorithmRSA // ErrUnsupportedKeyEncryptionAlgorithm is returned when an // unsupported key encryption algorithm OID is provided. var ErrUnsupportedKeyEncryptionAlgorithm = errors.New("pkcs7: unsupported key encryption algorithm provided") // KeyEncryptionHash determines the crypto.Hash algorithm to use // when encrypting a content key. Change the value of this variable // to change which algorithm is used in the Encrypt() function. var KeyEncryptionHash = crypto.SHA256 // ErrUnsupportedKeyEncryptionHash is returned when an // unsupported key encryption hash is provided. var ErrUnsupportedKeyEncryptionHash = errors.New("pkcs7: unsupported key encryption hash provided") // ErrPSKNotProvided is returned when attempting to encrypt // using a PSK without actually providing the PSK. var ErrPSKNotProvided = errors.New("pkcs7: cannot encrypt content: PSK not provided") const nonceSize = 12 type aesGCMParameters struct { Nonce []byte `asn1:"tag:4"` ICVLen int } func encryptAESGCM(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) { var keyLen int var algID asn1.ObjectIdentifier switch ContentEncryptionAlgorithm { case EncryptionAlgorithmAES128GCM: keyLen = 16 algID = OIDEncryptionAlgorithmAES128GCM case EncryptionAlgorithmAES256GCM: keyLen = 32 algID = OIDEncryptionAlgorithmAES256GCM default: return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESGCM: %d", ContentEncryptionAlgorithm) } if key == nil { // Create AES key key = make([]byte, keyLen) _, err := rand.Read(key) if err != nil { return nil, nil, err } } // Create nonce nonce := make([]byte, nonceSize) _, err := rand.Read(nonce) if err != nil { return nil, nil, err } // Encrypt content block, err := aes.NewCipher(key) if err != nil { return nil, nil, err } gcm, err := cipher.NewGCM(block) if err != nil { return nil, nil, err } ciphertext := gcm.Seal(nil, nonce, content, nil) // Prepare ASN.1 Encrypted Content Info paramSeq := aesGCMParameters{ Nonce: nonce, ICVLen: gcm.Overhead(), } paramBytes, err := asn1.Marshal(paramSeq) if err != nil { return nil, nil, err } eci := encryptedContentInfo{ ContentType: OIDData, ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{ Algorithm: algID, Parameters: asn1.RawValue{ Tag: asn1.TagSequence, Bytes: paramBytes, }, }, EncryptedContent: marshalEncryptedContent(ciphertext), } return key, &eci, nil } func encryptDESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) { if key == nil { // Create DES key key = make([]byte, 8) _, err := rand.Read(key) if err != nil { return nil, nil, err } } // Create CBC IV iv := make([]byte, des.BlockSize) _, err := rand.Read(iv) if err != nil { return nil, nil, err } // Encrypt padded content block, err := des.NewCipher(key) if err != nil { return nil, nil, err } mode := cipher.NewCBCEncrypter(block, iv) plaintext, err := pad(content, mode.BlockSize()) if err != nil { return nil, nil, err } cyphertext := make([]byte, len(plaintext)) mode.CryptBlocks(cyphertext, plaintext) // Prepare ASN.1 Encrypted Content Info eci := encryptedContentInfo{ ContentType: OIDData, ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{ Algorithm: OIDEncryptionAlgorithmDESCBC, Parameters: asn1.RawValue{Tag: 4, Bytes: iv}, }, EncryptedContent: marshalEncryptedContent(cyphertext), } return key, &eci, nil } func encryptAESCBC(content []byte, key []byte) ([]byte, *encryptedContentInfo, error) { var keyLen int var algID asn1.ObjectIdentifier switch ContentEncryptionAlgorithm { case EncryptionAlgorithmAES128CBC: keyLen = 16 algID = OIDEncryptionAlgorithmAES128CBC case EncryptionAlgorithmAES256CBC: keyLen = 32 algID = OIDEncryptionAlgorithmAES256CBC default: return nil, nil, fmt.Errorf("invalid ContentEncryptionAlgorithm in encryptAESCBC: %d", ContentEncryptionAlgorithm) } if key == nil { // Create AES key key = make([]byte, keyLen) _, err := rand.Read(key) if err != nil { return nil, nil, err } } // Create CBC IV iv := make([]byte, aes.BlockSize) _, err := rand.Read(iv) if err != nil { return nil, nil, err } // Encrypt padded content block, err := aes.NewCipher(key) if err != nil { return nil, nil, err } mode := cipher.NewCBCEncrypter(block, iv) plaintext, err := pad(content, mode.BlockSize()) if err != nil { return nil, nil, err } cyphertext := make([]byte, len(plaintext)) mode.CryptBlocks(cyphertext, plaintext) // Prepare ASN.1 Encrypted Content Info eci := encryptedContentInfo{ ContentType: OIDData, ContentEncryptionAlgorithm: pkix.AlgorithmIdentifier{ Algorithm: algID, Parameters: asn1.RawValue{Tag: 4, Bytes: iv}, }, EncryptedContent: marshalEncryptedContent(cyphertext), } return key, &eci, nil } // Encrypt creates and returns an envelope data PKCS7 structure with encrypted // recipient keys for each recipient public key. // // The algorithm used to perform encryption is determined by the current value // of the global ContentEncryptionAlgorithm package variable. By default, the // value is EncryptionAlgorithmDESCBC. To use a different algorithm, change the // value before calling Encrypt(). For example: // // ContentEncryptionAlgorithm = EncryptionAlgorithmAES256GCM // // TODO(fullsailor): Add support for encrypting content with other algorithms func Encrypt(content []byte, recipients []*x509.Certificate) ([]byte, error) { var eci *encryptedContentInfo var key []byte var err error // Apply chosen symmetric encryption method switch ContentEncryptionAlgorithm { case EncryptionAlgorithmDESCBC: key, eci, err = encryptDESCBC(content, nil) case EncryptionAlgorithmAES128CBC: fallthrough case EncryptionAlgorithmAES256CBC: key, eci, err = encryptAESCBC(content, nil) case EncryptionAlgorithmAES128GCM: fallthrough case EncryptionAlgorithmAES256GCM: key, eci, err = encryptAESGCM(content, nil) default: return nil, ErrUnsupportedEncryptionAlgorithm } if err != nil { return nil, err } // Prepare each recipient's encrypted cipher key recipientInfos := make([]recipientInfo, len(recipients)) for i, recipient := range recipients { algorithm := KeyEncryptionAlgorithm hash := KeyEncryptionHash var kea pkix.AlgorithmIdentifier switch { case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP): parameters, err := getParametersForKeyEncryptionAlgorithm(algorithm, hash) if err != nil { return nil, fmt.Errorf("failed to get parameters for key encryption: %v", err) } kea = pkix.AlgorithmIdentifier{ Algorithm: algorithm, Parameters: parameters, } case algorithm.Equal(OIDEncryptionAlgorithmRSA): kea = pkix.AlgorithmIdentifier{ Algorithm: algorithm, } default: return nil, ErrUnsupportedKeyEncryptionAlgorithm } encrypted, err := encryptKey(key, recipient, algorithm, hash) if err != nil { return nil, err } ias, err := cert2issuerAndSerial(recipient) if err != nil { return nil, err } info := recipientInfo{ Version: 0, IssuerAndSerialNumber: ias, KeyEncryptionAlgorithm: kea, EncryptedKey: encrypted, } recipientInfos[i] = info } // Prepare envelope content envelope := envelopedData{ EncryptedContentInfo: *eci, Version: 0, RecipientInfos: recipientInfos, } innerContent, err := asn1.Marshal(envelope) if err != nil { return nil, err } // Prepare outer payload structure wrapper := contentInfo{ ContentType: OIDEnvelopedData, Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent}, } return asn1.Marshal(wrapper) } func getParametersForKeyEncryptionAlgorithm(algorithm asn1.ObjectIdentifier, hash crypto.Hash) (asn1.RawValue, error) { if !algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP) { return asn1.RawValue{}, nil // return empty; not used } params := rsaOAEPAlgorithmParameters{} switch hash { case crypto.SHA1: params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA1} case crypto.SHA224: params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA224} case crypto.SHA256: params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA256} case crypto.SHA384: params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA384} case crypto.SHA512: params.HashFunc = pkix.AlgorithmIdentifier{Algorithm: OIDDigestAlgorithmSHA512} default: return asn1.RawValue{}, ErrUnsupportedAlgorithm } b, err := asn1.Marshal(params) if err != nil { return asn1.RawValue{}, fmt.Errorf("failed marshaling key encryption parameters: %v", err) } return asn1.RawValue{ FullBytes: b, }, nil } // EncryptUsingPSK creates and returns an encrypted data PKCS7 structure, // encrypted using caller provided pre-shared secret. func EncryptUsingPSK(content []byte, key []byte) ([]byte, error) { var eci *encryptedContentInfo var err error if key == nil { return nil, ErrPSKNotProvided } // Apply chosen symmetric encryption method switch ContentEncryptionAlgorithm { case EncryptionAlgorithmDESCBC: _, eci, err = encryptDESCBC(content, key) case EncryptionAlgorithmAES128GCM: fallthrough case EncryptionAlgorithmAES256GCM: _, eci, err = encryptAESGCM(content, key) default: return nil, ErrUnsupportedEncryptionAlgorithm } if err != nil { return nil, err } // Prepare encrypted-data content ed := encryptedData{ Version: 0, EncryptedContentInfo: *eci, } innerContent, err := asn1.Marshal(ed) if err != nil { return nil, err } // Prepare outer payload structure wrapper := contentInfo{ ContentType: OIDEncryptedData, Content: asn1.RawValue{Class: 2, Tag: 0, IsCompound: true, Bytes: innerContent}, } return asn1.Marshal(wrapper) } func marshalEncryptedContent(content []byte) asn1.RawValue { return asn1.RawValue{Bytes: content, Class: 2, IsCompound: false} } func encryptKey(key []byte, recipient *x509.Certificate, algorithm asn1.ObjectIdentifier, hash crypto.Hash) ([]byte, error) { pub, ok := recipient.PublicKey.(*rsa.PublicKey) if !ok { return nil, ErrUnsupportedKeyType } switch { case algorithm.Equal(OIDEncryptionAlgorithmRSA): return rsa.EncryptPKCS1v15(rand.Reader, pub, key) case algorithm.Equal(OIDEncryptionAlgorithmRSAESOAEP): return rsa.EncryptOAEP(hash.New(), rand.Reader, pub, key, nil) default: return nil, ErrUnsupportedKeyEncryptionAlgorithm } } func pad(data []byte, blocklen int) ([]byte, error) { if blocklen < 1 { return nil, fmt.Errorf("invalid blocklen %d", blocklen) } padlen := blocklen - (len(data) % blocklen) if padlen == 0 { padlen = blocklen } pad := bytes.Repeat([]byte{byte(padlen)}, padlen) return append(data, pad...), nil } pkcs7-0.2.1/encrypt_test.go000066400000000000000000000145261475362641200156350ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/pem" "io/ioutil" "os" "os/exec" "reflect" "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) } } } func Test_getParametersForKeyEncryptionAlgorithm(t *testing.T) { type args struct { algorithm asn1.ObjectIdentifier hash crypto.Hash } tests := []struct { name string args args expErr error }{ {name: "sha256", args: args{algorithm: OIDEncryptionAlgorithmRSAESOAEP, hash: crypto.SHA256}}, {name: "sha512", args: args{algorithm: OIDEncryptionAlgorithmRSAESOAEP, hash: crypto.SHA512}}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := getParametersForKeyEncryptionAlgorithm(tt.args.algorithm, tt.args.hash) if tt.expErr != nil { if err == nil { t.Errorf("getParametersForKeyEncryptionAlgorithm() error = %v, expErr %v", err, tt.expErr) return } if err.Error() != tt.expErr.Error() { t.Errorf("getParametersForKeyEncryptionAlgorithm() = %v, want %v", err.Error(), tt.expErr.Error()) return } } // test if the reverse operation results in the same value alg := pkix.AlgorithmIdentifier{Algorithm: tt.args.algorithm, Parameters: got} resultHash, err := getHashFuncForKeyEncryptionAlgorithm(alg) if err != nil { t.Errorf("getHashFuncForKeyEncryptionAlgorithm errors = %v", err) } if resultHash != tt.args.hash { t.Errorf("getHashFuncForKeyEncryptionAlgorithm() = %v, want %v", resultHash, tt.args.hash) } }) } } func Test_marshalEncryptedContent(t *testing.T) { content := []byte{} got := marshalEncryptedContent(content) expected := asn1.RawValue{Class: 2, Tag: 0, IsCompound: false, Bytes: []byte{}, FullBytes: nil} if !reflect.DeepEqual(expected, got) { t.Errorf("marshalEncryptedContent() = %v, want %v", got, expected) } content = []byte{34, 165, 121, 103, 15, 109, 119, 147, 39, 236, 212, 103, 143, 164, 172, 22} got = marshalEncryptedContent(content) expected = asn1.RawValue{Class: 2, Tag: 0, IsCompound: false, Bytes: []byte{34, 165, 121, 103, 15, 109, 119, 147, 39, 236, 212, 103, 143, 164, 172, 22}, FullBytes: nil} if !reflect.DeepEqual(expected, got) { t.Errorf("marshalEncryptedContent() = %v, want %v", got, expected) } } func TestEncryptAndDecryptWithOpenSSL(t *testing.T) { tf := UnmarshalTestFixture(RSAOAEPSHA256EncryptedTestFixture) // use existing fixture with cert + key content := []byte("this is the content") recipients := []*x509.Certificate{tf.Certificate} currentAlgorithm := ContentEncryptionAlgorithm ContentEncryptionAlgorithm = EncryptionAlgorithmAES256CBC defer func() { ContentEncryptionAlgorithm = currentAlgorithm }() encryptedContent, err := Encrypt(content, recipients) if err != nil { t.Fatal(err) } contentFile, err := ioutil.TempFile("", "content") if err != nil { t.Fatal(err) } defer os.Remove(contentFile.Name()) err = pem.Encode(contentFile, &pem.Block{Type: "PKCS7", Bytes: encryptedContent}) if err != nil { t.Fatal(err) } contentFile.Close() recipientFile, err := ioutil.TempFile("", "content") if err != nil { t.Fatal(err) } defer os.Remove(recipientFile.Name()) err = pem.Encode(recipientFile, &pem.Block{Type: "CERTIFICATE", Bytes: tf.Certificate.Raw}) if err != nil { t.Fatal(err) } privateKey, err := x509.MarshalPKCS8PrivateKey(tf.PrivateKey) if err != nil { t.Fatal(err) } err = pem.Encode(recipientFile, &pem.Block{Type: "PRIVATE KEY", Bytes: privateKey}) if err != nil { t.Fatal(err) } recipientFile.Close() // call openssl to decrypt the content opensslCMD := exec.Command("openssl", "cms", "-decrypt", "-inform", "pem", "-in", contentFile.Name(), "-recip", recipientFile.Name(), ) out, err := opensslCMD.CombinedOutput() if err != nil { t.Fatalf("openssl command failed with %s: %s", err, out) } if !bytes.Equal(content, out) { t.Errorf("EncryptAndDecryptWithOpenSSL() = %v, want %v", out, content) } } pkcs7-0.2.1/go.mod000066400000000000000000000001201475362641200136520ustar00rootroot00000000000000module github.com/smallstep/pkcs7 go 1.14 require golang.org/x/crypto v0.33.0 pkcs7-0.2.1/go.sum000066400000000000000000000132601475362641200137100ustar00rootroot00000000000000github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= pkcs7-0.2.1/internal/000077500000000000000000000000001475362641200143675ustar00rootroot00000000000000pkcs7-0.2.1/internal/legacy/000077500000000000000000000000001475362641200156335ustar00rootroot00000000000000pkcs7-0.2.1/internal/legacy/x509/000077500000000000000000000000001475362641200163405ustar00rootroot00000000000000pkcs7-0.2.1/internal/legacy/x509/debug.go000066400000000000000000000005451475362641200177610ustar00rootroot00000000000000package legacyx509 import "fmt" // legacyGodebugSetting is a type mimicking Go's internal godebug package // settings, which are used to enable / disable certain functionalities at // build time. type legacyGodebugSetting int func (s legacyGodebugSetting) Value() string { return fmt.Sprintf("%d", s) } func (s legacyGodebugSetting) IncNonDefault() {} pkcs7-0.2.1/internal/legacy/x509/doc.go000066400000000000000000000011711475362641200174340ustar00rootroot00000000000000/* Package legacyx509 is a copy of certain parts of Go's crypto/x509 package. It is based on Go 1.23, and has just the parts copied over required for parsing X509 certificates. The primary reason this copy exists is to keep support for parsing PKCS7 messages containing Simple Certificate Enrolment Protocol (SCEP) requests from Windows devices. Go 1.23 made a change marking certificates with a critical authority key identifier as invalid, which is mandated by RFC 5280, but apparently Windows marks those specific certificates as such, resulting in those SCEP requests failing from being parsed correctly. */ package legacyx509 pkcs7-0.2.1/internal/legacy/x509/oid.go000066400000000000000000000207721475362641200174520ustar00rootroot00000000000000// Copyright 2023 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package legacyx509 import ( "bytes" "encoding/asn1" "errors" "math" "math/big" "math/bits" "strconv" "strings" ) var ( errInvalidOID = errors.New("invalid oid") ) // An OID represents an ASN.1 OBJECT IDENTIFIER. type OID struct { der []byte } // ParseOID parses a Object Identifier string, represented by ASCII numbers separated by dots. func ParseOID(oid string) (OID, error) { var o OID return o, o.unmarshalOIDText(oid) } func newOIDFromDER(der []byte) (OID, bool) { if len(der) == 0 || der[len(der)-1]&0x80 != 0 { return OID{}, false } start := 0 for i, v := range der { // ITU-T X.690, section 8.19.2: // The subidentifier shall be encoded in the fewest possible octets, // that is, the leading octet of the subidentifier shall not have the value 0x80. if i == start && v == 0x80 { return OID{}, false } if v&0x80 == 0 { start = i + 1 } } return OID{der}, true } // OIDFromInts creates a new OID using ints, each integer is a separate component. func OIDFromInts(oid []uint64) (OID, error) { if len(oid) < 2 || oid[0] > 2 || (oid[0] < 2 && oid[1] >= 40) { return OID{}, errInvalidOID } length := base128IntLength(oid[0]*40 + oid[1]) for _, v := range oid[2:] { length += base128IntLength(v) } der := make([]byte, 0, length) der = appendBase128Int(der, oid[0]*40+oid[1]) for _, v := range oid[2:] { der = appendBase128Int(der, v) } return OID{der}, nil } func base128IntLength(n uint64) int { if n == 0 { return 1 } return (bits.Len64(n) + 6) / 7 } func appendBase128Int(dst []byte, n uint64) []byte { for i := base128IntLength(n) - 1; i >= 0; i-- { o := byte(n >> uint(i*7)) o &= 0x7f if i != 0 { o |= 0x80 } dst = append(dst, o) } return dst } func base128BigIntLength(n *big.Int) int { if n.Cmp(big.NewInt(0)) == 0 { return 1 } return (n.BitLen() + 6) / 7 } func appendBase128BigInt(dst []byte, n *big.Int) []byte { if n.Cmp(big.NewInt(0)) == 0 { return append(dst, 0) } for i := base128BigIntLength(n) - 1; i >= 0; i-- { o := byte(big.NewInt(0).Rsh(n, uint(i)*7).Bits()[0]) o &= 0x7f if i != 0 { o |= 0x80 } dst = append(dst, o) } return dst } // AppendText implements [encoding.TextAppender] func (o OID) AppendText(b []byte) ([]byte, error) { return append(b, o.String()...), nil } // MarshalText implements [encoding.TextMarshaler] func (o OID) MarshalText() ([]byte, error) { return o.AppendText(nil) } // UnmarshalText implements [encoding.TextUnmarshaler] func (o *OID) UnmarshalText(text []byte) error { return o.unmarshalOIDText(string(text)) } // cutString slices s around the first instance of sep, // returning the text before and after sep. // The found result reports whether sep appears in s. // If sep does not appear in s, cut returns s, "", false. func cutString(s, sep string) (before, after string, found bool) { if i := strings.Index(s, sep); i >= 0 { return s[:i], s[i+len(sep):], true } return s, "", false } func (o *OID) unmarshalOIDText(oid string) error { // (*big.Int).SetString allows +/- signs, but we don't want // to allow them in the string representation of Object Identifier, so // reject such encodings. for _, c := range oid { isDigit := c >= '0' && c <= '9' if !isDigit && c != '.' { return errInvalidOID } } var ( firstNum string secondNum string ) var nextComponentExists bool firstNum, oid, nextComponentExists = cutString(oid, ".") if !nextComponentExists { return errInvalidOID } secondNum, oid, nextComponentExists = cutString(oid, ".") var ( first = big.NewInt(0) second = big.NewInt(0) ) if _, ok := first.SetString(firstNum, 10); !ok { return errInvalidOID } if _, ok := second.SetString(secondNum, 10); !ok { return errInvalidOID } if first.Cmp(big.NewInt(2)) > 0 || (first.Cmp(big.NewInt(2)) < 0 && second.Cmp(big.NewInt(40)) >= 0) { return errInvalidOID } firstComponent := first.Mul(first, big.NewInt(40)) firstComponent.Add(firstComponent, second) der := appendBase128BigInt(make([]byte, 0, 32), firstComponent) for nextComponentExists { var strNum string strNum, oid, nextComponentExists = cutString(oid, ".") b, ok := big.NewInt(0).SetString(strNum, 10) if !ok { return errInvalidOID } der = appendBase128BigInt(der, b) } o.der = der return nil } // AppendBinary implements [encoding.BinaryAppender] func (o OID) AppendBinary(b []byte) ([]byte, error) { return append(b, o.der...), nil } // MarshalBinary implements [encoding.BinaryMarshaler] func (o OID) MarshalBinary() ([]byte, error) { return o.AppendBinary(nil) } // cloneBytes returns a copy of b[:len(b)]. // The result may have additional unused capacity. // Clone(nil) returns nil. func cloneBytes(b []byte) []byte { if b == nil { return nil } return append([]byte{}, b...) } // UnmarshalBinary implements [encoding.BinaryUnmarshaler] func (o *OID) UnmarshalBinary(b []byte) error { oid, ok := newOIDFromDER(cloneBytes(b)) if !ok { return errInvalidOID } *o = oid return nil } // Equal returns true when oid and other represents the same Object Identifier. func (oid OID) Equal(other OID) bool { // There is only one possible DER encoding of // each unique Object Identifier. return bytes.Equal(oid.der, other.der) } func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, failed bool) { offset = initOffset var ret64 int64 for shifted := 0; offset < len(bytes); shifted++ { // 5 * 7 bits per byte == 35 bits of data // Thus the representation is either non-minimal or too large for an int32 if shifted == 5 { failed = true return } ret64 <<= 7 b := bytes[offset] // integers should be minimally encoded, so the leading octet should // never be 0x80 if shifted == 0 && b == 0x80 { failed = true return } ret64 |= int64(b & 0x7f) offset++ if b&0x80 == 0 { ret = int(ret64) // Ensure that the returned value fits in an int on all platforms if ret64 > math.MaxInt32 { failed = true } return } } failed = true return } // EqualASN1OID returns whether an OID equals an asn1.ObjectIdentifier. If // asn1.ObjectIdentifier cannot represent the OID specified by oid, because // a component of OID requires more than 31 bits, it returns false. func (oid OID) EqualASN1OID(other asn1.ObjectIdentifier) bool { if len(other) < 2 { return false } v, offset, failed := parseBase128Int(oid.der, 0) if failed { // This should never happen, since we've already parsed the OID, // but just in case. return false } if v < 80 { a, b := v/40, v%40 if other[0] != a || other[1] != b { return false } } else { a, b := 2, v-80 if other[0] != a || other[1] != b { return false } } i := 2 for ; offset < len(oid.der); i++ { v, offset, failed = parseBase128Int(oid.der, offset) if failed { // Again, shouldn't happen, since we've already parsed // the OID, but better safe than sorry. return false } if i >= len(other) || v != other[i] { return false } } return i == len(other) } // Strings returns the string representation of the Object Identifier. func (oid OID) String() string { var b strings.Builder b.Grow(32) const ( valSize = 64 // size in bits of val. bitsPerByte = 7 maxValSafeShift = (1 << (valSize - bitsPerByte)) - 1 ) var ( start = 0 val = uint64(0) numBuf = make([]byte, 0, 21) bigVal *big.Int overflow bool ) for i, v := range oid.der { curVal := v & 0x7F valEnd := v&0x80 == 0 if valEnd { if start != 0 { b.WriteByte('.') } } if !overflow && val > maxValSafeShift { if bigVal == nil { bigVal = new(big.Int) } bigVal = bigVal.SetUint64(val) overflow = true } if overflow { bigVal = bigVal.Lsh(bigVal, bitsPerByte).Or(bigVal, big.NewInt(int64(curVal))) if valEnd { if start == 0 { b.WriteString("2.") bigVal = bigVal.Sub(bigVal, big.NewInt(80)) } numBuf = bigVal.Append(numBuf, 10) b.Write(numBuf) numBuf = numBuf[:0] val = 0 start = i + 1 overflow = false } continue } val <<= bitsPerByte val |= uint64(curVal) if valEnd { if start == 0 { if val < 80 { b.Write(strconv.AppendUint(numBuf, val/40, 10)) b.WriteByte('.') b.Write(strconv.AppendUint(numBuf, val%40, 10)) } else { b.WriteString("2.") b.Write(strconv.AppendUint(numBuf, val-80, 10)) } } else { b.Write(strconv.AppendUint(numBuf, val, 10)) } val = 0 start = i + 1 } } return b.String() } pkcs7-0.2.1/internal/legacy/x509/parser.go000066400000000000000000000766611475362641200202030ustar00rootroot00000000000000// Copyright 2021 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package legacyx509 import ( "bytes" "crypto/dsa" "crypto/ecdsa" "crypto/ed25519" "crypto/elliptic" "crypto/rsa" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "math/big" "net" "net/url" "strconv" "strings" "time" "unicode/utf16" "unicode/utf8" "golang.org/x/crypto/cryptobyte" cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1" stdx509 "crypto/x509" ) // ParseCertificates parses one or more certificates from the given ASN.1 DER // data. The certificates must be concatenated with no intermediate padding. func ParseCertificates(der []byte) ([]*stdx509.Certificate, error) { var certs []*stdx509.Certificate for len(der) > 0 { cert, err := parseCertificate(der) if err != nil { return nil, err } certs = append(certs, cert) der = der[len(cert.Raw):] } return certs, nil } // isPrintable reports whether the given b is in the ASN.1 PrintableString set. // This is a simplified version of encoding/asn1.isPrintable. func isPrintable(b byte) bool { return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || '0' <= b && b <= '9' || '\'' <= b && b <= ')' || '+' <= b && b <= '/' || b == ' ' || b == ':' || b == '=' || b == '?' || // This is technically not allowed in a PrintableString. // However, x509 certificates with wildcard strings don't // always use the correct string type so we permit it. b == '*' || // This is not technically allowed either. However, not // only is it relatively common, but there are also a // handful of CA certificates that contain it. At least // one of which will not expire until 2027. b == '&' } // parseASN1String parses the ASN.1 string types T61String, PrintableString, // UTF8String, BMPString, IA5String, and NumericString. This is mostly copied // from the respective encoding/asn1.parse... methods, rather than just // increasing the API surface of that package. func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) { switch tag { case cryptobyte_asn1.T61String: return string(value), nil case cryptobyte_asn1.PrintableString: for _, b := range value { if !isPrintable(b) { return "", errors.New("invalid PrintableString") } } return string(value), nil case cryptobyte_asn1.UTF8String: if !utf8.Valid(value) { return "", errors.New("invalid UTF-8 string") } return string(value), nil case cryptobyte_asn1.Tag(asn1.TagBMPString): if len(value)%2 != 0 { return "", errors.New("invalid BMPString") } // Strip terminator if present. if l := len(value); l >= 2 && value[l-1] == 0 && value[l-2] == 0 { value = value[:l-2] } s := make([]uint16, 0, len(value)/2) for len(value) > 0 { s = append(s, uint16(value[0])<<8+uint16(value[1])) value = value[2:] } return string(utf16.Decode(s)), nil case cryptobyte_asn1.IA5String: s := string(value) if isIA5String(s) != nil { return "", errors.New("invalid IA5String") } return s, nil case cryptobyte_asn1.Tag(asn1.TagNumericString): for _, b := range value { if !('0' <= b && b <= '9' || b == ' ') { return "", errors.New("invalid NumericString") } } return string(value), nil } return "", fmt.Errorf("unsupported string type: %v", tag) } // parseName parses a DER encoded Name as defined in RFC 5280. We may // want to export this function in the future for use in crypto/tls. func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) { if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RDNSequence") } var rdnSeq pkix.RDNSequence for !raw.Empty() { var rdnSet pkix.RelativeDistinguishedNameSET var set cryptobyte.String if !raw.ReadASN1(&set, cryptobyte_asn1.SET) { return nil, errors.New("x509: invalid RDNSequence") } for !set.Empty() { var atav cryptobyte.String if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute") } var attr pkix.AttributeTypeAndValue if !atav.ReadASN1ObjectIdentifier(&attr.Type) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute type") } var rawValue cryptobyte.String var valueTag cryptobyte_asn1.Tag if !atav.ReadAnyASN1(&rawValue, &valueTag) { return nil, errors.New("x509: invalid RDNSequence: invalid attribute value") } var err error attr.Value, err = parseASN1String(valueTag, rawValue) if err != nil { return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err) } rdnSet = append(rdnSet, attr) } rdnSeq = append(rdnSeq, rdnSet) } return &rdnSeq, nil } func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) { ai := pkix.AlgorithmIdentifier{} if !der.ReadASN1ObjectIdentifier(&ai.Algorithm) { return ai, errors.New("x509: malformed OID") } if der.Empty() { return ai, nil } var params cryptobyte.String var tag cryptobyte_asn1.Tag if !der.ReadAnyASN1Element(¶ms, &tag) { return ai, errors.New("x509: malformed parameters") } ai.Parameters.Tag = int(tag) ai.Parameters.FullBytes = params return ai, nil } func parseTime(der *cryptobyte.String) (time.Time, error) { var t time.Time switch { case der.PeekASN1Tag(cryptobyte_asn1.UTCTime): if !der.ReadASN1UTCTime(&t) { return t, errors.New("x509: malformed UTCTime") } case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime): if !der.ReadASN1GeneralizedTime(&t) { return t, errors.New("x509: malformed GeneralizedTime") } default: return t, errors.New("x509: unsupported time format") } return t, nil } func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) { notBefore, err := parseTime(&der) if err != nil { return time.Time{}, time.Time{}, err } notAfter, err := parseTime(&der) if err != nil { return time.Time{}, time.Time{}, err } return notBefore, notAfter, nil } func parseExtension(der cryptobyte.String) (pkix.Extension, error) { var ext pkix.Extension if !der.ReadASN1ObjectIdentifier(&ext.Id) { return ext, errors.New("x509: malformed extension OID field") } if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { if !der.ReadASN1Boolean(&ext.Critical) { return ext, errors.New("x509: malformed extension critical field") } } var val cryptobyte.String if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) { return ext, errors.New("x509: malformed extension value field") } ext.Value = val return ext, nil } func parsePublicKey(keyData *publicKeyInfo) (interface{}, error) { oid := keyData.Algorithm.Algorithm params := keyData.Algorithm.Parameters der := cryptobyte.String(keyData.PublicKey.RightAlign()) switch { case oid.Equal(oidPublicKeyRSA): // RSA public keys must have a NULL in the parameters. // See RFC 3279, Section 2.3.1. if !bytes.Equal(params.FullBytes, asn1.NullBytes) { return nil, errors.New("x509: RSA key missing NULL parameters") } p := &pkcs1PublicKey{N: new(big.Int)} if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid RSA public key") } if !der.ReadASN1Integer(p.N) { return nil, errors.New("x509: invalid RSA modulus") } if !der.ReadASN1Integer(&p.E) { return nil, errors.New("x509: invalid RSA public exponent") } if p.N.Sign() <= 0 { return nil, errors.New("x509: RSA modulus is not a positive number") } if p.E <= 0 { return nil, errors.New("x509: RSA public exponent is not a positive number") } pub := &rsa.PublicKey{ E: p.E, N: p.N, } return pub, nil case oid.Equal(oidPublicKeyECDSA): paramsDer := cryptobyte.String(params.FullBytes) namedCurveOID := new(asn1.ObjectIdentifier) if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) { return nil, errors.New("x509: invalid ECDSA parameters") } namedCurve := namedCurveFromOID(*namedCurveOID) if namedCurve == nil { return nil, errors.New("x509: unsupported elliptic curve") } x, y := elliptic.Unmarshal(namedCurve, der) if x == nil { return nil, errors.New("x509: failed to unmarshal elliptic curve point") } pub := &ecdsa.PublicKey{ Curve: namedCurve, X: x, Y: y, } return pub, nil case oid.Equal(oidPublicKeyEd25519): // RFC 8410, Section 3 // > For all of the OIDs, the parameters MUST be absent. if len(params.FullBytes) != 0 { return nil, errors.New("x509: Ed25519 key encoded with illegal parameters") } if len(der) != ed25519.PublicKeySize { return nil, errors.New("x509: wrong Ed25519 public key size") } return ed25519.PublicKey(der), nil // case oid.Equal(oidPublicKeyX25519): // // RFC 8410, Section 3 // // > For all of the OIDs, the parameters MUST be absent. // if len(params.FullBytes) != 0 { // return nil, errors.New("x509: X25519 key encoded with illegal parameters") // } // return ecdh.X25519().NewPublicKey(der) case oid.Equal(oidPublicKeyDSA): y := new(big.Int) if !der.ReadASN1Integer(y) { return nil, errors.New("x509: invalid DSA public key") } pub := &dsa.PublicKey{ Y: y, Parameters: dsa.Parameters{ P: new(big.Int), Q: new(big.Int), G: new(big.Int), }, } paramsDer := cryptobyte.String(params.FullBytes) if !paramsDer.ReadASN1(¶msDer, cryptobyte_asn1.SEQUENCE) || !paramsDer.ReadASN1Integer(pub.Parameters.P) || !paramsDer.ReadASN1Integer(pub.Parameters.Q) || !paramsDer.ReadASN1Integer(pub.Parameters.G) { return nil, errors.New("x509: invalid DSA parameters") } if pub.Y.Sign() <= 0 || pub.Parameters.P.Sign() <= 0 || pub.Parameters.Q.Sign() <= 0 || pub.Parameters.G.Sign() <= 0 { return nil, errors.New("x509: zero or negative DSA parameter") } return pub, nil default: return nil, errors.New("x509: unknown public key algorithm") } } func parseKeyUsageExtension(der cryptobyte.String) (stdx509.KeyUsage, error) { var usageBits asn1.BitString if !der.ReadASN1BitString(&usageBits) { return 0, errors.New("x509: invalid key usage") } var usage int for i := 0; i < 9; i++ { if usageBits.At(i) != 0 { usage |= 1 << uint(i) } } return stdx509.KeyUsage(usage), nil } func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) { var isCA bool if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return false, 0, errors.New("x509: invalid basic constraints") } if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) { if !der.ReadASN1Boolean(&isCA) { return false, 0, errors.New("x509: invalid basic constraints") } } maxPathLen := -1 if der.PeekASN1Tag(cryptobyte_asn1.INTEGER) { if !der.ReadASN1Integer(&maxPathLen) { return false, 0, errors.New("x509: invalid basic constraints") } } // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) return isCA, maxPathLen, nil } func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error { if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid subject alternative names") } for !der.Empty() { var san cryptobyte.String var tag cryptobyte_asn1.Tag if !der.ReadAnyASN1(&san, &tag) { return errors.New("x509: invalid subject alternative name") } if err := callback(int(tag^0x80), san); err != nil { return err } } return nil } func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) { err = forEachSAN(der, func(tag int, data []byte) error { switch tag { case nameTypeEmail: email := string(data) if err := isIA5String(email); err != nil { return errors.New("x509: SAN rfc822Name is malformed") } emailAddresses = append(emailAddresses, email) case nameTypeDNS: name := string(data) if err := isIA5String(name); err != nil { return errors.New("x509: SAN dNSName is malformed") } dnsNames = append(dnsNames, string(name)) case nameTypeURI: uriStr := string(data) if err := isIA5String(uriStr); err != nil { return errors.New("x509: SAN uniformResourceIdentifier is malformed") } uri, err := url.Parse(uriStr) if err != nil { return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err) } if len(uri.Host) > 0 { if _, ok := domainToReverseLabels(uri.Host); !ok { return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr) } } uris = append(uris, uri) case nameTypeIP: switch len(data) { case net.IPv4len, net.IPv6len: ipAddresses = append(ipAddresses, data) default: return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data))) } } return nil }) return } func parseAuthorityKeyIdentifier(e pkix.Extension) ([]byte, error) { // RFC 5280, Section 4.2.1.1 // if e.Critical { // // Conforming CAs MUST mark this extension as non-critical // return nil, errors.New("x509: authority key identifier incorrectly marked critical") // } val := cryptobyte.String(e.Value) var akid cryptobyte.String if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: invalid authority key identifier") } if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) { if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) { return nil, errors.New("x509: invalid authority key identifier") } return akid, nil } return nil, nil } func parseExtKeyUsageExtension(der cryptobyte.String) ([]stdx509.ExtKeyUsage, []asn1.ObjectIdentifier, error) { var extKeyUsages []stdx509.ExtKeyUsage var unknownUsages []asn1.ObjectIdentifier if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { return nil, nil, errors.New("x509: invalid extended key usages") } for !der.Empty() { var eku asn1.ObjectIdentifier if !der.ReadASN1ObjectIdentifier(&eku) { return nil, nil, errors.New("x509: invalid extended key usages") } if extKeyUsage, ok := extKeyUsageFromOID(eku); ok { extKeyUsages = append(extKeyUsages, stdx509.ExtKeyUsage(extKeyUsage)) } else { unknownUsages = append(unknownUsages, eku) } } return extKeyUsages, unknownUsages, nil } // func parseCertificatePoliciesExtension(der cryptobyte.String) ([]OID, error) { // var oids []OID // if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) { // return nil, errors.New("x509: invalid certificate policies") // } // for !der.Empty() { // var cp cryptobyte.String // var OIDBytes cryptobyte.String // if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) || !cp.ReadASN1(&OIDBytes, cryptobyte_asn1.OBJECT_IDENTIFIER) { // return nil, errors.New("x509: invalid certificate policies") // } // oid, ok := newOIDFromDER(OIDBytes) // if !ok { // return nil, errors.New("x509: invalid certificate policies") // } // oids = append(oids, oid) // } // return oids, nil // } // isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits. func isValidIPMask(mask []byte) bool { seenZero := false for _, b := range mask { if seenZero { if b != 0 { return false } continue } switch b { case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe: seenZero = true case 0xff: default: return false } } return true } func parseNameConstraintsExtension(out *stdx509.Certificate, e pkix.Extension) (unhandled bool, err error) { // RFC 5280, 4.2.1.10 // NameConstraints ::= SEQUENCE { // permittedSubtrees [0] GeneralSubtrees OPTIONAL, // excludedSubtrees [1] GeneralSubtrees OPTIONAL } // // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree // // GeneralSubtree ::= SEQUENCE { // base GeneralName, // minimum [0] BaseDistance DEFAULT 0, // maximum [1] BaseDistance OPTIONAL } // // BaseDistance ::= INTEGER (0..MAX) outer := cryptobyte.String(e.Value) var toplevel, permitted, excluded cryptobyte.String var havePermitted, haveExcluded bool if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) || !outer.Empty() || !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) || !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) || !toplevel.Empty() { return false, errors.New("x509: invalid NameConstraints extension") } if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 { // From RFC 5280, Section 4.2.1.10: // “either the permittedSubtrees field // or the excludedSubtrees MUST be // present” return false, errors.New("x509: empty name constraints extension") } getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) { for !subtrees.Empty() { var seq, value cryptobyte.String var tag cryptobyte_asn1.Tag if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) || !seq.ReadAnyASN1(&value, &tag) { return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension") } var ( dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific() emailTag = cryptobyte_asn1.Tag(1).ContextSpecific() ipTag = cryptobyte_asn1.Tag(7).ContextSpecific() uriTag = cryptobyte_asn1.Tag(6).ContextSpecific() ) switch tag { case dnsTag: domain := string(value) if err := isIA5String(domain); err != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) } trimmedDomain := domain if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { // constraints can have a leading // period to exclude the domain // itself, but that's not valid in a // normal domain name. trimmedDomain = trimmedDomain[1:] } if _, ok := domainToReverseLabels(trimmedDomain); !ok { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain) } dnsNames = append(dnsNames, domain) case ipTag: l := len(value) var ip, mask []byte switch l { case 8: ip = value[:4] mask = value[4:] case 32: ip = value[:16] mask = value[16:] default: return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l) } if !isValidIPMask(mask) { return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask) } ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)}) case emailTag: constraint := string(value) if err := isIA5String(constraint); err != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) } // If the constraint contains an @ then // it specifies an exact mailbox name. if strings.Contains(constraint, "@") { if _, ok := parseRFC2821Mailbox(constraint); !ok { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) } } else { // Otherwise it's a domain name. domain := constraint if len(domain) > 0 && domain[0] == '.' { domain = domain[1:] } if _, ok := domainToReverseLabels(domain); !ok { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint) } } emails = append(emails, constraint) case uriTag: domain := string(value) if err := isIA5String(domain); err != nil { return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error()) } if net.ParseIP(domain) != nil { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain) } trimmedDomain := domain if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' { // constraints can have a leading // period to exclude the domain itself, // but that's not valid in a normal // domain name. trimmedDomain = trimmedDomain[1:] } if _, ok := domainToReverseLabels(trimmedDomain); !ok { return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain) } uriDomains = append(uriDomains, domain) default: unhandled = true } } return dnsNames, ips, emails, uriDomains, nil } if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil { return false, err } if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil { return false, err } out.PermittedDNSDomainsCritical = e.Critical return unhandled, nil } func processExtensions(out *stdx509.Certificate) error { var err error for _, e := range out.Extensions { unhandled := false if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { switch e.Id[3] { case 15: out.KeyUsage, err = parseKeyUsageExtension(e.Value) if err != nil { return err } case 19: out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value) if err != nil { return err } out.BasicConstraintsValid = true out.MaxPathLenZero = out.MaxPathLen == 0 case 17: out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value) if err != nil { return err } if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 { // If we didn't parse anything then we do the critical check, below. unhandled = true } case 30: unhandled, err = parseNameConstraintsExtension(out, e) if err != nil { return err } case 31: // RFC 5280, 4.2.1.13 // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint // // DistributionPoint ::= SEQUENCE { // distributionPoint [0] DistributionPointName OPTIONAL, // reasons [1] ReasonFlags OPTIONAL, // cRLIssuer [2] GeneralNames OPTIONAL } // // DistributionPointName ::= CHOICE { // fullName [0] GeneralNames, // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } val := cryptobyte.String(e.Value) if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid CRL distribution points") } for !val.Empty() { var dpDER cryptobyte.String if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid CRL distribution point") } var dpNameDER cryptobyte.String var dpNamePresent bool if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } if !dpNamePresent { continue } if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } for !dpNameDER.Empty() { if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { break } var uri cryptobyte.String if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) { return errors.New("x509: invalid CRL distribution point") } out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri)) } } case 35: out.AuthorityKeyId, err = parseAuthorityKeyIdentifier(e) if err != nil { return err } case 37: out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value) if err != nil { return err } case 14: // RFC 5280, 4.2.1.2 if e.Critical { // Conforming CAs MUST mark this extension as non-critical return errors.New("x509: subject key identifier incorrectly marked critical") } val := cryptobyte.String(e.Value) var skid cryptobyte.String if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) { return errors.New("x509: invalid subject key identifier") } out.SubjectKeyId = skid // case 32: // out.Policies, err = parseCertificatePoliciesExtension(e.Value) // if err != nil { // return err // } // out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, 0, len(out.Policies)) // for _, oid := range out.Policies { // if oid, ok := oid.toASN1OID(); ok { // out.PolicyIdentifiers = append(out.PolicyIdentifiers, oid) // } // } default: // Unknown extensions are recorded if critical. unhandled = true } } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access if e.Critical { // Conforming CAs MUST mark this extension as non-critical return errors.New("x509: authority info access incorrectly marked critical") } val := cryptobyte.String(e.Value) if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") } for !val.Empty() { var aiaDER cryptobyte.String if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) { return errors.New("x509: invalid authority info access") } var method asn1.ObjectIdentifier if !aiaDER.ReadASN1ObjectIdentifier(&method) { return errors.New("x509: invalid authority info access") } if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) { continue } if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) { return errors.New("x509: invalid authority info access") } switch { case method.Equal(oidAuthorityInfoAccessOcsp): out.OCSPServer = append(out.OCSPServer, string(aiaDER)) case method.Equal(oidAuthorityInfoAccessIssuers): out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(aiaDER)) } } } else { // Unknown extensions are recorded if critical. unhandled = true } if e.Critical && unhandled { out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) } } return nil } var x509negativeserial = legacyGodebugSetting(0) // replaces godebug.New("x509negativeserial") func parseCertificate(der []byte) (*stdx509.Certificate, error) { cert := &stdx509.Certificate{} input := cryptobyte.String(der) // we read the SEQUENCE including length and tag bytes so that // we can populate Certificate.Raw, before unwrapping the // SEQUENCE so it can be operated on if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed certificate") } cert.Raw = input if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed certificate") } var tbs cryptobyte.String // do the same trick again as above to extract the raw // bytes for Certificate.RawTBSCertificate if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed tbs certificate") } cert.RawTBSCertificate = tbs if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed tbs certificate") } if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) { return nil, errors.New("x509: malformed version") } if cert.Version < 0 { return nil, errors.New("x509: malformed version") } // for backwards compat reasons Version is one-indexed, // rather than zero-indexed as defined in 5280 cert.Version++ if cert.Version > 3 { return nil, errors.New("x509: invalid version") } serial := new(big.Int) if !tbs.ReadASN1Integer(serial) { return nil, errors.New("x509: malformed serial number") } if serial.Sign() == -1 { if x509negativeserial.Value() != "1" { return nil, errors.New("x509: negative serial number") } else { x509negativeserial.IncNonDefault() } } cert.SerialNumber = serial var sigAISeq cryptobyte.String if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed signature algorithm identifier") } // Before parsing the inner algorithm identifier, extract // the outer algorithm identifier and make sure that they // match. var outerSigAISeq cryptobyte.String if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed algorithm identifier") } if !bytes.Equal(outerSigAISeq, sigAISeq) { return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match") } sigAI, err := parseAI(sigAISeq) if err != nil { return nil, err } cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI) var issuerSeq cryptobyte.String if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed issuer") } cert.RawIssuer = issuerSeq issuerRDNs, err := parseName(issuerSeq) if err != nil { return nil, err } cert.Issuer.FillFromRDNSequence(issuerRDNs) var validity cryptobyte.String if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed validity") } cert.NotBefore, cert.NotAfter, err = parseValidity(validity) if err != nil { return nil, err } var subjectSeq cryptobyte.String if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed issuer") } cert.RawSubject = subjectSeq subjectRDNs, err := parseName(subjectSeq) if err != nil { return nil, err } cert.Subject.FillFromRDNSequence(subjectRDNs) var spki cryptobyte.String if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed spki") } cert.RawSubjectPublicKeyInfo = spki if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed spki") } var pkAISeq cryptobyte.String if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed public key algorithm identifier") } pkAI, err := parseAI(pkAISeq) if err != nil { return nil, err } cert.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(pkAI.Algorithm) var spk asn1.BitString if !spki.ReadASN1BitString(&spk) { return nil, errors.New("x509: malformed subjectPublicKey") } if cert.PublicKeyAlgorithm != stdx509.UnknownPublicKeyAlgorithm { cert.PublicKey, err = parsePublicKey(&publicKeyInfo{ Algorithm: pkAI, PublicKey: spk, }) if err != nil { return nil, err } } if cert.Version > 1 { if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) { return nil, errors.New("x509: malformed issuerUniqueID") } if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) { return nil, errors.New("x509: malformed subjectUniqueID") } if cert.Version == 3 { var extensions cryptobyte.String var present bool if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) { return nil, errors.New("x509: malformed extensions") } if present { seenExts := make(map[string]bool) if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed extensions") } for !extensions.Empty() { var extension cryptobyte.String if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) { return nil, errors.New("x509: malformed extension") } ext, err := parseExtension(extension) if err != nil { return nil, err } oidStr := ext.Id.String() if seenExts[oidStr] { return nil, fmt.Errorf("x509: certificate contains duplicate extension with OID %q", oidStr) } seenExts[oidStr] = true cert.Extensions = append(cert.Extensions, ext) } err = processExtensions(cert) if err != nil { return nil, err } } } } var signature asn1.BitString if !input.ReadASN1BitString(&signature) { return nil, errors.New("x509: malformed signature") } cert.Signature = signature.RightAlign() return cert, nil } pkcs7-0.2.1/internal/legacy/x509/pkcs1.go000066400000000000000000000005061475362641200177110ustar00rootroot00000000000000// Copyright 2011 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package legacyx509 import ( "math/big" ) // pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key. type pkcs1PublicKey struct { N *big.Int E int } pkcs7-0.2.1/internal/legacy/x509/verify.go000066400000000000000000000117571475362641200202060ustar00rootroot00000000000000package legacyx509 import ( "bytes" "strings" ) // rfc2821Mailbox represents a “mailbox” (which is an email address to most // people) by breaking it into the “local” (i.e. before the '@') and “domain” // parts. type rfc2821Mailbox struct { local, domain string } // parseRFC2821Mailbox parses an email address into local and domain parts, // based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280, // Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The // format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”. func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) { if len(in) == 0 { return mailbox, false } localPartBytes := make([]byte, 0, len(in)/2) if in[0] == '"' { // Quoted-string = DQUOTE *qcontent DQUOTE // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127 // qcontent = qtext / quoted-pair // qtext = non-whitespace-control / // %d33 / %d35-91 / %d93-126 // quoted-pair = ("\" text) / obs-qp // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text // // (Names beginning with “obs-” are the obsolete syntax from RFC 2822, // Section 4. Since it has been 16 years, we no longer accept that.) in = in[1:] QuotedString: for { if len(in) == 0 { return mailbox, false } c := in[0] in = in[1:] switch { case c == '"': break QuotedString case c == '\\': // quoted-pair if len(in) == 0 { return mailbox, false } if in[0] == 11 || in[0] == 12 || (1 <= in[0] && in[0] <= 9) || (14 <= in[0] && in[0] <= 127) { localPartBytes = append(localPartBytes, in[0]) in = in[1:] } else { return mailbox, false } case c == 11 || c == 12 || // Space (char 32) is not allowed based on the // BNF, but RFC 3696 gives an example that // assumes that it is. Several “verified” // errata continue to argue about this point. // We choose to accept it. c == 32 || c == 33 || c == 127 || (1 <= c && c <= 8) || (14 <= c && c <= 31) || (35 <= c && c <= 91) || (93 <= c && c <= 126): // qtext localPartBytes = append(localPartBytes, c) default: return mailbox, false } } } else { // Atom ("." Atom)* NextChar: for len(in) > 0 { // atext from RFC 2822, Section 3.2.4 c := in[0] switch { case c == '\\': // Examples given in RFC 3696 suggest that // escaped characters can appear outside of a // quoted string. Several “verified” errata // continue to argue the point. We choose to // accept it. in = in[1:] if len(in) == 0 { return mailbox, false } fallthrough case ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '!' || c == '#' || c == '$' || c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' || c == '-' || c == '/' || c == '=' || c == '?' || c == '^' || c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || c == '~' || c == '.': localPartBytes = append(localPartBytes, in[0]) in = in[1:] default: break NextChar } } if len(localPartBytes) == 0 { return mailbox, false } // From RFC 3696, Section 3: // “period (".") may also appear, but may not be used to start // or end the local part, nor may two or more consecutive // periods appear.” twoDots := []byte{'.', '.'} if localPartBytes[0] == '.' || localPartBytes[len(localPartBytes)-1] == '.' || bytes.Contains(localPartBytes, twoDots) { return mailbox, false } } if len(in) == 0 || in[0] != '@' { return mailbox, false } in = in[1:] // The RFC species a format for domains, but that's known to be // violated in practice so we accept that anything after an '@' is the // domain part. if _, ok := domainToReverseLabels(in); !ok { return mailbox, false } mailbox.local = string(localPartBytes) mailbox.domain = in return mailbox, true } // domainToReverseLabels converts a textual domain name like foo.example.com to // the list of labels in reverse order, e.g. ["com", "example", "foo"]. func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) { for len(domain) > 0 { if i := strings.LastIndexByte(domain, '.'); i == -1 { reverseLabels = append(reverseLabels, domain) domain = "" } else { reverseLabels = append(reverseLabels, domain[i+1:]) domain = domain[:i] if i == 0 { // domain == "" // domain is prefixed with an empty label, append an empty // string to reverseLabels to indicate this. reverseLabels = append(reverseLabels, "") } } } if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 { // An empty label at the end indicates an absolute value. return nil, false } for _, label := range reverseLabels { if len(label) == 0 { // Empty labels are otherwise invalid. return nil, false } for _, c := range label { if c < 33 || c > 126 { // Invalid character. return nil, false } } } return reverseLabels, true } pkcs7-0.2.1/internal/legacy/x509/x509.go000066400000000000000000000453211475362641200174010ustar00rootroot00000000000000// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package x509 implements a subset of the X.509 standard. // // It allows parsing and generating certificates, certificate signing // requests, certificate revocation lists, and encoded public and private keys. // It provides a certificate verifier, complete with a chain builder. // // The package targets the X.509 technical profile defined by the IETF (RFC // 2459/3280/5280), and as further restricted by the CA/Browser Forum Baseline // Requirements. There is minimal support for features outside of these // profiles, as the primary goal of the package is to provide compatibility // with the publicly trusted TLS certificate ecosystem and its policies and // constraints. // // On macOS and Windows, certificate verification is handled by system APIs, but // the package aims to apply consistent validation rules across operating // systems. package legacyx509 import ( "bytes" "crypto" "crypto/elliptic" stdx509 "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "fmt" "strconv" "unicode" // Explicitly import these for their crypto.RegisterHash init side-effects. // Keep these as blank imports, even if they're imported above. _ "crypto/sha1" _ "crypto/sha256" _ "crypto/sha512" ) type publicKeyInfo struct { Raw asn1.RawContent Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } type SignatureAlgorithm int const ( UnknownSignatureAlgorithm SignatureAlgorithm = iota MD2WithRSA // Unsupported. MD5WithRSA // Only supported for signing, not verification. SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. SHA256WithRSA SHA384WithRSA SHA512WithRSA DSAWithSHA1 // Unsupported. DSAWithSHA256 // Unsupported. ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. ECDSAWithSHA256 ECDSAWithSHA384 ECDSAWithSHA512 SHA256WithRSAPSS SHA384WithRSAPSS SHA512WithRSAPSS PureEd25519 ) func (algo SignatureAlgorithm) String() string { for _, details := range signatureAlgorithmDetails { if details.algo == algo { return details.name } } return strconv.Itoa(int(algo)) } type PublicKeyAlgorithm int const ( UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota RSA DSA // Only supported for parsing. ECDSA Ed25519 ) var publicKeyAlgoName = [...]string{ RSA: "RSA", DSA: "DSA", ECDSA: "ECDSA", Ed25519: "Ed25519", } func (algo PublicKeyAlgorithm) String() string { if 0 < algo && int(algo) < len(publicKeyAlgoName) { return publicKeyAlgoName[algo] } return strconv.Itoa(int(algo)) } // OIDs for signature algorithms // // pkcs-1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } // // RFC 3279 2.2.1 RSA Signature Algorithms // // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } // // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } // // dsaWithSha1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } // // RFC 3279 2.2.3 ECDSA Signature Algorithm // // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-x962(10045) // signatures(4) ecdsa-with-SHA1(1)} // // RFC 4055 5 PKCS #1 Version 1.5 // // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } // // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } // // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } // // RFC 5758 3.1 DSA Signature Algorithms // // dsaWithSha256 OBJECT IDENTIFIER ::= { // joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) // csor(3) algorithms(4) id-dsa-with-sha2(3) 2} // // RFC 5758 3.2 ECDSA Signature Algorithm // // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } // // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } // // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } // // RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers // // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } var ( oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA // but it's specified by ISO. Microsoft's makecert.exe has been known // to produce certificates with this OID. oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} ) var signatureAlgorithmDetails = []struct { algo SignatureAlgorithm name string oid asn1.ObjectIdentifier params asn1.RawValue pubKeyAlgo PublicKeyAlgorithm hash crypto.Hash isRSAPSS bool }{ {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false}, {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false}, {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false}, {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false}, {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true}, {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true}, {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true}, {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false}, {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false}, {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false}, {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false}, {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, } var emptyRawValue = asn1.RawValue{} // DER encoded RSA PSS parameters for the // SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3. // The parameters contain the following values: // - hashAlgorithm contains the associated hash identifier with NULL parameters // - maskGenAlgorithm always contains the default mgf1SHA1 identifier // - saltLength contains the length of the associated hash // - trailerField always contains the default trailerFieldBC value var ( pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}} pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}} pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}} ) // pssParameters reflects the parameters in an AlgorithmIdentifier that // specifies RSA PSS. See RFC 3447, Appendix A.2.3. type pssParameters struct { // The following three fields are not marked as // optional because the default values specify SHA-1, // which is no longer suitable for use in signatures. Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` SaltLength int `asn1:"explicit,tag:2"` TrailerField int `asn1:"optional,explicit,tag:3,default:1"` } func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) stdx509.SignatureAlgorithm { if ai.Algorithm.Equal(oidSignatureEd25519) { // RFC 8410, Section 3 // > For all of the OIDs, the parameters MUST be absent. if len(ai.Parameters.FullBytes) != 0 { return stdx509.UnknownSignatureAlgorithm } } if !ai.Algorithm.Equal(oidSignatureRSAPSS) { for _, details := range signatureAlgorithmDetails { if ai.Algorithm.Equal(details.oid) { return stdx509.SignatureAlgorithm(details.algo) } } return stdx509.UnknownSignatureAlgorithm } // RSA PSS is special because it encodes important parameters // in the Parameters. var params pssParameters if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { return stdx509.UnknownSignatureAlgorithm } var mgf1HashFunc pkix.AlgorithmIdentifier if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { return stdx509.UnknownSignatureAlgorithm } // PSS is greatly overburdened with options. This code forces them into // three buckets by requiring that the MGF1 hash function always match the // message hash function (as recommended in RFC 3447, Section 8.1), that the // salt length matches the hash length, and that the trailer field has the // default value. if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) || !params.MGF.Algorithm.Equal(oidMGF1) || !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) || params.TrailerField != 1 { return stdx509.UnknownSignatureAlgorithm } switch { case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: return stdx509.SHA256WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: return stdx509.SHA384WithRSAPSS case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: return stdx509.SHA512WithRSAPSS } return stdx509.UnknownSignatureAlgorithm } var ( // RFC 3279, 2.3 Public Key Algorithms // // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) // rsadsi(113549) pkcs(1) 1 } // // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } // // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) // x9-57(10040) x9cm(4) 1 } oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} // RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters // // id-ecPublicKey OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} // RFC 8410, Section 3 // // id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 } // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110} oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} ) // getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm // identifier for public key types supported in certificates and CSRs. Marshal // and Parse functions may support a different set of public key types. func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) stdx509.PublicKeyAlgorithm { switch { case oid.Equal(oidPublicKeyRSA): return stdx509.RSA case oid.Equal(oidPublicKeyDSA): return stdx509.DSA case oid.Equal(oidPublicKeyECDSA): return stdx509.ECDSA case oid.Equal(oidPublicKeyEd25519): return stdx509.Ed25519 } return stdx509.UnknownPublicKeyAlgorithm } // RFC 5480, 2.1.1.1. Named Curve // // secp224r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 33 } // // secp256r1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) // prime(1) 7 } // // secp384r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 34 } // // secp521r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 35 } // // NB: secp256r1 is equivalent to prime256v1 var ( oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} ) func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { switch { case oid.Equal(oidNamedCurveP224): return elliptic.P224() case oid.Equal(oidNamedCurveP256): return elliptic.P256() case oid.Equal(oidNamedCurveP384): return elliptic.P384() case oid.Equal(oidNamedCurveP521): return elliptic.P521() } return nil } // KeyUsage represents the set of actions that are valid for a given key. It's // a bitmap of the KeyUsage* constants. type KeyUsage int const ( KeyUsageDigitalSignature KeyUsage = 1 << iota KeyUsageContentCommitment KeyUsageKeyEncipherment KeyUsageDataEncipherment KeyUsageKeyAgreement KeyUsageCertSign KeyUsageCRLSign KeyUsageEncipherOnly KeyUsageDecipherOnly ) // RFC 5280, 4.2.1.12 Extended Key Usage // // anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } // // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } // // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } // id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } // id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } var ( oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} ) // ExtKeyUsage represents an extended set of actions that are valid for a given key. // Each of the ExtKeyUsage* constants define a unique action. type ExtKeyUsage int const ( ExtKeyUsageAny ExtKeyUsage = iota ExtKeyUsageServerAuth ExtKeyUsageClientAuth ExtKeyUsageCodeSigning ExtKeyUsageEmailProtection ExtKeyUsageIPSECEndSystem ExtKeyUsageIPSECTunnel ExtKeyUsageIPSECUser ExtKeyUsageTimeStamping ExtKeyUsageOCSPSigning ExtKeyUsageMicrosoftServerGatedCrypto ExtKeyUsageNetscapeServerGatedCrypto ExtKeyUsageMicrosoftCommercialCodeSigning ExtKeyUsageMicrosoftKernelCodeSigning ) // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. var extKeyUsageOIDs = []struct { extKeyUsage ExtKeyUsage oid asn1.ObjectIdentifier }{ {ExtKeyUsageAny, oidExtKeyUsageAny}, {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, } func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { for _, pair := range extKeyUsageOIDs { if oid.Equal(pair.oid) { return pair.extKeyUsage, true } } return } const ( nameTypeEmail = 1 nameTypeDNS = 2 nameTypeURI = 6 nameTypeIP = 7 ) var ( oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} ) var ( oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} ) func isIA5String(s string) error { for _, r := range s { // Per RFC5280 "IA5String is limited to the set of ASCII characters" if r > unicode.MaxASCII { return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s) } } return nil } pkcs7-0.2.1/parse_go1.23_test.go000066400000000000000000000256721475362641200162600ustar00rootroot00000000000000//go:build go1.23 // +build go1.23 package pkcs7 import ( "encoding/base64" "testing" ) func TestParseWindowsSCEPCertificateRequest(t *testing.T) { // base64 encoded SCEP requests from a Windows device b64 := `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` data, err := base64.StdEncoding.DecodeString(b64) if err != nil { t.Errorf("failed decoding base64 SCEP request data: %v", err) } p7, err := Parse(data) if err == nil { t.Errorf("expected error while parsing SCEP request data") } if err.Error() != "x509: authority key identifier incorrectly marked critical" { t.Errorf(`expected "x509: authority key identifier incorrectly marked critical"; got "%s"`, err.Error()) } if p7 != nil { t.Errorf("expected p7 to be nil; got %v", p7) } // enable the legacy parser when Go 1.23 or newer is used, and parse it again SetFallbackLegacyX509CertificateParserEnabled(true) t.Cleanup(func() { SetFallbackLegacyX509CertificateParserEnabled(false) }) p7, err = Parse(data) if err != nil { t.Errorf("failed parsing SCEP request data with legacy X509 certificate parser enabled: %v", err) } if len(p7.Certificates) != 1 { t.Errorf("expected a single certificate; got %d", len(p7.Certificates)) } if cn := p7.Certificates[0].Subject.CommonName; cn != "SCEP Protocol Certificate" { t.Errorf("expected certificate subject common name to be SCEP Protocol Certificate; got %v", cn) } } pkcs7-0.2.1/parse_test.go000066400000000000000000000245211475362641200152570ustar00rootroot00000000000000//go:build !go1.23 // +build !go1.23 package pkcs7 import ( "encoding/base64" "testing" ) func TestParseWindowsSCEPCertificateRequest(t *testing.T) { // base64 encoded SCEP requests from a Windows device b64 := `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` data, err := base64.StdEncoding.DecodeString(b64) if err != nil { t.Errorf("failed decoding base64 SCEP request data: %v", err) } p7, err := Parse(data) if err != nil { t.Errorf("failed parsing SCEP request data: %v", err) } if len(p7.Certificates) != 1 { t.Errorf("expected a single certificate; got %d", len(p7.Certificates)) } if cn := p7.Certificates[0].Subject.CommonName; cn != "SCEP Protocol Certificate" { t.Errorf("expected certificate subject common name to be SCEP Protocol Certificate; got %v", cn) } } pkcs7-0.2.1/pkcs7.go000066400000000000000000000314701475362641200141360ustar00rootroot00000000000000// Package pkcs7 implements parsing and generation of some PKCS#7 structures. package pkcs7 import ( "bytes" "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "io" "sort" "sync" _ "crypto/sha1" // for crypto.SHA1 legacyx509 "github.com/smallstep/pkcs7/internal/legacy/x509" ) // PKCS7 Represents a PKCS7 structure type PKCS7 struct { Content []byte Certificates []*x509.Certificate CRLs []pkix.CertificateList Signers []signerInfo Hasher Hasher raw interface{} } // Hasher is an interface defining a custom hash calculator. type Hasher interface { Hash(crypto.Hash, io.Reader) ([]byte, error) } type contentInfo struct { ContentType asn1.ObjectIdentifier Content asn1.RawValue `asn1:"explicit,optional,tag:0"` } // ErrUnsupportedContentType is returned when a PKCS7 content type is not supported. // Currently only Data (1.2.840.113549.1.7.1), Signed Data (1.2.840.113549.1.7.2), // and Enveloped Data are supported (1.2.840.113549.1.7.3) var ErrUnsupportedContentType = errors.New("pkcs7: cannot parse data: unimplemented content type") type unsignedData []byte var ( // Signed Data OIDs OIDData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 1} OIDSignedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 2} OIDEnvelopedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 3} OIDEncryptedData = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 7, 6} OIDAttributeContentType = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 3} OIDAttributeMessageDigest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 4} OIDAttributeSigningTime = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 5} // Digest Algorithms OIDDigestAlgorithmSHA1 = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 26} OIDDigestAlgorithmSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} OIDDigestAlgorithmSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} OIDDigestAlgorithmSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} OIDDigestAlgorithmSHA224 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 4} OIDDigestAlgorithmDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} OIDDigestAlgorithmDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} OIDDigestAlgorithmECDSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} OIDDigestAlgorithmECDSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} OIDDigestAlgorithmECDSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} OIDDigestAlgorithmECDSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} // Signature Algorithms OIDEncryptionAlgorithmRSAMD5 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} // see https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.4 OIDEncryptionAlgorithmRSASHA1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} // ditto OIDEncryptionAlgorithmRSASHA256 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} // ditto OIDEncryptionAlgorithmRSASHA384 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} // ditto OIDEncryptionAlgorithmRSASHA512 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} // ditto OIDEncryptionAlgorithmRSASHA224 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 14} // ditto OIDEncryptionAlgorithmECDSAP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} OIDEncryptionAlgorithmECDSAP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} OIDEncryptionAlgorithmECDSAP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} // Asymmetric Encryption Algorithms OIDEncryptionAlgorithmRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} // see https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.2 OIDEncryptionAlgorithmRSAESOAEP = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 7} // see https://www.rfc-editor.org/rfc/rfc8017#appendix-A.2.1 // Symmetric Encryption Algorithms OIDEncryptionAlgorithmDESCBC = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 7} // see https://www.rfc-editor.org/rfc/rfc8018.html#appendix-B.2.1 OIDEncryptionAlgorithmDESEDE3CBC = asn1.ObjectIdentifier{1, 2, 840, 113549, 3, 7} // see https://www.rfc-editor.org/rfc/rfc8018.html#appendix-B.2.2 OIDEncryptionAlgorithmAES256CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 42} // see https://www.rfc-editor.org/rfc/rfc3565.html#section-4.1 OIDEncryptionAlgorithmAES128GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 6} // see https://www.rfc-editor.org/rfc/rfc5084.html#section-3.2 OIDEncryptionAlgorithmAES128CBC = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 2} // see https://www.rfc-editor.org/rfc/rfc8018.html#appendix-B.2.5 OIDEncryptionAlgorithmAES256GCM = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 1, 46} // see https://www.rfc-editor.org/rfc/rfc5084.html#section-3.2 ) func getHashForOID(oid asn1.ObjectIdentifier) (crypto.Hash, error) { switch { case oid.Equal(OIDDigestAlgorithmSHA1), oid.Equal(OIDDigestAlgorithmECDSASHA1), oid.Equal(OIDDigestAlgorithmDSA), oid.Equal(OIDDigestAlgorithmDSASHA1), oid.Equal(OIDEncryptionAlgorithmRSA): return crypto.SHA1, nil case oid.Equal(OIDDigestAlgorithmSHA256), oid.Equal(OIDDigestAlgorithmECDSASHA256): return crypto.SHA256, nil case oid.Equal(OIDDigestAlgorithmSHA384), oid.Equal(OIDDigestAlgorithmECDSASHA384): return crypto.SHA384, nil case oid.Equal(OIDDigestAlgorithmSHA512), oid.Equal(OIDDigestAlgorithmECDSASHA512): return crypto.SHA512, nil } return crypto.Hash(0), ErrUnsupportedAlgorithm } // getDigestOIDForSignatureAlgorithm takes an x509.SignatureAlgorithm // and returns the corresponding OID digest algorithm func getDigestOIDForSignatureAlgorithm(digestAlg x509.SignatureAlgorithm) (asn1.ObjectIdentifier, error) { switch digestAlg { case x509.SHA1WithRSA, x509.ECDSAWithSHA1: return OIDDigestAlgorithmSHA1, nil case x509.SHA256WithRSA, x509.ECDSAWithSHA256: return OIDDigestAlgorithmSHA256, nil case x509.SHA384WithRSA, x509.ECDSAWithSHA384: return OIDDigestAlgorithmSHA384, nil case x509.SHA512WithRSA, x509.ECDSAWithSHA512: return OIDDigestAlgorithmSHA512, nil } return nil, fmt.Errorf("pkcs7: cannot convert hash to oid, unknown hash algorithm") } // getOIDForEncryptionAlgorithm takes the public or private key type of the signer and // the OID of a digest algorithm to return the appropriate signerInfo.DigestEncryptionAlgorithm func getOIDForEncryptionAlgorithm(pkey interface{}, OIDDigestAlg asn1.ObjectIdentifier) (asn1.ObjectIdentifier, error) { switch k := pkey.(type) { case *rsa.PrivateKey, *rsa.PublicKey: switch { default: return OIDEncryptionAlgorithmRSA, nil case OIDDigestAlg.Equal(OIDEncryptionAlgorithmRSA): return OIDEncryptionAlgorithmRSA, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1): return OIDEncryptionAlgorithmRSASHA1, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256): return OIDEncryptionAlgorithmRSASHA256, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384): return OIDEncryptionAlgorithmRSASHA384, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512): return OIDEncryptionAlgorithmRSASHA512, nil } case *ecdsa.PrivateKey, *ecdsa.PublicKey: switch { case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA1): return OIDDigestAlgorithmECDSASHA1, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA256): return OIDDigestAlgorithmECDSASHA256, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA384): return OIDDigestAlgorithmECDSASHA384, nil case OIDDigestAlg.Equal(OIDDigestAlgorithmSHA512): return OIDDigestAlgorithmECDSASHA512, nil } case *dsa.PrivateKey, *dsa.PublicKey: return OIDDigestAlgorithmDSA, nil case crypto.Signer: // This generic case is here to cover types from other packages. It // was specifically added to handle the private keyRSA type in the // github.com/go-piv/piv-go/piv package. return getOIDForEncryptionAlgorithm(k.Public(), OIDDigestAlg) } return nil, fmt.Errorf("pkcs7: cannot convert encryption algorithm to oid, unknown private key type %T", pkey) } // Parse decodes a DER encoded PKCS7 package func Parse(data []byte) (p7 *PKCS7, err error) { if len(data) == 0 { return nil, errors.New("pkcs7: input data is empty") } var info contentInfo der, err := ber2der(data) if err != nil { return nil, err } rest, err := asn1.Unmarshal(der, &info) if len(rest) > 0 { err = asn1.SyntaxError{Msg: "trailing data"} return } if err != nil { return } // fmt.Printf("--> Content Type: %s", info.ContentType) switch { case info.ContentType.Equal(OIDSignedData): return parseSignedData(info.Content.Bytes) case info.ContentType.Equal(OIDEnvelopedData): return parseEnvelopedData(info.Content.Bytes) case info.ContentType.Equal(OIDEncryptedData): return parseEncryptedData(info.Content.Bytes) } return nil, ErrUnsupportedContentType } func parseEnvelopedData(data []byte) (*PKCS7, error) { var ed envelopedData if _, err := asn1.Unmarshal(data, &ed); err != nil { return nil, err } return &PKCS7{ raw: ed, }, nil } func parseEncryptedData(data []byte) (*PKCS7, error) { var ed encryptedData if _, err := asn1.Unmarshal(data, &ed); err != nil { return nil, err } return &PKCS7{ raw: ed, }, nil } // SetFallbackLegacyX509CertificateParserEnabled enables parsing certificates // embedded in a PKCS7 message using the logic from crypto/x509 from before // Go 1.23. Go 1.23 introduced a breaking change in case a certificate contains // a critical authority key identifier, which is the correct thing to do based // on RFC 5280, but it breaks Windows devices performing the Simple Certificate // Enrolment Protocol (SCEP), as the certificates embedded in those requests // apparently have authority key identifier extensions marked critical. // // See https://go-review.googlesource.com/c/go/+/562341 for the change in the // Go source. // // When [SetFallbackLegacyX509CertificateParserEnabled] is called with true, it // enables parsing using the legacy crypto/x509 certificate parser. It'll first // try to parse the certificates using the regular Go crypto/x509 package, but // if it fails on the above case, it'll retry parsing the certificates using a // copy of the crypto/x509 package based on Go 1.23, but skips checking the // authority key identifier extension being critical or not. func SetFallbackLegacyX509CertificateParserEnabled(v bool) { legacyX509CertificateParser.Lock() legacyX509CertificateParser.enabled = v legacyX509CertificateParser.Unlock() } var legacyX509CertificateParser struct { sync.RWMutex enabled bool } func isLegacyX509ParserEnabled() bool { legacyX509CertificateParser.RLock() defer legacyX509CertificateParser.RUnlock() return legacyX509CertificateParser.enabled } func (raw rawCertificates) Parse() ([]*x509.Certificate, error) { if len(raw.Raw) == 0 { return nil, nil } var val asn1.RawValue if _, err := asn1.Unmarshal(raw.Raw, &val); err != nil { return nil, err } certificates, err := x509.ParseCertificates(val.Bytes) if err != nil && err.Error() == "x509: authority key identifier incorrectly marked critical" { if isLegacyX509ParserEnabled() { certificates, err = legacyx509.ParseCertificates(val.Bytes) } } return certificates, err } func isCertMatchForIssuerAndSerial(cert *x509.Certificate, ias issuerAndSerial) bool { return cert.SerialNumber.Cmp(ias.SerialNumber) == 0 && bytes.Equal(cert.RawIssuer, ias.IssuerName.FullBytes) } // Attribute represents a key value pair attribute. Value must be marshalable byte // `encoding/asn1` type Attribute struct { Type asn1.ObjectIdentifier Value interface{} } type attributes struct { types []asn1.ObjectIdentifier values []interface{} } // Add adds the attribute, maintaining insertion order func (attrs *attributes) Add(attrType asn1.ObjectIdentifier, value interface{}) { attrs.types = append(attrs.types, attrType) attrs.values = append(attrs.values, value) } type sortableAttribute struct { SortKey []byte Attribute attribute } type attributeSet []sortableAttribute func (sa attributeSet) Len() int { return len(sa) } func (sa attributeSet) Less(i, j int) bool { return bytes.Compare(sa[i].SortKey, sa[j].SortKey) < 0 } func (sa attributeSet) Swap(i, j int) { sa[i], sa[j] = sa[j], sa[i] } func (sa attributeSet) Attributes() []attribute { attrs := make([]attribute, len(sa)) for i, attr := range sa { attrs[i] = attr.Attribute } return attrs } func (attrs *attributes) ForMarshalling() ([]attribute, error) { sortables := make(attributeSet, len(attrs.types)) for i := range sortables { attrType := attrs.types[i] attrValue := attrs.values[i] asn1Value, err := asn1.Marshal(attrValue) if err != nil { return nil, err } attr := attribute{ Type: attrType, Value: asn1.RawValue{Tag: 17, IsCompound: true, Bytes: asn1Value}, // 17 == SET tag } encoded, err := asn1.Marshal(attr) if err != nil { return nil, err } sortables[i] = sortableAttribute{ SortKey: encoded, Attribute: attr, } } sort.Sort(sortables) return sortables.Attributes(), nil } pkcs7-0.2.1/pkcs7_test.go000066400000000000000000000436221475362641200151770ustar00rootroot00000000000000package pkcs7 import ( "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "log" "math/big" "os" "time" ) var test1024Key, test2048Key, test3072Key, test4096Key *rsa.PrivateKey func init() { test1024Key = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: fromBase10("123024078101403810516614073341068864574068590522569345017786163424062310013967742924377390210586226651760719671658568413826602264886073432535341149584680111145880576802262550990305759285883150470245429547886689754596541046564560506544976611114898883158121012232676781340602508151730773214407220733898059285561"), E: 65537, }, D: fromBase10("118892427340746627750435157989073921703209000249285930635312944544706203626114423392257295670807166199489096863209592887347935991101581502404113203993092422730000157893515953622392722273095289787303943046491132467130346663160540744582438810535626328230098940583296878135092036661410664695896115177534496784545"), Primes: []*big.Int{ fromBase10("12172745919282672373981903347443034348576729562395784527365032103134165674508405592530417723266847908118361582847315228810176708212888860333051929276459099"), fromBase10("10106518193772789699356660087736308350857919389391620140340519320928952625438936098550728858345355053201610649202713962702543058578827268756755006576249339"), }, } test1024Key.Precompute() test2048Key = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: fromBase10("14314132931241006650998084889274020608918049032671858325988396851334124245188214251956198731333464217832226406088020736932173064754214329009979944037640912127943488972644697423190955557435910767690712778463524983667852819010259499695177313115447116110358524558307947613422897787329221478860907963827160223559690523660574329011927531289655711860504630573766609239332569210831325633840174683944553667352219670930408593321661375473885147973879086994006440025257225431977751512374815915392249179976902953721486040787792801849818254465486633791826766873076617116727073077821584676715609985777563958286637185868165868520557"), E: 3, }, D: fromBase10("9542755287494004433998723259516013739278699355114572217325597900889416163458809501304132487555642811888150937392013824621448709836142886006653296025093941418628992648429798282127303704957273845127141852309016655778568546006839666463451542076964744073572349705538631742281931858219480985907271975884773482372966847639853897890615456605598071088189838676728836833012254065983259638538107719766738032720239892094196108713378822882383694456030043492571063441943847195939549773271694647657549658603365629458610273821292232646334717612674519997533901052790334279661754176490593041941863932308687197618671528035670452762731"), Primes: []*big.Int{ fromBase10("130903255182996722426771613606077755295583329135067340152947172868415809027537376306193179624298874215608270802054347609836776473930072411958753044562214537013874103802006369634761074377213995983876788718033850153719421695468704276694983032644416930879093914927146648402139231293035971427838068945045019075433"), fromBase10("109348945610485453577574767652527472924289229538286649661240938988020367005475727988253438647560958573506159449538793540472829815903949343191091817779240101054552748665267574271163617694640513549693841337820602726596756351006149518830932261246698766355347898158548465400674856021497190430791824869615170301029"), }, } test2048Key.Precompute() test3072Key = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: fromBase10("4799422180968749215324244710281712119910779465109490663934897082847293004098645365195947978124390029272750644394844443980065532911010718425428791498896288210928474905407341584968381379157418577471272697781778686372450913810019702928839200328075568223462554606149618941566459398862673532997592879359280754226882565483298027678735544377401276021471356093819491755877827249763065753555051973844057308627201762456191918852016986546071426986328720794061622370410645440235373576002278045257207695462423797272017386006110722769072206022723167102083033531426777518054025826800254337147514768377949097720074878744769255210076910190151785807232805749219196645305822228090875616900385866236956058984170647782567907618713309775105943700661530312800231153745705977436176908325539234432407050398510090070342851489496464612052853185583222422124535243967989533830816012180864309784486694786581956050902756173889941244024888811572094961378021"), E: 65537, }, D: fromBase10("4068124900056380177006532461065648259352178312499768312132802353620854992915205894105621345694615110794369150964768050224096623567443679436821868510233726084582567244003894477723706516831312989564775159596496449435830457803384416702014837685962523313266832032687145914871879794104404800823188153886925022171560391765913739346955738372354826804228989767120353182641396181570533678315099748218734875742705419933837638038793286534641711407564379950728858267828581787483317040753987167237461567332386718574803231955771633274184646232632371006762852623964054645811527580417392163873708539175349637050049959954373319861427407953413018816604365474462455009323937599275324390953644555294418021286807661559165324810415569396577697316798600308544755741549699523972971375304826663847015905713096287495342701286542193782001358775773848824496321550110946106870685499577993864871847542645561943034990484973293461948058147956373115641615329"), Primes: []*big.Int{ fromBase10("2378529069722721185825622840841310902793949682948530343491428052737890236476884657507685118578733560141370511507721598189068683665232991988491561624429938984370132428230072355214627085652359350722926394699707232921674771664421591347888367477300909202851476404132163673865768760147403525700174918450753162242834161458300343282159799476695001920226357456953682236859505243928716782707623075239350380352265954107362618991716602898266999700316937680986690964564264877"), fromBase10("2017811025336026464312837780072272578817919741496395062543647660689775637351085991504709917848745137013798005682591633910555599626950744674459976829106750083386168859581016361317479081273480343110649405858059581933773354781034946787147300862495438979895430001323443224335618577322449133208754541656374335100929456885995320929464029817626916719434010943205170760536768893924932021302887114400922813817969176636993508191950649313115712159241971065134077636674146073"), }, } test3072Key.Precompute() test4096Key = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ N: fromBase10("633335480064287130853997429184971616419051348693342219741748040433588285601270210251206421401040394238592139790962887290698043839174341843721930134010306454716566698330215646704263665452264344664385995704186692432827662862845900348526672531755932642433662686500295989783595767573119607065791980381547677840410600100715146047382485989885183858757974681241303484641390718944520330953604501686666386926996348457928415093305041429178744778762826377713889019740060910363468343855830206640274442887621960581569183233822878661711798998132931623726434336448716605363514220760343097572198620479297583609779817750646169845195672483600293522186340560792255595411601450766002877850696008003794520089358819042318331840490155176019070646738739580486357084733208876620846449161909966690602374519398451042362690200166144326179405976024265116931974936425064291406950542193873313447617169603706868220189295654943247311295475722243471700112334609817776430552541319671117235957754556272646031356496763094955985615723596562217985372503002989591679252640940571608314743271809251568670314461039035793703429977801961867815257832671786542212589906513979094156334941265621017752516999186481477500481433634914622735206243841674973785078408289183000133399026553"), E: 65537, }, D: fromBase10("439373650557744155078930178606343279553665694488479749802070836418412881168612407941793966086633543867614175621952769177088930851151267623886678906158545451731745754402575409204816390946376103491325109185445659065122640946673660760274557781540431107937331701243915001777636528502669576801704352961341634812275635811512806966908648671988644114352046582195051714797831307925775689566757438907578527366568747104508496278929566712224252103563340770696548181508180254674236716995730292431858611476396845443056967589437890065663497768422598977743046882539288481002449571403783500529740184608873520856954837631427724158592309018382711485601884461168736465751756282510065053161144027097169985941910909130083273691945578478173708396726266170473745329617793866669307716920992380350270584929908460462802627239204245339385636926433446418108504614031393494119344916828744888432279343816084433424594432427362258172264834429525166677273382617457205387388293888430391895615438030066428745187333897518037597413369705720436392869403948934993623418405908467147848576977008003556716087129242155836114780890054057743164411952731290520995017097151300091841286806603044227906213832083363876549637037625314539090155417589796428888619937329669464810549362433"), Primes: []*big.Int{ fromBase10("25745433817240673759910623230144796182285844101796353869339294232644316274580053211056707671663014355388701931204078502829809738396303142990312095225333440050808647355535878394534263839500592870406002873182360027755750148248672968563366185348499498613479490545488025779331426515670185366021612402246813511722553210128074701620113404560399242413747318161403908617342170447610792422053460359960010544593668037305465806912471260799852789913123044326555978680190904164976511331681163576833618899773550873682147782263100803907156362439021929408298804955194748640633152519828940133338948391986823456836070708197320166146761"), fromBase10("24599914864909676687852658457515103765368967514652318497893275892114442089314173678877914038802355565271545910572804267918959612739009937926962653912943833939518967731764560204997062096919833970670512726396663920955497151415639902788974842698619579886297871162402643104696160155894685518587660015182381685605752989716946154299190561137541792784125356553411300817844325739404126956793095254412123887617931225840421856505925283322918693259047428656823141903489964287619982295891439430302405252447010728112098326033634688757933930065610737780413018498561434074501822951716586796047404555397992425143397497639322075233073"), }, } test4096Key.Precompute() } func fromBase10(base10 string) *big.Int { i, ok := new(big.Int).SetString(base10, 10) if !ok { panic("bad number: " + base10) } return i } type certKeyPair struct { Certificate *x509.Certificate PrivateKey *crypto.PrivateKey } func createTestCertificate(sigAlg x509.SignatureAlgorithm) (certKeyPair, error) { signer, err := createTestCertificateByIssuer("Eddard Stark", nil, sigAlg, true) if err != nil { return certKeyPair{}, err } pair, err := createTestCertificateByIssuer("Jon Snow", signer, sigAlg, false) if err != nil { return certKeyPair{}, err } return *pair, nil } func createTestCertificateByIssuer(name string, issuer *certKeyPair, sigAlg x509.SignatureAlgorithm, isCA bool) (*certKeyPair, error) { var ( err error priv crypto.PrivateKey derCert []byte issuerCert *x509.Certificate issuerKey crypto.PrivateKey ) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 32) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { return nil, err } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ CommonName: name, Organization: []string{"Acme Co"}, }, NotBefore: time.Now().Add(-1 * time.Second), NotAfter: time.Now().AddDate(1, 0, 0), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}, } if issuer != nil { issuerCert = issuer.Certificate issuerKey = *issuer.PrivateKey } switch sigAlg { case x509.SHA1WithRSA: priv = test1024Key switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA1WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA1 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA1 } case x509.SHA256WithRSA: priv = test2048Key switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA256WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA256 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } case x509.SHA384WithRSA: priv = test3072Key switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA384WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA384 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } case x509.SHA512WithRSA: priv = test4096Key switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA512WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA512 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } case x509.ECDSAWithSHA1: priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, err } switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA1WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA1 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA1 } case x509.ECDSAWithSHA256: priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, err } switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA256WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA256 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } case x509.ECDSAWithSHA384: priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) if err != nil { return nil, err } switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA384WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA384 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } case x509.ECDSAWithSHA512: priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) if err != nil { return nil, err } switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA512WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA512 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA256 } case x509.DSAWithSHA1: var dsaPriv dsa.PrivateKey params := &dsaPriv.Parameters err = dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160) if err != nil { return nil, err } err = dsa.GenerateKey(&dsaPriv, rand.Reader) if err != nil { return nil, err } switch issuerKey.(type) { case *rsa.PrivateKey: template.SignatureAlgorithm = x509.SHA1WithRSA case *ecdsa.PrivateKey: template.SignatureAlgorithm = x509.ECDSAWithSHA1 case *dsa.PrivateKey: template.SignatureAlgorithm = x509.DSAWithSHA1 } priv = &dsaPriv } if isCA { template.IsCA = true template.KeyUsage |= x509.KeyUsageCertSign template.BasicConstraintsValid = true } if issuer == nil { // no issuer given,make this a self-signed root cert issuerCert = &template issuerKey = priv } log.Println("creating cert", name, "issued by", issuerCert.Subject.CommonName, "with sigalg", sigAlg) switch priv.(type) { case *rsa.PrivateKey: switch issuerKey.(type) { case *rsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey.(*rsa.PrivateKey)) case *ecdsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey.(*ecdsa.PrivateKey)) case *dsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*rsa.PrivateKey).Public(), issuerKey.(*dsa.PrivateKey)) } case *ecdsa.PrivateKey: switch issuerKey.(type) { case *rsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey.(*rsa.PrivateKey)) case *ecdsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey.(*ecdsa.PrivateKey)) case *dsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*ecdsa.PrivateKey).Public(), issuerKey.(*dsa.PrivateKey)) } case *dsa.PrivateKey: pub := &priv.(*dsa.PrivateKey).PublicKey switch issuerKey := issuerKey.(type) { case *rsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, pub, issuerKey) case *ecdsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*dsa.PublicKey), issuerKey) case *dsa.PrivateKey: derCert, err = x509.CreateCertificate(rand.Reader, &template, issuerCert, priv.(*dsa.PublicKey), issuerKey) } } if err != nil { return nil, err } if len(derCert) == 0 { return nil, fmt.Errorf("no certificate created, probably due to wrong keys. types were %T and %T", priv, issuerKey) } cert, err := x509.ParseCertificate(derCert) if err != nil { return nil, err } pem.Encode(os.Stdout, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}) return &certKeyPair{ Certificate: cert, PrivateKey: &priv, }, nil } type TestFixture struct { Input []byte Certificate *x509.Certificate PrivateKey *rsa.PrivateKey } func UnmarshalTestFixture(testPEMBlock string) TestFixture { var result TestFixture var derBlock *pem.Block var pemBlock = []byte(testPEMBlock) for { derBlock, pemBlock = pem.Decode(pemBlock) if derBlock == nil { break } switch derBlock.Type { case "PKCS7": result.Input = derBlock.Bytes case "CERTIFICATE": result.Certificate, _ = x509.ParseCertificate(derBlock.Bytes) case "RSA PRIVATE KEY": result.PrivateKey, _ = x509.ParsePKCS1PrivateKey(derBlock.Bytes) } } return result } pkcs7-0.2.1/sign.go000066400000000000000000000356021475362641200140500ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/dsa" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "math/big" "sync" "time" ) func init() { defaultMessageDigestAlgorithm.oid = OIDDigestAlgorithmSHA1 } var defaultMessageDigestAlgorithm struct { sync.RWMutex oid asn1.ObjectIdentifier } // SetDefaultDigestAlgorithm sets the default digest algorithm // to be used for signing operations on [SignedData]. // // This must be called before creating a new instance of [SignedData] // using [NewSignedData]. // // When this function is not called, the default digest algorithm is SHA1. func SetDefaultDigestAlgorithm(d asn1.ObjectIdentifier) error { defaultMessageDigestAlgorithm.Lock() defer defaultMessageDigestAlgorithm.Unlock() switch { case d.Equal(OIDDigestAlgorithmSHA1), d.Equal(OIDDigestAlgorithmSHA224), d.Equal(OIDDigestAlgorithmSHA256), d.Equal(OIDDigestAlgorithmSHA384), d.Equal(OIDDigestAlgorithmSHA512), d.Equal(OIDDigestAlgorithmDSA), d.Equal(OIDDigestAlgorithmDSASHA1), d.Equal(OIDDigestAlgorithmECDSASHA1), d.Equal(OIDDigestAlgorithmECDSASHA256), d.Equal(OIDDigestAlgorithmECDSASHA384), d.Equal(OIDDigestAlgorithmECDSASHA512): break default: return fmt.Errorf("unsupported message digest algorithm %v", d) } defaultMessageDigestAlgorithm.oid = d return nil } func defaultMessageDigestAlgorithmOID() asn1.ObjectIdentifier { defaultMessageDigestAlgorithm.RLock() defer defaultMessageDigestAlgorithm.RUnlock() return defaultMessageDigestAlgorithm.oid } // 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: defaultMessageDigestAlgorithmOID()}, nil } // SignerInfoConfig are optional values to include when adding a signer type SignerInfoConfig struct { ExtraSignedAttributes []Attribute ExtraUnsignedAttributes []Attribute } type signedData struct { Version int `asn1:"default:1"` DigestAlgorithmIdentifiers []pkix.AlgorithmIdentifier `asn1:"set"` ContentInfo contentInfo Certificates rawCertificates `asn1:"optional,tag:0"` CRLs []pkix.CertificateList `asn1:"optional,tag:1"` SignerInfos []signerInfo `asn1:"set"` } type signerInfo struct { Version int `asn1:"default:1"` IssuerAndSerialNumber issuerAndSerial DigestAlgorithm pkix.AlgorithmIdentifier AuthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:0"` DigestEncryptionAlgorithm pkix.AlgorithmIdentifier EncryptedDigest []byte UnauthenticatedAttributes []attribute `asn1:"optional,omitempty,tag:1"` } type attribute struct { Type asn1.ObjectIdentifier Value asn1.RawValue `asn1:"set"` } func marshalAttributes(attrs []attribute) ([]byte, error) { encodedAttributes, err := asn1.Marshal(struct { A []attribute `asn1:"set"` }{A: attrs}) if err != nil { return nil, err } // Remove the leading sequence octets var raw asn1.RawValue asn1.Unmarshal(encodedAttributes, &raw) return raw.Bytes, nil } type rawCertificates struct { Raw asn1.RawContent } type issuerAndSerial struct { IssuerName asn1.RawValue SerialNumber *big.Int } // SetDigestAlgorithm sets the digest algorithm to be used in the signing process. // // This should be called before adding signers func (sd *SignedData) SetDigestAlgorithm(d asn1.ObjectIdentifier) { sd.digestOid = d } // SetEncryptionAlgorithm sets the encryption algorithm to be used in the signing process. // // This should be called before adding signers func (sd *SignedData) SetEncryptionAlgorithm(d asn1.ObjectIdentifier) { sd.encryptionOid = d } // AddSigner is a wrapper around AddSignerChain() that adds a signer without any parent. func (sd *SignedData) AddSigner(ee *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error { var parents []*x509.Certificate return sd.AddSignerChain(ee, pkey, parents, config) } // AddSignerChain signs attributes about the content and adds certificates // and signers infos to the Signed Data. The certificate and private key // of the end-entity signer are used to issue the signature, and any // parent of that end-entity that need to be added to the list of // certifications can be specified in the parents slice. // // The signature algorithm used to hash the data is the one of the end-entity // certificate. func (sd *SignedData) AddSignerChain(ee *x509.Certificate, pkey crypto.PrivateKey, parents []*x509.Certificate, config SignerInfoConfig) error { // Following RFC 2315, 9.2 SignerInfo type, the distinguished name of // the issuer of the end-entity signer is stored in the issuerAndSerialNumber // section of the SignedData.SignerInfo, alongside the serial number of // the end-entity. var ias issuerAndSerial ias.SerialNumber = ee.SerialNumber if len(parents) == 0 { // no parent, the issuer is the end-entity cert itself ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer} } else { err := verifyPartialChain(ee, parents) if err != nil { return err } // the first parent is the issuer ias.IssuerName = asn1.RawValue{FullBytes: parents[0].RawSubject} } sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers, pkix.AlgorithmIdentifier{Algorithm: sd.digestOid}, ) hash, err := getHashForOID(sd.digestOid) if err != nil { return err } h := hash.New() h.Write(sd.data) sd.messageDigest = h.Sum(nil) encryptionOid, err := getOIDForEncryptionAlgorithm(pkey, sd.digestOid) if err != nil { return err } attrs := &attributes{} attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType) attrs.Add(OIDAttributeMessageDigest, sd.messageDigest) attrs.Add(OIDAttributeSigningTime, time.Now().UTC()) for _, attr := range config.ExtraSignedAttributes { attrs.Add(attr.Type, attr.Value) } finalAttrs, err := attrs.ForMarshalling() if err != nil { return err } unsignedAttrs := &attributes{} for _, attr := range config.ExtraUnsignedAttributes { unsignedAttrs.Add(attr.Type, attr.Value) } finalUnsignedAttrs, err := unsignedAttrs.ForMarshalling() if err != nil { return err } // create signature of signed attributes signature, err := signAttributes(finalAttrs, pkey, hash) if err != nil { return err } signer := signerInfo{ AuthenticatedAttributes: finalAttrs, UnauthenticatedAttributes: finalUnsignedAttrs, DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid}, DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: encryptionOid}, IssuerAndSerialNumber: ias, EncryptedDigest: signature, Version: 1, } sd.certs = append(sd.certs, ee) if len(parents) > 0 { sd.certs = append(sd.certs, parents...) } sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer) return nil } // SignWithoutAttr issues a signature on the content of the pkcs7 SignedData. // Unlike AddSigner/AddSignerChain, it calculates the digest on the data alone // and does not include any signed attributes like timestamp and so on. // // This function is needed to sign old Android APKs, something you probably // shouldn't do unless you're maintaining backward compatibility for old // applications. func (sd *SignedData) SignWithoutAttr(ee *x509.Certificate, pkey crypto.PrivateKey, config SignerInfoConfig) error { var signature []byte sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers, pkix.AlgorithmIdentifier{Algorithm: sd.digestOid}) hash, err := getHashForOID(sd.digestOid) if err != nil { return err } h := hash.New() h.Write(sd.data) sd.messageDigest = h.Sum(nil) switch pkey := pkey.(type) { case *dsa.PrivateKey: // dsa doesn't implement crypto.Signer so we make a special case // https://github.com/golang/go/issues/27889 r, s, err := dsa.Sign(rand.Reader, pkey, sd.messageDigest) if err != nil { return err } signature, err = asn1.Marshal(dsaSignature{r, s}) if err != nil { return err } default: key, ok := pkey.(crypto.Signer) if !ok { return errors.New("pkcs7: private key does not implement crypto.Signer") } signature, err = key.Sign(rand.Reader, sd.messageDigest, hash) if err != nil { return err } } var ias issuerAndSerial ias.SerialNumber = ee.SerialNumber // no parent, the issue is the end-entity cert itself ias.IssuerName = asn1.RawValue{FullBytes: ee.RawIssuer} if sd.encryptionOid == nil { // if the encryption algorithm wasn't set by SetEncryptionAlgorithm, // infer it from the digest algorithm sd.encryptionOid, err = getOIDForEncryptionAlgorithm(pkey, sd.digestOid) } if err != nil { return err } signer := signerInfo{ DigestAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.digestOid}, DigestEncryptionAlgorithm: pkix.AlgorithmIdentifier{Algorithm: sd.encryptionOid}, IssuerAndSerialNumber: ias, EncryptedDigest: signature, Version: 1, } // create signature of signed attributes sd.certs = append(sd.certs, ee) sd.sd.SignerInfos = append(sd.sd.SignerInfos, signer) return nil } func (si *signerInfo) SetUnauthenticatedAttributes(extraUnsignedAttrs []Attribute) error { unsignedAttrs := &attributes{} for _, attr := range extraUnsignedAttrs { unsignedAttrs.Add(attr.Type, attr.Value) } finalUnsignedAttrs, err := unsignedAttrs.ForMarshalling() if err != nil { return err } si.UnauthenticatedAttributes = finalUnsignedAttrs return nil } // AddCertificate adds the certificate to the payload. Useful for parent certificates func (sd *SignedData) AddCertificate(cert *x509.Certificate) { sd.certs = append(sd.certs, cert) } // Detach removes content from the signed data struct to make it a detached signature. // This must be called right before Finish() func (sd *SignedData) Detach() { sd.sd.ContentInfo = contentInfo{ContentType: OIDData} } // GetSignedData returns the private Signed Data func (sd *SignedData) GetSignedData() *signedData { return &sd.sd } // Finish marshals the content and its signers func (sd *SignedData) Finish() ([]byte, error) { sd.sd.Certificates = marshalCertificates(sd.certs) inner, err := asn1.Marshal(sd.sd) if err != nil { return nil, err } outer := contentInfo{ ContentType: OIDSignedData, Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: inner, IsCompound: true}, } return asn1.Marshal(outer) } // RemoveAuthenticatedAttributes removes authenticated attributes from signedData // similar to OpenSSL's PKCS7_NOATTR or -noattr flags func (sd *SignedData) RemoveAuthenticatedAttributes() { for i := range sd.sd.SignerInfos { sd.sd.SignerInfos[i].AuthenticatedAttributes = nil } } // RemoveUnauthenticatedAttributes removes unauthenticated attributes from signedData func (sd *SignedData) RemoveUnauthenticatedAttributes() { for i := range sd.sd.SignerInfos { sd.sd.SignerInfos[i].UnauthenticatedAttributes = nil } } // verifyPartialChain checks that a given cert is issued by the first parent in the list, // then continue down the path. It doesn't require the last parent to be a root CA, // or to be trusted in any truststore. It simply verifies that the chain provided, albeit // partial, makes sense. func verifyPartialChain(cert *x509.Certificate, parents []*x509.Certificate) error { if len(parents) == 0 { return fmt.Errorf("pkcs7: zero parents provided to verify the signature of certificate %q", cert.Subject.CommonName) } err := cert.CheckSignatureFrom(parents[0]) if err != nil { return fmt.Errorf("pkcs7: certificate signature from parent is invalid: %v", err) } if len(parents) == 1 { // there is no more parent to check, return return nil } return verifyPartialChain(parents[0], parents[1:]) } func cert2issuerAndSerial(cert *x509.Certificate) (issuerAndSerial, error) { var ias issuerAndSerial // The issuer RDNSequence has to match exactly the sequence in the certificate // We cannot use cert.Issuer.ToRDNSequence() here since it mangles the sequence ias.IssuerName = asn1.RawValue{FullBytes: cert.RawIssuer} ias.SerialNumber = cert.SerialNumber return ias, nil } // signs the DER encoded form of the attributes with the private key func signAttributes(attrs []attribute, pkey crypto.PrivateKey, digestAlg crypto.Hash) ([]byte, error) { attrBytes, err := marshalAttributes(attrs) if err != nil { return nil, err } h := digestAlg.New() h.Write(attrBytes) hash := h.Sum(nil) // dsa doesn't implement crypto.Signer so we make a special case // https://github.com/golang/go/issues/27889 switch pkey := pkey.(type) { case *dsa.PrivateKey: r, s, err := dsa.Sign(rand.Reader, pkey, hash) if err != nil { return nil, err } return asn1.Marshal(dsaSignature{r, s}) } key, ok := pkey.(crypto.Signer) if !ok { return nil, errors.New("pkcs7: private key does not implement crypto.Signer") } return key.Sign(rand.Reader, hash, digestAlg) } type dsaSignature struct { R, S *big.Int } // concats and wraps the certificates in the RawValue structure func marshalCertificates(certs []*x509.Certificate) rawCertificates { var buf bytes.Buffer for _, cert := range certs { buf.Write(cert.Raw) } rawCerts, _ := marshalCertificateBytes(buf.Bytes()) return rawCerts } // Even though, the tag & length are stripped out during marshalling the // RawContent, we have to encode it into the RawContent. If its missing, // then `asn1.Marshal()` will strip out the certificate wrapper instead. func marshalCertificateBytes(certs []byte) (rawCertificates, error) { var val = asn1.RawValue{Bytes: certs, Class: 2, Tag: 0, IsCompound: true} b, err := asn1.Marshal(val) if err != nil { return rawCertificates{}, err } return rawCertificates{Raw: b}, nil } // DegenerateCertificate creates a signed data structure containing only the // provided certificate or certificate chain. func DegenerateCertificate(cert []byte) ([]byte, error) { rawCert, err := marshalCertificateBytes(cert) if err != nil { return nil, err } emptyContent := contentInfo{ContentType: OIDData} sd := signedData{ Version: 1, ContentInfo: emptyContent, Certificates: rawCert, CRLs: []pkix.CertificateList{}, } content, err := asn1.Marshal(sd) if err != nil { return nil, err } signedContent := contentInfo{ ContentType: OIDSignedData, Content: asn1.RawValue{Class: 2, Tag: 0, Bytes: content, IsCompound: true}, } return asn1.Marshal(signedContent) } pkcs7-0.2.1/sign_test.go000066400000000000000000000312461475362641200151070ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto/dsa" "crypto/x509" "encoding/asn1" "encoding/pem" "fmt" "io/ioutil" "log" "math/big" "os" "os/exec" "testing" ) func TestSignWithGlobalDefaultDigestAlgorithm(t *testing.T) { if err := SetDefaultDigestAlgorithm(asn1.ObjectIdentifier{}); err == nil { t.Fatal("expected an error setting invalid digest algorithm") } currentDigestAlgorithm := defaultMessageDigestAlgorithmOID() if !currentDigestAlgorithm.Equal(OIDDigestAlgorithmSHA1) { t.Fatalf("expected digest algorithm %q, but got %q", OIDDigestAlgorithmSHA512, currentDigestAlgorithm) } if err := SetDefaultDigestAlgorithm(OIDDigestAlgorithmSHA512); err != nil { t.Fatalf("failed setting default digest algorithm: %v", err) } defer func() { currentDigestAlgorithm := defaultMessageDigestAlgorithmOID() if !currentDigestAlgorithm.Equal(OIDDigestAlgorithmSHA512) { t.Fatalf("expected digest algorithm %q, but got %q", OIDDigestAlgorithmSHA512, currentDigestAlgorithm) } if err := SetDefaultDigestAlgorithm(OIDDigestAlgorithmSHA1); err != nil { t.Fatalf("failed resetting default digest algorithm: %v", err) } currentDigestAlgorithm = defaultMessageDigestAlgorithmOID() if !currentDigestAlgorithm.Equal(OIDDigestAlgorithmSHA1) { t.Fatalf("expected digest algorithm %q, but got %q", OIDDigestAlgorithmSHA1, currentDigestAlgorithm) } }() cert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, x509.ECDSAWithSHA256, true) if err != nil { t.Fatalf("failed cannot generate root cert: %v", err) } truststore := x509.NewCertPool() truststore.AddCert(cert.Certificate) toBeSigned, err := NewSignedData([]byte("test")) if err != nil { t.Fatalf("failed creating signed data: %v", err) } if !toBeSigned.digestOid.Equal(OIDDigestAlgorithmSHA512) { t.Fatalf("expected digest algorithm %q, but got %q", OIDDigestAlgorithmSHA512, toBeSigned.digestOid) } if err := toBeSigned.AddSignerChain(cert.Certificate, *cert.PrivateKey, nil, SignerInfoConfig{}); err != nil { t.Fatalf("failed adding signer chain: %v", err) } signed, err := toBeSigned.Finish() if err != nil { t.Fatalf("failed signing data: %v", err) } pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed}) p7, err := Parse(signed) if err != nil { t.Fatalf("failed parsing PEM encoded signed data: %v", err) } if err := p7.VerifyWithChain(truststore); err != nil { t.Fatalf("failed verifying PKCS7: %v", err) } if !bytes.Equal([]byte("test"), p7.Content) { t.Fatal("parsed PKCS7 content does not equal signed content") } if !p7.Signers[0].DigestAlgorithm.Algorithm.Equal(OIDDigestAlgorithmSHA512) { t.Fatalf("expected digest algorithm %q, but got %q", OIDDigestAlgorithmSHA512, p7.Signers[0].DigestAlgorithm.Algorithm) } } func TestSign(t *testing.T) { content := []byte("Hello World") sigalgs := []x509.SignatureAlgorithm{ x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA512WithRSA, x509.ECDSAWithSHA1, x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512, } for _, sigalgroot := range sigalgs { rootCert, err := createTestCertificateByIssuer("PKCS7 Test Root CA", nil, sigalgroot, true) if err != nil { t.Fatalf("test %s: cannot generate root cert: %s", sigalgroot, err) } truststore := x509.NewCertPool() truststore.AddCert(rootCert.Certificate) for _, sigalginter := range sigalgs { interCert, err := createTestCertificateByIssuer("PKCS7 Test Intermediate Cert", rootCert, sigalginter, true) if err != nil { t.Fatalf("test %s/%s: cannot generate intermediate cert: %s", sigalgroot, sigalginter, err) } var parents []*x509.Certificate parents = append(parents, interCert.Certificate) for _, sigalgsigner := range sigalgs { signerCert, err := createTestCertificateByIssuer("PKCS7 Test Signer Cert", interCert, sigalgsigner, false) if err != nil { t.Fatalf("test %s/%s/%s: cannot generate signer cert: %s", sigalgroot, sigalginter, sigalgsigner, err) } for _, testDetach := range []bool{false, true} { log.Printf("test %s/%s/%s detached %t\n", sigalgroot, sigalginter, sigalgsigner, testDetach) toBeSigned, err := NewSignedData(content) if err != nil { t.Fatalf("test %s/%s/%s: cannot initialize signed data: %s", sigalgroot, sigalginter, sigalgsigner, err) } // Set the digest to match the end entity cert signerDigest, _ := getDigestOIDForSignatureAlgorithm(signerCert.Certificate.SignatureAlgorithm) toBeSigned.SetDigestAlgorithm(signerDigest) if err := toBeSigned.AddSignerChain(signerCert.Certificate, *signerCert.PrivateKey, parents, SignerInfoConfig{}); err != nil { t.Fatalf("test %s/%s/%s: cannot add signer: %s", sigalgroot, sigalginter, sigalgsigner, err) } if testDetach { toBeSigned.Detach() } signed, err := toBeSigned.Finish() if err != nil { t.Fatalf("test %s/%s/%s: cannot finish signing data: %s", sigalgroot, sigalginter, sigalgsigner, err) } pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: signed}) p7, err := Parse(signed) if err != nil { t.Fatalf("test %s/%s/%s: cannot parse signed data: %s", sigalgroot, sigalginter, sigalgsigner, err) } if testDetach { p7.Content = content } if !bytes.Equal(content, p7.Content) { t.Errorf("test %s/%s/%s: content was not found in the parsed data:\n\tExpected: %s\n\tActual: %s", sigalgroot, sigalginter, sigalgsigner, content, p7.Content) } if err := p7.VerifyWithChain(truststore); err != nil { t.Errorf("test %s/%s/%s: cannot verify signed data: %s", sigalgroot, sigalginter, sigalgsigner, err) } if !signerDigest.Equal(p7.Signers[0].DigestAlgorithm.Algorithm) { t.Errorf("test %s/%s/%s: expected digest algorithm %q but got %q", sigalgroot, sigalginter, sigalgsigner, signerDigest, p7.Signers[0].DigestAlgorithm.Algorithm) } } } } } } 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-----`) func TestDSASignAndVerifyWithOpenSSL(t *testing.T) { content := []byte("Hello World") // write the content to a temp file tmpContentFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_content") if err != nil { t.Fatal(err) } ioutil.WriteFile(tmpContentFile.Name(), content, 0755) block, _ := pem.Decode([]byte(dsaPublicCert)) if block == nil { t.Fatal("failed to parse certificate PEM") } signerCert, err := x509.ParseCertificate(block.Bytes) if err != nil { t.Fatal("failed to parse certificate: " + err.Error()) } // write the signer cert to a temp file tmpSignerCertFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_signer") if err != nil { t.Fatal(err) } ioutil.WriteFile(tmpSignerCertFile.Name(), dsaPublicCert, 0755) priv := dsa.PrivateKey{ PublicKey: dsa.PublicKey{Parameters: dsa.Parameters{P: fromHex("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7"), Q: fromHex("9760508F15230BCCB292B982A2EB840BF0581CF5"), G: fromHex("F7E1A085D69B3DDECBBCAB5C36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A"), }, }, X: fromHex("7D6E1A3DD4019FD809669D8AB8DA73807CEF7EC1"), } toBeSigned, err := NewSignedData(content) if err != nil { t.Fatalf("test case: cannot initialize signed data: %s", err) } if err := toBeSigned.SignWithoutAttr(signerCert, &priv, SignerInfoConfig{}); err != nil { t.Fatalf("Cannot add signer: %s", err) } toBeSigned.Detach() signed, err := toBeSigned.Finish() if err != nil { t.Fatalf("test case: cannot finish signing data: %s", err) } // write the signature to a temp file tmpSignatureFile, err := ioutil.TempFile("", "TestDSASignAndVerifyWithOpenSSL_signature") if err != nil { t.Fatal(err) } ioutil.WriteFile(tmpSignatureFile.Name(), pem.EncodeToMemory(&pem.Block{Type: "PKCS7", Bytes: signed}), 0755) // call openssl to verify the signature on the content using the root opensslCMD := exec.Command("openssl", "smime", "-verify", "-noverify", "-in", tmpSignatureFile.Name(), "-inform", "PEM", "-content", tmpContentFile.Name()) out, err := opensslCMD.CombinedOutput() if err != nil { t.Fatalf("test case: openssl command failed with %s: %s", err, out) } os.Remove(tmpSignatureFile.Name()) // clean up os.Remove(tmpContentFile.Name()) // clean up os.Remove(tmpSignerCertFile.Name()) // clean up } func ExampleSignedData() { // generate a signing cert or load a key pair cert, err := createTestCertificate(x509.SHA256WithRSA) if err != nil { fmt.Printf("Cannot create test certificates: %s", err) } // Initialize a SignedData struct with content to be signed signedData, err := NewSignedData([]byte("Example data to be signed")) if err != nil { fmt.Printf("Cannot initialize signed data: %s", err) } // Add the signing cert and private key if err := signedData.AddSigner(cert.Certificate, cert.PrivateKey, SignerInfoConfig{}); err != nil { fmt.Printf("Cannot add signer: %s", err) } // Call Detach() is you want to remove content from the signature // and generate an S/MIME detached signature signedData.Detach() // Finish() to obtain the signature bytes detachedSignature, err := signedData.Finish() if err != nil { fmt.Printf("Cannot finish signing data: %s", err) } pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: detachedSignature}) } func TestUnmarshalSignedAttribute(t *testing.T) { cert, err := createTestCertificate(x509.SHA512WithRSA) if err != nil { t.Fatal(err) } content := []byte("Hello World") toBeSigned, err := NewSignedData(content) if err != nil { t.Fatalf("Cannot initialize signed data: %s", err) } oidTest := asn1.ObjectIdentifier{2, 3, 4, 5, 6, 7} testValue := "TestValue" if err := toBeSigned.AddSigner(cert.Certificate, *cert.PrivateKey, SignerInfoConfig{ ExtraSignedAttributes: []Attribute{Attribute{Type: oidTest, Value: testValue}}, }); err != nil { t.Fatalf("Cannot add signer: %s", err) } signed, err := toBeSigned.Finish() if err != nil { t.Fatalf("Cannot finish signing data: %s", err) } p7, err := Parse(signed) if err != nil { t.Fatalf("Cannot parse signed data: %v", err) } var actual string err = p7.UnmarshalSignedAttribute(oidTest, &actual) if err != nil { t.Fatalf("Cannot unmarshal test value: %s", err) } if testValue != actual { t.Errorf("Attribute does not match test value\n\tExpected: %s\n\tActual: %s", testValue, actual) } } func TestDegenerateCertificate(t *testing.T) { cert, err := createTestCertificate(x509.SHA1WithRSA) if err != nil { t.Fatal(err) } deg, err := DegenerateCertificate(cert.Certificate.Raw) if err != nil { t.Fatal(err) } testOpenSSLParse(t, deg) pem.Encode(os.Stdout, &pem.Block{Type: "PKCS7", Bytes: deg}) } // writes the cert to a temporary file and tests that openssl can read it. func testOpenSSLParse(t *testing.T, certBytes []byte) { tmpCertFile, err := ioutil.TempFile("", "testCertificate") if err != nil { t.Fatal(err) } defer os.Remove(tmpCertFile.Name()) // clean up if _, err := tmpCertFile.Write(certBytes); err != nil { t.Fatal(err) } opensslCMD := exec.Command("openssl", "pkcs7", "-inform", "der", "-in", tmpCertFile.Name()) _, err = opensslCMD.Output() if err != nil { t.Fatal(err) } if err := tmpCertFile.Close(); err != nil { t.Fatal(err) } } func fromHex(s string) *big.Int { result, ok := new(big.Int).SetString(s, 16) if !ok { panic(s) } return result } pkcs7-0.2.1/verify.go000066400000000000000000000313121475362641200144060ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/subtle" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "errors" "fmt" "time" ) // Verify is a wrapper around VerifyWithChain() that initializes an empty // trust store, effectively disabling certificate verification when validating // a signature. func (p7 *PKCS7) Verify() (err error) { return p7.VerifyWithChain(nil) } // VerifyWithChain checks the signatures of a PKCS7 object. // // If truststore is not nil, it also verifies the chain of trust of // the end-entity signer cert to one of the roots in the // truststore. When the PKCS7 object includes the signing time // authenticated attr verifies the chain at that time and UTC now // otherwise. func (p7 *PKCS7) VerifyWithChain(truststore *x509.CertPool) (err error) { if len(p7.Signers) == 0 { return errors.New("pkcs7: Message has no signers") } for _, signer := range p7.Signers { if err := verifySignature(p7, signer, truststore); err != nil { return err } } return nil } // VerifyWithChainAtTime checks the signatures of a PKCS7 object. // // If truststore is not nil, it also verifies the chain of trust of // the end-entity signer cert to a root in the truststore at // currentTime. It does not use the signing time authenticated // attribute. func (p7 *PKCS7) VerifyWithChainAtTime(truststore *x509.CertPool, currentTime time.Time) (err error) { if len(p7.Signers) == 0 { return errors.New("pkcs7: Message has no signers") } for _, signer := range p7.Signers { if err := verifySignatureAtTime(p7, signer, truststore, currentTime); err != nil { return err } } return nil } // SigningTimeNotValidError is returned when the signing time attribute // falls outside of the signer certificate validity. type SigningTimeNotValidError struct { SigningTime time.Time NotBefore time.Time // NotBefore of signer NotAfter time.Time // NotAfter of signer } func (e *SigningTimeNotValidError) Error() string { return fmt.Sprintf("pkcs7: signing time %q is outside of certificate validity %q to %q", e.SigningTime.Format(time.RFC3339), e.NotBefore.Format(time.RFC3339), e.NotAfter.Format(time.RFC3339)) } func verifySignatureAtTime(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool, currentTime time.Time) (err error) { signedData := p7.Content ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) if ee == nil { return errors.New("pkcs7: No certificate for signer") } if len(signer.AuthenticatedAttributes) > 0 { // TODO(fullsailor): First check the content type match var ( digest []byte signingTime time.Time ) err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest) if err != nil { return err } hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm) if err != nil { return err } computed, err := calculateHash(p7.Hasher, hash, p7.Content) if err != nil { return err } if subtle.ConstantTimeCompare(digest, computed) != 1 { return &MessageDigestMismatchError{ ExpectedDigest: digest, ActualDigest: computed, } } signedData, err = marshalAttributes(signer.AuthenticatedAttributes) if err != nil { return err } err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime) if err == nil { // signing time found, performing validity check if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { return &SigningTimeNotValidError{ SigningTime: signingTime, NotBefore: ee.NotBefore, NotAfter: ee.NotAfter, } } } } if truststore != nil { _, err = verifyCertChain(ee, p7.Certificates, truststore, currentTime) if err != nil { return err } } sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm) if err != nil { return err } return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest) } func verifySignature(p7 *PKCS7, signer signerInfo, truststore *x509.CertPool) (err error) { signedData := p7.Content ee := getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) if ee == nil { return errors.New("pkcs7: No certificate for signer") } signingTime := time.Now().UTC() if len(signer.AuthenticatedAttributes) > 0 { // TODO(fullsailor): First check the content type match var digest []byte err := unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeMessageDigest, &digest) if err != nil { return err } hash, err := getHashForOID(signer.DigestAlgorithm.Algorithm) if err != nil { return err } computed, err := calculateHash(p7.Hasher, hash, p7.Content) if err != nil { return err } if subtle.ConstantTimeCompare(digest, computed) != 1 { return &MessageDigestMismatchError{ ExpectedDigest: digest, ActualDigest: computed, } } signedData, err = marshalAttributes(signer.AuthenticatedAttributes) if err != nil { return err } err = unmarshalAttribute(signer.AuthenticatedAttributes, OIDAttributeSigningTime, &signingTime) if err == nil { // signing time found, performing validity check if signingTime.After(ee.NotAfter) || signingTime.Before(ee.NotBefore) { return &SigningTimeNotValidError{ SigningTime: signingTime, NotBefore: ee.NotBefore, NotAfter: ee.NotAfter, } } } } if truststore != nil { _, err = verifyCertChain(ee, p7.Certificates, truststore, signingTime) if err != nil { return err } } sigalg, err := getSignatureAlgorithm(signer.DigestEncryptionAlgorithm, signer.DigestAlgorithm) if err != nil { return err } return ee.CheckSignature(sigalg, signedData, signer.EncryptedDigest) } // GetOnlySigner returns an x509.Certificate for the first signer of the signed // data payload. If there are more or less than one signer, nil is returned func (p7 *PKCS7) GetOnlySigner() *x509.Certificate { if len(p7.Signers) != 1 { return nil } signer := p7.Signers[0] return getCertFromCertsByIssuerAndSerial(p7.Certificates, signer.IssuerAndSerialNumber) } // UnmarshalSignedAttribute decodes a single attribute from the signer info func (p7 *PKCS7) UnmarshalSignedAttribute(attributeType asn1.ObjectIdentifier, out interface{}) error { sd, ok := p7.raw.(signedData) if !ok { return errors.New("pkcs7: payload is not signedData content") } if len(sd.SignerInfos) < 1 { return errors.New("pkcs7: payload has no signers") } attributes := sd.SignerInfos[0].AuthenticatedAttributes return unmarshalAttribute(attributes, attributeType, out) } func parseSignedData(data []byte) (*PKCS7, error) { var sd signedData asn1.Unmarshal(data, &sd) certs, err := sd.Certificates.Parse() if err != nil { return nil, err } // fmt.Printf("--> Signed Data Version %d\n", sd.Version) var compound asn1.RawValue var content unsignedData // The Content.Bytes maybe empty on PKI responses. if len(sd.ContentInfo.Content.Bytes) > 0 { if _, err := asn1.Unmarshal(sd.ContentInfo.Content.Bytes, &compound); err != nil { return nil, err } } // Compound octet string if compound.IsCompound { if compound.Tag == 4 { for len(compound.Bytes) > 0 { var cdata asn1.RawValue if _, err = asn1.Unmarshal(compound.Bytes, &cdata); err != nil { return nil, err } content = append(content, cdata.Bytes...) compound.Bytes = compound.Bytes[len(cdata.FullBytes):] } } else { content = compound.Bytes } } else { // assuming this is tag 04 content = compound.Bytes } return &PKCS7{ Content: content, Certificates: certs, CRLs: sd.CRLs, Signers: sd.SignerInfos, raw: sd}, nil } // verifyCertChain takes an end-entity certs, a list of potential intermediates and a // truststore, and built all potential chains between the EE and a trusted root. // // When verifying chains that may have expired, currentTime can be set to a past date // to allow the verification to pass. If unset, currentTime is set to the current UTC time. func verifyCertChain(ee *x509.Certificate, certs []*x509.Certificate, truststore *x509.CertPool, currentTime time.Time) (chains [][]*x509.Certificate, err error) { intermediates := x509.NewCertPool() for _, intermediate := range certs { intermediates.AddCert(intermediate) } verifyOptions := x509.VerifyOptions{ Roots: truststore, Intermediates: intermediates, KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, CurrentTime: currentTime, } chains, err = ee.Verify(verifyOptions) if err != nil { return chains, fmt.Errorf("pkcs7: failed to verify certificate chain: %v", err) } return } // MessageDigestMismatchError is returned when the signer data digest does not // match the computed digest for the contained content type MessageDigestMismatchError struct { ExpectedDigest []byte ActualDigest []byte } func (err *MessageDigestMismatchError) Error() string { return fmt.Sprintf("pkcs7: Message digest mismatch\n\tExpected: %X\n\tActual : %X", err.ExpectedDigest, err.ActualDigest) } func getSignatureAlgorithm(digestEncryption, digest pkix.AlgorithmIdentifier) (x509.SignatureAlgorithm, error) { switch { case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA1): return x509.ECDSAWithSHA1, nil case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA256): return x509.ECDSAWithSHA256, nil case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA384): return x509.ECDSAWithSHA384, nil case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmECDSASHA512): return x509.ECDSAWithSHA512, nil case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSA), digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1), digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256), digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384), digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512): switch { case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA1): return x509.SHA1WithRSA, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA256): return x509.SHA256WithRSA, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA384): return x509.SHA384WithRSA, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512), digest.Algorithm.Equal(OIDEncryptionAlgorithmRSASHA512): return x509.SHA512WithRSA, nil default: return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q", digest.Algorithm.String(), digestEncryption.Algorithm.String()) } case digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSA), digestEncryption.Algorithm.Equal(OIDDigestAlgorithmDSASHA1): switch { case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1): return x509.DSAWithSHA1, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256): return x509.DSAWithSHA256, nil default: return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q", digest.Algorithm.String(), digestEncryption.Algorithm.String()) } case digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP256), digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP384), digestEncryption.Algorithm.Equal(OIDEncryptionAlgorithmECDSAP521): switch { case digest.Algorithm.Equal(OIDDigestAlgorithmSHA1): return x509.ECDSAWithSHA1, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA256): return x509.ECDSAWithSHA256, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA384): return x509.ECDSAWithSHA384, nil case digest.Algorithm.Equal(OIDDigestAlgorithmSHA512): return x509.ECDSAWithSHA512, nil default: return -1, fmt.Errorf("pkcs7: unsupported digest %q for encryption algorithm %q", digest.Algorithm.String(), digestEncryption.Algorithm.String()) } default: return -1, fmt.Errorf("pkcs7: unsupported algorithm %q", digestEncryption.Algorithm.String()) } } func getCertFromCertsByIssuerAndSerial(certs []*x509.Certificate, ias issuerAndSerial) *x509.Certificate { for _, cert := range certs { if isCertMatchForIssuerAndSerial(cert, ias) { return cert } } return nil } func unmarshalAttribute(attrs []attribute, attributeType asn1.ObjectIdentifier, out interface{}) error { for _, attr := range attrs { if attr.Type.Equal(attributeType) { _, err := asn1.Unmarshal(attr.Value.Bytes, out) return err } } return errors.New("pkcs7: attribute type not in attributes") } func calculateHash(hasher Hasher, hashFunc crypto.Hash, content []byte) (computed []byte, err error) { if hasher != nil { computed, err = hasher.Hash(hashFunc, bytes.NewReader(content)) } else { if !hashFunc.Available() { return nil, fmt.Errorf("hash function %v not available", hashFunc) } h := hashFunc.New() _, _ = h.Write(content) computed = h.Sum(nil) } return } pkcs7-0.2.1/verify_dsa_go1.15_test.go000066400000000000000000000135531475362641200172750ustar00rootroot00000000000000//go:build !go1.16 // +build !go1.16 // Support for DSA was deprecated in Go 1.16, so the tests in this file will only be // executed when a Go version below that is used. Also see https://github.com/golang/go/issues/4033. 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-----`) 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 } pkcs7-0.2.1/verify_test.go000066400000000000000000001423561475362641200154600ustar00rootroot00000000000000package pkcs7 import ( "bytes" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/base64" "encoding/hex" "encoding/pem" "fmt" "io" "io/ioutil" "math/big" "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) } } func TestInvalidSigningTime(t *testing.T) { key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("failed generating ECDSA key: %v", err) } // define certificate validity to a timeframe in the past, so that // the certificate itself is not valid at the time of signing. notBefore := time.Now().UTC().Round(time.Minute).Add(-2 * time.Hour) notAfter := time.Now().UTC().Round(time.Minute).Add(-1 * time.Hour) template := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "TestInvalidSigningtime", }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}, } der, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key) if err != nil { t.Fatalf("failed creating certificate: %v", err) } cert, err := x509.ParseCertificate(der) if err != nil { t.Fatalf("failed parsing certificate: %v", err) } toBeSignedData, err := NewSignedData([]byte("test-invalid-signing-time")) if err != nil { t.Fatalf("failed creating signed data: %v", err) } // add the signer cert, and add attributes, including the signing // time attribute, containing the current time if err := toBeSignedData.AddSigner(cert, key, SignerInfoConfig{}); err != nil { t.Fatalf("failed adding signer: %v", err) } // finalizes the signed data signedData, err := toBeSignedData.Finish() if err != nil { t.Fatalf("failed signing data: %v", err) } p7, err := Parse(signedData) if err != nil { t.Fatalf("failed parsing signed data: %v", err) } signerCert := p7.GetOnlySigner() if !bytes.Equal(cert.Signature, signerCert.Signature) { t.Fatal("unexpected signer certificate obtained from P7 data") } // verify without a chain (self-signed cert), at time.Now() err = p7.VerifyWithChainAtTime(nil, time.Now()) if err == nil { t.Fatal("expected verification error, but got nil") } signingTimeErr, ok := err.(*SigningTimeNotValidError) if !ok { t.Fatalf("expected *SigningTimeNotValidError, but got %T", err) } if signingTimeErr.NotBefore != notBefore { t.Errorf("expected notBefore to be %q, but got %q", notBefore, signingTimeErr.NotBefore) } if signingTimeErr.NotAfter != notAfter { t.Errorf("expected notAfter to be %q, but got %q", notAfter, signingTimeErr.NotAfter) } // verify without a chain (self-signed cert), but without specifying the time err = p7.VerifyWithChain(nil) if err == nil { t.Fatal("expected verification error, but got nil") } signingTimeErr, ok = err.(*SigningTimeNotValidError) if !ok { t.Fatalf("expected *SigningTimeNotValidError, but got %T", err) } if signingTimeErr.NotBefore != notBefore { t.Errorf("expected notBefore to be %q, but got %q", notBefore, signingTimeErr.NotBefore) } if signingTimeErr.NotAfter != notAfter { t.Errorf("expected notAfter to be %q, but got %q", notAfter, signingTimeErr.NotAfter) } } 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 TestVerifyWithHasher(t *testing.T) { fixture := UnmarshalTestFixture(HashCalcSignedTestFixture) p7, err := Parse(fixture.Input) if err != nil { t.Errorf("Parse encountered unexpected error: %v", err) } const longBuffer = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam a molestie odio, id accumsan dolor. Praesent ultricies enim et pharetra molestie. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur vitae pellentesque tortor. Curabitur nulla mi, semper non lectus nec, auctor euismod tellus. Nunc vestibulum nisi quis felis efficitur, vel finibus nunc vehicula. Mauris ipsum mi, eleifend in urna non, pellentesque facilisis turpis. Ut eleifend viverra imperdiet. Vestibulum ut ligula non nunc vestibulum lobortis. Curabitur at elementum nisl. Sed facilisis ligula in pulvinar aliquet. Sed semper interdum ipsum quis hendrerit." p7.Content = []byte(longBuffer) p7.Hasher = &testHasher{} if err := p7.Verify(); err != nil { t.Errorf("Verify failed with error: %v", err) } } func TestVerifyWithHasherError(t *testing.T) { fixture := UnmarshalTestFixture(HashCalcSignedTestFixture) p7, err := Parse(fixture.Input) if err != nil { t.Errorf("Parse encountered unexpected error: %v", err) } dummyError := fmt.Errorf("dummy error") p7.Hasher = &testHasher{retErr: dummyError} if err := p7.Verify(); err != dummyError { t.Errorf("Verify did not return expected error: %v", err) } } type testHasher struct { retErr error } func (m *testHasher) Hash(hashFunc crypto.Hash, reader io.Reader) ([]byte, error) { if m.retErr != nil { return nil, m.retErr } if !hashFunc.Available() { return nil, fmt.Errorf("hash function %v not available", hashFunc) } h := hashFunc.New() bufferSize := 128 buffer := make([]byte, bufferSize) for { count, err := reader.Read(buffer) if count > 0 { h.Write(buffer[:count]) } if err == io.EOF { break } if err != nil { return nil, err } } return h.Sum(nil), nil } var HashCalcSignedTestFixture = ` -----BEGIN PKCS7----- MIIIjgYJKoZIhvcNAQcCoIIIfzCCCHsCAQExCTAHBgUrDgMCGjCCApAGCSqGSIb3 DQEHAaCCAoEEggJ9TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3Rl dHVyIGFkaXBpc2NpbmcgZWxpdC4gTmFtIGEgbW9sZXN0aWUgb2RpbywgaWQgYWNj dW1zYW4gZG9sb3IuIFByYWVzZW50IHVsdHJpY2llcyBlbmltIGV0IHBoYXJldHJh IG1vbGVzdGllLiBMb3JlbSBpcHN1bSBkb2xvciBzaXQgYW1ldCwgY29uc2VjdGV0 dXIgYWRpcGlzY2luZyBlbGl0LiBDdXJhYml0dXIgdml0YWUgcGVsbGVudGVzcXVl IHRvcnRvci4gQ3VyYWJpdHVyIG51bGxhIG1pLCBzZW1wZXIgbm9uIGxlY3R1cyBu ZWMsIGF1Y3RvciBldWlzbW9kIHRlbGx1cy4gTnVuYyB2ZXN0aWJ1bHVtIG5pc2kg cXVpcyBmZWxpcyBlZmZpY2l0dXIsIHZlbCBmaW5pYnVzIG51bmMgdmVoaWN1bGEu IE1hdXJpcyBpcHN1bSBtaSwgZWxlaWZlbmQgaW4gdXJuYSBub24sIHBlbGxlbnRl c3F1ZSBmYWNpbGlzaXMgdHVycGlzLiBVdCBlbGVpZmVuZCB2aXZlcnJhIGltcGVy ZGlldC4gVmVzdGlidWx1bSB1dCBsaWd1bGEgbm9uIG51bmMgdmVzdGlidWx1bSBs b2JvcnRpcy4gQ3VyYWJpdHVyIGF0IGVsZW1lbnR1bSBuaXNsLiBTZWQgZmFjaWxp c2lzIGxpZ3VsYSBpbiBwdWx2aW5hciBhbGlxdWV0LiBTZWQgc2VtcGVyIGludGVy ZHVtIGlwc3VtIHF1aXMgaGVuZHJlcml0LqCCBI8wggItMIIBlqADAgECAgReT4E0 MA0GCSqGSIb3DQEBBQUAMDkxEDAOBgNVBAoTB0FjbWUgQ28xJTAjBgNVBAMTHFBL Q1M3IFRlc3QgSW50ZXJtZWRpYXRlIENlcnQwHhcNMjUwMjAyMTgxNzAzWhcNMjYw MjAyMTgxNzA0WjAzMRAwDgYDVQQKEwdBY21lIENvMR8wHQYDVQQDExZQS0NTNyBU ZXN0IFNpZ25lciBDZXJ0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvMS2h EtmDRbmN83sWNs7nn4IpQlLJxS6yQoqBvRA8ZlSR57UbrOmJD/c1x+BBQUIjrkmk xlw6TzEUTv2iVb3GoE1cd3vapUujosS2n1k4f4vIU8qDbweK9RBDC8GJSlLwi83v gXg1/It5xVXwW9Al+Xx9v1Qr4S/YL2UvPnIEOQIDAQABo0gwRjAOBgNVHQ8BAf8E BAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAUJnmLplTS8997 3/Ud35byl8ofTe0wDQYJKoZIhvcNAQEFBQADgYEAUj63vKTNYJ6r9hIbnYq6AeAQ 5SHgPQ9auP/QbMm9DbEx8pJGaXgAGXxkBK8RVEFms8OCJIK+9JdGceN+aVl3FL/n V5inmA43yuFAamD/gvhbqdxvf86/d7YgZn3ecKYaoZKaRJxGs/qbTl3XY8jDOhMz J9m0sEPi9mUuQUst6NUwggJaMIIBw6ADAgECAgUAtGVULDANBgkqhkiG9w0BAQUF ADAvMRAwDgYDVQQKEwdBY21lIENvMRswGQYDVQQDExJQS0NTNyBUZXN0IFJvb3Qg Q0EwHhcNMjUwMjAyMTgxNzAzWhcNMjYwMjAyMTgxNzA0WjA5MRAwDgYDVQQKEwdB Y21lIENvMSUwIwYDVQQDExxQS0NTNyBUZXN0IEludGVybWVkaWF0ZSBDZXJ0MIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvMS2hEtmDRbmN83sWNs7nn4IpQlLJ xS6yQoqBvRA8ZlSR57UbrOmJD/c1x+BBQUIjrkmkxlw6TzEUTv2iVb3GoE1cd3va pUujosS2n1k4f4vIU8qDbweK9RBDC8GJSlLwi83vgXg1/It5xVXwW9Al+Xx9v1Qr 4S/YL2UvPnIEOQIDAQABo3gwdjAOBgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYI KwYBBQUHAwQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJnmLplTS89973/Ud 35byl8ofTe0wHwYDVR0jBBgwFoAUJnmLplTS89973/Ud35byl8ofTe0wDQYJKoZI hvcNAQEFBQADgYEAZ3EEdFK3otrKGlGvGJJrdzdBYzxnq/J7+VlhWBNNapBaMiBc hoTQDOrGHkzST6NezqzwTzLEEl+RRecpGJFDlj3+P5BFIeRGpUyf55nZjRJEmYer j4iLuLyoMTeU1grLAFy0zp78x4AjDT/6GiqKlXZX/YbZaODQyUjjhuISJ4cxggFC MIIBPgIBATBBMDkxEDAOBgNVBAoTB0FjbWUgQ28xJTAjBgNVBAMTHFBLQ1M3IFRl c3QgSW50ZXJtZWRpYXRlIENlcnQCBF5PgTQwBwYFKw4DAhqgXTAYBgkqhkiG9w0B CQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNTAyMDIxODE3MDRaMCMG CSqGSIb3DQEJBDEWBBQuICjf8Q5uyWggGVKRZeomIoxeQjALBgkqhkiG9w0BAQUE gYCV3EPgmvq5IgP9yGrKfyrT2v5+Caw3aUkAC8rdi+NQME0FR0Ov0DCHfrgr8CR9 +d16d5vQZFrSKKocQmT/Jm30ggrrS6yVDIODt1c3qdkItnp9W67l7pEly87Wpwi/ 0X418iR3Q/g0kDj0Vw52dS2dJsFuebD1ZU/JPveXvywGcw== -----END PKCS7----- -----BEGIN CERTIFICATE----- MIICLTCCAZagAwIBAgIEXk+BNDANBgkqhkiG9w0BAQUFADA5MRAwDgYDVQQKEwdB Y21lIENvMSUwIwYDVQQDExxQS0NTNyBUZXN0IEludGVybWVkaWF0ZSBDZXJ0MB4X DTI1MDIwMjE4MTcwM1oXDTI2MDIwMjE4MTcwNFowMzEQMA4GA1UEChMHQWNtZSBD bzEfMB0GA1UEAxMWUEtDUzcgVGVzdCBTaWduZXIgQ2VydDCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEArzEtoRLZg0W5jfN7FjbO55+CKUJSycUuskKKgb0QPGZU kee1G6zpiQ/3NcfgQUFCI65JpMZcOk8xFE79olW9xqBNXHd72qVLo6LEtp9ZOH+L yFPKg28HivUQQwvBiUpS8IvN74F4NfyLecVV8FvQJfl8fb9UK+Ev2C9lLz5yBDkC AwEAAaNIMEYwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMEMB8G A1UdIwQYMBaAFCZ5i6ZU0vPfe9/1Hd+W8pfKH03tMA0GCSqGSIb3DQEBBQUAA4GB AFI+t7ykzWCeq/YSG52KugHgEOUh4D0PWrj/0GzJvQ2xMfKSRml4ABl8ZASvEVRB ZrPDgiSCvvSXRnHjfmlZdxS/51eYp5gON8rhQGpg/4L4W6ncb3/Ov3e2IGZ93nCm GqGSmkScRrP6m05d12PIwzoTMyfZtLBD4vZlLkFLLejV -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICWjCCAcOgAwIBAgIFALRlVCwwDQYJKoZIhvcNAQEFBQAwLzEQMA4GA1UEChMH QWNtZSBDbzEbMBkGA1UEAxMSUEtDUzcgVGVzdCBSb290IENBMB4XDTI1MDIwMjE4 MTcwM1oXDTI2MDIwMjE4MTcwNFowOTEQMA4GA1UEChMHQWNtZSBDbzElMCMGA1UE AxMcUEtDUzcgVGVzdCBJbnRlcm1lZGlhdGUgQ2VydDCBnzANBgkqhkiG9w0BAQEF AAOBjQAwgYkCgYEArzEtoRLZg0W5jfN7FjbO55+CKUJSycUuskKKgb0QPGZUkee1 G6zpiQ/3NcfgQUFCI65JpMZcOk8xFE79olW9xqBNXHd72qVLo6LEtp9ZOH+LyFPK g28HivUQQwvBiUpS8IvN74F4NfyLecVV8FvQJfl8fb9UK+Ev2C9lLz5yBDkCAwEA AaN4MHYwDgYDVR0PAQH/BAQDAgKkMBMGA1UdJQQMMAoGCCsGAQUFBwMEMA8GA1Ud EwEB/wQFMAMBAf8wHQYDVR0OBBYEFCZ5i6ZU0vPfe9/1Hd+W8pfKH03tMB8GA1Ud IwQYMBaAFCZ5i6ZU0vPfe9/1Hd+W8pfKH03tMA0GCSqGSIb3DQEBBQUAA4GBAGdx BHRSt6LayhpRrxiSa3c3QWM8Z6vye/lZYVgTTWqQWjIgXIaE0Azqxh5M0k+jXs6s 8E8yxBJfkUXnKRiRQ5Y9/j+QRSHkRqVMn+eZ2Y0SRJmHq4+Ii7i8qDE3lNYKywBc tM6e/MeAIw0/+hoqipV2V/2G2Wjg0MlI44biEieH -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICLjCCAZegAwIBAgIEDhD97zANBgkqhkiG9w0BAQsFADAvMRAwDgYDVQQKEwdB Y21lIENvMRswGQYDVQQDExJQS0NTNyBUZXN0IFJvb3QgQ0EwHhcNMjUwMjAyMTgx NzAzWhcNMjYwMjAyMTgxNzA0WjAvMRAwDgYDVQQKEwdBY21lIENvMRswGQYDVQQD ExJQS0NTNyBUZXN0IFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGB AK8xLaES2YNFuY3zexY2zuefgilCUsnFLrJCioG9EDxmVJHntRus6YkP9zXH4EFB QiOuSaTGXDpPMRRO/aJVvcagTVx3e9qlS6OixLafWTh/i8hTyoNvB4r1EEMLwYlK UvCLze+BeDX8i3nFVfBb0CX5fH2/VCvhL9gvZS8+cgQ5AgMBAAGjVzBVMA4GA1Ud DwEB/wQEAwICpDATBgNVHSUEDDAKBggrBgEFBQcDBDAPBgNVHRMBAf8EBTADAQH/ MB0GA1UdDgQWBBQmeYumVNLz33vf9R3flvKXyh9N7TANBgkqhkiG9w0BAQsFAAOB gQCpWSM5epx+nsZRdH6QGLR9q1JxSZ6+IeWgccu2WLE8k3usyItTCfkVMncPqzr3 og/vYQFEMvfEyFCJy9CBpLXTjkOOuOD5M9mNaGnUMjPIpBkxtBLIaFz3qeuqDj04 5i35yuWnAykAR+6kxEbNpkMD5uHznshVU8Mum990qP9Fqg== -----END CERTIFICATE-----` func TestVerifyAppStore(t *testing.T) { fixture := UnmarshalTestFixture(AppStoreReceiptFixture) p7, err := Parse(fixture.Input) if err != nil { t.Errorf("Parse encountered unexpected error: %v", err) } if err := p7.Verify(); err != nil { t.Errorf("Verify failed with error: %v", err) } } var AppStoreReceiptFixture = ` -----BEGIN PKCS7----- MIITtgYJKoZIhvcNAQcCoIITpzCCE6MCAQExCzAJBgUrDgMCGgUAMIIDVwYJKoZI hvcNAQcBoIIDSASCA0QxggNAMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQEC AQEEAwIBADALAgEDAgEBBAMMATEwCwIBCwIBAQQDAgEAMAsCAQ8CAQEEAwIBADAL AgEQAgEBBAMCAQAwCwIBGQIBAQQDAgEDMAwCAQoCAQEEBBYCNCswDAIBDgIBAQQE AgIAjTANAgENAgEBBAUCAwFgvTANAgETAgEBBAUMAzEuMDAOAgEJAgEBBAYCBFAy NDcwGAIBAgIBAQQQDA5jb20uemhpaHUudGVzdDAYAgEEAgECBBCS+ZODNMHwT1Nz gWYDXyWZMBsCAQACAQEEEwwRUHJvZHVjdGlvblNhbmRib3gwHAIBBQIBAQQU4nRh YCEZx70Flzv7hvJRjJZckYIwHgIBDAIBAQQWFhQyMDE2LTA3LTIzVDA2OjIxOjEx WjAeAgESAgEBBBYWFDIwMTMtMDgtMDFUMDc6MDA6MDBaMD0CAQYCAQEENbR21I+a 8+byMXo3NPRoDWQmSXQF2EcCeBoD4GaL//ZCRETp9rGFPSg1KekCP7Kr9HAqw09m MEICAQcCAQEEOlVJozYYBdugybShbiiMsejDMNeCbZq6CrzGBwW6GBy+DGWxJI91 Y3ouXN4TZUhuVvLvN1b0m5T3ggQwggFaAgERAgEBBIIBUDGCAUwwCwICBqwCAQEE AhYAMAsCAgatAgEBBAIMADALAgIGsAIBAQQCFgAwCwICBrICAQEEAgwAMAsCAgaz AgEBBAIMADALAgIGtAIBAQQCDAAwCwICBrUCAQEEAgwAMAsCAga2AgEBBAIMADAM AgIGpQIBAQQDAgEBMAwCAgarAgEBBAMCAQEwDAICBq4CAQEEAwIBADAMAgIGrwIB AQQDAgEAMAwCAgaxAgEBBAMCAQAwGwICBqcCAQEEEgwQMTAwMDAwMDIyNTMyNTkw MTAbAgIGqQIBAQQSDBAxMDAwMDAwMjI1MzI1OTAxMB8CAgaoAgEBBBYWFDIwMTYt MDctMjNUMDY6MjE6MTFaMB8CAgaqAgEBBBYWFDIwMTYtMDctMjNUMDY6MjE6MTFa MCACAgamAgEBBBcMFWNvbS56aGlodS50ZXN0LnRlc3RfMaCCDmUwggV8MIIEZKAD AgECAggO61eH554JjTANBgkqhkiG9w0BAQUFADCBljELMAkGA1UEBhMCVVMxEzAR BgNVBAoMCkFwcGxlIEluYy4xLDAqBgNVBAsMI0FwcGxlIFdvcmxkd2lkZSBEZXZl bG9wZXIgUmVsYXRpb25zMUQwQgYDVQQDDDtBcHBsZSBXb3JsZHdpZGUgRGV2ZWxv cGVyIFJlbGF0aW9ucyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNTExMTMw MjE1MDlaFw0yMzAyMDcyMTQ4NDdaMIGJMTcwNQYDVQQDDC5NYWMgQXBwIFN0b3Jl IGFuZCBpVHVuZXMgU3RvcmUgUmVjZWlwdCBTaWduaW5nMSwwKgYDVQQLDCNBcHBs ZSBXb3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczETMBEGA1UECgwKQXBwbGUg SW5jLjELMAkGA1UEBhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQClz4H9JaKBW9aH7SPaMxyO4iPApcQmyz3Gn+xKDVWG/6QC15fKOVRtfX+yVBid xCxScY5ke4LOibpJ1gjltIhxzz9bRi7GxB24A6lYogQ+IXjV27fQjhKNg0xbKmg3 k8LyvR7E0qEMSlhSqxLj7d0fmBWQNS3CzBLKjUiB91h4VGvojDE2H0oGDEdU8zeQ uLKSiX1fpIVK4cCc4Lqku4KXY/Qrk8H9Pm/KwfU8qY9SGsAlCnYO3v6Z/v/Ca/Vb XqxzUUkIVonMQ5DMjoEC0KCXtlyxoWlph5AQaCYmObgdEHOwCl3Fc9DfdjvYLdmI HuPsB8/ijtDT+iZVge/iA0kjAgMBAAGjggHXMIIB0zA/BggrBgEFBQcBAQQzMDEw LwYIKwYBBQUHMAGGI2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtd3dkcjA0 MB0GA1UdDgQWBBSRpJz8xHa3n6CK9E31jzZd7SsEhTAMBgNVHRMBAf8EAjAAMB8G A1UdIwQYMBaAFIgnFwmpthhgi+zruvZHWcVSVKO3MIIBHgYDVR0gBIIBFTCCAREw ggENBgoqhkiG92NkBQYBMIH+MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9u IHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5j ZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25k aXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0 aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDYGCCsGAQUFBwIBFipodHRwOi8vd3d3 LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eS8wDgYDVR0PAQH/BAQDAgeA MBAGCiqGSIb3Y2QGCwEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQANphvTLj3jWysH bkKWbNPojEMwgl/gXNGNvr0PvRr8JZLbjIXDgFnf4+LXLgUUrA3btrj+/DUufMut F2uOfx/kd7mxZ5W0E16mGYZ2+FogledjjA9z/Ojtxh+umfhlSFyg4Cg6wBA3Lbmg BDkfc7nIBf3y3n8aKipuKwH8oCBc2et9J6Yz+PWY4L5E27FMZ/xuCk/J4gao0pfz p45rUaJahHVl0RYEYuPBX/UIqc9o2ZIAycGMs/iNAGS6WGDAfK+PdcppuVsq1h1o bphC9UynNxmbzDscehlD86Ntv0hgBgw2kivs3hi1EdotI9CO/KBpnBcbnoB7OUdF MGEvxxOoMIIEIjCCAwqgAwIBAgIIAd68xDltoBAwDQYJKoZIhvcNAQEFBQAwYjEL MAkGA1UEBhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxl IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENB MB4XDTEzMDIwNzIxNDg0N1oXDTIzMDIwNzIxNDg0N1owgZYxCzAJBgNVBAYTAlVT MRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBXb3JsZHdpZGUg RGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29ybGR3aWRlIERl dmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKOFSmy1aqyCQ5SOmM7uxfuH8mkbw0 U3rOfGOAYXdkXqUHI7Y5/lAtFVZYcC1+xG7BSoU+L/DehBqhV8mvexj/avoVEkkV CBmsqtsqMu2WY2hSFT2Miuy/axiV4AOsAX2XBWfODoWVN2rtCbauZ81RZJ/GXNG8 V25nNYB2NqSHgW44j9grFU57Jdhav06DwY3Sk9UacbVgnJ0zTlX5ElgMhrgWDcHl d0WNUEi6Ky3klIXh6MSdxmilsKP8Z35wugJZS3dCkTm59c3hTO/AO0iMpuUhXf1q arunFjVg0uat80YpyejDi+l5wGphZxWy8P3laLxiX27Pmd3vG2P+kmWrAgMBAAGj gaYwgaMwHQYDVR0OBBYEFIgnFwmpthhgi+zruvZHWcVSVKO3MA8GA1UdEwEB/wQF MAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wLgYDVR0fBCcw JTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5jcmwwDgYDVR0PAQH/ BAQDAgGGMBAGCiqGSIb3Y2QGAgEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQBPz+9Z viz1smwvj+4ThzLoBTWobot9yWkMudkXvHcs1Gfi/ZptOllc34MBvbKuKmFysa/N w0Uwj6ODDc4dR7Txk4qjdJukw5hyhzs+r0ULklS5MruQGFNrCk4QttkdUGwhgAqJ TleMa1s8Pab93vcNIx0LSiaHP7qRkkykGRIZbVf1eliHe2iK5IaMSuviSRSqpd1V AKmuu0swruGgsbwpgOYJd+W+NKIByn/c4grmO7i77LpilfMFY0GCzQ87HUyVpNur +cmV6U/kTecmmYHpvPm0KdIBembhLoz2IYrF+Hjhga6/05Cdqa3zr/04GpZnMBxR pVzscYqCtGwPDBUfMIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQsw CQYDVQQGEwJVUzETMBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUg Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0Ew HhcNMDYwNDI1MjE0MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzET MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne +Uts9QerIjAC6Bg++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjcz y8QPTc4UadHJGXL1XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQ Z48ItCD3y6wsIG9wtj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCS C7EhFi501TwN22IWq6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINB hzOKgbEwWOxaBDKMaLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIB djAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9Bp R5R2Cf70a40uQKb3R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ CF4wggERBgNVHSAEggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcC ARYeaHR0cHM6Ly93d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCB thqBs1JlbGlhbmNlIG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFz c3VtZXMgYWNjZXB0YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJk IHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5 IGFuZCBjZXJ0aWZpY2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3 DQEBBQUAA4IBAQBcNplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizU sZAS2L70c5vu0mQPy3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJ fBdAVhEedNO3iyM7R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr 1KIkIxH3oayPc4FgxhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltk wGMzd/c6ByxW69oPIQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIq xw8dtk2cXmPIS4AXUKqK1drk/NAJBzewdXUhMYIByzCCAccCAQEwgaMwgZYxCzAJ BgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSwwKgYDVQQLDCNBcHBsZSBX b3JsZHdpZGUgRGV2ZWxvcGVyIFJlbGF0aW9uczFEMEIGA1UEAww7QXBwbGUgV29y bGR3aWRlIERldmVsb3BlciBSZWxhdGlvbnMgQ2VydGlmaWNhdGlvbiBBdXRob3Jp dHkCCA7rV4fnngmNMAkGBSsOAwIaBQAwDQYJKoZIhvcNAQEBBQAEggEAasPtnide NWyfUtewW9OSgcQA8pW+5tWMR0469cBPZR84uJa0gyfmPspySvbNOAwnrwzZHYLa ujOxZLip4DUw4F5s3QwUa3y4BXpF4J+NSn9XNvxNtnT/GcEQtCuFwgJ0o3F0ilhv MTHrwiwyx/vr+uNDqlORK8lfK+1qNp+A/kzh8eszMrn4JSeTh9ZYxLHE56WkTQGD VZXl0gKgxSOmDrcp1eQxdlymzrPv9U60wUJ0bkPfrU9qZj3mJrmrkQk61JTe3j6/ QfjfFBG9JG2mUmYQP1KQ3SypGHzDW8vngvsGu//tNU0NFfOqQu4bYU4VpQl0nPtD 4B85NkrgvQsWAQ== -----END PKCS7-----` func TestVerifyApkEcdsa(t *testing.T) { fixture := UnmarshalTestFixture(ApkEcdsaFixture) p7, err := Parse(fixture.Input) if err != nil { t.Errorf("Parse encountered unexpected error: %v", err) } p7.Content, err = base64.StdEncoding.DecodeString(ApkEcdsaContent) if err != nil { t.Errorf("Failed to decode base64 signature file: %v", err) } if err := p7.Verify(); err != nil { t.Errorf("Verify failed with error: %v", err) } } var ApkEcdsaFixture = `-----BEGIN PKCS7----- MIIDAgYJKoZIhvcNAQcCoIIC8zCCAu8CAQExDzANBglghkgBZQMEAgMFADALBgkq hkiG9w0BBwGgggH3MIIB8zCCAVSgAwIBAgIJAOxXdFsvm3YiMAoGCCqGSM49BAME MBIxEDAOBgNVBAMMB2VjLXA1MjEwHhcNMTYwMzMxMTUzMTIyWhcNNDMwODE3MTUz MTIyWjASMRAwDgYDVQQDDAdlYy1wNTIxMIGbMBAGByqGSM49AgEGBSuBBAAjA4GG AAQAYX95sSjPEQqgyLD04tNUyq9y/w8seblOpfqa/Amx6H4GFdrjGXX0YTfXKr9G hAyIyQSnNrIg0zDlWQUbBPRW4CYBLFOg1pUn1NBhKFD4NtO1KWvYtNOYDegFjRCP B0p+fEXDbq8QFDYvlh+NZUJ16+ih8XNIf1C29xuLEqN6oKOnAvajUDBOMB0GA1Ud DgQWBBT/Ra3kz60gQ7tYk3byZckcLabt8TAfBgNVHSMEGDAWgBT/Ra3kz60gQ7tY k3byZckcLabt8TAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMEA4GMADCBiAJCAP39 hYLsWk2H84oEw+HJqGGjexhqeD3vSO1mWhopripE/81oy3yV10puYoJe11xDSfcD j2VfNCHazuXO3kSxGA/1AkIBLUJxp/WYbYzhBGKr6lcxczKI/wuMfkZ6vL+0EMJV A/2uEoeqvnl7BsdkicyaOBNEADijuVdaPPIWzKClt9OaVxExgdAwgc0CAQEwHzAS MRAwDgYDVQQDDAdlYy1wNTIxAgkA7Fd0Wy+bdiIwDQYJYIZIAWUDBAIDBQAwCgYI KoZIzj0EAwQEgYswgYgCQgD1pVSNo7qTm9A6tpt3SU2yRa+xpJAnUbpZ+Gu36B71 JnQBUzRgTGevniqHpyagi7b2zjWh1uvfz9FfrITUwGMddgJCAPjiBRcl7rKpxmZn V1MvcJOX41xRSJu1wmBiYXqaJarL+gQ/Wl7RYsMtqLjmNColvLaHNxCaWOO/8nAE Hg0OMA60 -----END PKCS7-----` var ApkEcdsaContent = `U2lnbmF0dXJlLVZlcnNpb246IDEuMA0KU0hBLTUxMi1EaWdlc3QtTWFuaWZlc3Q6IFAvVDRqSWtTMjQvNzFxeFE2WW1MeEtNdkRPUUF0WjUxR090dFRzUU9yemhHRQ0KIEpaUGVpWUtyUzZYY090bStYaWlFVC9uS2tYdWVtUVBwZ2RBRzFKUzFnPT0NCkNyZWF0ZWQtQnk6IDEuMCAoQW5kcm9pZCBTaWduQXBrKQ0KDQpOYW1lOiBBbmRyb2lkTWFuaWZlc3QueG1sDQpTSEEtNTEyLURpZ2VzdDogcm9NbWVQZmllYUNQSjFJK2VzMVpsYis0anB2UXowNHZqRWVpL2U0dkN1ald0VVVWSHEzMkNXDQogMUxsOHZiZGMzMCtRc1FlN29ibld4dmhLdXN2K3c1a2c9PQ0KDQpOYW1lOiByZXNvdXJjZXMuYXJzYw0KU0hBLTUxMi1EaWdlc3Q6IG5aYW1aUzlPZTRBRW41cEZaaCtoQ1JFT3krb1N6a3hHdU5YZU0wUFF6WGVBVlVQV3hSVzFPYQ0KIGVLbThRbXdmTmhhaS9HOEcwRUhIbHZEQWdlcy9HUGtBPT0NCg0KTmFtZTogY2xhc3Nlcy5kZXgNClNIQS01MTItRGlnZXN0OiBlbWlDQld2bkVSb0g2N2lCa3EwcUgrdm5tMkpaZDlMWUNEV051N3RNYzJ3bTRtV0dYSUVpWmcNCiBWZkVPV083MFRlZnFjUVhldkNtN2hQMnRpT0U3Y0w5UT09DQoNCg==` func TestVerifyFirefoxAddon(t *testing.T) { fixture := UnmarshalTestFixture(FirefoxAddonFixture) p7, err := Parse(fixture.Input) if err != nil { t.Errorf("Parse encountered unexpected error: %v", err) } p7.Content = FirefoxAddonContent certPool := x509.NewCertPool() certPool.AppendCertsFromPEM(FirefoxAddonRootCert) // 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") } signingTime := mustParseTime("2017-02-23T09:06:16-05:00") chains, err := verifyCertChain(ee, p7.Certificates, certPool, signingTime) if err != nil { t.Error(err) } if len(chains) != 1 { t.Errorf("Expected to find one chain, but found %d", len(chains)) } if len(chains[0]) != 3 { t.Errorf("Expected to find three certificates in chain, but found %d", len(chains[0])) } if chains[0][0].Subject.CommonName != "tabscope@xuldev.org" { t.Errorf("Expected to find EE certificate with subject 'tabscope@xuldev.org', but found '%s'", chains[0][0].Subject.CommonName) } if chains[0][1].Subject.CommonName != "production-signing-ca.addons.mozilla.org" { t.Errorf("Expected to find intermediate certificate with subject 'production-signing-ca.addons.mozilla.org', but found '%s'", chains[0][1].Subject.CommonName) } if chains[0][2].Subject.CommonName != "root-ca-production-amo" { t.Errorf("Expected to find root certificate with subject 'root-ca-production-amo', but found '%s'", chains[0][2].Subject.CommonName) } } 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") } chains, err := verifyCertChain(ee, p7.Certificates, truststore, time.Now()) if err != nil { t.Fatal(err) } if len(chains) != 1 { t.Fatalf("Expected to find one chain, but found %d", len(chains)) } if len(chains[0]) != 3 { t.Fatalf("Expected to find three certificates in chain, but found %d", len(chains[0])) } if chains[0][0].Subject.CommonName != "PKCS7 Test Signer Cert" { t.Fatalf("Expected to find EE certificate with subject 'PKCS7 Test Signer Cert', but found '%s'", chains[0][0].Subject.CommonName) } if chains[0][1].Subject.CommonName != "PKCS7 Test Intermediate Cert" { t.Fatalf("Expected to find intermediate certificate with subject 'PKCS7 Test Intermediate Cert', but found '%s'", chains[0][1].Subject.CommonName) } if chains[0][2].Subject.CommonName != "PKCS7 Test Root CA" { t.Fatalf("Expected to find root certificate with subject 'PKCS7 Test Root CA', but found '%s'", chains[0][2].Subject.CommonName) } os.Remove(tmpSignerCertFile.Name()) // clean up os.Remove(tmpSignerKeyFile.Name()) // clean up } os.Remove(tmpInterCertFile.Name()) // clean up } } os.Remove(tmpContentFile.Name()) // clean up } var sampleAppleAppAttestationReceiptFixture = []byte(` -----BEGIN ----- MIAGCSqGSIb3DQEHAqCAMIACAQExDzANBglghkgBZQMEAgEFADCABgkqhkiG9w0B BwGggCSABIID6DGCBAswIwIBAgIBAQQbOFlFMjNOWlM1Ny5jb20ua2F5YWsudHJh dmVsMIIC7gIBAwIBAQSCAuQwggLgMIICZqADAgECAgYBdNZm2hAwCgYIKoZIzj0E AwIwTzEjMCEGA1UEAwwaQXBwbGUgQXBwIEF0dGVzdGF0aW9uIENBIDExEzARBgNV BAoMCkFwcGxlIEluYy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwHhcNMjAwOTI3MjAy ODE4WhcNMjAwOTMwMjAyODE4WjCBkTFJMEcGA1UEAwxANTY3N2VhOGQyYTc0YWQ2 Y2IyYThkODZiN2UxZmJkZmM4ODRiMjJmNWVlNjEzM2MwOTg5MTE1NDMwOTc4NzY0 YTEaMBgGA1UECwwRQUFBIENlcnRpZmljYXRpb24xEzARBgNVBAoMCkFwcGxlIElu Yy4xEzARBgNVBAgMCkNhbGlmb3JuaWEwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC AASVMXfBQ2n1hERgyf113lWGstIXHIbeiLJi+oIYyZj/aqNGPACJWSmRK/v5B67u Z2bZrNNSoRrwJyoNiwerRvmdo4HqMIHnMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/ BAQDAgTwMHUGCSqGSIb3Y2QIBQRoMGakAwIBCr+JMAMCAQG/iTEDAgEAv4kyAwIB Ab+JMwMCAQG/iTQdBBs4WUUyM05aUzU3LmNvbS5rYXlhay50cmF2ZWylBgQEc2tz IL+JNgMCAQW/iTcDAgEAv4k5AwIBAL+JOgMCAQAwGwYJKoZIhvdjZAgHBA4wDL+K eAgEBjE0LjAuMTAzBgkqhkiG92NkCAIEJjAkoSIEIMmvmBS106CCCA0l+C2IhciY KtSnKp+1qGmv597EqyV9MAoGCCqGSM49BAMCA2gAMGUCMQC2xV2A+e9j96iphB6G 3Vm53fzMw+lZ/LlgKAHvZy6K3gNCnyMev8/O79TwiHFxBqcCMDwneBrN7P2REtFV dPjdGFSqJQ1AS2VJtX31VRHZzY7FNRLqyTPqkuF9xnay6NWlYzAoAgEEAgEBBCC9 2s44kCAWK/w87A2CBCqO7rxzyw/c+bUL3gOkdjKdZjBgAgEFAgEBBFgrZVk0U1Nu T2pkaWsrWGkzaUJTK1NrR1ZTR004NmlKeVBTYWMrbnUxdU94d2ZvVEFLbXg4U2N0 M1hyQmorenYvcE9kVUpodzJ6N3E2SDhHem8vekJtdz09MA4CAQYCAQEEBkFUVEVT VDASAgEHAgEBBApwcm9kdWN0aW9uMCACAQwCAQEEGDIwMjAtMDktMjhUMjA6Mjg6 MTkEJy45NDJaMCACARUCAQEEGDIwMjAtMTItMjdUMjA6Mjg6MTkuOTQyWgAAAAAA AKCAMIIDrTCCA1SgAwIBAgIQWTNWreVZgs9EQjes30UbUzAKBggqhkjOPQQDAjB8 MTAwLgYDVQQDDCdBcHBsZSBBcHBsaWNhdGlvbiBJbnRlZ3JhdGlvbiBDQSA1IC0g RzExJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYD VQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0yMDA1MTkxNzQ3MzFaFw0y MTA2MTgxNzQ3MzFaMFoxNjA0BgNVBAMMLUFwcGxpY2F0aW9uIEF0dGVzdGF0aW9u IEZyYXVkIFJlY2VpcHQgU2lnbmluZzETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkG A1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR/6RU0bMOKe5g8k9HQ Q1/Yq9pWcATTLFiGZVGVerR498sq+LpF9/p46sYsSeT5zcCEtQMU8QIz2pt2+kQq K7hyo4IB2DCCAdQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBTZF/5LZ5A4S5L0 287VV4AUC489yTBDBggrBgEFBQcBAQQ3MDUwMwYIKwYBBQUHMAGGJ2h0dHA6Ly9v Y3NwLmFwcGxlLmNvbS9vY3NwMDMtYWFpY2E1ZzEwMTCCARwGA1UdIASCARMwggEP MIIBCwYJKoZIhvdjZAUBMIH9MIHDBggrBgEFBQcCAjCBtgyBs1JlbGlhbmNlIG9u IHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0YW5j ZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBjb25k aXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZpY2F0 aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMDUGCCsGAQUFBwIBFilodHRwOi8vd3d3 LmFwcGxlLmNvbS9jZXJ0aWZpY2F0ZWF1dGhvcml0eTAdBgNVHQ4EFgQUaR7HD0fs 443ddTdE8+nhWmwQViUwDgYDVR0PAQH/BAQDAgeAMA8GCSqGSIb3Y2QMDwQCBQAw CgYIKoZIzj0EAwIDRwAwRAIgJRgWXF4pnFn2hTmtXduZ9jc+9g7NCEWp/Xca1iQt LCICIF0qmypfq6NjgWWNGED3r0gL12uhlNg0IIf01pNbtRuuMIIC+TCCAn+gAwIB AgIQVvuD1Cv/jcM3mSO1Wq5uvTAKBggqhkjOPQQDAzBnMRswGQYDVQQDDBJBcHBs ZSBSb290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xOTAz MjIxNzUzMzNaFw0zNDAzMjIwMDAwMDBaMHwxMDAuBgNVBAMMJ0FwcGxlIEFwcGxp Y2F0aW9uIEludGVncmF0aW9uIENBIDUgLSBHMTEmMCQGA1UECwwdQXBwbGUgQ2Vy dGlmaWNhdGlvbiBBdXRob3JpdHkxEzARBgNVBAoMCkFwcGxlIEluYy4xCzAJBgNV BAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEks5jvX2GsasoCjsc4a/7 BJSAkaz2Md+myyg1b0RL4SHlV90SjY26gnyVvkn6vjPKrs0EGfEvQyX69L6zy4N+ uqOB9zCB9DAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFLuw3qFYM4iapIqZ 3r6966/ayySrMEYGCCsGAQUFBwEBBDowODA2BggrBgEFBQcwAYYqaHR0cDovL29j c3AuYXBwbGUuY29tL29jc3AwMy1hcHBsZXJvb3RjYWczMDcGA1UdHwQwMC4wLKAq oCiGJmh0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxlcm9vdGNhZzMuY3JsMB0GA1Ud DgQWBBTZF/5LZ5A4S5L0287VV4AUC489yTAOBgNVHQ8BAf8EBAMCAQYwEAYKKoZI hvdjZAYCAwQCBQAwCgYIKoZIzj0EAwMDaAAwZQIxAI1vpp+h4OTsW05zipJ/PXhT mI/02h9YHsN1Sv44qEwqgxoaqg2mZG3huZPo0VVM7QIwZzsstOHoNwd3y9Xsdqga OlU7PzVqyMXmkrDhYb6ASWnkXyupbOERAqrMYdk4t3NKMIICQzCCAcmgAwIBAgII LcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwSQXBwbGUgUm9vdCBDQSAt IEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTETMBEG A1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcNMTQwNDMwMTgxOTA2WhcN MzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBSb290IENBIC0gRzMxJjAk BgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApB cHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49AgEGBSuBBAAiA2IABJjp Lz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtfTjjTuxxEtX/1H7YyYl3J 6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517IDvYuVTZXpmkOlEKMaNC MEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySrMA8GA1UdEwEB/wQFMAMB Af8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gAMGUCMQCD6cHEFl4aXTQY 2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4at+qIxUCMG1mihDK1A3U T82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM6BgD56KyKAAAMYIBljCC AZICAQEwgZAwfDEwMC4GA1UEAwwnQXBwbGUgQXBwbGljYXRpb24gSW50ZWdyYXRp b24gQ0EgNSAtIEcxMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhv cml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMCEFkzVq3lWYLP REI3rN9FG1MwDQYJYIZIAWUDBAIBBQCggZUwGAYJKoZIhvcNAQkDMQsGCSqGSIb3 DQEHATAcBgkqhkiG9w0BCQUxDxcNMjAwOTI4MjAyODIwWjAqBgkqhkiG9w0BCTQx HTAbMA0GCWCGSAFlAwQCAQUAoQoGCCqGSM49BAMCMC8GCSqGSIb3DQEJBDEiBCDL FFlod6+72Z/XBkt+1Gg9wc1binQgsCMpZ5A1Ge4fnjAKBggqhkjOPQQDAgRHMEUC IQCE46Koolc/FuL29/MUK1Auqt2XUJPK2DD9aDJgbPPKBwIgbsggotsin/9j1y/Z 4pBdpYCE6+FY7zCTIp/IaUWymtYAAAAAAAA= -----END -----`) func TestParseSignedOctetStringWithAppleAttestation(t *testing.T) { decodedReceipt, _ := pem.Decode(sampleAppleAppAttestationReceiptFixture) p7, err := Parse(decodedReceipt.Bytes) if err != nil { t.Fatal("could not parse receipt containing compound octet string", err) } expectedContent := "3182040b3023020102020101041b38594532334e5a5335372e636f6d2e6b617961" + "6b2e74726176656c308202ee020103020101048202e4308202e030820266a00302010202060174d666da10" + "300a06082a8648ce3d040302304f3123302106035504030c1a4170706c6520417070204174746573746174" + "696f6e204341203131133011060355040a0c0a4170706c6520496e632e3113301106035504080c0a43616c" + "69666f726e6961301e170d3230303932373230323831385a170d3230303933303230323831385a3081913149" + "304706035504030c4035363737656138643261373461643663623261386438366237653166626466633838346" + "232326635656536313333633039383931313534333039373837363461311a3018060355040b0c1141414120436" + "57274696669636174696f6e31133011060355040a0c0a4170706c6520496e632e3113301106035504080c0a436" + "16c69666f726e69613059301306072a8648ce3d020106082a8648ce3d03010703420004953177c14369f5844460" + "c9fd75de5586b2d2171c86de88b262fa8218c998ff6aa3463c00895929912bfbf907aeee6766d9acd352a11af02" + "72a0d8b07ab46f99da381ea3081e7300c0603551d130101ff04023000300e0603551d0f0101ff0404030204f0307" + "506092a864886f76364080504683066a40302010abf893003020101bf893103020100bf893203020101bf8933030" + "20101bf89341d041b38594532334e5a5335372e636f6d2e6b6179616b2e74726176656ca5060404736b7320bf893603" + "020105bf893703020100bf893903020100bf893a03020100301b06092a864886f763640807040e300cbf8a780804063" + "1342e302e31303306092a864886f76364080204263024a1220420c9af9814b5d3a082080d25f82d8885c8982ad4a72a9fb5a8" + "69afe7dec4ab257d300a06082a8648ce3d0403020368003065023100b6c55d80f9ef63f7a8a9841e86dd59b9ddfcccc3e959f" + "cb9602801ef672e8ade03429f231ebfcfceefd4f088717106a702303c27781acdecfd9112d15574f8dd1854aa250d404b6549b5" + "7df55511d9cd8ec53512eac933ea92e17dc676b2e8d5a56330280201040201010420bddace389020162bfc3cec0d82042a8eee" + "bc73cb0fdcf9b50bde03a476329d66306002010502010104582b65593453536e4f6a64696b2b5869336942532b536b47565347" + "4d3836694a79505361632b6e7531754f7877666f54414b6d7838536374335872426a2b7a762f704f64554a6877327a37713648" + "38477a6f2f7a426d773d3d300e02010602010104064154544553543012020107020101040a70726f64756374696f6e30200201" + "0c0201010418323032302d30392d32385432303a32383a31392e3934325a30200201150201010418323032302d31322d3237" + "5432303a32383a31392e3934325a" if hex.EncodeToString(p7.Content) != expectedContent { t.Fatal("could not parse contained compound octet string content fully") } } func TestAzureAttestationSignatureValidation(t *testing.T) { // attested data from https://learn.microsoft.com/en-us/azure/virtual-machines/instance-metadata-service?tabs=linux#attested-data b64 := `MIIEEgYJKoZIhvcNAQcCoIIEAzCCA/8CAQExDzANBgkqhkiG9w0BAQsFADCBugYJKoZIhvcNAQcBoIGsBIGpeyJub25jZSI6IjEyMzQ1NjY3NjYiLCJwbGFuIjp7Im5hbWUiOiIiLCJwcm9kdWN0IjoiIiwicHVibGlzaGVyIjoiIn0sInRpbWVTdGFtcCI6eyJjcmVhdGVkT24iOiIxMS8yMC8xOCAyMjowNzozOSAtMDAwMCIsImV4cGlyZXNPbiI6IjExLzIwLzE4IDIyOjA4OjI0IC0wMDAwIn0sInZtSWQiOiIifaCCAj8wggI7MIIBpKADAgECAhBnxW5Kh8dslEBA0E2mIBJ0MA0GCSqGSIb3DQEBBAUAMCsxKTAnBgNVBAMTIHRlc3RzdWJkb21haW4ubWV0YWRhdGEuYXp1cmUuY29tMB4XDTE4MTEyMDIxNTc1N1oXDTE4MTIyMDIxNTc1NlowKzEpMCcGA1UEAxMgdGVzdHN1YmRvbWFpbi5tZXRhZGF0YS5henVyZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAML/tBo86ENWPzmXZ0kPkX5dY5QZ150mA8lommszE71x2sCLonzv4/UWk4H+jMMWRRwIea2CuQ5RhdWAHvKq6if4okKNt66fxm+YTVz9z0CTfCLmLT+nsdfOAsG1xZppEapC0Cd9vD6NCKyE8aYI1pliaeOnFjG0WvMY04uWz2MdAgMBAAGjYDBeMFwGA1UdAQRVMFOAENnYkHLa04Ut4Mpt7TkJFfyhLTArMSkwJwYDVQQDEyB0ZXN0c3ViZG9tYWluLm1ldGFkYXRhLmF6dXJlLmNvbYIQZ8VuSofHbJRAQNBNpiASdDANBgkqhkiG9w0BAQQFAAOBgQCLSM6aX5Bs1KHCJp4VQtxZPzXF71rVKCocHy3N9PTJQ9Fpnd+bYw2vSpQHg/AiG82WuDFpPReJvr7Pa938mZqW9HUOGjQKK2FYDTg6fXD8pkPdyghlX5boGWAMMrf7bFkup+lsT+n2tRw2wbNknO1tQ0wICtqy2VqzWwLi45RBwTGB6DCB5QIBATA/MCsxKTAnBgNVBAMTIHRlc3RzdWJkb21haW4ubWV0YWRhdGEuYXp1cmUuY29tAhBnxW5Kh8dslEBA0E2mIBJ0MA0GCSqGSIb3DQEBCwUAMA0GCSqGSIb3DQEBAQUABIGAld1BM/yYIqqv8SDE4kjQo3Ul/IKAVR8ETKcve5BAdGSNkTUooUGVniTXeuvDj5NkmazOaKZp9fEtByqqPOyw/nlXaZgOO44HDGiPUJ90xVYmfeK6p9RpJBu6kiKhnnYTelUk5u75phe5ZbMZfBhuPhXmYAdjc7Nmw97nx8NnprQ=` data, err := base64.StdEncoding.DecodeString(b64) if err != nil { t.Errorf("failed decoding base64 attested data: %v", err) } p7, err := Parse(data) if err != nil { t.Errorf("failed parsing attested data: %v", err) } err = p7.Verify() if err != nil { t.Errorf("failed verifying data: %v", err) } }