diff --git a/include/polarssl/pk.h b/include/polarssl/pk.h index 97e6cb9f4..584f77fa3 100644 --- a/include/polarssl/pk.h +++ b/include/polarssl/pk.h @@ -405,21 +405,6 @@ int pk_parse_key( pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen ); -#if defined(POLARSSL_FS_IO) -/** \ingroup x509_module */ -/** - * \brief Load and parse a private key - * - * \param ctx key to be initialized - * \param path filename to read the private key from - * \param password password to decrypt the file (can be NULL) - * - * \return 0 if successful, or a specific PK or PEM error code - */ -int pk_parse_keyfile( pk_context *ctx, - const char *path, const char *password ); -#endif /* POLARSSL_FS_IO */ - /** \ingroup x509_module */ /** * \brief Parse a public key @@ -434,6 +419,19 @@ int pk_parse_public_key( pk_context *ctx, const unsigned char *key, size_t keylen ); #if defined(POLARSSL_FS_IO) +/** \ingroup x509_module */ +/** + * \brief Load and parse a private key + * + * \param ctx key to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int pk_parse_keyfile( pk_context *ctx, + const char *path, const char *password ); + /** \ingroup x509_module */ /** * \brief Load and parse a public key @@ -446,6 +444,65 @@ int pk_parse_public_key( pk_context *ctx, int pk_parse_public_keyfile( pk_context *ctx, const char *path ); #endif /* POLARSSL_FS_IO */ +/** + * \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 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 pk_write_key_der( pk_context *pk, 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 + * return value to determine where you should start + * using the buffer + * + * \param key public key 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 pk_write_pubkey_der( pk_context *key, unsigned char *buf, size_t size ); + +#if defined(POLARSSL_BASE64_C) +/** + * \brief Write a public key to a PEM string + * + * \param key public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 successful, or a specific error code + */ +int pk_write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size ); + +/** + * \brief Write a private key to a PKCS#1 or SEC1 PEM string + * + * \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 pk_write_key_pem( pk_context *key, unsigned char *buf, size_t size ); +#endif /* POLARSSL_BASE64_C */ + +/* + * WARNING: Low-level functions. You probably do not want to use these unless + * you are certain you do ;) + */ + /** * \brief Parse a SubjectPublicKeyInfo DER structure * @@ -458,6 +515,19 @@ int pk_parse_public_keyfile( pk_context *ctx, const char *path ); int pk_parse_get_pubkey( unsigned char **p, const unsigned char *end, pk_context *pk ); +/** + * \brief Write a subjectPublicKey to ASN.1 data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param key public key to write away + * + * \return the length written or a negative error code + */ +int pk_write_pubkey( unsigned char **p, unsigned char *start, + const pk_context *key ); + #ifdef __cplusplus } #endif diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h index 552d45395..d41e7086e 100644 --- a/include/polarssl/x509write.h +++ b/include/polarssl/x509write.h @@ -389,36 +389,6 @@ int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); -/** - * \brief Write a public key to a 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 key public key 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_pubkey_der( pk_context *key, unsigned char *buf, size_t size ); - -/** - * \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 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( pk_context *pk, unsigned char *buf, size_t size ); - /** * \brief Write a CSR (Certificate Signing Request) to a * DER structure @@ -465,28 +435,6 @@ int x509write_crt_pem( x509write_cert *ctx, unsigned char *buf, size_t size, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); -/** - * \brief Write a public key to a PEM string - * - * \param key public key 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_pubkey_pem( pk_context *key, unsigned char *buf, size_t size ); - -/** - * \brief Write a private key to a PKCS#1 or SEC1 PEM string - * - * \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( pk_context *key, unsigned char *buf, size_t size ); - /** * \brief Write a CSR (Certificate Signing Request) to a * PEM string diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index fcd601cbf..e839beaba 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -42,6 +42,7 @@ set(src pk.c pk_wrap.c pkparse.c + pkwrite.c rsa.c sha1.c sha256.c diff --git a/library/Makefile b/library/Makefile index 1316155f0..f70ef5632 100644 --- a/library/Makefile +++ b/library/Makefile @@ -50,6 +50,7 @@ OBJS= aes.o arc4.o asn1parse.o \ padlock.o pbkdf2.o pem.o \ pkcs5.o pkcs11.o pkcs12.o \ pk.o pk_wrap.o pkparse.o \ + pkwrite.o \ rsa.o sha1.o sha256.o \ sha512.o ssl_cache.o ssl_cli.o \ ssl_srv.o ssl_ciphersuites.o \ diff --git a/library/pkwrite.c b/library/pkwrite.c new file mode 100644 index 000000000..741df08e9 --- /dev/null +++ b/library/pkwrite.c @@ -0,0 +1,389 @@ +/* + * Public Key layer for writing key files and structures + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_PK_C) + +#include "polarssl/pk.h" +#include "polarssl/asn1write.h" +#include "polarssl/oid.h" + +#if defined(POLARSSL_RSA_C) +#include "polarssl/rsa.h" +#endif +#if defined(POLARSSL_ECP_C) +#include "polarssl/ecp.h" +#endif +#if defined(POLARSSL_ECDSA_C) +#include "polarssl/ecdsa.h" +#endif +#if defined(POLARSSL_BASE64_C) +#include "polarssl/base64.h" +#endif + +#if defined(POLARSSL_MEMORY_C) +#include "polarssl/memory.h" +#else +#include +#define polarssl_malloc malloc +#define polarssl_free free +#endif + +#if defined(POLARSSL_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start, + rsa_context *rsa ) +{ + int ret; + size_t len = 0; + + ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->E ) ); + ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->N ) ); + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} +#endif /* POLARSSL_RSA_C */ + +#if defined(POLARSSL_ECP_C) +/* + * EC public key is an EC point + */ +static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start, + ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + unsigned char buf[POLARSSL_ECP_MAX_PT_LEN]; + + if( ( ret = ecp_point_write_binary( &ec->grp, &ec->Q, + POLARSSL_ECP_PF_UNCOMPRESSED, + &len, buf, sizeof( buf ) ) ) != 0 ) + { + return( ret ); + } + + if( *p - start < (int) len ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *p -= len; + memcpy( *p, buf, len ); + + return( len ); +} + +/* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * } + */ +static int pk_write_ec_param( unsigned char **p, unsigned char *start, + ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + const char *oid; + size_t oid_len; + + if( ( ret = oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 ) + return( ret ); + + ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) ); + + return( len ); +} +#endif /* POLARSSL_ECP_C */ + +int pk_write_pubkey( unsigned char **p, unsigned char *start, + const pk_context *key ) +{ + int ret; + size_t len = 0; + +#if defined(POLARSSL_RSA_C) + if( pk_get_type( key ) == POLARSSL_PK_RSA ) + ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, pk_rsa( *key ) ) ); + else +#endif +#if defined(POLARSSL_ECP_C) + if( pk_get_type( key ) == POLARSSL_PK_ECKEY ) + ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, pk_ec( *key ) ) ); + else +#endif + return( POLARSSL_ERR_PK_FEATURE_UNAVAILABLE ); + + return( len ); +} + +int pk_write_pubkey_der( pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c; + size_t len = 0, par_len = 0, oid_len; + const char *oid; + + c = buf + size; + + ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, key ) ); + + if( c - buf < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + *--c = 0; + len += 1; + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) ); + + if( ( ret = oid_get_oid_by_pk_alg( pk_get_type( key ), + &oid, &oid_len ) ) != 0 ) + { + return( ret ); + } + +#if defined(POLARSSL_ECP_C) + if( pk_get_type( key ) == POLARSSL_PK_ECKEY ) + { + ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, pk_ec( *key ) ) ); + } +#endif + + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, oid, oid_len, + par_len ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + +int pk_write_key_der( pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c = buf + size; + size_t len = 0; + +#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_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, pk_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, pk_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_PK_FEATURE_UNAVAILABLE ); + + return( len ); +} + +#if defined(POLARSSL_BASE64_C) +static int pk_write_pemify( const char *begin_str, const char *end_str, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t size ) +{ + int ret; + unsigned char base_buf[4096]; + unsigned char *c = base_buf, *p = buf; + size_t len = 0, olen = sizeof(base_buf); + + if( ( ret = base64_encode( base_buf, &olen, der_data, der_len ) ) != 0 ) + return( ret ); + + if( olen + strlen( begin_str ) + strlen( end_str ) + + olen / 64 > size ) + { + return( POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + memcpy( p, begin_str, strlen( begin_str ) ); + p += strlen( begin_str ); + + while( olen ) + { + len = ( olen > 64 ) ? 64 : olen; + memcpy( p, c, len ); + olen -= len; + p += len; + c += len; + *p++ = '\n'; + } + + memcpy( p, end_str, strlen( end_str ) ); + p += strlen( end_str ); + + *p = '\0'; + + return( 0 ); +} + +#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" +#define PEM_END_PUBLIC_KEY "-----END PUBLIC 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" + +int pk_write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[4096]; + + if( ( ret = pk_write_pubkey_der( key, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = pk_write_pemify( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, + output_buf + sizeof(output_buf) - ret, + ret, buf, size ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int pk_write_key_pem( pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[4096]; + char *begin, *end; + + if( ( ret = pk_write_key_der( key, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + +#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_PK_FEATURE_UNAVAILABLE ); + + if( ( ret = pk_write_pemify( begin, end, + output_buf + sizeof(output_buf) - ret, + ret, buf, size ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* POLARSSL_BASE64_C */ + +#endif /* POLARSSL_PK_C */ diff --git a/library/x509write.c b/library/x509write.c index d4861d77d..2231206fc 100644 --- a/library/x509write.c +++ b/library/x509write.c @@ -117,99 +117,6 @@ exit: return( ret ); } -#if defined(POLARSSL_RSA_C) -/* - * RSAPublicKey ::= SEQUENCE { - * modulus INTEGER, -- n - * publicExponent INTEGER -- e - * } - */ -static int x509_write_rsa_pubkey( unsigned char **p, unsigned char *start, - rsa_context *rsa ) -{ - int ret; - size_t len = 0; - - ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->E ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( p, start, &rsa->N ) ); - - ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); - - return( len ); -} -#endif /* POLARSSL_RSA_C */ - -#if defined(POLARSSL_ECP_C) -/* - * EC public key is an EC point - */ -static int x509_write_ec_pubkey( unsigned char **p, unsigned char *start, - ecp_keypair *ec ) -{ - int ret; - size_t len = 0; - unsigned char buf[POLARSSL_ECP_MAX_PT_LEN]; - - if( ( ret = ecp_point_write_binary( &ec->grp, &ec->Q, - POLARSSL_ECP_PF_UNCOMPRESSED, - &len, buf, sizeof( buf ) ) ) != 0 ) - { - return( ret ); - } - - if( *p - start < (int) len ) - return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); - - *p -= len; - memcpy( *p, buf, len ); - - return( len ); -} - -/* - * ECParameters ::= CHOICE { - * namedCurve OBJECT IDENTIFIER - * } - */ -static int x509_write_ec_param( unsigned char **p, unsigned char *start, - ecp_keypair *ec ) -{ - int ret; - size_t len = 0; - const char *oid; - size_t oid_len; - - if( ( ret = oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 ) - return( ret ); - - ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) ); - - return( len ); -} -#endif /* POLARSSL_ECP_C */ - -static int x509_write_pubkey( unsigned char **p, unsigned char *start, - const pk_context *key ) -{ - int ret; - size_t len = 0; - -#if defined(POLARSSL_RSA_C) - if( pk_get_type( key ) == POLARSSL_PK_RSA ) - ASN1_CHK_ADD( len, x509_write_rsa_pubkey( p, start, pk_rsa( *key ) ) ); - else -#endif -#if defined(POLARSSL_ECP_C) - if( pk_get_type( key ) == POLARSSL_PK_ECKEY ) - ASN1_CHK_ADD( len, x509_write_ec_pubkey( p, start, pk_ec( *key ) ) ); - else -#endif - return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE ); - - return( len ); -} - void x509write_csr_init( x509write_csr *ctx ) { memset( ctx, 0, sizeof(x509write_csr) ); @@ -426,7 +333,7 @@ int x509write_crt_set_subject_key_identifier( x509write_cert *ctx ) size_t len = 0; memset( buf, 0, sizeof(buf)); - ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, ctx->subject_key ) ); + ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->subject_key ) ); sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); c = buf + sizeof(buf) - 20; @@ -448,7 +355,7 @@ int x509write_crt_set_authority_key_identifier( x509write_cert *ctx ) size_t len = 0; memset( buf, 0, sizeof(buf)); - ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, ctx->issuer_key ) ); + ASN1_CHK_ADD( len, pk_write_pubkey( &c, buf, ctx->issuer_key ) ); sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); c = buf + sizeof(buf) - 20; @@ -506,137 +413,6 @@ int x509write_crt_set_ns_cert_type( x509write_cert *ctx, return( 0 ); } -int x509write_pubkey_der( pk_context *key, unsigned char *buf, size_t size ) -{ - int ret; - unsigned char *c; - size_t len = 0, par_len = 0, oid_len; - const char *oid; - - c = buf + size; - - ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, key ) ); - - if( c - buf < 1 ) - return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); - - /* - * SubjectPublicKeyInfo ::= SEQUENCE { - * algorithm AlgorithmIdentifier, - * subjectPublicKey BIT STRING } - */ - *--c = 0; - len += 1; - - ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) ); - - if( ( ret = oid_get_oid_by_pk_alg( pk_get_type( key ), - &oid, &oid_len ) ) != 0 ) - { - return( ret ); - } - -#if defined(POLARSSL_ECP_C) - if( pk_get_type( key ) == POLARSSL_PK_ECKEY ) - { - ASN1_CHK_ADD( par_len, x509_write_ec_param( &c, buf, pk_ec( *key ) ) ); - } -#endif - - ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, oid, oid_len, - par_len ) ); - - ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); - - return( len ); -} - -int x509write_key_der( pk_context *key, unsigned char *buf, size_t size ) -{ - int ret; - unsigned char *c = buf + size; - size_t len = 0; - -#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_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 ); -} - /* * RelativeDistinguishedName ::= * SET OF AttributeTypeAndValue @@ -856,8 +632,8 @@ int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size, ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ); - ASN1_CHK_ADD( pub_len, x509write_pubkey_der( ctx->key, - tmp_buf, c - tmp_buf ) ); + ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->key, + tmp_buf, c - tmp_buf ) ); c -= pub_len; len += pub_len; @@ -951,8 +727,8 @@ int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size, /* * SubjectPublicKeyInfo */ - ASN1_CHK_ADD( pub_len, x509write_pubkey_der( ctx->subject_key, - tmp_buf, c - tmp_buf ) ); + ASN1_CHK_ADD( pub_len, pk_write_pubkey_der( ctx->subject_key, + tmp_buf, c - tmp_buf ) ); c -= pub_len; len += pub_len; @@ -1040,14 +816,6 @@ int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size, #define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" #define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" -#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" -#define PEM_END_PUBLIC_KEY "-----END PUBLIC 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, const unsigned char *der_data, size_t der_len, @@ -1111,67 +879,6 @@ int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size, return( 0 ); } -int x509write_pubkey_pem( pk_context *key, unsigned char *buf, size_t size ) -{ - int ret; - unsigned char output_buf[4096]; - - if( ( ret = x509write_pubkey_der( key, output_buf, - sizeof(output_buf) ) ) < 0 ) - { - return( ret ); - } - - if( ( ret = x509write_pemify( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, - output_buf + sizeof(output_buf) - ret, - ret, buf, size ) ) != 0 ) - { - return( ret ); - } - - return( 0 ); -} - -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( key, output_buf, - sizeof(output_buf) ) ) < 0 ) - { - return( ret ); - } - -#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 ) - { - return( ret ); - } - - return( 0 ); -} - int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c index c78f99073..3661341d4 100644 --- a/programs/pkey/key_app_writer.c +++ b/programs/pkey/key_app_writer.c @@ -89,14 +89,14 @@ static int write_public_key( pk_context *key, const char *output_file ) if( opt.output_format == OUTPUT_FORMAT_PEM ) { - if( ( ret = x509write_pubkey_pem( key, output_buf, 16000 ) ) != 0 ) + if( ( ret = pk_write_pubkey_pem( key, output_buf, 16000 ) ) != 0 ) return( ret ); len = strlen( (char *) output_buf ); } else { - if( ( ret = x509write_pubkey_der( key, output_buf, 16000 ) ) < 0 ) + if( ( ret = pk_write_pubkey_der( key, output_buf, 16000 ) ) < 0 ) return( ret ); len = ret; @@ -125,14 +125,14 @@ static int write_private_key( pk_context *key, const char *output_file ) memset(output_buf, 0, 16000); if( opt.output_format == OUTPUT_FORMAT_PEM ) { - if( ( ret = x509write_key_pem( key, output_buf, 16000 ) ) != 0 ) + if( ( ret = pk_write_key_pem( key, output_buf, 16000 ) ) != 0 ) return( ret ); len = strlen( (char *) output_buf ); } else { - if( ( ret = x509write_key_der( key, output_buf, 16000 ) ) < 0 ) + if( ( ret = pk_write_key_der( key, output_buf, 16000 ) ) < 0 ) return( ret ); len = ret; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 706a3a13e..dae517247 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -69,6 +69,7 @@ add_test_suite(pbkdf2) add_test_suite(pkcs1_v21) add_test_suite(pkcs5) add_test_suite(pkparse) +add_test_suite(pkwrite) add_test_suite(shax) add_test_suite(rsa) add_test_suite(version) diff --git a/tests/Makefile b/tests/Makefile index b68bb8a5c..4c74e2556 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -47,7 +47,7 @@ APPS = test_suite_aes.ecb test_suite_aes.cbc \ test_suite_md test_suite_mdx \ test_suite_mpi test_suite_pbkdf2 \ test_suite_pkcs1_v21 test_suite_pkcs5 \ - test_suite_pkparse \ + test_suite_pkparse test_suite_pkwrite \ test_suite_rsa test_suite_shax \ test_suite_x509parse test_suite_x509write \ test_suite_xtea test_suite_version @@ -280,6 +280,10 @@ test_suite_pkparse: test_suite_pkparse.c ../library/libpolarssl.a echo " CC $@.c" $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ +test_suite_pkwrite: test_suite_pkwrite.c ../library/libpolarssl.a + echo " CC $@.c" + $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ + test_suite_rsa: test_suite_rsa.c ../library/libpolarssl.a echo " CC $@.c" $(CC) $(CFLAGS) $(OFLAGS) $@.c $(LDFLAGS) -o $@ diff --git a/tests/suites/test_suite_pkwrite.data b/tests/suites/test_suite_pkwrite.data new file mode 100644 index 000000000..68adef655 --- /dev/null +++ b/tests/suites/test_suite_pkwrite.data @@ -0,0 +1,15 @@ +Public key write check RSA +depends_on:POLARSSL_RSA_C:POLARSSL_BASE64_C +pk_write_pubkey_check:"data_files/server1.pubkey" + +Public key write check EC +depends_on:POLARSSL_ECP_C:POLARSSL_BASE64_C:POLARSSL_ECP_DP_SECP192R1_ENABLED +pk_write_pubkey_check:"data_files/ec_pub.pem" + +Private key write check RSA +depends_on:POLARSSL_RSA_C:POLARSSL_BASE64_C +pk_write_key_check:"data_files/server1.key" + +Private key write check EC +depends_on:POLARSSL_ECP_C:POLARSSL_BASE64_C:POLARSSL_ECP_DP_SECP192R1_ENABLED +pk_write_key_check:"data_files/ec_prv.sec1.pem" diff --git a/tests/suites/test_suite_pkwrite.function b/tests/suites/test_suite_pkwrite.function new file mode 100644 index 000000000..5a277f59a --- /dev/null +++ b/tests/suites/test_suite_pkwrite.function @@ -0,0 +1,68 @@ +/* BEGIN_HEADER */ +#include +#include +#include +/* END_HEADER */ + +/* BEGIN_DEPENDENCIES + * depends_on:POLARSSL_PK_C:POLARSSL_BIGNUM_C + * END_DEPENDENCIES + */ + +/* BEGIN_CASE */ +void pk_write_pubkey_check( char *key_file ) +{ + pk_context key; + unsigned char buf[5000]; + unsigned char check_buf[5000]; + int ret; + FILE *f; + + memset( buf, 0, sizeof( buf ) ); + memset( check_buf, 0, sizeof( check_buf ) ); + + pk_init( &key ); + TEST_ASSERT( pk_parse_public_keyfile( &key, key_file ) == 0 ); + + ret = pk_write_pubkey_pem( &key, buf, sizeof( buf ) - 1); + TEST_ASSERT( ret >= 0 ); + + f = fopen( key_file, "r" ); + TEST_ASSERT( f != NULL ); + fread( check_buf, 1, sizeof( check_buf ) - 1, f ); + fclose( f ); + + TEST_ASSERT( strncmp( (char *) buf, (char *) check_buf, sizeof( buf ) ) == 0 ); + + pk_free( &key ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void pk_write_key_check( char *key_file ) +{ + pk_context key; + unsigned char buf[5000]; + unsigned char check_buf[5000]; + int ret; + FILE *f; + + memset( buf, 0, sizeof( buf ) ); + memset( check_buf, 0, sizeof( check_buf ) ); + + pk_init( &key ); + TEST_ASSERT( pk_parse_keyfile( &key, key_file, NULL ) == 0 ); + + ret = pk_write_key_pem( &key, buf, sizeof( buf ) - 1); + TEST_ASSERT( ret >= 0 ); + + f = fopen( key_file, "r" ); + TEST_ASSERT( f != NULL ); + fread( check_buf, 1, sizeof( check_buf ) - 1, f ); + fclose( f ); + + TEST_ASSERT( strncmp( (char *) buf, (char *) check_buf, sizeof( buf ) ) == 0 ); + + pk_free( &key ); +} +/* END_CASE */ diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data index dcb137af1..1b2754ee5 100644 --- a/tests/suites/test_suite_x509write.data +++ b/tests/suites/test_suite_x509write.data @@ -29,19 +29,3 @@ x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req. Certificate write check Server1 SHA1 depends_on:POLARSSL_SHA1_C:POLARSSL_RSA_C:POLARSSL_PKCS1_V15:POLARSSL_DES_C:POLARSSL_CIPHER_MODE_CBC:POLARSSL_MD5_C x509_crt_check:"data_files/server1.key":"":"C=NL,O=PolarSSL,CN=PolarSSL Server 1":"data_files/test-ca.key":"PolarSSLTest":"C=NL,O=PolarSSL,CN=PolarSSL Test CA":"1":"20110212144406":"20210212144406":POLARSSL_MD_SHA1:"data_files/server1.crt" - -Public key write check RSA -depends_on:POLARSSL_RSA_C:POLARSSL_BASE64_C -x509_pubkey_check:"data_files/server1.pubkey" - -Public key write check EC -depends_on:POLARSSL_ECP_C:POLARSSL_BASE64_C:POLARSSL_ECP_DP_SECP192R1_ENABLED -x509_pubkey_check:"data_files/ec_pub.pem" - -Private key write check RSA -depends_on:POLARSSL_RSA_C:POLARSSL_BASE64_C -x509_key_check:"data_files/server1.key" - -Private key write check EC -depends_on:POLARSSL_ECP_C:POLARSSL_BASE64_C:POLARSSL_ECP_DP_SECP192R1_ENABLED -x509_key_check:"data_files/ec_prv.sec1.pem" diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 296952745..68c7b1c9d 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -127,61 +127,3 @@ void x509_crt_check( char *subject_key_file, char *subject_pwd, mpi_free( &serial ); } /* END_CASE */ - -/* BEGIN_CASE */ -void x509_pubkey_check( char *key_file ) -{ - pk_context key; - unsigned char buf[5000]; - unsigned char check_buf[5000]; - int ret; - FILE *f; - - memset( buf, 0, sizeof( buf ) ); - memset( check_buf, 0, sizeof( check_buf ) ); - - pk_init( &key ); - TEST_ASSERT( pk_parse_public_keyfile( &key, key_file ) == 0 ); - - ret = x509write_pubkey_pem( &key, buf, sizeof( buf ) - 1); - TEST_ASSERT( ret >= 0 ); - - f = fopen( key_file, "r" ); - TEST_ASSERT( f != NULL ); - fread( check_buf, 1, sizeof( check_buf ) - 1, f ); - fclose( f ); - - TEST_ASSERT( strncmp( (char *) buf, (char *) check_buf, sizeof( buf ) ) == 0 ); - - pk_free( &key ); -} -/* END_CASE */ - -/* BEGIN_CASE */ -void x509_key_check( char *key_file ) -{ - pk_context key; - unsigned char buf[5000]; - unsigned char check_buf[5000]; - int ret; - FILE *f; - - memset( buf, 0, sizeof( buf ) ); - memset( check_buf, 0, sizeof( check_buf ) ); - - pk_init( &key ); - TEST_ASSERT( pk_parse_keyfile( &key, key_file, NULL ) == 0 ); - - ret = x509write_key_pem( &key, buf, sizeof( buf ) - 1); - TEST_ASSERT( ret >= 0 ); - - f = fopen( key_file, "r" ); - TEST_ASSERT( f != NULL ); - fread( check_buf, 1, sizeof( check_buf ) - 1, f ); - fclose( f ); - - TEST_ASSERT( strncmp( (char *) buf, (char *) check_buf, sizeof( buf ) ) == 0 ); - - pk_free( &key ); -} -/* END_CASE */