Skip to content

Commit 6e95914

Browse files
Andres Amaya Garciasimonbutcher
authored andcommitted
Add new function mbedtls_asn1_write_named_bitstring()
Add a new function mbedtls_asn1_write_named_bitstring() that removes trailing 0s at the end of DER encoded bitstrings. The function is implemented according to Hanno Becker's suggestions. This commit also changes the functions x509write_crt_set_ns_cert_type and crt_set_key_usage to call the new function as the use named bitstrings instead of the regular bitstrings.
1 parent 86016a0 commit 6e95914

File tree

4 files changed

+110
-25
lines changed

4 files changed

+110
-25
lines changed

include/mbedtls/asn1write.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,26 @@ int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
282282
int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
283283
const unsigned char *buf, size_t bits );
284284

285+
/**
286+
* \brief Write a named bitstring tag (MBEDTLS_ASN1_BIT_STRING) and
287+
* value in ASN.1 format
288+
* Note: function works backwards in data buffer
289+
*
290+
* As stated in RFC5280 Appending B, trailing zeroes are
291+
* omitted when encoding named bitstrings in DER.
292+
*
293+
* \param p Reference to current position pointer.
294+
* \param start Start of the buffer (for bounds-checking).
295+
* \param buf The bitstring.
296+
* \param bits The total number of bits in the bitstring.
297+
*
298+
* \return The length written or a negative error code.
299+
*/
300+
int mbedtls_asn1_write_named_bitstring( unsigned char **p,
301+
unsigned char *start,
302+
const unsigned char *buf,
303+
size_t bits );
304+
285305
/**
286306
* \brief Write an octet string tag (#MBEDTLS_ASN1_OCTET_STRING)
287307
* and value in ASN.1 format.

library/asn1write.c

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -290,26 +290,75 @@ int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
290290
return( mbedtls_asn1_write_tagged_string(p, start, MBEDTLS_ASN1_IA5_STRING, text, text_len) );
291291
}
292292

293+
int mbedtls_asn1_write_named_bitstring( unsigned char **p,
294+
unsigned char *start,
295+
const unsigned char *buf,
296+
size_t bits )
297+
{
298+
size_t unused_bits, byte_len;
299+
const unsigned char *cur_byte;
300+
unsigned char cur_byte_shifted;
301+
unsigned char bit;
302+
303+
byte_len = ( bits + 7 ) / 8;
304+
unused_bits = ( byte_len * 8 ) - bits;
305+
306+
/*
307+
* Named bitstrings require that trailing 0s are excluded in the encoding
308+
* of the bitstring. Trailing 0s are considered part of the 'unused' bits
309+
* when encoding this value in the first content octet
310+
*/
311+
if( bits != 0 )
312+
{
313+
cur_byte = buf + byte_len - 1;
314+
cur_byte_shifted = *cur_byte >> unused_bits;
315+
316+
for( ; ; )
317+
{
318+
bit = cur_byte_shifted & 0x1;
319+
cur_byte_shifted >>= 1;
320+
321+
if( bit != 0 )
322+
break;
323+
324+
bits--;
325+
if( bits == 0 )
326+
break;
327+
328+
if( bits % 8 == 0 )
329+
cur_byte_shifted = *--cur_byte;
330+
}
331+
}
332+
333+
return( mbedtls_asn1_write_bitstring( p, start, buf, bits ) );
334+
}
335+
293336
int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
294337
const unsigned char *buf, size_t bits )
295338
{
296339
int ret;
297-
size_t len = 0, size;
340+
size_t len = 0;
341+
size_t unused_bits, byte_len;
298342

299-
size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );
343+
byte_len = ( bits + 7 ) / 8;
344+
unused_bits = ( byte_len * 8 ) - bits;
300345

301-
// Calculate byte length
302-
//
303-
if( *p < start || (size_t)( *p - start ) < size + 1 )
346+
if( *p < start || (size_t)( *p - start ) < byte_len + 1 )
304347
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
305348

