]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.17] crypto/x509: support NumericString in DN components
authorRoland Shoemaker <roland@golang.org>
Fri, 3 Sep 2021 16:56:23 +0000 (09:56 -0700)
committerRoland Shoemaker <roland@golang.org>
Wed, 9 Feb 2022 21:57:04 +0000 (21:57 +0000)
Updates #48171
Fixes #51000

Change-Id: Ia2e1920c0938a1f8659935a4f725a7e5090ef2c0
Reviewed-on: https://go-review.googlesource.com/c/go/+/347034
Trust: Roland Shoemaker <roland@golang.org>
Run-TryBot: Roland Shoemaker <roland@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
(cherry picked from commit 896df422a7cecbace10f5877beeeb1476b6061ae)
Reviewed-on: https://go-review.googlesource.com/c/go/+/382857
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
src/crypto/x509/parser.go
src/crypto/x509/parser_test.go [new file with mode: 0644]

index f085162a4e88be3d998cdb1bdfebb61282cdee0f..9a500a8098ca8f5c8212c32c19df870dc3333874 100644 (file)
@@ -51,9 +51,9 @@ func isPrintable(b byte) bool {
 }
 
 // parseASN1String parses the ASN.1 string types T61String, PrintableString,
-// UTF8String, BMPString, and IA5String. This is mostly copied from the
-// respective encoding/asn1.parse... methods, rather than just increasing
-// the API surface of that package.
+// 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:
@@ -93,6 +93,13 @@ func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
                        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)
 }
diff --git a/src/crypto/x509/parser_test.go b/src/crypto/x509/parser_test.go
new file mode 100644 (file)
index 0000000..d7cf7ea
--- /dev/null
@@ -0,0 +1,102 @@
+// 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 x509
+
+import (
+       "encoding/asn1"
+       "testing"
+
+       cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+func TestParseASN1String(t *testing.T) {
+       tests := []struct {
+               name        string
+               tag         cryptobyte_asn1.Tag
+               value       []byte
+               expected    string
+               expectedErr string
+       }{
+               {
+                       name:     "T61String",
+                       tag:      cryptobyte_asn1.T61String,
+                       value:    []byte{80, 81, 82},
+                       expected: string("PQR"),
+               },
+               {
+                       name:     "PrintableString",
+                       tag:      cryptobyte_asn1.PrintableString,
+                       value:    []byte{80, 81, 82},
+                       expected: string("PQR"),
+               },
+               {
+                       name:        "PrintableString (invalid)",
+                       tag:         cryptobyte_asn1.PrintableString,
+                       value:       []byte{1, 2, 3},
+                       expectedErr: "invalid PrintableString",
+               },
+               {
+                       name:     "UTF8String",
+                       tag:      cryptobyte_asn1.UTF8String,
+                       value:    []byte{80, 81, 82},
+                       expected: string("PQR"),
+               },
+               {
+                       name:        "UTF8String (invalid)",
+                       tag:         cryptobyte_asn1.UTF8String,
+                       value:       []byte{255},
+                       expectedErr: "invalid UTF-8 string",
+               },
+               {
+                       name:     "BMPString",
+                       tag:      cryptobyte_asn1.Tag(asn1.TagBMPString),
+                       value:    []byte{80, 81},
+                       expected: string("偑"),
+               },
+               {
+                       name:        "BMPString (invalid length)",
+                       tag:         cryptobyte_asn1.Tag(asn1.TagBMPString),
+                       value:       []byte{255},
+                       expectedErr: "invalid BMPString",
+               },
+               {
+                       name:     "IA5String",
+                       tag:      cryptobyte_asn1.IA5String,
+                       value:    []byte{80, 81},
+                       expected: string("PQ"),
+               },
+               {
+                       name:        "IA5String (invalid)",
+                       tag:         cryptobyte_asn1.IA5String,
+                       value:       []byte{255},
+                       expectedErr: "invalid IA5String",
+               },
+               {
+                       name:     "NumericString",
+                       tag:      cryptobyte_asn1.Tag(asn1.TagNumericString),
+                       value:    []byte{49, 50},
+                       expected: string("12"),
+               },
+               {
+                       name:        "NumericString (invalid)",
+                       tag:         cryptobyte_asn1.Tag(asn1.TagNumericString),
+                       value:       []byte{80},
+                       expectedErr: "invalid NumericString",
+               },
+       }
+
+       for _, tc := range tests {
+               t.Run(tc.name, func(t *testing.T) {
+                       out, err := parseASN1String(tc.tag, tc.value)
+                       if err != nil && err.Error() != tc.expectedErr {
+                               t.Fatalf("parseASN1String returned unexpected error: got %q, want %q", err, tc.expectedErr)
+                       } else if err == nil && tc.expectedErr != "" {
+                               t.Fatalf("parseASN1String didn't fail, expected: %s", tc.expectedErr)
+                       }
+                       if out != tc.expected {
+                               t.Fatalf("parseASN1String returned unexpected value: got %q, want %q", out, tc.expected)
+                       }
+               })
+       }
+}