diff --git a/include/mbedtls/pk.h b/include/mbedtls/pk.h index ee06b2fd201c..694a7aef9ef1 100644 --- a/include/mbedtls/pk.h +++ b/include/mbedtls/pk.h @@ -566,6 +566,17 @@ 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 Write a private key to a PKCS#8 or SEC8 PEM string + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pkcs8_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); #endif /* MBEDTLS_PEM_WRITE_C */ #endif /* MBEDTLS_PK_WRITE_C */ diff --git a/library/pkwrite.c b/library/pkwrite.c index 8eabd889b559..fae7afb5af93 100644 --- a/library/pkwrite.c +++ b/library/pkwrite.c @@ -363,6 +363,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" @@ -451,6 +454,19 @@ 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 { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL } + * } + */ + +#define PRV_PKCS8_DER_MAX_BYTES 22 + PRV_DER_MAX_BYTES + + int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) { int ret; @@ -510,6 +526,65 @@ int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_ return( 0 ); } + +int mbedtls_pkcs8_write_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; + unsigned char *c; + int len = 0; + const char *oid; + size_t oid_len; + + if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) + return( ret ); +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + } + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + } + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + len = ret; + c = output_buf + sizeof(output_buf) - len; + + /* Wrap PKCS1 key in OCTET STRING */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, output_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, output_buf, MBEDTLS_ASN1_OCTET_STRING ) ); + + /* privateKeyAlgorithm */ + if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ), + &oid, &oid_len ) ) != 0 ) + return ret; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier(&c, output_buf, oid, oid_len, 0) ); + + /* version */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, output_buf, 0 ) ); + + /* sequence and length */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, output_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, output_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + if( ( ret = mbedtls_pem_write_buffer( begin, end, + output_buf + sizeof(output_buf) - len, + len, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} #endif /* MBEDTLS_PEM_WRITE_C */ #endif /* MBEDTLS_PK_WRITE_C */ diff --git a/programs/pkey/gen_key.c b/programs/pkey/gen_key.c index a7f5c90a6c7d..9beae0ec89ad 100644 --- a/programs/pkey/gen_key.c +++ b/programs/pkey/gen_key.c @@ -102,6 +102,7 @@ int dev_random_entropy_poll( void *data, unsigned char *output, #define FORMAT_PEM 0 #define FORMAT_DER 1 +#define FORMAT_PEM_PKCS8 2 #define DFL_TYPE MBEDTLS_PK_RSA #define DFL_RSA_KEYSIZE 4096 @@ -154,10 +155,18 @@ static int write_private_key( mbedtls_pk_context *key, const char *output_file ) size_t len = 0; memset(output_buf, 0, 16000); - if( opt.format == FORMAT_PEM ) + if( opt.format == FORMAT_PEM || opt.format == FORMAT_PEM_PKCS8) { - if( ( ret = mbedtls_pk_write_key_pem( key, output_buf, 16000 ) ) != 0 ) - return( ret ); + if (opt.format == FORMAT_PEM_PKCS8) + { + if( ( ret = mbedtls_pkcs8_write_key_pem( key, output_buf, 16000 ) ) != 0 ) + return( ret ); + } + else + { + if( ( ret = mbedtls_pk_write_key_pem( key, output_buf, 16000 ) ) != 0 ) + return( ret ); + } len = strlen( (char *) output_buf ); } @@ -255,6 +264,8 @@ int main( int argc, char *argv[] ) opt.format = FORMAT_PEM; else if( strcmp( q, "der" ) == 0 ) opt.format = FORMAT_DER; + else if( strcmp( q, "pkcs8" ) == 0 ) + opt.format = FORMAT_PEM_PKCS8; else goto usage; }