306-
len = size + 1;
307-
(*p) -= size;
308-
memcpy( *p, buf, size );
349+
len = byte_len + 1;
309350

310-
// Write unused bits
311-
//
312-
*--(*p) = (unsigned char) (size * 8 - bits);
351+
/* Write the bitstring. Ensure the unused bits are zeroed */
352+
if( byte_len > 0 )
353+
{
354+
byte_len--;
355+
*--( *p ) = buf[byte_len] & ~( ( 0x1 << unused_bits ) - 1 );
356+
( *p ) -= byte_len;
357+
memcpy( *p, buf, byte_len );
358+
}
359+
360+
/* Write unused bits */
361+
*--( *p ) = (unsigned char)unused_bits;
313362

314363
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) );
315364
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) );

library/x509write_crt.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,23 +221,36 @@ int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *
221221
int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx,
222222
unsigned int key_usage )
223223
{
224-
unsigned char buf[4], ku;
224+
unsigned char buf[5], ku[2];
225225
unsigned char *c;
226226
int ret;
227-
228-
/* We currently only support 7 bits, from 0x80 to 0x02 */
229-
if( ( key_usage & ~0xfe ) != 0 )
227+
const unsigned int allowed_bits = MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
228+
MBEDTLS_X509_KU_NON_REPUDIATION |
229+
MBEDTLS_X509_KU_KEY_ENCIPHERMENT |
230+
MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
231+
MBEDTLS_X509_KU_KEY_AGREEMENT |
232+
MBEDTLS_X509_KU_KEY_CERT_SIGN |
233+
MBEDTLS_X509_KU_CRL_SIGN |
234+
MBEDTLS_X509_KU_ENCIPHER_ONLY |
235+
MBEDTLS_X509_KU_DECIPHER_ONLY;
236+
237+
/* Check that nothing other than the allowed flags is set */
238+
if( ( key_usage & ~allowed_bits ) != 0 )
230239
return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE );
231240

232-
c = buf + 4;
233-
ku = (unsigned char) key_usage;
241+
c = buf + 5;
242+
ku[0] = (unsigned char)( key_usage );
243+
ku[1] = (unsigned char)( key_usage >> 8 );
244+
ret = mbedtls_asn1_write_named_bitstring( &c, buf, ku, 9 );
234245

235-
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 )
246+
if( ret < 0 )
236247
return( ret );
248+
else if( ret < 3 || ret > 5 )
249+
return( MBEDTLS_ERR_X509_INVALID_FORMAT );
237250

238251
ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
239252
MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
240-
1, buf, 4 );
253+
1, c, (size_t)ret );
241254
if( ret != 0 )
242255
return( ret );
243256

@@ -253,12 +266,13 @@ int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
253266

254267
c = buf + 4;
255268

256-
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
269+
ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 );
270+
if( ret < 3 || ret > 4 )
257271
return( ret );
258272

259273
ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
260274
MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
261-
0, buf, 4 );
275+
0, c, (size_t)ret );
262276
if( ret != 0 )
263277
return( ret );
264278

library/x509write_csr.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,13 @@ int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned ch
9494

9595
c = buf + 4;
9696

97-
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
97+
ret = mbedtls_asn1_write_named_bitstring( &c, buf, &key_usage, 8 );
98+
if( ret < 3 || ret > 4 )
9899
return( ret );
99100

100101
ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
101102
MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
102-
buf, 4 );
103+
c, (size_t)ret );
103104
if( ret != 0 )
104105
return( ret );
105106

@@ -115,12 +116,13 @@ int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx,
115116

116117
c = buf + 4;
117118

118-
if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
119+
ret = mbedtls_asn1_write_named_bitstring( &c, buf, &ns_cert_type, 8 );
120+
if( ret < 3 || ret > 4 )
119121
return( ret );
120122

121123
ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
122124
MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
123-
buf, 4 );
125+
c, (size_t)ret );
124126
if( ret != 0 )
125127
return( ret );
126128

0 commit comments

Comments
 (0)