Skip to content

Commit

Permalink
crypto/x509: write exact BitLength in ASN.1 encoding for certificate …
Browse files Browse the repository at this point in the history
…KeyUsage

The encoded value of the certificate KeyUsage did contain additonal padding
that was not present with other certificate generators. According to ITU-T
X.690 the BitLength value should have no padding in a DER encoding.

See discussion:
https://groups.google.com/forum/#!topic/golang-nuts/dzaJ3hMpDcs

This CL has been discussed at: http://golang.org/cl/168990043

Change-Id: I1eff3f441b0566966a2d279631901ad9287c917d
Reviewed-on: https://go-review.googlesource.com/2255
Reviewed-by: Adam Langley <[email protected]>
  • Loading branch information
agl committed Jan 15, 2015
1 parent d1210ac commit 2fe8ead
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
23 changes: 22 additions & 1 deletion src/crypto/x509/x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,26 @@ func reverseBitsInAByte(in byte) byte {
return b3
}

// asn1BitLength returns the bit-length of bitString by considering the
// most-significant bit in a byte to be the "first" bit. This convention
// matches ASN.1, but differs from almost everything else.
func asn1BitLength(bitString []byte) int {
bitLen := len(bitString) * 8

for i := range bitString {
b := bitString[len(bitString)-i-1]

for bit := uint(0); bit < 8; bit++ {
if (b>>bit)&1 == 1 {
return bitLen
}
bitLen--
}
}

return 0
}

var (
oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
oidExtensionKeyUsage = []int{2, 5, 29, 15}
Expand Down Expand Up @@ -1203,7 +1223,8 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
l = 2
}

ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
bitString := a[:l]
ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
if err != nil {
return
}
Expand Down
22 changes: 22 additions & 0 deletions src/crypto/x509/x509_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,28 @@ func TestMaxPathLen(t *testing.T) {
}
}

func TestASN1BitLength(t *testing.T) {
tests := []struct {
bytes []byte
bitLen int
}{
{nil, 0},
{[]byte{0x00}, 0},
{[]byte{0x00, 0x00}, 0},
{[]byte{0xf0}, 4},
{[]byte{0x88}, 5},
{[]byte{0xff}, 8},
{[]byte{0xff, 0x80}, 9},
{[]byte{0xff, 0x81}, 16},
}

for i, test := range tests {
if got := asn1BitLength(test.bytes); got != test.bitLen {
t.Errorf("#%d: calculated bit-length of %d for %x, wanted %d", i, got, test.bytes, test.bitLen)
}
}
}

// This CSR was generated with OpenSSL:
// openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
//
Expand Down

0 comments on commit 2fe8ead

Please sign in to comment.