Skip to content

Conversation

@areed
Copy link
Contributor

@areed areed commented Feb 20, 2025

When importing a private key into an NSS database with a certificate, the certificate common name is used as the value of the CKA_SUBJECT attribute on the key object. This fixes the serialization to work when the CN contains characters that aren't valid for the asn1 printable string type.

💔Thank you!

joshdrake
joshdrake previously approved these changes Feb 20, 2025
nssdb/keys.go Outdated
Comment on lines 244 to 248
var printableRx = regexp.MustCompile(`^[a-zA-Z0-9 '()+,\-.\\:=?]*$`)

func isPrintable(s string) bool {
return printableRx.MatchString(s)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a limitation of nssdb?

The unicode package has a method for validating whether a run is printable IsPrint(rune). Some more complicated limitations can be done using the In(r rune, ranges ...*RangeTable) function, for example, to limit the runes to be in the Latin RangeTable, or you can also create your own.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refers to the asn.1 type of printable strings, which is more restrictive than the unicode IsPrint function. In a certificate where the common name contains only printable characters it's encoded with the asn1 tag for PrintableString. For anything else it gets the asn1 tag for UTF8String. (At least that's how it works for our certificates.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looping runes will perform better:

crypto/x509util/utils.go

Lines 183 to 213 in 9fd47c3

// isPrintableString reports whether the given s is a valid ASN.1 PrintableString.
// If asterisk is allowAsterisk then '*' is also allowed, reflecting existing
// practice. If ampersand is allowAmpersand then '&' is allowed as well.
func isPrintableString(s string, asterisk, ampersand bool) bool {
for _, b := range s {
valid := '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.
(asterisk && 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.
(ampersand && b == '&')
if !valid {
return false
}
}
return true
}

Go ans1 loops around bytes using a similar method, this is for one byte https://github.com/golang/go/blob/f24b299df2896a4e8a80863dbb55a264f4b9bb68/src/encoding/asn1/asn1.go#L422-L444

Copy link
Contributor Author

@areed areed Feb 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

@maraino maraino left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@areed areed merged commit 9694c65 into master Feb 24, 2025
12 checks passed
@areed areed deleted the areed/nssdb-non-printable branch February 24, 2025 21:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants