From 8f851d3338cde7ebc879e5fa48b3fdb2084ef402 Mon Sep 17 00:00:00 2001 From: rgnote <5878554+rgnote@users.noreply.github.com> Date: Thu, 26 May 2022 18:33:15 -0700 Subject: [PATCH 1/2] Fix package name and add DER parsing support Signed-off-by: rgnote <5878554+rgnote@users.noreply.github.com> --- x509/cert.go | 32 +++++++++++++++++++++----------- x509/key.go | 2 +- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/x509/cert.go b/x509/cert.go index 995cee70..23d46b3b 100644 --- a/x509/cert.go +++ b/x509/cert.go @@ -1,4 +1,4 @@ -package cryptoutil +package x509 import ( "crypto/x509" @@ -12,21 +12,31 @@ func ReadCertificateFile(path string) ([]*x509.Certificate, error) { if err != nil { return nil, err } - return ParseCertificatePEM(data) + return parseCertificates(data) } -// ParseCertificatePEM parses a certificate PEM, -// Does not perform any additional validations if the certs are a valid cert chain. -func ParseCertificatePEM(data []byte) ([]*x509.Certificate, error) { +// parseCertificates parses certificates from either PEM or DER data +// returns an empty list if no certificates are found +func parseCertificates(data []byte) ([]*x509.Certificate, error) { var certs []*x509.Certificate block, rest := pem.Decode(data) - for block != nil { - cert, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return nil, err + if block == nil { + // data may be in DER format + cert, err := x509.ParseCertificate(data) + if err == nil { + certs = append(certs, cert) + } + } else { + // data is in PEM format + for block != nil { + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + return nil, err + } + certs = append(certs, cert) + block, rest = pem.Decode(rest) } - certs = append(certs, cert) - block, rest = pem.Decode(rest) } + return certs, nil } diff --git a/x509/key.go b/x509/key.go index 2599c5ee..68e7f615 100644 --- a/x509/key.go +++ b/x509/key.go @@ -1,4 +1,4 @@ -package cryptoutil +package x509 import ( "crypto" From 5a9386cb716a6d0f9475969e070fee65a67e6a48 Mon Sep 17 00:00:00 2001 From: rgnote <5878554+rgnote@users.noreply.github.com> Date: Wed, 1 Jun 2022 11:57:35 -0700 Subject: [PATCH 2/2] address comments Signed-off-by: rgnote <5878554+rgnote@users.noreply.github.com> --- x509/cert.go | 7 ++--- x509/cert_test.go | 50 ++++++++++++++++++++++++++++++++++++ x509/testdata/der.der | Bin 0 -> 867 bytes x509/testdata/invalid | 2 ++ x509/testdata/multi-der.der | Bin 0 -> 1734 bytes x509/testdata/multi-pem.crt | 42 ++++++++++++++++++++++++++++++ x509/testdata/pem.crt | 21 +++++++++++++++ 7 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 x509/cert_test.go create mode 100644 x509/testdata/der.der create mode 100644 x509/testdata/invalid create mode 100644 x509/testdata/multi-der.der create mode 100644 x509/testdata/multi-pem.crt create mode 100644 x509/testdata/pem.crt diff --git a/x509/cert.go b/x509/cert.go index 23d46b3b..20e11a41 100644 --- a/x509/cert.go +++ b/x509/cert.go @@ -22,10 +22,11 @@ func parseCertificates(data []byte) ([]*x509.Certificate, error) { block, rest := pem.Decode(data) if block == nil { // data may be in DER format - cert, err := x509.ParseCertificate(data) - if err == nil { - certs = append(certs, cert) + derCerts, err := x509.ParseCertificates(data) + if err != nil { + return nil, err } + certs = append(certs, derCerts...) } else { // data is in PEM format for block != nil { diff --git a/x509/cert_test.go b/x509/cert_test.go new file mode 100644 index 00000000..2de95b7b --- /dev/null +++ b/x509/cert_test.go @@ -0,0 +1,50 @@ +package x509 + +import ( + "crypto/x509" + "testing" +) + +func TestLoadPemFile(t *testing.T) { + certs, err := ReadCertificateFile("testdata/pem.crt") + verifyNoError(t, err) + verifyNumCerts(t, certs, 1) +} + +func TestLoadMultiPemFile(t *testing.T) { + certs, err := ReadCertificateFile("testdata/multi-pem.crt") + verifyNoError(t, err) + verifyNumCerts(t, certs, 2) +} + +func TestLoadDerFile(t *testing.T) { + certs, err := ReadCertificateFile("testdata/der.der") + verifyNoError(t, err) + verifyNumCerts(t, certs, 1) +} + +func TestLoadMultiDerFile(t *testing.T) { + certs, err := ReadCertificateFile("testdata/multi-der.der") + verifyNoError(t, err) + verifyNumCerts(t, certs, 2) +} + +func TestLoadInvalidFile(t *testing.T) { + certs, err := ReadCertificateFile("testdata/invalid") + if err == nil { + t.Fatalf("invalid file should throw an error") + } + verifyNumCerts(t, certs, 0) +} + +func verifyNoError(t *testing.T, err error) { + if err != nil { + t.Fatalf("Error : %q", err) + } +} + +func verifyNumCerts(t *testing.T, certs []*x509.Certificate, num int) { + if len(certs) != num { + t.Fatalf("test case should return only %d certificate/s", num) + } +} diff --git a/x509/testdata/der.der b/x509/testdata/der.der new file mode 100644 index 0000000000000000000000000000000000000000..232c4b6121f7236eb429572c591127e8aa60166f GIT binary patch literal 867 zcmXqLVvaXxVsc-=%*4pV#LdD01dNIi!5oVWc-c6$+C196^D;7WvoaX?7%CXZu`!3T za0`pO=j10P<^*S^=P3l`=a(orJ1XcZ1Q{C&8wi3_a0zoERKNt8kp&Ip#CZ)Y4U7#f z3=KdaN}SgSnM-Bcni!Rky~D`Lz}&>h&tTBR$i>ve$jER;wQNEqTZNL?*8|PlT25)q z`^#D;cyw(?(H}P^=i{5Y=CZ`AoYwPxn9$_*FlaSTqkBQl-IR;3zv?XJZ?fglUN`;v zHjy@g%H7t&4dp!?4?QnsCF#q@{hF3>zf*mx#eBBwb|+7(Me-Kk+i>Eg8eg;MvG>v4 zmsk=`c`noVmTCR%^a+iLPv>?ehMTV`5xG?_`;jk@3_*EunPN{PO=3Mc%Jd@cgsZLDb_S zlVPG{+>Yt**OqTjnN_tv{-E&t*-5{7a~_0bimhb6mG`oFa$(uA%+@AxCT2zk#>Gws z4hDR{_><*lWc<&<0!$HX2K*qtFo@4;zzn1eWI+OaEMhDo{U5yRSLnH_tn&@{l{~Ba z-lMzHdyqpJm}r2Z%*f#FaQi^Os(&YV-hZDK;_A738Uv@}n$5y(Z5r&xr?Q`w?A*nm zyKV{B<*y$<@^|eoPWNg)?owUxV0~UrKC@<@v8C(bz9&1wb5{Kkn)W96nC=smoSjpW zf8PntNDs4X-f`Yk@$kuvf9Gx;3SM<)Lf6X=v2Hz6?^Z=gm=bbRTvM6jq*l?z>U;6vh=ZpX(UQTUo1KYI8Veth&tTBR$i>ve$jER;wQNEqTZNL?*8|PlT25)q z`^#D;cyw(?(H}P^=i{5Y=CZ`AoYwPxn9$_*FlaSTqkBQl-IR;3zv?XJZ?fglUN`;v zHjy@g%H7t&4dp!?4?QnsCF#q@{hF3>zf*mx#eBBwb|+7(Me-Kk+i>Eg8eg;MvG>v4 zmsk=`c`noVmTCR%^a+iLPv>?ehMTV`5xG?_`;jk@3_*EunPN{PO=3Mc%Jd@cgsZLDb_S zlVPG{+>Yt**OqTjnN_tv{-E&t*-5{7a~_0bimhb6mG`oFa$(uA%+@AxCT2zk#>Gws z4hDR{_><*lWc<&<0!$HX2K*qtFo@4;zzn1eWI+OaEMhDo{U5yRSLnH_tn&@{l{~Ba z-lMzHdyqpJm}r2Z%*f#FaQi^Os(&YV-hZDK;_A738Uv@}n$5y(Z5r&xr?Q`w?A*nm zyKV{B<*y$<@^|eoPWNg)?owUxV0~UrKC@<@v8C(bz9&1wb5{Kkn)W96nC=smoSjpW zf8PntNDs4X-f`Yk@$kuvf9Gx;3SM<)Lf6X=v2Hz6?^Z=gm=bbRTvM6jq*l?z>U;6vh=ZpX(UQTUo1KYI8VetQR0D)DFHvj+t literal 0 HcmV?d00001 diff --git a/x509/testdata/multi-pem.crt b/x509/testdata/multi-pem.crt new file mode 100644 index 00000000..a5658a22 --- /dev/null +++ b/x509/testdata/multi-pem.crt @@ -0,0 +1,42 @@ +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- diff --git a/x509/testdata/pem.crt b/x509/testdata/pem.crt new file mode 100644 index 00000000..8afb2190 --- /dev/null +++ b/x509/testdata/pem.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE-----