Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PKCS#8 writing support #2413

Open
wants to merge 20 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Features
* Add MBEDTLS_REMOVE_3DES_CIPHERSUITES to allow removing 3DES ciphersuites
from the default list (enabled by default). See
https://sweet32.info/SWEET32_CCS16.pdf.
* Add support for writing unencrypted PKCS#8 private keys in PEM and DER
format. Contributed by mvgalen.

API Changes
* Add a new X.509 API call `mbedtls_x509_parse_der_nocopy()`.
Expand Down
30 changes: 30 additions & 0 deletions include/mbedtls/pk.h
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,21 @@ int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path )
*/
int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );

/**
* \brief This function writes an unencrypted private key to a PKCS#8
* or SEC8 DER structure.
*
* \param ctx The private key to write.
* \param buf The buffer that will hold the encoded private key.
* \param size The length of the output buffer \p buf.
*
* \return The length of data written on success.
* \return A negative error code on failure.
*/
int mbedtls_pkcs8_write_unencrypted_key_der( mbedtls_pk_context *ctx,
unsigned char *buf,
size_t size );

/**
* \brief Write a public key to a SubjectPublicKeyInfo DER structure
* Note: data is written at the end of the buffer! Use the
Expand Down Expand Up @@ -740,6 +755,21 @@ int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, si
* \return 0 if successful, or a specific error code
*/
int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size );

/**
* \brief This function writes an unencrypted private key to a PKCS#8
* or SEC8 PEM string.
*
* \param ctx The private to write.
* \param buf The buffer that will hold the encoded private key.
* \param size The length of the output buffer \p buf.
*
* \return \c 0 on success.
* \return A negative error code on failure.
*/
int mbedtls_pkcs8_write_unencrypted_key_pem( mbedtls_pk_context *ctx,
unsigned char *buf,
size_t size );
#endif /* MBEDTLS_PEM_WRITE_C */
#endif /* MBEDTLS_PK_WRITE_C */

Expand Down
100 changes: 100 additions & 0 deletions library/pkwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,62 @@ int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, si
return( (int) len );
}

int mbedtls_pkcs8_write_unencrypted_key_der( mbedtls_pk_context *key,
unsigned char *buf,
size_t size )
{
int ret;
size_t len;
unsigned char *c;
const char *oid;
size_t oid_len, par_len = 0;

PK_VALIDATE_RET( key != NULL );
PK_VALIDATE_RET( buf != NULL || size == 0 );

if( ( ret = mbedtls_pk_write_key_der( key, buf, size ) ) < 0 )
return( ret );

len = ret;
c = buf + size - len;

/* Wrap PKCS1 key in OCTET STRING */
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len,
mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) );

/* privateKeyAlgorithm */
ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ),
&oid,
&oid_len );
if( ret != 0 )
return ret;

#if defined(MBEDTLS_ECP_C)
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
{
MBEDTLS_ASN1_CHK_ADD( par_len,
pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) );
}
#endif /* MBEDTLS_ECP_C */

MBEDTLS_ASN1_CHK_ADD( len,
mbedtls_asn1_write_algorithm_identifier( &c, buf,
oid, oid_len,
par_len ) );

/* version */
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) );

/* sequence and length */
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
MBEDTLS_ASN1_CHK_ADD( len,
mbedtls_asn1_write_tag( &c,
buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );

return( (int)len );
}

int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
int ret;
Expand Down Expand Up @@ -448,6 +504,9 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n"
#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n"

#define PEM_BEGIN_PRIVATE_KEY "-----BEGIN PRIVATE KEY-----\n"
#define PEM_END_PRIVATE_KEY "-----END PRIVATE KEY-----\n"

#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n"
#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n"
#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n"
Expand Down Expand Up @@ -536,6 +595,17 @@ int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_
#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \
RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES

/*
* PKCS8 envelope:
* PrivateKeyInfo ::= SEQUENCE { 1 + 3
* version Version, 1 + 1 + 1
* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 1 + 1 + 22
* privateKey PrivateKey,
* attributes [0] IMPLICIT Attributes OPTIONAL }
* }
*/
#define PRV_PKCS8_DER_MAX_BYTES ( 31 + ( PRV_DER_MAX_BYTES ) )

int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size )
{
int ret;
Expand Down Expand Up @@ -601,6 +671,36 @@ int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_

return( 0 );
}

