From 6de63e480d77857c271f56d72d8d53ad43ac4837 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Thu, 12 Sep 2013 04:59:34 +0200 Subject: [PATCH] Add EC support to x509write_key --- include/polarssl/x509write.h | 12 +-- library/x509parse.c | 2 +- library/x509write.c | 119 +++++++++++++++++---- tests/suites/test_suite_x509write.function | 2 +- 4 files changed, 108 insertions(+), 27 deletions(-) diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h index 159747889..a063695c8 100644 --- a/include/polarssl/x509write.h +++ b/include/polarssl/x509write.h @@ -395,19 +395,19 @@ int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size ); int x509write_pubkey_der( pk_context *key, unsigned char *buf, size_t size ); /** - * \brief Write a RSA key to a PKCS#1 DER structure + * \brief Write a private key to a PKCS#1 or SEC1 DER structure * Note: data is written at the end of the buffer! Use the * return value to determine where you should start * using the buffer * - * \param rsa RSA to write away + * \param key private to write away * \param buf buffer to write to * \param size size of the buffer * * \return length of data written if successful, or a specific * error code */ -int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size ); +int x509write_key_der( pk_context *pk, unsigned char *buf, size_t size ); /** * \brief Write a CSR (Certificate Signing Request) to a @@ -458,15 +458,15 @@ int x509write_crt_pem( x509write_cert *ctx, unsigned char *buf, size_t size ); int x509write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size ); /** - * \brief Write a RSA key to a PKCS#1 PEM string + * \brief Write a private key to a PKCS#1 or SEC1 PEM string * - * \param rsa RSA to write away + * \param key private to write away * \param buf buffer to write to * \param size size of the buffer * * \return 0 successful, or a specific error code */ -int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size ); +int x509write_key_pem( pk_context *key, unsigned char *buf, size_t size ); /** * \brief Write a CSR (Certificate Signing Request) to a diff --git a/library/x509parse.c b/library/x509parse.c index fc84e6164..b3725a7c2 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -2521,7 +2521,7 @@ static int x509parse_key_sec1_der( ecp_keypair *eck, unsigned char *end2; /* - * RFC 5915, orf SEC1 Appendix C.4 + * RFC 5915, or SEC1 Appendix C.4 * * ECPrivateKey ::= SEQUENCE { * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), diff --git a/library/x509write.c b/library/x509write.c index 937b899fc..d55e24187 100644 --- a/library/x509write.c +++ b/library/x509write.c @@ -542,26 +542,86 @@ int x509write_pubkey_der( pk_context *key, unsigned char *buf, size_t size ) return( len ); } -int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size ) +int x509write_key_der( pk_context *key, unsigned char *buf, size_t size ) { int ret; - unsigned char *c; + unsigned char *c = buf + size; size_t len = 0; - c = buf + size; +#if defined(POLARSSL_RSA_C) + if( pk_get_type( key ) == POLARSSL_PK_RSA ) + { + rsa_context *rsa = pk_rsa( *key ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->QP ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DQ ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DP ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->Q ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->P ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->D ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) ); - ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 0 ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->QP ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DQ ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->DP ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->Q ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->P ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->D ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) ); + ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 0 ) ); - ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + } + else +#endif +#if defined(POLARSSL_ECP_C) + if( pk_get_type( key ) == POLARSSL_PK_ECKEY ) + { + ecp_keypair *ec = pk_ec( *key ); + size_t pub_len = 0, par_len = 0; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + + /* publicKey */ + ASN1_CHK_ADD( pub_len, x509_write_ec_pubkey( &c, buf, ec ) ); + + if( c - buf < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + *--c = 0; + pub_len += 1; + + ASN1_CHK_ADD( pub_len, asn1_write_len( &c, buf, pub_len ) ); + ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) ); + + ASN1_CHK_ADD( pub_len, asn1_write_len( &c, buf, pub_len ) ); + ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, buf, + ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1 ) ); + len += pub_len; + + /* parameters */ + ASN1_CHK_ADD( par_len, x509_write_ec_param( &c, buf, ec ) ); + + ASN1_CHK_ADD( par_len, asn1_write_len( &c, buf, par_len ) ); + ASN1_CHK_ADD( par_len, asn1_write_tag( &c, buf, + ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ); + len += par_len; + + /* privateKey: write as MPI then fix tag */ + ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &ec->d ) ); + *c = ASN1_OCTET_STRING; + + /* version */ + ASN1_CHK_ADD( len, asn1_write_int( &c, buf, 1 ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + } + else +#endif + return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE ); return( len ); } @@ -957,8 +1017,10 @@ int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t 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 RSA PRIVATE KEY-----\n" -#define PEM_END_PRIVATE_KEY "-----END RSA 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" +#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n" #if defined(POLARSSL_BASE64_C) static int x509write_pemify( const char *begin_str, const char *end_str, @@ -1042,18 +1104,37 @@ int x509write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size ) return( 0 ); } -int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size ) +int x509write_key_pem( pk_context *key, unsigned char *buf, size_t size ) { int ret; unsigned char output_buf[4096]; + char *begin, *end; - if( ( ret = x509write_key_der( rsa, output_buf, + if( ( ret = x509write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) { return( ret ); } - if( ( ret = x509write_pemify( PEM_BEGIN_PRIVATE_KEY, PEM_END_PRIVATE_KEY, +#if defined(POLARSSL_RSA_C) + if( pk_get_type( key ) == POLARSSL_PK_RSA ) + { + begin = PEM_BEGIN_PRIVATE_KEY_RSA; + end = PEM_END_PRIVATE_KEY_RSA; + } + else +#endif +#if defined(POLARSSL_ECP_C) + if( pk_get_type( key ) == POLARSSL_PK_ECKEY ) + { + begin = PEM_BEGIN_PRIVATE_KEY_EC; + end = PEM_END_PRIVATE_KEY_EC; + } + else +#endif + return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE ); + + if( ( ret = x509write_pemify( begin, end, output_buf + sizeof(output_buf) - ret, ret, buf, size ) ) != 0 ) { diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 13931036b..c2d4e4eee 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -169,7 +169,7 @@ void x509_key_check( char *key_file ) pk_init( &key ); TEST_ASSERT( x509parse_keyfile( &key, key_file, NULL ) == 0 ); - ret = x509write_key_pem( pk_rsa( key ), buf, sizeof( buf ) - 1); + ret = x509write_key_pem( &key, buf, sizeof( buf ) - 1); TEST_ASSERT( ret >= 0 ); f = fopen( key_file, "r" );