int mbedtls_pkcs8_write_unencrypted_key_pem( mbedtls_pk_context *key,
unsigned char *buf,
size_t size )
{
int ret;
unsigned char output_buf[PRV_PKCS8_DER_MAX_BYTES];
const char *begin = PEM_BEGIN_PRIVATE_KEY;
const char *end = PEM_END_PRIVATE_KEY;
size_t olen = 0;
size_t len = 0;

ret = mbedtls_pkcs8_write_unencrypted_key_der( key,
output_buf,
sizeof( output_buf ) );
if( ret < 0 )
return( ret );

len = (size_t)ret;

ret = mbedtls_pem_write_buffer( begin,
end,
output_buf + sizeof( output_buf ) - len,
len,
buf,
size,
&olen );

return( ret );
}
#endif /* MBEDTLS_PEM_WRITE_C */

#endif /* MBEDTLS_PK_WRITE_C */
59 changes: 52 additions & 7 deletions programs/pkey/gen_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,14 @@ int dev_random_entropy_poll( void *data, unsigned char *output,
#define FORMAT_PEM 0
#define FORMAT_DER 1

#define SYNTAX_PKCS1 0
#define SYNTAX_PKCS8 1

#define DFL_TYPE MBEDTLS_PK_RSA
#define DFL_RSA_KEYSIZE 4096
#define DFL_FILENAME "keyfile.key"
#define DFL_FORMAT FORMAT_PEM
#define DFL_SYNTAX SYNTAX_PKCS8
#define DFL_USE_DEV_RANDOM 0

#define USAGE \
Expand All @@ -121,6 +125,7 @@ int dev_random_entropy_poll( void *data, unsigned char *output,
" ec_curve=%%s see below\n" \
" filename=%%s default: keyfile.key\n" \
" format=pem|der default: pem\n" \
" syntax=pkcs1|pkcs8 default: pkcs1\n" \
USAGE_DEV_RANDOM \
"\n"

Expand Down Expand Up @@ -159,32 +164,63 @@ struct options
int ec_curve; /* curve identifier for EC keys */
const char *filename; /* filename of the key file */
int format; /* the output format to use */
int syntax; /* the standard syntax to use */
int use_dev_random; /* use /dev/random as entropy source */
} opt;

#define KEY_OUTPUT_BUFFER_LEN 16000

static int write_private_key( mbedtls_pk_context *key, const char *output_file )
{
int ret;
FILE *f;
unsigned char output_buf[16000];
unsigned char output_buf[KEY_OUTPUT_BUFFER_LEN];
unsigned char *c = output_buf;
size_t len = 0;

memset(output_buf, 0, 16000);
memset( output_buf, 0, sizeof( output_buf ) );
if( opt.format == FORMAT_PEM )
{
if( ( ret = mbedtls_pk_write_key_pem( key, output_buf, 16000 ) ) != 0 )
return( ret );
if( opt.syntax == SYNTAX_PKCS1 )
{
ret = mbedtls_pk_write_key_pem( key,
output_buf,
sizeof( output_buf ) );
if( ret != 0 )
return( ret );
}
else
{
ret = mbedtls_pkcs8_write_unencrypted_key_pem( key,
output_buf,
sizeof( output_buf ) );
if( ret != 0 )
return( ret );
}

len = strlen( (char *) output_buf );
}
else
{
if( ( ret = mbedtls_pk_write_key_der( key, output_buf, 16000 ) ) < 0 )
return( ret );
if( opt.syntax == SYNTAX_PKCS1 )
{
ret = mbedtls_pk_write_key_der( key,
output_buf,
sizeof( output_buf ) );
if( ret < 0 )
return( ret );
}
else
{
ret = mbedtls_pkcs8_write_unencrypted_key_der( key,
output_buf,
sizeof( output_buf ) );
if( ret < 0 )
return( ret );
}

len = ret;
c = output_buf + sizeof(output_buf) - len;
c = output_buf + sizeof( output_buf ) - len;
}

if( ( f = fopen( output_file, "wb" ) ) == NULL )
Expand Down Expand Up @@ -275,6 +311,15 @@ int main( int argc, char *argv[] )
else
goto usage;
}
else if( strcmp( p, "syntax" ) == 0 )
{
if( strcmp( q, "pkcs1" ) == 0 )
opt.syntax = SYNTAX_PKCS1;
else if( strcmp( q, "pkcs8" ) == 0 )
opt.syntax = SYNTAX_PKCS8;
else
goto usage;
}
else if( strcmp( p, "rsa_keysize" ) == 0 )
{
opt.rsa_keysize = atoi( q );
Expand Down
Loading