diff --git a/include/polarssl/asn1.h b/include/polarssl/asn1.h index ec8cbfafc8..45fd6cd877 100644 --- a/include/polarssl/asn1.h +++ b/include/polarssl/asn1.h @@ -154,8 +154,8 @@ typedef struct _asn1_named_data asn1_named_data; /** - * Get the length of an ASN.1 element. - * Updates the pointer to immediately behind the length. + * \brief Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. * * \param p The position in the ASN.1 data * \param end End of data @@ -170,8 +170,8 @@ int asn1_get_len( unsigned char **p, size_t *len ); /** - * Get the tag and length of the tag. Check for the requested tag. - * Updates the pointer to immediately behind the tag and length. + * \brief Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. * * \param p The position in the ASN.1 data * \param end End of data @@ -186,8 +186,8 @@ int asn1_get_tag( unsigned char **p, size_t *len, int tag ); /** - * Retrieve a boolean ASN.1 tag and its value. - * Updates the pointer to immediately behind the full tag. + * \brief Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. * * \param p The position in the ASN.1 data * \param end End of data @@ -200,8 +200,8 @@ int asn1_get_bool( unsigned char **p, int *val ); /** - * Retrieve an integer ASN.1 tag and its value. - * Updates the pointer to immediately behind the full tag. + * \brief Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. * * \param p The position in the ASN.1 data * \param end End of data @@ -214,8 +214,8 @@ int asn1_get_int( unsigned char **p, int *val ); /** - * Retrieve a bitstring ASN.1 tag and its value. - * Updates the pointer to immediately behind the full tag. + * \brief Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. * * \param p The position in the ASN.1 data * \param end End of data @@ -227,8 +227,9 @@ int asn1_get_bitstring( unsigned char **p, const unsigned char *end, asn1_bitstring *bs); /** - * Retrieve a bitstring ASN.1 tag without unused bits and its value. - * Updates the pointer to the beginning of the bit/octet string. + * \brief Retrieve a bitstring ASN.1 tag without unused bits and its + * value. + * Updates the pointer to the beginning of the bit/octet string. * * \param p The position in the ASN.1 data * \param end End of data @@ -240,8 +241,8 @@ int asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, size_t *len ); /** - * Parses and splits an ASN.1 "SEQUENCE OF " - * Updated the pointer to immediately behind the full sequence tag. + * \brief Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. * * \param p The position in the ASN.1 data * \param end End of data @@ -257,8 +258,8 @@ int asn1_get_sequence_of( unsigned char **p, #if defined(POLARSSL_BIGNUM_C) /** - * Retrieve a MPI value from an integer ASN.1 tag. - * Updates the pointer to immediately behind the full tag. + * \brief Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. * * \param p The position in the ASN.1 data * \param end End of data @@ -272,8 +273,9 @@ int asn1_get_mpi( unsigned char **p, #endif /** - * Retrieve an AlgorithmIdentifier ASN.1 sequence. - * Updates the pointer to immediately behind the full AlgorithmIdentifier. + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. * * \param p The position in the ASN.1 data * \param end End of data @@ -287,8 +289,10 @@ int asn1_get_alg( unsigned char **p, asn1_buf *alg, asn1_buf *params ); /** - * Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no params. - * Updates the pointer to immediately behind the full AlgorithmIdentifier. + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no + * params. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. * * \param p The position in the ASN.1 data * \param end End of data @@ -301,7 +305,8 @@ int asn1_get_alg_null( unsigned char **p, asn1_buf *alg ); /** - * Find a specific named_data entry in a sequence or list based on the OID. + * \brief Find a specific named_data entry in a sequence or list based on + * the OID. * * \param list The list to seek through * \param oid The OID to look for @@ -313,12 +318,20 @@ asn1_named_data *asn1_find_named_data( asn1_named_data *list, const char *oid, size_t len ); /** - * Free a asn1_named_data entry + * \brief Free a asn1_named_data entry * * \param entry The named data entry to free */ void asn1_free_named_data( asn1_named_data *entry ); +/** + * \brief Free all entries in a asn1_named_data list + * Head will be set to NULL + * + * \param head Pointer to the head of the list of named data entries to free + */ +void asn1_free_named_data_list( asn1_named_data **head ); + #ifdef __cplusplus } #endif diff --git a/include/polarssl/asn1write.h b/include/polarssl/asn1write.h index 4659b24c12..d7f7b521a2 100644 --- a/include/polarssl/asn1write.h +++ b/include/polarssl/asn1write.h @@ -29,7 +29,7 @@ #include "asn1.h" -#define ASN1_CHK_ADD(g, f) if( ( ret = f ) < 0 ) return( ret ); else g += ret +#define ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else g += ret; } while( 0 ) #ifdef __cplusplus extern "C" { @@ -105,24 +105,41 @@ int asn1_write_null( unsigned char **p, unsigned char *start ); * \param p reference to current position pointer * \param start start of the buffer (for bounds-checking) * \param oid the OID to write + * \param oid_len length of the OID * * \return the length written or a negative error code */ -int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid ); +int asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ); /** * \brief Write an AlgorithmIdentifier sequence in ASN.1 format * Note: function works backwards in data buffer - * Note: Uses NULL as algorithm parameter * * \param p reference to current position pointer * \param start start of the buffer (for bounds-checking) * \param oid the OID of the algorithm + * \param oid_len length of the OID + * \param par_len length of parameters, which must be already written. + * If 0, NULL parameters are added * * \return the length written or a negative error code */ int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, - const char *oid ); + const char *oid, size_t oid_len, + size_t par_len ); + +/** + * \brief Write a boolean tag (ASN1_BOOLEAN) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param boolean 0 or 1 + * + * \return the length written or a negative error code + */ +int asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ); /** * \brief Write an int tag (ASN1_INTEGER) and value in ASN.1 format @@ -144,11 +161,12 @@ int asn1_write_int( unsigned char **p, unsigned char *start, int val ); * \param p reference to current position pointer * \param start start of the buffer (for bounds-checking) * \param text the text to write + * \param text_len length of the text * * \return the length written or a negative error code */ int asn1_write_printable_string( unsigned char **p, unsigned char *start, - char *text ); + const char *text, size_t text_len ); /** * \brief Write an IA5 string tag (ASN1_IA5_STRING) and @@ -158,11 +176,12 @@ int asn1_write_printable_string( unsigned char **p, unsigned char *start, * \param p reference to current position pointer * \param start start of the buffer (for bounds-checking) * \param text the text to write + * \param text_len length of the text * * \return the length written or a negative error code */ int asn1_write_ia5_string( unsigned char **p, unsigned char *start, - char *text ); + const char *text, size_t text_len ); /** * \brief Write a bitstring tag (ASN1_BIT_STRING) and @@ -193,6 +212,28 @@ int asn1_write_bitstring( unsigned char **p, unsigned char *start, */ int asn1_write_octet_string( unsigned char **p, unsigned char *start, const unsigned char *buf, size_t size ); + +/** + * \brief Create or find a specific named_data entry for writing in a + * sequence or list based on the OID. If not already in there, + * a new entry is added to the head of the list. + * Warning: Destructive behaviour for the val data! + * + * \param list Pointer to the location of the head of the list to seek + * through (will be updated in case of a new entry) + * \param oid The OID to look for + * \param oid_len Size of the OID + * \param val Data to store (can be NULL if you want to fill it by hand) + * \param val_len Minimum length of the data buffer needed + * + * \return NULL if if there was a memory allocation error, or a pointer + * to the new / existing entry. + */ +asn1_named_data *asn1_store_named_data( asn1_named_data **list, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ); + #ifdef __cplusplus } #endif diff --git a/include/polarssl/config.h b/include/polarssl/config.h index b9f3f27ca4..e738dee4d4 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -401,11 +401,11 @@ /** * \def POLARSSL_ERROR_STRERROR_DUMMY * - * Enable a dummy error function to make use of error_strerror() in + * Enable a dummy error function to make use of polarssl_strerror() in * third party libraries easier. * * Disable if you run into name conflicts and want to really remove the - * error_strerror() + * polarssl_strerror() */ #define POLARSSL_ERROR_STRERROR_DUMMY @@ -1384,7 +1384,7 @@ * * Module: library/x509write.c * - * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_RSA_C + * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_C * * This module is required for X.509 certificate request writing. */ diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h index 434312525e..346b3a8483 100644 --- a/include/polarssl/ecp.h +++ b/include/polarssl/ecp.h @@ -133,6 +133,7 @@ ecp_keypair; */ #define POLARSSL_ECP_MAX_BITS 521 #define POLARSSL_ECP_MAX_BYTES ( ( POLARSSL_ECP_MAX_BITS + 7 ) / 8 ) +#define POLARSSL_ECP_MAX_PT_LEN ( 2 * POLARSSL_ECP_MAX_BYTES + 1 ) /* * Maximum window size (actually, NAF width) used for point multipliation. diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h index ddaf8a75ca..ba0ce7d39f 100644 --- a/include/polarssl/oid.h +++ b/include/polarssl/oid.h @@ -371,7 +371,20 @@ int oid_get_attr_short_name( const asn1_buf *oid, const char **short_name ); int oid_get_pk_alg( const asn1_buf *oid, pk_type_t *pk_alg ); /** - * \brief Translate ECParameters OID into an EC group identifier + * \brief Translate pk_type into PublicKeyAlgorithm OID + * + * \param pk_alg Public key type to look for + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or POLARSSL_ERR_OID_NOT_FOUND + */ +int oid_get_oid_by_pk_alg( pk_type_t pk_alg, + const char **oid, size_t *olen ); + +#if defined(POLARSSL_ECP_C) +/** + * \brief Translate NamedCurve OID into an EC group identifier * * \param oid OID to use * \param grp_id place to store group id @@ -380,6 +393,19 @@ int oid_get_pk_alg( const asn1_buf *oid, pk_type_t *pk_alg ); */ int oid_get_ec_grp( const asn1_buf *oid, ecp_group_id *grp_id ); +/** + * \brief Translate EC group identifier into NamedCurve OID + * + * \param grp_id EC group identifier + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or POLARSSL_ERR_OID_NOT_FOUND + */ +int oid_get_oid_by_ec_grp( ecp_group_id grp_id, + const char **oid, size_t *olen ); +#endif /* POLARSSL_ECP_C */ + #if defined(POLARSSL_MD_C) /** * \brief Translate SignatureAlgorithm OID into md_type and pk_type @@ -409,11 +435,12 @@ int oid_get_sig_alg_desc( const asn1_buf *oid, const char **desc ); * \param md_alg message digest algorithm * \param pk_alg public key algorithm * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID * * \return 0 if successful, or POLARSSL_ERR_OID_NOT_FOUND */ int oid_get_oid_by_sig_alg( pk_type_t pk_alg, md_type_t md_alg, - const char **oid ); + const char **oid, size_t *olen ); /** * \brief Translate hash algorithm OID into md_type @@ -441,10 +468,11 @@ int oid_get_extended_key_usage( const asn1_buf *oid, const char **desc ); * * \param md_alg message digest algorithm * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID * * \return 0 if successful, or POLARSSL_ERR_OID_NOT_FOUND */ -int oid_get_oid_by_md( md_type_t md_alg, const char **oid ); +int oid_get_oid_by_md( md_type_t md_alg, const char **oid, size_t *olen ); #if defined(POLARSSL_CIPHER_C) /** diff --git a/include/polarssl/pk.h b/include/polarssl/pk.h index b71a90cece..f8c6cc89a2 100644 --- a/include/polarssl/pk.h +++ b/include/polarssl/pk.h @@ -369,6 +369,15 @@ int pk_debug( const pk_context *ctx, pk_debug_item *items ); */ const char * pk_get_name( const pk_context *ctx ); +/** + * \brief Get the key typee + * + * \param ctx Context to use + * + * \return Type on success, or POLARSSL_PK_NONE + */ +pk_type_t pk_get_type( const pk_context *ctx ); + #ifdef __cplusplus } #endif diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index e68789ce9a..00e9b0bcec 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -31,8 +31,6 @@ #if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C) #include "asn1.h" -#include "rsa.h" -#include "ecp.h" #include "dhm.h" #include "md.h" #include "pk.h" @@ -151,7 +149,7 @@ extern "C" { * \{ */ /** - * \name Structures for parsing X.509 certificates and CRLs + * \name Structures for parsing X.509 certificates, CRLs and CSRs * \{ */ @@ -227,12 +225,12 @@ typedef struct _x509_cert md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. POLARSSL_MD_SHA256 */ pk_type_t sig_pk /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. POLARSSL_PK_RSA */; - struct _x509_cert *next; /**< Next certificate in the CA-chain. */ + struct _x509_cert *next; /**< Next certificate in the CA-chain. */ } x509_cert; -/** - * Certificate revocation list entry. +/** + * Certificate revocation list entry. * Contains the CA-specific serial numbers and revocation dates. */ typedef struct _x509_crl_entry @@ -249,8 +247,8 @@ typedef struct _x509_crl_entry } x509_crl_entry; -/** - * Certificate revocation list structure. +/** + * Certificate revocation list structure. * Every CRL may have multiple entries. */ typedef struct _x509_crl @@ -265,7 +263,7 @@ typedef struct _x509_crl x509_name issuer; /**< The parsed issuer data (named information object). */ - x509_time this_update; + x509_time this_update; x509_time next_update; x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ @@ -277,10 +275,32 @@ typedef struct _x509_crl md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. POLARSSL_MD_SHA256 */ pk_type_t sig_pk /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. POLARSSL_PK_RSA */; - struct _x509_crl *next; + struct _x509_crl *next; } x509_crl; -/** \} name Structures for parsing X.509 certificates and CRLs */ + +/** + * Certificate Signing Request (CSR) structure. + */ +typedef struct _x509_csr +{ + x509_buf raw; /**< The raw CSR data (DER). */ + x509_buf cri; /**< The raw CertificateRequestInfo body (DER). */ + + int version; + + x509_buf subject_raw; /**< The raw subject data (DER). */ + x509_name subject; /**< The parsed subject data (named information object). */ + + pk_context pk; /**< Container for the public key context. */ + + x509_buf sig_oid; + x509_buf sig; + md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. POLARSSL_MD_SHA256 */ + pk_type_t sig_pk /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. POLARSSL_PK_RSA */; +} +x509_csr; +/** \} name Structures for parsing X.509 certificates, CRLs and CSRs */ /** \} addtogroup x509_module */ /** @@ -317,6 +337,7 @@ int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, size_t buflen */ int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ); +#if defined(POLARSSL_FS_IO) /** \ingroup x509_module */ /** * \brief Load one or more certificates and add them @@ -348,6 +369,7 @@ int x509parse_crtfile( x509_cert *chain, const char *path ); * if partly successful or a specific X509 or PEM error code */ int x509parse_crtpath( x509_cert *chain, const char *path ); +#endif /* POLARSSL_FS_IO */ /** \ingroup x509_module */ /** @@ -362,6 +384,19 @@ int x509parse_crtpath( x509_cert *chain, const char *path ); */ int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ); +/** \ingroup x509_module */ +/** + * \brief Load a Certificate Signing Request (CSR) + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_csr( x509_csr *csr, const unsigned char *buf, size_t buflen ); + +#if defined(POLARSSL_FS_IO) /** \ingroup x509_module */ /** * \brief Load one or more CRLs and add them @@ -374,6 +409,18 @@ int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ); */ int x509parse_crlfile( x509_crl *chain, const char *path ); +/** \ingroup x509_module */ +/** + * \brief Load a Certificate Signing Request (CSR) + * + * \param csr CSR context to fill + * \param path filename to read the CSR from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_csrfile( x509_csr *csr, const char *path ); +#endif /* POLARSSL_FS_IO */ + #if defined(POLARSSL_RSA_C) /** \ingroup x509_module */ /** @@ -391,6 +438,7 @@ int x509parse_key_rsa( rsa_context *rsa, 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 RSA key @@ -403,6 +451,7 @@ int x509parse_key_rsa( rsa_context *rsa, */ int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, const char *password ); +#endif /* POLARSSL_FS_IO */ /** \ingroup x509_module */ /** @@ -417,6 +466,7 @@ int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, int x509parse_public_key_rsa( rsa_context *rsa, const unsigned char *key, size_t keylen ); +#if defined(POLARSSL_FS_IO) /** \ingroup x509_module */ /** * \brief Load and parse a public RSA key @@ -427,6 +477,7 @@ int x509parse_public_key_rsa( rsa_context *rsa, * \return 0 if successful, or a specific X509 or PEM error code */ int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path ); +#endif /* POLARSSL_FS_IO */ #endif /* POLARSSL_RSA_C */ /** \ingroup x509_module */ @@ -445,6 +496,7 @@ int x509parse_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 @@ -457,6 +509,7 @@ int x509parse_key( pk_context *ctx, */ int x509parse_keyfile( pk_context *ctx, const char *path, const char *password ); +#endif /* POLARSSL_FS_IO */ /** \ingroup x509_module */ /** @@ -471,6 +524,7 @@ int x509parse_keyfile( pk_context *ctx, int x509parse_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 public key @@ -481,6 +535,7 @@ int x509parse_public_key( pk_context *ctx, * \return 0 if successful, or a specific X509 or PEM error code */ int x509parse_public_keyfile( pk_context *ctx, const char *path ); +#endif /* POLARSSL_FS_IO */ /** \ingroup x509_module */ /** @@ -494,6 +549,7 @@ int x509parse_public_keyfile( pk_context *ctx, const char *path ); */ int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen ); +#if defined(POLARSSL_FS_IO) /** \ingroup x509_module */ /** * \brief Load and parse DHM parameters @@ -504,6 +560,7 @@ int x509parse_dhm( dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen * \return 0 if successful, or a specific X509 or PEM error code */ int x509parse_dhmfile( dhm_context *dhm, const char *path ); +#endif /* POLARSSL_FS_IO */ /** \} name Functions to read in DHM parameters, a certificate, CRL or private RSA key */ @@ -563,6 +620,21 @@ int x509parse_cert_info( char *buf, size_t size, const char *prefix, int x509parse_crl_info( char *buf, size_t size, const char *prefix, const x509_crl *crl ); +/** + * \brief Returns an informational string about the + * CSR. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param csr The X509 CSR to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_csr_info( char *buf, size_t size, const char *prefix, + const x509_csr *csr ); + /** * \brief Give an known OID, return its descriptive string. * @@ -680,6 +752,13 @@ void x509_free( x509_cert *crt ); */ void x509_crl_free( x509_crl *crl ); +/** + * \brief Unallocate all CSR data + * + * \param csr CSR to free + */ +void x509_csr_free( x509_csr *csr ); + /** \} name Functions to clear a certificate, CRL or private RSA key */ diff --git a/include/polarssl/x509write.h b/include/polarssl/x509write.h index 1a53c296d1..552d45395d 100644 --- a/include/polarssl/x509write.h +++ b/include/polarssl/x509write.h @@ -60,29 +60,42 @@ extern "C" { * \{ */ -/** - * Container for CSR named objects - */ -typedef struct _x509_req_name -{ - char oid[128]; - char name[128]; - - struct _x509_req_name *next; -} -x509_req_name; - /** * Container for a CSR */ -typedef struct _x509_csr +typedef struct _x509write_csr { - rsa_context *rsa; - x509_req_name *subject; + pk_context *key; + asn1_named_data *subject; md_type_t md_alg; asn1_named_data *extensions; } -x509_csr; +x509write_csr; + +#define X509_CRT_VERSION_1 0 +#define X509_CRT_VERSION_2 1 +#define X509_CRT_VERSION_3 2 + +#define X509_RFC5280_MAX_SERIAL_LEN 32 +#define X509_RFC5280_UTC_TIME_LEN 15 + +/** + * Container for writing a certificate (CRT) + */ +typedef struct _x509write_cert +{ + int version; + mpi serial; + pk_context *subject_key; + pk_context *issuer_key; + asn1_named_data *subject; + asn1_named_data *issuer; + md_type_t md_alg; + char not_before[X509_RFC5280_UTC_TIME_LEN + 1]; + char not_after[X509_RFC5280_UTC_TIME_LEN + 1]; + asn1_named_data *extensions; +} +x509write_cert; /* \} name */ /* \} addtogroup x509_module */ @@ -92,7 +105,7 @@ x509_csr; * * \param ctx CSR context to initialize */ -void x509write_csr_init( x509_csr *ctx ); +void x509write_csr_init( x509write_csr *ctx ); /** * \brief Set the subject name for a CSR @@ -106,16 +119,16 @@ void x509write_csr_init( x509_csr *ctx ); * \return 0 if subject name was parsed successfully, or * a specific error code */ -int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name ); +int x509write_csr_set_subject_name( x509write_csr *ctx, char *subject_name ); /** - * \brief Set the RSA key for a CSR (public key will be included, + * \brief Set the key for a CSR (public key will be included, * private key used to sign the CSR when writing it) * * \param ctx CSR context to use - * \param rsa RSA key to include + * \param key Asymetric key to include */ -void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa ); +void x509write_csr_set_key( x509write_csr *ctx, pk_context *key ); /** * \brief Set the MD algorithm to use for the signature @@ -124,7 +137,7 @@ void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa ); * \param ctx CSR context to use * \param md_alg MD algorithm to use */ -void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg ); +void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg ); /** * \brief Set the Key Usage Extension flags @@ -135,7 +148,7 @@ void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg ); * * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED */ -int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ); +int x509write_csr_set_key_usage( x509write_csr *ctx, unsigned char key_usage ); /** * \brief Set the Netscape Cert Type flags @@ -146,7 +159,8 @@ int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ); * * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED */ -int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type ); +int x509write_csr_set_ns_cert_type( x509write_csr *ctx, + unsigned char ns_cert_type ); /** * \brief Generic function to add to or replace an extension in the CSR @@ -159,7 +173,7 @@ int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type ); * * \return 0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED */ -int x509write_csr_set_extension( x509_csr *ctx, +int x509write_csr_set_extension( x509write_csr *ctx, const char *oid, size_t oid_len, const unsigned char *val, size_t val_len ); @@ -168,37 +182,242 @@ int x509write_csr_set_extension( x509_csr *ctx, * * \param ctx CSR context to free */ -void x509write_csr_free( x509_csr *ctx ); +void x509write_csr_free( x509write_csr *ctx ); /** - * \brief Write a RSA public key to a PKCS#1 DER structure + * \brief Initialize a CRT writing context + * + * \param ctx CRT context to initialize + */ +void x509write_crt_init( x509write_cert *ctx ); + +/** + * \brief Set the verion for a Certificate + * Default: X509_CRT_VERSION_3 + * + * \param ctx CRT context to use + * \param version version to set (X509_CRT_VERSION_1, X509_CRT_VERSION_2 or + * X509_CRT_VERSION_3) + */ +void x509write_crt_set_version( x509write_cert *ctx, int version ); + +/** + * \brief Set the serial number for a Certificate. + * + * \param ctx CRT context to use + * \param serial serial number to set + * + * \return 0 if successful + */ +int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial ); + +/** + * \brief Set the validity period for a Certificate + * Timestamps should be in string format for UTC timezone + * i.e. "YYYYMMDDhhmmss" + * e.g. "20131231235959" for December 31st 2013 + * at 23:59:59 + * + * \param ctx CRT context to use + * \param not_before not_before timestamp + * \param not_after not_after timestamp + * + * \return 0 if timestamp was parsed successfully, or + * a specific error code + */ +int x509write_crt_set_validity( x509write_cert *ctx, char *not_before, + char *not_after ); + +/** + * \brief Set the issuer name for a Certificate + * Issuer names should contain a comma-separated list + * of OID types and values: + * e.g. "C=NL,O=Offspark,CN=PolarSSL CA" + * + * \param ctx CRT context to use + * \param issuer_name issuer name to set + * + * \return 0 if issuer name was parsed successfully, or + * a specific error code + */ +int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name ); + +/** + * \brief Set the subject name for a Certificate + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=NL,O=Offspark,CN=PolarSSL Server 1" + * + * \param ctx CRT context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name ); + +/** + * \brief Set the subject public key for the certificate + * + * \param ctx CRT context to use + * \param key public key to include + */ +void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key ); + +/** + * \brief Set the issuer key used for signing the certificate + * + * \param ctx CRT context to use + * \param key private key to sign with + */ +void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. POLARSSL_MD_SHA1) + * + * \param ctx CRT context to use + * \param md_ald MD algorithm to use + */ +void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg ); + +/** + * \brief Generic function to add to or replace an extension in the + * CRT + * + * \param ctx CRT context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param critical if the extension is critical (per the RFC's definition) + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_crt_set_extension( x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ); + +/** + * \brief Set the basicConstraints extension for a CRT + * + * \param ctx CRT context to use + * \param is_ca is this a CA certificate + * \param max_pathlen maximum length of certificate chains below this + * certificate (only for CA certificates, -1 is + * inlimited) + * + * \return 0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_crt_set_basic_constraints( x509write_cert *ctx, + int is_ca, int max_pathlen ); + +/** + * \brief Set the subjectKeyIdentifier extension for a CRT + * Requires that x509write_crt_set_subject_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_crt_set_subject_key_identifier( x509write_cert *ctx ); + +/** + * \brief Set the authorityKeyIdentifier extension for a CRT + * Requires that x509write_crt_set_issuer_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_crt_set_authority_key_identifier( x509write_cert *ctx ); + +/** + * \brief Set the Key Usage Extension flags + * (e.g. KU_DIGITAL_SIGNATURE | KU_KEY_CERT_SIGN) + * + * \param ctx CRT context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_crt_set_key_usage( x509write_cert *ctx, unsigned char key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. NS_CERT_TYPE_SSL_CLIENT | NS_CERT_TYPE_EMAIL) + * + * \param ctx CRT context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_crt_set_ns_cert_type( x509write_cert *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Free the contents of a CRT write context + * + * \param ctx CRT context to free + */ +void x509write_crt_free( x509write_cert *ctx ); + +/** + * \brief Write a built up certificate to a X509 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 crt certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +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( rsa_context *rsa, 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 @@ -210,34 +429,63 @@ int x509write_key_der( rsa_context *rsa, unsigned char *buf, size_t size ); * \param ctx CSR to write away * \param buf buffer to write to * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter * * \return length of data written if successful, or a specific * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. */ -int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ); +int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); #if defined(POLARSSL_BASE64_C) /** - * \brief Write a RSA public key to a PKCS#1 PEM string + * \brief Write a built up certificate to a X509 PEM string * - * \param rsa RSA to write away + * \param crt certificate to write away * \param buf buffer to write to * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter * * \return 0 successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. */ -int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size ); +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 RSA key to a PKCS#1 PEM string + * \brief Write a public key to a PEM string * - * \param rsa RSA to write away + * \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_key_pem( rsa_context *rsa, unsigned char *buf, size_t size ); +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 @@ -246,10 +494,19 @@ int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size ); * \param ctx CSR to write away * \param buf buffer to write to * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter * * \return 0 successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for couermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. */ -int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size ); +int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); #endif /* POLARSSL_BASE64_C */ #ifdef __cplusplus diff --git a/library/asn1parse.c b/library/asn1parse.c index f6b271ec52..957359917f 100644 --- a/library/asn1parse.c +++ b/library/asn1parse.c @@ -354,6 +354,18 @@ void asn1_free_named_data( asn1_named_data *cur ) memset( cur, 0, sizeof( asn1_named_data ) ); } +void asn1_free_named_data_list( asn1_named_data **head ) +{ + asn1_named_data *cur; + + while( ( cur = *head ) != NULL ) + { + *head = cur->next; + asn1_free_named_data( cur ); + polarssl_free( cur ); + } +} + asn1_named_data *asn1_find_named_data( asn1_named_data *list, const char *oid, size_t len ) { diff --git a/library/asn1write.c b/library/asn1write.c index 463c730fba..d4c1d8d027 100644 --- a/library/asn1write.c +++ b/library/asn1write.c @@ -29,6 +29,14 @@ #include "polarssl/asn1write.h" +#if defined(POLARSSL_MEMORY_C) +#include "polarssl/memory.h" +#else +#include +#define polarssl_malloc malloc +#define polarssl_free free +#endif + int asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) { if( len < 0x80 ) @@ -135,14 +143,14 @@ int asn1_write_null( unsigned char **p, unsigned char *start ) return( len ); } -int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid ) +int asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ) { int ret; size_t len = 0; ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, - (const unsigned char *) oid, strlen( oid ) ) ); - + (const unsigned char *) oid, oid_len ) ); ASN1_CHK_ADD( len , asn1_write_len( p, start, len ) ); ASN1_CHK_ADD( len , asn1_write_tag( p, start, ASN1_OID ) ); @@ -150,29 +158,43 @@ int asn1_write_oid( unsigned char **p, unsigned char *start, const char *oid ) } int asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, - const char *oid ) + const char *oid, size_t oid_len, + size_t par_len ) { int ret; - size_t null_len = 0; - size_t oid_len = 0; size_t len = 0; - // Write NULL - // - ASN1_CHK_ADD( null_len, asn1_write_null( p, start ) ); + if( par_len == 0 ) + ASN1_CHK_ADD( len, asn1_write_null( p, start ) ); + else + len += par_len; - // Write OID - // - ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) ); + ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) ); - len = oid_len + null_len; - ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + null_len ) ); + 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 ); } +int asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (boolean) ? 1 : 0; + len++; + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BOOLEAN ) ); + + return( len ); +} + int asn1_write_int( unsigned char **p, unsigned char *start, int val ) { int ret; @@ -204,13 +226,13 @@ int asn1_write_int( unsigned char **p, unsigned char *start, int val ) } int asn1_write_printable_string( unsigned char **p, unsigned char *start, - char *text ) + const char *text, size_t text_len ) { int ret; size_t len = 0; ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, - (const unsigned char *) text, strlen( text ) ) ); + (const unsigned char *) text, text_len ) ); ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_PRINTABLE_STRING ) ); @@ -219,13 +241,13 @@ int asn1_write_printable_string( unsigned char **p, unsigned char *start, } int asn1_write_ia5_string( unsigned char **p, unsigned char *start, - char *text ) + const char *text, size_t text_len ) { int ret; size_t len = 0; ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, - (const unsigned char *) text, strlen( text ) ) ); + (const unsigned char *) text, text_len ) ); ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_IA5_STRING ) ); @@ -273,4 +295,65 @@ int asn1_write_octet_string( unsigned char **p, unsigned char *start, return( len ); } + +asn1_named_data *asn1_store_named_data( asn1_named_data **head, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ) +{ + asn1_named_data *cur; + + if( ( cur = asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) + { + // Add new entry if not present yet based on OID + // + if( ( cur = polarssl_malloc( sizeof(asn1_named_data) ) ) == NULL ) + return( NULL ); + + memset( cur, 0, sizeof(asn1_named_data) ); + + cur->oid.len = oid_len; + cur->oid.p = polarssl_malloc( oid_len ); + if( cur->oid.p == NULL ) + { + polarssl_free( cur ); + return( NULL ); + } + + cur->val.len = val_len; + cur->val.p = polarssl_malloc( val_len ); + if( cur->val.p == NULL ) + { + polarssl_free( cur->oid.p ); + polarssl_free( cur ); + return( NULL ); + } + + memcpy( cur->oid.p, oid, oid_len ); + + cur->next = *head; + *head = cur; + } + else if( cur->val.len < val_len ) + { + // Enlarge existing value buffer if needed + // + polarssl_free( cur->val.p ); + cur->val.p = NULL; + + cur->val.len = val_len; + cur->val.p = polarssl_malloc( val_len ); + if( cur->val.p == NULL ) + { + polarssl_free( cur->oid.p ); + polarssl_free( cur ); + return( NULL ); + } + } + + if( val != NULL ) + memcpy( cur->val.p, val, val_len ); + + return( cur ); +} #endif diff --git a/library/oid.c b/library/oid.c index c5608c3a1f..81b313e338 100644 --- a/library/oid.c +++ b/library/oid.c @@ -93,12 +93,13 @@ int FN_NAME( const asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \ * attribute from a oid_descriptor_t wrapper. */ #define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ -int FN_NAME( ATTR1_TYPE ATTR1, const char **oid_str ) \ +int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ { \ const TYPE_T *cur = LIST; \ while( cur->descriptor.asn1 != NULL ) { \ if( cur->ATTR1 == ATTR1 ) { \ - *oid_str = cur->descriptor.asn1; \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ return( 0 ); \ } \ cur++; \ @@ -112,12 +113,14 @@ int FN_NAME( ATTR1_TYPE ATTR1, const char **oid_str ) \ */ #define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \ ATTR2_TYPE, ATTR2) \ -int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid_str ) \ +int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ + size_t *olen ) \ { \ const TYPE_T *cur = LIST; \ while( cur->descriptor.asn1 != NULL ) { \ if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \ - *oid_str = cur->descriptor.asn1; \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ return( 0 ); \ } \ cur++; \ @@ -365,7 +368,9 @@ static const oid_pk_alg_t oid_pk_alg[] = FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg); FN_OID_GET_ATTR1(oid_get_pk_alg, oid_pk_alg_t, pk_alg, pk_type_t, pk_alg); +FN_OID_GET_OID_BY_ATTR1(oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, pk_type_t, pk_alg); +#if defined(POLARSSL_ECP_C) /* * For namedCurve (RFC 5480) */ @@ -404,6 +409,8 @@ static const oid_ecp_grp_t oid_ecp_grp[] = FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp); FN_OID_GET_ATTR1(oid_get_ec_grp, oid_ecp_grp_t, grp_id, ecp_group_id, grp_id); +FN_OID_GET_OID_BY_ATTR1(oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, ecp_group_id, grp_id); +#endif /* POLARSSL_ECP_C */ #if defined(POLARSSL_CIPHER_C) /* diff --git a/library/pk.c b/library/pk.c index 77f5034048..80eccc911b 100644 --- a/library/pk.c +++ b/library/pk.c @@ -273,4 +273,15 @@ const char * pk_get_name( const pk_context *ctx ) return( ctx->pk_info->name ); } +/* + * Access the PK type + */ +pk_type_t pk_get_type( const pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( POLARSSL_PK_NONE ); + + return( ctx->pk_info->type ); +} + #endif /* POLARSSL_PK_C */ diff --git a/library/rsa.c b/library/rsa.c index c82ffaa8a1..d39a09b23f 100644 --- a/library/rsa.c +++ b/library/rsa.c @@ -935,10 +935,9 @@ int rsa_rsassa_pkcs1_v15_sign( rsa_context *ctx, if( md_info == NULL ) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - if( oid_get_oid_by_md( md_alg, &oid ) != 0 ) + if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) return( POLARSSL_ERR_RSA_BAD_INPUT_DATA ); - oid_size = strlen( oid ); nb_pad -= 10 + oid_size; hashlen = md_get_size( md_info ); diff --git a/library/x509parse.c b/library/x509parse.c index 55cc9e3780..d606615c8a 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -131,6 +131,29 @@ static int x509_crl_get_version( unsigned char **p, return( 0 ); } +/* + * Version ::= INTEGER { v1(0) } + */ +static int x509_csr_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( POLARSSL_ERR_X509_CERT_INVALID_VERSION + ret ); + } + + return( 0 ); +} + /* * CertificateSerialNumber ::= INTEGER */ @@ -1624,6 +1647,205 @@ int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ) return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT ); } +/* + * Parse a CSR + */ +int x509parse_csr( x509_csr *csr, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; +#if defined(POLARSSL_PEM_C) + size_t use_len; + pem_context pem; +#endif + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + memset( csr, 0, sizeof( x509_csr ) ); + +#if defined(POLARSSL_PEM_C) + pem_init( &pem ); + ret = pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE REQUEST-----", + "-----END CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + + /* + * Steal PEM buffer + */ + p = pem.buf; + pem.buf = NULL; + len = pem.buflen; + pem_free( &pem ); + } + else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + pem_free( &pem ); + return( ret ); + } + else +#endif + { + /* + * nope, copy the raw DER data + */ + p = (unsigned char *) polarssl_malloc( len = buflen ); + + if( p == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + buflen = 0; + } + + csr->raw.p = p; + csr->raw.len = len; + end = p + len; + + /* + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * CertificationRequestInfo ::= SEQUENCE { + */ + csr->cri.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + end = p + len; + csr->cri.len = end - csr->cri.p; + + /* + * Version ::= INTEGER { v1(0) } + */ + if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) + { + x509_csr_free( csr ); + return( ret ); + } + + csr->version++; + + if( csr->version != 1 ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); + } + + /* + * subject Name + */ + csr->subject_raw.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) + { + x509_csr_free( csr ); + return( ret ); + } + + csr->subject_raw.len = p - csr->subject_raw.p; + + /* + * subjectPKInfo SubjectPublicKeyInfo + */ + if( ( ret = x509_get_pubkey( &p, end, &csr->pk ) ) != 0 ) + { + x509_csr_free( csr ); + return( ret ); + } + + /* + * attributes [0] Attributes + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_CONTEXT_SPECIFIC ) ) != 0 ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + // TODO Parse Attributes / extension requests + + p += len; + + end = csr->raw.p + csr->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + */ + if( ( ret = x509_get_alg_null( &p, end, &csr->sig_oid ) ) != 0 ) + { + x509_csr_free( csr ); + return( ret ); + } + + if( ( ret = x509_get_sig_alg( &csr->sig_oid, &csr->sig_md, + &csr->sig_pk ) ) != 0 ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); + } + + if( ( ret = x509_get_sig( &p, end, &csr->sig ) ) != 0 ) + { + x509_csr_free( csr ); + return( ret ); + } + + if( p != end ) + { + x509_csr_free( csr ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + /* * Parse one or more CRLs and add them to the chained list */ @@ -1695,6 +1917,7 @@ int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ) return( ret ); } else +#endif { /* * nope, copy the raw DER data @@ -1708,16 +1931,6 @@ int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ) buflen = 0; } -#else - p = (unsigned char *) polarssl_malloc( len = buflen ); - - if( p == NULL ) - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - - memcpy( p, buf, buflen ); - - buflen = 0; -#endif crl->raw.p = p; crl->raw.len = len; @@ -2075,6 +2288,26 @@ cleanup: return( ret ); } +/* + * Load a CSR into the structure + */ +int x509parse_csrfile( x509_csr *csr, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( ( ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_csr( csr, buf, n ); + + memset( buf, 0, n + 1 ); + polarssl_free( buf ); + + return( ret ); +} + /* * Load one or more CRLs and add them to the chained list */ @@ -2291,7 +2524,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), @@ -3287,6 +3520,53 @@ int x509parse_crl_info( char *buf, size_t size, const char *prefix, return( (int) ( size - n ) ); } +/* + * Return an informational string about the CSR. + */ +int x509parse_csr_info( char *buf, size_t size, const char *prefix, + const x509_csr *csr ) +{ + int ret; + size_t n; + char *p; + const char *desc; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + ret = snprintf( p, n, "%sCSR version : %d", + prefix, csr->version ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%ssubject name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &csr->subject ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%ssigned using : ", prefix ); + SAFE_SNPRINTF(); + + ret = oid_get_sig_alg_desc( &csr->sig_oid, &desc ); + if( ret != 0 ) + ret = snprintf( p, n, "???" ); + else + ret = snprintf( p, n, "%s", desc ); + SAFE_SNPRINTF(); + + if( ( ret = x509_key_size_helper( key_size_str, BEFORE_COLON, + pk_get_name( &csr->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str, + (int) pk_get_size( &csr->pk ) ); + SAFE_SNPRINTF(); + + return( (int) ( size - n ) ); +} + /* * Return 0 if the x509_time is still valid, or 1 otherwise. */ @@ -3947,6 +4227,37 @@ void x509_crl_free( x509_crl *crl ) while( crl_cur != NULL ); } +/* + * Unallocate all CSR data + */ +void x509_csr_free( x509_csr *csr ) +{ + x509_name *name_cur; + x509_name *name_prv; + + if( csr == NULL ) + return; + + pk_free( &csr->pk ); + + name_cur = csr->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + memset( name_prv, 0, sizeof( x509_name ) ); + polarssl_free( name_prv ); + } + + if( csr->raw.p != NULL ) + { + memset( csr->raw.p, 0, csr->raw.len ); + polarssl_free( csr->raw.p ); + } + + memset( csr, 0, sizeof( x509_csr ) ); +} + #if defined(POLARSSL_SELF_TEST) #include "polarssl/certs.h" diff --git a/library/x509write.c b/library/x509write.c index 7e04e12068..d4861d77d8 100644 --- a/library/x509write.c +++ b/library/x509write.c @@ -23,6 +23,13 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +/* + * References: + * - certificates: RFC 5280, updated by RFC 6818 + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + #include "polarssl/config.h" #if defined(POLARSSL_X509_WRITE_C) @@ -33,6 +40,8 @@ #include "polarssl/md.h" #include "polarssl/oid.h" +#include "polarssl/sha1.h" + #if defined(POLARSSL_BASE64_C) #include "polarssl/base64.h" #endif @@ -45,57 +54,17 @@ #define polarssl_free free #endif -void x509write_csr_init( x509_csr *ctx ) -{ - memset( ctx, 0, sizeof(x509_csr) ); -} - -void x509write_csr_free( x509_csr *ctx ) -{ - x509_req_name *cur; - asn1_named_data *cur_ext; - - while( ( cur = ctx->subject ) != NULL ) - { - ctx->subject = cur->next; - polarssl_free( cur ); - } - - while( ( cur_ext = ctx->extensions ) != NULL ) - { - ctx->extensions = cur_ext->next; - asn1_free_named_data( cur_ext ); - polarssl_free( cur_ext ); - } - - memset( ctx, 0, sizeof(x509_csr) ); -} - -void x509write_csr_set_md_alg( x509_csr *ctx, md_type_t md_alg ) -{ - ctx->md_alg = md_alg; -} - -void x509write_csr_set_rsa_key( x509_csr *ctx, rsa_context *rsa ) -{ - ctx->rsa = rsa; -} - -int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name ) +static int x509write_string_to_names( asn1_named_data **head, char *name ) { int ret = 0; - char *s = subject_name, *c = s; + char *s = name, *c = s; char *end = s + strlen( s ); char *oid = NULL; int in_tag = 1; - x509_req_name *cur; + asn1_named_data *cur; - while( ctx->subject ) - { - cur = ctx->subject; - ctx->subject = ctx->subject->next; - polarssl_free( cur ); - } + /* Clear existing chain if present */ + asn1_free_named_data_list( head ); while( c <= end ) { @@ -127,27 +96,15 @@ int x509write_csr_set_subject_name( x509_csr *ctx, char *subject_name ) if( !in_tag && ( *c == ',' || c == end ) ) { - if( c - s > 127 ) + if( ( cur = asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) s, + c - s ) ) == NULL ) { - ret = POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA; - goto exit; + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); } - cur = polarssl_malloc( sizeof(x509_req_name) ); - - if( cur == NULL ) - { - ret = POLARSSL_ERR_X509WRITE_MALLOC_FAILED; - goto exit; - } - - memset( cur, 0, sizeof(x509_req_name) ); - - cur->next = ctx->subject; - ctx->subject = cur; - - strncpy( cur->oid, oid, strlen( oid ) ); - strncpy( cur->name, s, c - s ); + while( c < end && *(c + 1) == ' ' ) + c++; s = c + 1; in_tag = 1; @@ -160,64 +117,158 @@ exit: return( ret ); } -int x509write_csr_set_extension( x509_csr *ctx, - const char *oid, size_t oid_len, - const unsigned char *val, size_t val_len ) +#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) ); +} + +void x509write_csr_free( x509write_csr *ctx ) +{ + asn1_free_named_data_list( &ctx->subject ); + asn1_free_named_data_list( &ctx->extensions ); + + memset( ctx, 0, sizeof(x509write_csr) ); +} + +void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void x509write_csr_set_key( x509write_csr *ctx, pk_context *key ) +{ + ctx->key = key; +} + +int x509write_csr_set_subject_name( x509write_csr *ctx, char *subject_name ) +{ + return x509write_string_to_names( &ctx->subject, subject_name ); +} + +/* The first byte of the value in the asn1_named_data structure is reserved + * to store the critical boolean for us + */ +static int x509_set_extension( asn1_named_data **head, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ) { asn1_named_data *cur; - if( ( cur = asn1_find_named_data( ctx->extensions, oid, - oid_len ) ) == NULL ) + if( ( cur = asn1_store_named_data( head, oid, oid_len, + NULL, val_len + 1 ) ) == NULL ) { - cur = polarssl_malloc( sizeof(asn1_named_data) ); - if( cur == NULL ) - return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); - - memset( cur, 0, sizeof(asn1_named_data) ); - - cur->oid.len = oid_len; - cur->oid.p = polarssl_malloc( oid_len ); - if( cur->oid.p == NULL ) - { - polarssl_free( cur ); - return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); - } - - cur->val.len = val_len; - cur->val.p = polarssl_malloc( val_len ); - if( cur->val.p == NULL ) - { - polarssl_free( cur->oid.p ); - polarssl_free( cur ); - return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); - } - - memcpy( cur->oid.p, oid, oid_len ); - - cur->next = ctx->extensions; - ctx->extensions = cur; + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); } - if( cur->val.len != val_len ) - { - polarssl_free( cur->val.p ); - - cur->val.len = val_len; - cur->val.p = polarssl_malloc( val_len ); - if( cur->val.p == NULL ) - { - polarssl_free( cur->oid.p ); - polarssl_free( cur ); - return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); - } - } - - memcpy( cur->val.p, val, val_len ); + cur->val.p[0] = critical; + memcpy( cur->val.p + 1, val, val_len ); return( 0 ); } -int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ) +int x509write_csr_set_extension( x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ) +{ + return x509_set_extension( &ctx->extensions, oid, oid_len, + 0, val, val_len ); +} + +int x509write_csr_set_key_usage( x509write_csr *ctx, unsigned char key_usage ) { unsigned char buf[4]; unsigned char *c; @@ -237,7 +288,8 @@ int x509write_csr_set_key_usage( x509_csr *ctx, unsigned char key_usage ) return( 0 ); } -int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type ) +int x509write_csr_set_ns_cert_type( x509write_csr *ctx, + unsigned char ns_cert_type ) { unsigned char buf[4]; unsigned char *c; @@ -257,26 +309,214 @@ int x509write_csr_set_ns_cert_type( x509_csr *ctx, unsigned char ns_cert_type ) return( 0 ); } -int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size ) +void x509write_crt_init( x509write_cert *ctx ) +{ + memset( ctx, 0, sizeof(x509write_cert) ); + + mpi_init( &ctx->serial ); + ctx->version = X509_CRT_VERSION_3; +} + +void x509write_crt_free( x509write_cert *ctx ) +{ + mpi_free( &ctx->serial ); + + asn1_free_named_data_list( &ctx->subject ); + asn1_free_named_data_list( &ctx->issuer ); + asn1_free_named_data_list( &ctx->extensions ); + + memset( ctx, 0, sizeof(x509write_csr) ); +} + +void x509write_crt_set_md_alg( x509write_cert *ctx, md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void x509write_crt_set_subject_key( x509write_cert *ctx, pk_context *key ) +{ + ctx->subject_key = key; +} + +void x509write_crt_set_issuer_key( x509write_cert *ctx, pk_context *key ) +{ + ctx->issuer_key = key; +} + +int x509write_crt_set_subject_name( x509write_cert *ctx, char *subject_name ) +{ + return x509write_string_to_names( &ctx->subject, subject_name ); +} + +int x509write_crt_set_issuer_name( x509write_cert *ctx, char *issuer_name ) +{ + return x509write_string_to_names( &ctx->issuer, issuer_name ); +} + +int x509write_crt_set_serial( x509write_cert *ctx, const mpi *serial ) { int ret; - unsigned char *c; + + if( ( ret = mpi_copy( &ctx->serial, serial ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int x509write_crt_set_validity( x509write_cert *ctx, char *not_before, + char *not_after ) +{ + if( strlen(not_before) != X509_RFC5280_UTC_TIME_LEN - 1 || + strlen(not_after) != X509_RFC5280_UTC_TIME_LEN - 1 ) + { + return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA ); + } + strncpy( ctx->not_before, not_before, X509_RFC5280_UTC_TIME_LEN ); + strncpy( ctx->not_after , not_after , X509_RFC5280_UTC_TIME_LEN ); + ctx->not_before[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + ctx->not_after[X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + + return( 0 ); +} + +int x509write_crt_set_extension( x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ) +{ + return x509_set_extension( &ctx->extensions, oid, oid_len, + critical, val, val_len ); +} + +int x509write_crt_set_basic_constraints( x509write_cert *ctx, + int is_ca, int max_pathlen ) +{ + int ret; + unsigned char buf[9]; + unsigned char *c = buf + sizeof(buf); size_t len = 0; - c = buf + size - 1; + memset( buf, 0, sizeof(buf) ); - /* - * RSAPublicKey ::= SEQUENCE { - * modulus INTEGER, -- n - * publicExponent INTEGER -- e - * } - */ - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->E ) ); - ASN1_CHK_ADD( len, asn1_write_mpi( &c, buf, &rsa->N ) ); + if( is_ca && max_pathlen > 127 ) + return( POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA ); + + if( is_ca ) + { + if( max_pathlen >= 0 ) + { + ASN1_CHK_ADD( len, asn1_write_int( &c, buf, max_pathlen ) ); + } + ASN1_CHK_ADD( len, asn1_write_bool( &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 ) ); + return x509write_crt_set_extension( ctx, OID_BASIC_CONSTRAINTS, + OID_SIZE( OID_BASIC_CONSTRAINTS ), + 0, buf + sizeof(buf) - len, len ); +} + +int x509write_crt_set_subject_key_identifier( x509write_cert *ctx ) +{ + int ret; + unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf)); + ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, ctx->subject_key ) ); + + sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + c = buf + sizeof(buf) - 20; + len = 20; + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_OCTET_STRING ) ); + + return x509write_crt_set_extension( ctx, OID_SUBJECT_KEY_IDENTIFIER, + OID_SIZE( OID_SUBJECT_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} + +int x509write_crt_set_authority_key_identifier( x509write_cert *ctx ) +{ + int ret; + unsigned char buf[POLARSSL_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf)); + ASN1_CHK_ADD( len, x509_write_pubkey( &c, buf, ctx->issuer_key ) ); + + sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + c = buf + sizeof(buf) - 20; + len = 20; + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONTEXT_SPECIFIC | 0 ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return x509write_crt_set_extension( ctx, OID_AUTHORITY_KEY_IDENTIFIER, + OID_SIZE( OID_AUTHORITY_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} + +int x509write_crt_set_key_usage( x509write_cert *ctx, unsigned char key_usage ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) + return( ret ); + + ret = x509write_crt_set_extension( ctx, OID_KEY_USAGE, + OID_SIZE( OID_KEY_USAGE ), + 1, buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int x509write_crt_set_ns_cert_type( x509write_cert *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = x509write_crt_set_extension( ctx, OID_NS_CERT_TYPE, + OID_SIZE( OID_NS_CERT_TYPE ), + 0, buf, 4 ); + if( ret != 0 ) + return( ret ); + + 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 ); @@ -291,7 +531,21 @@ int x509write_pubkey_der( rsa_context *rsa, unsigned char *buf, size_t size ) ASN1_CHK_ADD( len, asn1_write_len( &c, buf, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( &c, buf, ASN1_BIT_STRING ) ); - ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, buf, OID_PKCS1_RSA ) ); + 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 ) ); @@ -299,75 +553,130 @@ int x509write_pubkey_der( rsa_context *rsa, 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 - 1; - - 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 ) ); - - // TODO: Make NON RSA Specific variant later on -/* *--c = 0; - len += 1; - - len += asn1_write_len( &c, len); - len += asn1_write_tag( &c, ASN1_BIT_STRING ); - - len += asn1_write_oid( &c, OID_PKCS1_RSA ); - - len += asn1_write_int( &c, 0 ); - - len += asn1_write_len( &c, len); - len += asn1_write_tag( &c, ASN1_CONSTRUCTED | ASN1_SEQUENCE );*/ - -/* for(i = 0; i < len; ++i) +#if defined(POLARSSL_RSA_C) + if( pk_get_type( key ) == POLARSSL_PK_RSA ) { - if (i % 16 == 0 ) printf("\n"); - printf("%02x ", c[i]); + 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 ) ); } - printf("\n");*/ + 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 ); } -static int x509_write_name( unsigned char **p, unsigned char *start, char *oid, - char *name ) +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_write_name( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + const unsigned char *name, size_t name_len ) { int ret; - size_t string_len = 0; - size_t oid_len = 0; size_t len = 0; // Write PrintableString for all except OID_PKCS9_EMAIL // - if( OID_SIZE( OID_PKCS9_EMAIL ) == strlen( oid ) && - memcmp( oid, OID_PKCS9_EMAIL, strlen( oid ) ) == 0 ) + if( OID_SIZE( OID_PKCS9_EMAIL ) == oid_len && + memcmp( oid, OID_PKCS9_EMAIL, oid_len ) == 0 ) { - ASN1_CHK_ADD( string_len, asn1_write_ia5_string( p, start, name ) ); + ASN1_CHK_ADD( len, asn1_write_ia5_string( p, start, + (const char *) name, + name_len ) ); } else - ASN1_CHK_ADD( string_len, asn1_write_printable_string( p, start, name ) ); + { + ASN1_CHK_ADD( len, asn1_write_printable_string( p, start, + (const char *) name, + name_len ) ); + } // Write OID // - ASN1_CHK_ADD( oid_len, asn1_write_oid( p, start, oid ) ); + ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_len ) ); - len = oid_len + string_len; - ASN1_CHK_ADD( len, asn1_write_len( p, start, oid_len + string_len ) ); + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); @@ -376,8 +685,30 @@ static int x509_write_name( unsigned char **p, unsigned char *start, char *oid, return( len ); } +static int x509_write_names( unsigned char **p, unsigned char *start, + asn1_named_data *first ) +{ + int ret; + size_t len = 0; + asn1_named_data *cur = first; + + while( cur != NULL ) + { + ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p, + cur->oid.len, + cur->val.p, cur->val.len ) ); + cur = cur->next; + } + + 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 ); +} + static int x509_write_sig( unsigned char **p, unsigned char *start, - const char *oid, unsigned char *sig, size_t size ) + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ) { int ret; size_t len = 0; @@ -397,47 +728,115 @@ static int x509_write_sig( unsigned char **p, unsigned char *start, // Write OID // - ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid ) ); + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid, + oid_len, 0 ) ); return( len ); } -int x509write_csr_der( x509_csr *ctx, unsigned char *buf, size_t size ) +static int x509_write_time( unsigned char **p, unsigned char *start, + const char *time, size_t size ) +{ + int ret; + size_t len = 0; + + /* + * write ASN1_UTC_TIME if year < 2050 (2 bytes shorter) + */ + if( time[0] == '2' && time[1] == '0' && time [2] < '5' ) + { + ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, + (const unsigned char *) time + 2, + size - 2 ) ); + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_UTC_TIME ) ); + } + else + { + ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, + (const unsigned char *) time, + size ) ); + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_GENERALIZED_TIME ) ); + } + + return( len ); +} + +static int x509_write_extension( unsigned char **p, unsigned char *start, + asn1_named_data *ext ) +{ + int ret; + size_t len = 0; + + ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->val.p + 1, + ext->val.len - 1 ) ); + ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->val.len - 1 ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OCTET_STRING ) ); + + if( ext->val.p[0] != 0 ) + { + ASN1_CHK_ADD( len, asn1_write_bool( p, start, 1 ) ); + } + + ASN1_CHK_ADD( len, asn1_write_raw_buffer( p, start, ext->oid.p, + ext->oid.len ) ); + ASN1_CHK_ADD( len, asn1_write_len( p, start, ext->oid.len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_OID ) ); + + 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 ); +} + +/* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * -- contains the DER encoding of an ASN.1 value + * -- corresponding to the extension type identified + * -- by extnID + * } + */ +static int x509_write_extensions( unsigned char **p, unsigned char *start, + asn1_named_data *first ) +{ + int ret; + size_t len = 0; + asn1_named_data *cur_ext = first; + + while( cur_ext != NULL ) + { + ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) ); + cur_ext = cur_ext->next; + } + + return( len ); +} + +int x509write_csr_der( x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; const char *sig_oid; + size_t sig_oid_len = 0; unsigned char *c, *c2; unsigned char hash[64]; unsigned char sig[POLARSSL_MPI_MAX_SIZE]; unsigned char tmp_buf[2048]; - size_t sub_len = 0, pub_len = 0, sig_len = 0; + size_t pub_len = 0, sig_and_oid_len = 0, sig_len; size_t len = 0; - x509_req_name *cur = ctx->subject; - asn1_named_data *cur_ext = ctx->extensions; + pk_type_t pk_alg; - c = tmp_buf + 2048 - 1; + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); - while( cur_ext != NULL ) - { - size_t ext_len = 0; - - ASN1_CHK_ADD( ext_len, asn1_write_raw_buffer( &c, tmp_buf, cur_ext->val.p, - cur_ext->val.len ) ); - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, cur_ext->val.len ) ); - ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_OCTET_STRING ) ); - - ASN1_CHK_ADD( ext_len, asn1_write_raw_buffer( &c, tmp_buf, cur_ext->oid.p, - cur_ext->oid.len ) ); - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, cur_ext->oid.len ) ); - ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_OID ) ); - - ASN1_CHK_ADD( ext_len, asn1_write_len( &c, tmp_buf, ext_len ) ); - ASN1_CHK_ADD( ext_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); - - cur_ext = cur_ext->next; - - len += ext_len; - } + ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); if( len ) { @@ -447,7 +846,8 @@ int x509write_csr_der( x509_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_SET ) ); - ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ ) ); + ASN1_CHK_ADD( len, asn1_write_oid( &c, tmp_buf, OID_PKCS9_CSR_EXT_REQ, + OID_SIZE( OID_PKCS9_CSR_EXT_REQ ) ) ); ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); @@ -456,42 +856,15 @@ int x509write_csr_der( x509_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, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->E ) ); - ASN1_CHK_ADD( pub_len, asn1_write_mpi( &c, tmp_buf, &ctx->rsa->N ) ); - - ASN1_CHK_ADD( pub_len, asn1_write_len( &c, tmp_buf, pub_len ) ); - ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); - - if( c - tmp_buf < 1 ) - return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + ASN1_CHK_ADD( pub_len, x509write_pubkey_der( ctx->key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; /* - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL } + * Subject ::= Name */ - *--c = 0; - pub_len += 1; - - ASN1_CHK_ADD( pub_len, asn1_write_len( &c, tmp_buf, pub_len ) ); - ASN1_CHK_ADD( pub_len, asn1_write_tag( &c, tmp_buf, ASN1_BIT_STRING ) ); - - ASN1_CHK_ADD( pub_len, asn1_write_algorithm_identifier( &c, tmp_buf, OID_PKCS1_RSA ) ); - - len += pub_len; - ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, pub_len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); - - while( cur != NULL ) - { - ASN1_CHK_ADD( sub_len, x509_write_name( &c, tmp_buf, cur->oid, cur->name ) ); - - cur = cur->next; - } - - len += sub_len; - ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) ); /* * Version ::= INTEGER { v1(0), v2(1), v3(2) } @@ -501,35 +874,179 @@ int x509write_csr_der( x509_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_SEQUENCE ) ); + /* + * Prepare signature + */ md( md_info_from_type( ctx->md_alg ), c, len, hash ); - rsa_pkcs1_sign( ctx->rsa, NULL, NULL, RSA_PRIVATE, ctx->md_alg, 0, hash, sig ); + pk_alg = pk_get_type( ctx->key ); + if( pk_alg == POLARSSL_PK_ECKEY ) + pk_alg = POLARSSL_PK_ECDSA; - // Generate correct OID - // - ret = oid_get_oid_by_sig_alg( POLARSSL_PK_RSA, ctx->md_alg, &sig_oid ); + if( ( ret = pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 || + ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } - c2 = buf + size - 1; - ASN1_CHK_ADD( sig_len, x509_write_sig( &c2, buf, sig_oid, sig, ctx->rsa->len ) ); + /* + * Write data to output buffer + */ + c2 = buf + size; + ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); c2 -= len; memcpy( c2, c, len ); - len += sig_len; + len += sig_and_oid_len; ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) ); ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); return( len ); } +int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[POLARSSL_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + pk_type_t pk_alg; + + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + /* Signature algorithm needed in TBS, and later for actual signature */ + pk_alg = pk_get_type( ctx->issuer_key ); + if( pk_alg == POLARSSL_PK_ECKEY ) + pk_alg = POLARSSL_PK_ECDSA; + + if( ( ret = oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + */ + ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) ); + + /* + * SubjectPublicKeyInfo + */ + ASN1_CHK_ADD( pub_len, x509write_pubkey_der( ctx->subject_key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ + sub_len = 0; + + ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after, + X509_RFC5280_UTC_TIME_LEN ) ); + + ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before, + X509_RFC5280_UTC_TIME_LEN ) ); + + len += sub_len; + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + /* + * Issuer ::= Name + */ + ASN1_CHK_ADD( len, x509_write_names( &c, tmp_buf, ctx->issuer ) ); + + /* + * Signature ::= AlgorithmIdentifier + */ + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( &c, tmp_buf, + sig_oid, strlen( sig_oid ), 0 ) ); + + /* + * Serial ::= INTEGER + */ + ASN1_CHK_ADD( len, asn1_write_mpi( &c, tmp_buf, &ctx->serial ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + sub_len = 0; + ASN1_CHK_ADD( sub_len, asn1_write_int( &c, tmp_buf, ctx->version ) ); + len += sub_len; + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, sub_len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ); + + ASN1_CHK_ADD( len, asn1_write_len( &c, tmp_buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c, tmp_buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + /* + * Make signature + */ + md( md_info_from_type( ctx->md_alg ), c, len, hash ); + + if( ( ret = pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + ASN1_CHK_ADD( sig_and_oid_len, x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + ASN1_CHK_ADD( len, asn1_write_len( &c2, buf, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( &c2, buf, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ); + + return( len ); +} + +#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" +#define PEM_END_CRT "-----END CERTIFICATE-----\n" + #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 "-----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, @@ -571,19 +1088,42 @@ static int x509write_pemify( const char *begin_str, const char *end_str, return( 0 ); } -int x509write_pubkey_pem( rsa_context *rsa, unsigned char *buf, size_t size ) +int x509write_crt_pem( x509write_cert *crt, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; unsigned char output_buf[4096]; - if( ( ret = x509write_pubkey_der( rsa, output_buf, + if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = x509write_pemify( PEM_BEGIN_CRT, PEM_END_CRT, + output_buf + sizeof(output_buf) - ret, + ret, buf, size ) ) != 0 ) + { + return( ret ); + } + + 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) - 1 - ret, + output_buf + sizeof(output_buf) - ret, ret, buf, size ) ) != 0 ) { return( ret ); @@ -592,19 +1132,38 @@ int x509write_pubkey_pem( rsa_context *rsa, 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, - output_buf + sizeof(output_buf) - 1 - 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 ); @@ -613,19 +1172,21 @@ int x509write_key_pem( rsa_context *rsa, unsigned char *buf, size_t size ) return( 0 ); } -int x509write_csr_pem( x509_csr *ctx, unsigned char *buf, size_t size ) +int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; unsigned char output_buf[4096]; - if( ( ret = x509write_csr_der( ctx, output_buf, - sizeof(output_buf) ) ) < 0 ) + if( ( ret = x509write_csr_der( ctx, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) { return( ret ); } if( ( ret = x509write_pemify( PEM_BEGIN_CSR, PEM_END_CSR, - output_buf + sizeof(output_buf) - 1 - ret, + output_buf + sizeof(output_buf) - ret, ret, buf, size ) ) != 0 ) { return( ret ); diff --git a/programs/.gitignore b/programs/.gitignore index 2b7510f6e0..32ca900dad 100644 --- a/programs/.gitignore +++ b/programs/.gitignore @@ -40,3 +40,5 @@ util/strerror x509/cert_app x509/cert_req x509/crl_app +x509/cert_write +x509/req_app diff --git a/programs/pkey/ecdsa.c b/programs/pkey/ecdsa.c index 8d52b6726b..7e500bba12 100644 --- a/programs/pkey/ecdsa.c +++ b/programs/pkey/ecdsa.c @@ -51,7 +51,7 @@ #endif #endif /* !defined(ECPARAMS) */ -#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ECDSA_C) || \ +#if !defined(POLARSSL_ECDSA_C) || \ !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) || \ !defined(ECPARAMS) int main( int argc, char *argv[] ) @@ -59,9 +59,9 @@ int main( int argc, char *argv[] ) ((void) argc); ((void) argv); - printf("POLARSSL_BIGNUM_C and/or POLARSSL_ECDSA_C and/or " + printf("POLARSSL_ECDSA_C and/or " "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C not defined," - "and/or not EC domain parameter available\n" ); + "and/or no EC domain parameter available\n" ); return( 0 ); } #else @@ -194,6 +194,5 @@ exit: return( ret ); } -#endif /* POLARSSL_BIGNUM_C && POLARSSL_ECDSA_C && - POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C && +#endif /* POLARSSL_ECDSA_C && POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C && ECPARAMS */ diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c index d9ab45c941..371b03a53a 100644 --- a/programs/pkey/key_app_writer.c +++ b/programs/pkey/key_app_writer.c @@ -33,21 +33,16 @@ #include "polarssl/config.h" -#include "polarssl/error.h" -#include "polarssl/rsa.h" -#include "polarssl/x509.h" -#include "polarssl/base64.h" #include "polarssl/x509write.h" +#include "polarssl/error.h" -#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_FS_IO) +#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_FS_IO) int main( int argc, char *argv[] ) { ((void) argc); ((void) argv); - printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " - "POLARSSL_X509_WRITE_C and/or POLARSSL_FS_IO not defined.\n"); + printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_FS_IO not defined.\n" ); return( 0 ); } #else @@ -82,7 +77,7 @@ struct options int output_format; /* the output format to use */ } opt; -static int write_public_key( rsa_context *rsa, const char *output_file ) +static int write_public_key( pk_context *key, const char *output_file ) { int ret; FILE *f; @@ -94,14 +89,14 @@ static int write_public_key( rsa_context *rsa, const char *output_file ) if( opt.output_format == OUTPUT_FORMAT_PEM ) { - if( ( ret = x509write_pubkey_pem( rsa, output_buf, 16000 ) ) != 0 ) + if( ( ret = x509write_pubkey_pem( key, output_buf, 16000 ) ) != 0 ) return( ret ); len = strlen( (char *) output_buf ); } else { - if( ( ret = x509write_pubkey_der( rsa, output_buf, 16000 ) ) < 0 ) + if( ( ret = x509write_pubkey_der( key, output_buf, 16000 ) ) < 0 ) return( ret ); len = ret; @@ -119,7 +114,7 @@ static int write_public_key( rsa_context *rsa, const char *output_file ) return( 0 ); } -static int write_private_key( rsa_context *rsa, const char *output_file ) +static int write_private_key( pk_context *key, const char *output_file ) { int ret; FILE *f; @@ -130,14 +125,14 @@ static int write_private_key( rsa_context *rsa, const char *output_file ) memset(output_buf, 0, 16000); if( opt.output_format == OUTPUT_FORMAT_PEM ) { - if( ( ret = x509write_key_pem( rsa, output_buf, 16000 ) ) != 0 ) + if( ( ret = x509write_key_pem( key, output_buf, 16000 ) ) != 0 ) return( ret ); len = strlen( (char *) output_buf ); } else { - if( ( ret = x509write_key_der( rsa, output_buf, 16000 ) ) < 0 ) + if( ( ret = x509write_key_der( key, output_buf, 16000 ) ) < 0 ) return( ret ); len = ret; @@ -168,7 +163,7 @@ static int write_private_key( rsa_context *rsa, const char *output_file ) int main( int argc, char *argv[] ) { int ret = 0; - rsa_context rsa; + pk_context key; char buf[1024]; int i; char *p, *q; @@ -176,12 +171,13 @@ int main( int argc, char *argv[] ) /* * Set to sane values */ - memset( &rsa, 0, sizeof( rsa_context ) ); - memset( buf, 0, 1024 ); + pk_init( &key ); + memset( buf, 0, sizeof( buf ) ); if( argc == 0 ) { usage: + ret = 1; printf( USAGE ); goto exit; } @@ -254,15 +250,11 @@ int main( int argc, char *argv[] ) printf( "\n . Loading the private key ..." ); fflush( stdout ); - ret = x509parse_keyfile_rsa( &rsa, opt.filename, NULL ); + ret = x509parse_keyfile( &key, opt.filename, NULL ); if( ret != 0 ) { -#ifdef POLARSSL_ERROR_C - polarssl_strerror( ret, buf, 1024 ); -#endif - printf( " failed\n ! x509parse_key_rsa returned %d - %s\n\n", ret, buf ); - rsa_free( &rsa ); + printf( " failed\n ! x509parse_key returned %d", ret ); goto exit; } @@ -272,14 +264,23 @@ int main( int argc, char *argv[] ) * 1.2 Print the key */ printf( " . Key information ...\n" ); - mpi_write_file( "N: ", &rsa.N, 16, NULL ); - mpi_write_file( "E: ", &rsa.E, 16, NULL ); - mpi_write_file( "D: ", &rsa.D, 16, NULL ); - mpi_write_file( "P: ", &rsa.P, 16, NULL ); - mpi_write_file( "Q: ", &rsa.Q, 16, NULL ); - mpi_write_file( "DP: ", &rsa.DP, 16, NULL ); - mpi_write_file( "DQ: ", &rsa.DQ, 16, NULL ); - mpi_write_file( "QP: ", &rsa.QP, 16, NULL ); + +#if defined(POLARSSL_RSA_C) + if( pk_get_type( &key ) == POLARSSL_PK_RSA ) + { + rsa_context *rsa = pk_rsa( key ); + mpi_write_file( "N: ", &rsa->N, 16, NULL ); + mpi_write_file( "E: ", &rsa->E, 16, NULL ); + mpi_write_file( "D: ", &rsa->D, 16, NULL ); + mpi_write_file( "P: ", &rsa->P, 16, NULL ); + mpi_write_file( "Q: ", &rsa->Q, 16, NULL ); + mpi_write_file( "DP: ", &rsa->DP, 16, NULL ); + mpi_write_file( "DQ: ", &rsa->DQ, 16, NULL ); + mpi_write_file( "QP: ", &rsa->QP, 16, NULL ); + } + else +#endif + printf("key type not supported yet\n"); } else if( opt.mode == MODE_PUBLIC ) @@ -290,15 +291,11 @@ int main( int argc, char *argv[] ) printf( "\n . Loading the public key ..." ); fflush( stdout ); - ret = x509parse_public_keyfile_rsa( &rsa, opt.filename ); + ret = x509parse_public_keyfile( &key, opt.filename ); if( ret != 0 ) { -#ifdef POLARSSL_ERROR_C - polarssl_strerror( ret, buf, 1024 ); -#endif - printf( " failed\n ! x509parse_public_key_rsa returned %d - %s\n\n", ret, buf ); - rsa_free( &rsa ); + printf( " failed\n ! x509parse_public_key returned %d", ret ); goto exit; } @@ -308,24 +305,43 @@ int main( int argc, char *argv[] ) * 1.2 Print the key */ printf( " . Key information ...\n" ); - mpi_write_file( "N: ", &rsa.N, 16, NULL ); - mpi_write_file( "E: ", &rsa.E, 16, NULL ); + +#if defined(POLARSSL_RSA_C) + if( pk_get_type( &key ) == POLARSSL_PK_RSA ) + { + rsa_context *rsa = pk_rsa( key ); + mpi_write_file( "N: ", &rsa->N, 16, NULL ); + mpi_write_file( "E: ", &rsa->E, 16, NULL ); + } + else +#endif + printf("key type not supported yet\n"); } else goto usage; if( opt.output_mode == OUTPUT_MODE_PUBLIC ) { - write_public_key( &rsa, opt.output_file ); + write_public_key( &key, opt.output_file ); } if( opt.output_mode == OUTPUT_MODE_PRIVATE ) { - write_private_key( &rsa, opt.output_file ); + write_private_key( &key, opt.output_file ); } exit: - rsa_free( &rsa ); + if( ret != 0 && ret != 1) + { +#ifdef POLARSSL_ERROR_C + polarssl_strerror( ret, buf, sizeof( buf ) ); + printf( " - %s\n", buf ); +#else + printf("\n"); +#endif + } + + pk_free( &key ); #if defined(_WIN32) printf( " + Press Enter to exit this program.\n" ); @@ -334,5 +350,4 @@ exit: return( ret ); } -#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && - POLARSSL_X509_WRITE_C && POLARSSL_FS_IO */ +#endif /* POLARSSL_X509_WRITE_C && POLARSSL_FS_IO */ diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt index d07cff82d7..fe46da5dbe 100644 --- a/programs/x509/CMakeLists.txt +++ b/programs/x509/CMakeLists.txt @@ -16,9 +16,15 @@ target_link_libraries(cert_app ${libs}) add_executable(crl_app crl_app.c) target_link_libraries(crl_app ${libs}) +add_executable(req_app req_app.c) +target_link_libraries(req_app ${libs}) + add_executable(cert_req cert_req.c) target_link_libraries(cert_req ${libs}) -install(TARGETS cert_app crl_app cert_req +add_executable(cert_write cert_write.c) +target_link_libraries(cert_write ${libs}) + +install(TARGETS cert_app crl_app req_app cert_req cert_write DESTINATION "bin" PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c index 40d76d8e80..0096735bda 100644 --- a/programs/x509/cert_app.c +++ b/programs/x509/cert_app.c @@ -39,6 +39,25 @@ #include "polarssl/ssl.h" #include "polarssl/x509.h" +#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ENTROPY_C) || \ + !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_CLI_C) || \ + !defined(POLARSSL_NET_C) || !defined(POLARSSL_RSA_C) || \ + !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) || \ + !defined(POLARSSL_CTR_DRBG_C) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BIGNUM_C and/or POLARSSL_ENTROPY_C and/or " + "POLARSSL_SSL_TLS_C and/or POLARSSL_SSL_CLI_C and/or " + "POLARSSL_NET_C and/or POLARSSL_RSA_C and/or " + "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO and/or " + "POLARSSL_CTR_DRBG_C not defined.\n"); + return( 0 ); +} +#else + #define MODE_NONE 0 #define MODE_FILE 1 #define MODE_SSL 2 @@ -130,24 +149,6 @@ static int my_verify( void *data, x509_cert *crt, int depth, int *flags ) " permissive=%%d default: 0 (disabled)\n" \ "\n" -#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_ENTROPY_C) || \ - !defined(POLARSSL_SSL_TLS_C) || !defined(POLARSSL_SSL_CLI_C) || \ - !defined(POLARSSL_NET_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) || \ - !defined(POLARSSL_CTR_DRBG_C) -int main( int argc, char *argv[] ) -{ - ((void) argc); - ((void) argv); - - printf("POLARSSL_BIGNUM_C and/or POLARSSL_ENTROPY_C and/or " - "POLARSSL_SSL_TLS_C and/or POLARSSL_SSL_CLI_C and/or " - "POLARSSL_NET_C and/or POLARSSL_RSA_C and/or " - "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO and/or " - "POLARSSL_CTR_DRBG_C not defined.\n"); - return( 0 ); -} -#else int main( int argc, char *argv[] ) { int ret = 0, server_fd; diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c index 384ef08d64..c0c014fe34 100644 --- a/programs/x509/cert_req.c +++ b/programs/x509/cert_req.c @@ -33,12 +33,26 @@ #include "polarssl/config.h" -#include "polarssl/error.h" -#include "polarssl/rsa.h" -#include "polarssl/x509.h" -#include "polarssl/base64.h" #include "polarssl/x509write.h" -#include "polarssl/oid.h" +#include "polarssl/entropy.h" +#include "polarssl/ctr_drbg.h" +#include "polarssl/error.h" + +#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_X509_PARSE_C) || \ + !defined(POLARSSL_FS_IO) || \ + !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_X509_PARSE_C and/or " + "POLARSSL_FS_IO and/or " + "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C " + "not defined.\n"); + return( 0 ); +} +#else #define DFL_FILENAME "keyfile.key" #define DFL_DEBUG_LEVEL 0 @@ -60,7 +74,9 @@ struct options unsigned char ns_cert_type; /* NS cert type */ } opt; -int write_certificate_request( x509_csr *req, char *output_file ) +int write_certificate_request( x509write_csr *req, char *output_file, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) { int ret; FILE *f; @@ -68,7 +84,7 @@ int write_certificate_request( x509_csr *req, char *output_file ) size_t len = 0; memset( output_buf, 0, 4096 ); - if( ( ret = x509write_csr_pem( req, output_buf, 4096 ) ) < 0 ) + if( ( ret = x509write_csr_pem( req, output_buf, 4096, f_rng, p_rng ) ) < 0 ) return( ret ); len = strlen( (char *) output_buf ); @@ -85,7 +101,7 @@ int write_certificate_request( x509_csr *req, char *output_file ) } #define USAGE \ - "\n usage: key_app param=<>...\n" \ + "\n usage: cert_req param=<>...\n" \ "\n acceptable parameters:\n" \ " filename=%%s default: keyfile.key\n" \ " debug_level=%%d default: 0 (disabled)\n" \ @@ -111,34 +127,25 @@ int write_certificate_request( x509_csr *req, char *output_file ) " object_signing_ca\n" \ "\n" -#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) -int main( int argc, char *argv[] ) -{ - ((void) argc); - ((void) argv); - - printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " - "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); - return( 0 ); -} -#else int main( int argc, char *argv[] ) { int ret = 0; - rsa_context rsa; + pk_context key; char buf[1024]; int i, j, n; char *p, *q, *r; - x509_csr req; + x509write_csr req; + entropy_context entropy; + ctr_drbg_context ctr_drbg; + const char *pers = "csr example app"; /* * Set to sane values */ x509write_csr_init( &req ); x509write_csr_set_md_alg( &req, POLARSSL_MD_SHA1 ); - memset( &rsa, 0, sizeof( rsa_context ) ); - memset( buf, 0, 1024 ); + pk_init( &key ); + memset( buf, 0, sizeof( buf ) ); if( argc == 0 ) { @@ -249,35 +256,51 @@ int main( int argc, char *argv[] ) x509write_csr_set_ns_cert_type( &req, opt.ns_cert_type ); /* - * 1.0. Check the subject name for validity + * 0. Seed the PRNG */ - if( ( ret = x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 ) + printf( " . Seeding the random number generator..." ); + fflush( stdout ); + + entropy_init( &entropy ); + if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, + (const unsigned char *) pers, + strlen( pers ) ) ) != 0 ) { -#ifdef POLARSSL_ERROR_C - error_strerror( ret, buf, 1024 ); -#endif - printf( " failed\n ! x509write_csr_set_subject_name returned %d - %s\n\n", ret, buf ); + printf( " failed\n ! ctr_drbg_init returned %d", ret ); goto exit; } + printf( " ok\n" ); + + /* + * 1.0. Check the subject name for validity + */ + printf( " . Checking subjet name..." ); + fflush( stdout ); + + if( ( ret = x509write_csr_set_subject_name( &req, opt.subject_name ) ) != 0 ) + { + printf( " failed\n ! x509write_csr_set_subject_name returned %d", ret ); + goto exit; + } + + printf( " ok\n" ); + /* * 1.1. Load the key */ - printf( "\n . Loading the private key ..." ); + printf( " . Loading the private key ..." ); fflush( stdout ); - ret = x509parse_keyfile_rsa( &rsa, opt.filename, NULL ); + ret = x509parse_keyfile( &key, opt.filename, NULL ); if( ret != 0 ) { -#ifdef POLARSSL_ERROR_C - error_strerror( ret, buf, 1024 ); -#endif - printf( " failed\n ! x509parse_key_rsa returned %d - %s\n\n", ret, buf ); + printf( " failed\n ! x509parse_keyfile returned %d", ret ); goto exit; } - x509write_csr_set_rsa_key( &req, &rsa ); + x509write_csr_set_key( &req, &key ); printf( " ok\n" ); @@ -287,20 +310,29 @@ int main( int argc, char *argv[] ) printf( " . Writing the certificate request ..." ); fflush( stdout ); - if( ( ret = write_certificate_request( &req, opt.output_file ) ) != 0 ) + if( ( ret = write_certificate_request( &req, opt.output_file, + ctr_drbg_random, &ctr_drbg ) ) != 0 ) { -#ifdef POLARSSL_ERROR_C - error_strerror( ret, buf, 1024 ); -#endif - printf( " failed\n ! write_certifcate_request %d - %s\n\n", ret, buf ); + printf( " failed\n ! write_certifcate_request %d", ret ); goto exit; } printf( " ok\n" ); exit: + + if( ret != 0 && ret != 1) + { +#ifdef POLARSSL_ERROR_C + polarssl_strerror( ret, buf, sizeof( buf ) ); + printf( " - %s\n", buf ); +#else + printf("\n"); +#endif + } + x509write_csr_free( &req ); - rsa_free( &rsa ); + pk_free( &key ); #if defined(_WIN32) printf( " + Press Enter to exit this program.\n" ); @@ -309,5 +341,5 @@ exit: return( ret ); } -#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && - POLARSSL_X509_PARSE_C && POLARSSL_FS_IO */ +#endif /* POLARSSL_X509_WRITE_C && POLARSSL_X509_PARSE_C && POLARSSL_FS_IO && + POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C */ diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c new file mode 100644 index 0000000000..37cea589ef --- /dev/null +++ b/programs/x509/cert_write.c @@ -0,0 +1,653 @@ +/* + * Certificate generation and signing + * + * 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. + */ + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include + +#include "polarssl/config.h" + +#include "polarssl/x509write.h" +#include "polarssl/entropy.h" +#include "polarssl/ctr_drbg.h" +#include "polarssl/error.h" + +#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_X509_PARSE_C) || \ + !defined(POLARSSL_FS_IO) || \ + !defined(POLARSSL_ENTROPY_C) || !defined(POLARSSL_CTR_DRBG_C) || \ + !defined(POLARSSL_ERROR_C) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_X509_PARSE_C and/or " + "POLARSSL_FS_IO and/or " + "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C and/or " + "POLARSSL_ERROR_C not defined.\n"); + return( 0 ); +} +#else + +#define DFL_ISSUER_CRT "" +#define DFL_REQUEST_FILE "" +#define DFL_SUBJECT_KEY "subject.key" +#define DFL_ISSUER_KEY "ca.key" +#define DFL_SUBJECT_PWD "" +#define DFL_ISSUER_PWD "" +#define DFL_OUTPUT_FILENAME "cert.crt" +#define DFL_SUBJECT_NAME "CN=Cert,O=PolarSSL,C=NL" +#define DFL_ISSUER_NAME "CN=CA,O=PolarSSL,C=NL" +#define DFL_NOT_BEFORE "20010101000000" +#define DFL_NOT_AFTER "20301231235959" +#define DFL_SERIAL "1" +#define DFL_SELFSIGN 0 +#define DFL_IS_CA 0 +#define DFL_MAX_PATHLEN -1 +#define DFL_KEY_USAGE 0 +#define DFL_NS_CERT_TYPE 0 + +/* + * global options + */ +struct options +{ + char *issuer_crt; /* filename of the issuer certificate */ + char *request_file; /* filename of the certificate request */ + char *subject_key; /* filename of the subject key file */ + char *issuer_key; /* filename of the issuer key file */ + char *subject_pwd; /* password for the subject key file */ + char *issuer_pwd; /* password for the issuer key file */ + char *output_file; /* where to store the constructed key file */ + char *subject_name; /* subject name for certificate */ + char *issuer_name; /* issuer name for certificate */ + char *not_before; /* validity period not before */ + char *not_after; /* validity period not after */ + char *serial; /* serial number string */ + int selfsign; /* selfsign the certificate */ + int is_ca; /* is a CA certificate */ + int max_pathlen; /* maximum CA path length */ + unsigned char key_usage; /* key usage flags */ + unsigned char ns_cert_type; /* NS cert type */ +} opt; + +int write_certificate( x509write_cert *crt, char *output_file, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + FILE *f; + unsigned char output_buf[4096]; + size_t len = 0; + + memset( output_buf, 0, 4096 ); + if( ( ret = x509write_crt_pem( crt, output_buf, 4096, f_rng, p_rng ) ) < 0 ) + return( ret ); + + len = strlen( (char *) output_buf ); + + if( ( f = fopen( output_file, "w" ) ) == NULL ) + return( -1 ); + + if( fwrite( output_buf, 1, len, f ) != len ) + return( -1 ); + + fclose(f); + + return( 0 ); +} + +#define USAGE \ + "\n usage: cert_write param=<>...\n" \ + "\n acceptable parameters:\n" \ + " request_file=%%s default: (empty)\n" \ + " If request_file is specified, subject_key,\n" \ + " subject_pwd and subject_name are ignored!\n" \ + " subject_key=%%s default: subject.key\n" \ + " subject_pwd=%%s default: (empty)\n" \ + " subject_name=%%s default: CN=Cert,O=PolarSSL,C=NL\n" \ + "\n" \ + " issuer_crt=%%s default: (empty)\n" \ + " If issuer_crt is specified, issuer_name is\n" \ + " ignored!\n" \ + " issuer_name=%%s default: CN=CA,O=PolarSSL,C=NL\n" \ + "\n" \ + " selfsign=%%d default: 0 (false)\n" \ + " If selfsign is enabled, issuer_name and\n" \ + " issuer_key are required (issuer_crt and\n" \ + " subject_* are ignored\n" \ + " issuer_key=%%s default: ca.key\n" \ + " issuer_pwd=%%s default: (empty)\n" \ + " output_file=%%s default: cert.crt\n" \ + " serial=%%s default: 1\n" \ + " not_before=%%s default: 20010101000000\n"\ + " not_after=%%s default: 20301231235959\n"\ + " is_ca=%%d default: 0 (disabled)\n" \ + " max_pathlen=%%d default: -1 (none)\n" \ + " key_usage=%%s default: (empty)\n" \ + " Comma-separated-list of values:\n" \ + " digital_signature\n" \ + " non_repudiation\n" \ + " key_encipherment\n" \ + " data_encipherment\n" \ + " key_agreement\n" \ + " key_certificate_sign\n" \ + " crl_sign\n" \ + " ns_cert_type=%%s default: (empty)\n" \ + " Comma-separated-list of values:\n" \ + " ssl_client\n" \ + " ssl_server\n" \ + " email\n" \ + " object_signing\n" \ + " ssl_ca\n" \ + " email_ca\n" \ + " object_signing_ca\n" \ + "\n" + +int main( int argc, char *argv[] ) +{ + int ret = 0; + x509_cert issuer_crt; + pk_context loaded_issuer_key, loaded_subject_key; + pk_context *issuer_key = &loaded_issuer_key, + *subject_key = &loaded_subject_key; + char buf[1024]; + char issuer_name[128]; + char subject_name[128]; + int i, j, n; + char *p, *q, *r; + x509_csr csr; + x509write_cert crt; + mpi serial; + entropy_context entropy; + ctr_drbg_context ctr_drbg; + const char *pers = "crt example app"; + + /* + * Set to sane values + */ + x509write_crt_init( &crt ); + x509write_crt_set_md_alg( &crt, POLARSSL_MD_SHA1 ); + pk_init( &loaded_issuer_key ); + pk_init( &loaded_subject_key ); + mpi_init( &serial ); + memset( &csr, 0, sizeof(x509_csr) ); + memset( &issuer_crt, 0, sizeof(x509_cert) ); + memset( buf, 0, 1024 ); + + if( argc == 0 ) + { + usage: + printf( USAGE ); + ret = 1; + goto exit; + } + + opt.issuer_crt = DFL_ISSUER_CRT; + opt.request_file = DFL_REQUEST_FILE; + opt.request_file = DFL_REQUEST_FILE; + opt.subject_key = DFL_SUBJECT_KEY; + opt.issuer_key = DFL_ISSUER_KEY; + opt.subject_pwd = DFL_SUBJECT_PWD; + opt.issuer_pwd = DFL_ISSUER_PWD; + opt.output_file = DFL_OUTPUT_FILENAME; + opt.subject_name = DFL_SUBJECT_NAME; + opt.issuer_name = DFL_ISSUER_NAME; + opt.not_before = DFL_NOT_BEFORE; + opt.not_after = DFL_NOT_AFTER; + opt.serial = DFL_SERIAL; + opt.selfsign = DFL_SELFSIGN; + opt.is_ca = DFL_IS_CA; + opt.max_pathlen = DFL_MAX_PATHLEN; + opt.key_usage = DFL_KEY_USAGE; + opt.ns_cert_type = DFL_NS_CERT_TYPE; + + for( i = 1; i < argc; i++ ) + { + + p = argv[i]; + if( ( q = strchr( p, '=' ) ) == NULL ) + goto usage; + *q++ = '\0'; + + n = strlen( p ); + for( j = 0; j < n; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + if( strcmp( p, "request_file" ) == 0 ) + opt.request_file = q; + else if( strcmp( p, "subject_key" ) == 0 ) + opt.subject_key = q; + else if( strcmp( p, "issuer_key" ) == 0 ) + opt.issuer_key = q; + else if( strcmp( p, "subject_pwd" ) == 0 ) + opt.subject_pwd = q; + else if( strcmp( p, "issuer_pwd" ) == 0 ) + opt.issuer_pwd = q; + else if( strcmp( p, "issuer_crt" ) == 0 ) + opt.issuer_crt = q; + else if( strcmp( p, "output_file" ) == 0 ) + opt.output_file = q; + else if( strcmp( p, "subject_name" ) == 0 ) + { + opt.subject_name = q; + } + else if( strcmp( p, "issuer_name" ) == 0 ) + { + opt.issuer_name = q; + } + else if( strcmp( p, "not_before" ) == 0 ) + { + opt.not_before = q; + } + else if( strcmp( p, "not_after" ) == 0 ) + { + opt.not_after = q; + } + else if( strcmp( p, "serial" ) == 0 ) + { + opt.serial = q; + } + else if( strcmp( p, "selfsign" ) == 0 ) + { + opt.selfsign = atoi( q ); + if( opt.selfsign < 0 || opt.selfsign > 1 ) + goto usage; + } + else if( strcmp( p, "is_ca" ) == 0 ) + { + opt.is_ca = atoi( q ); + if( opt.is_ca < 0 || opt.is_ca > 1 ) + goto usage; + } + else if( strcmp( p, "max_pathlen" ) == 0 ) + { + opt.max_pathlen = atoi( q ); + if( opt.max_pathlen < -1 || opt.max_pathlen > 127 ) + goto usage; + } + else if( strcmp( p, "key_usage" ) == 0 ) + { + while( q != NULL ) + { + if( ( r = strchr( q, ',' ) ) != NULL ) + *r++ = '\0'; + + if( strcmp( q, "digital_signature" ) == 0 ) + opt.key_usage |= KU_DIGITAL_SIGNATURE; + else if( strcmp( q, "non_repudiation" ) == 0 ) + opt.key_usage |= KU_NON_REPUDIATION; + else if( strcmp( q, "key_encipherment" ) == 0 ) + opt.key_usage |= KU_KEY_ENCIPHERMENT; + else if( strcmp( q, "data_encipherment" ) == 0 ) + opt.key_usage |= KU_DATA_ENCIPHERMENT; + else if( strcmp( q, "key_agreement" ) == 0 ) + opt.key_usage |= KU_KEY_AGREEMENT; + else if( strcmp( q, "key_cert_sign" ) == 0 ) + opt.key_usage |= KU_KEY_CERT_SIGN; + else if( strcmp( q, "crl_sign" ) == 0 ) + opt.key_usage |= KU_CRL_SIGN; + else + goto usage; + + q = r; + } + } + else if( strcmp( p, "ns_cert_type" ) == 0 ) + { + while( q != NULL ) + { + if( ( r = strchr( q, ',' ) ) != NULL ) + *r++ = '\0'; + + if( strcmp( q, "ssl_client" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_SSL_CLIENT; + else if( strcmp( q, "ssl_server" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_SSL_SERVER; + else if( strcmp( q, "email" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_EMAIL; + else if( strcmp( q, "object_signing" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING; + else if( strcmp( q, "ssl_ca" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_SSL_CA; + else if( strcmp( q, "email_ca" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_EMAIL_CA; + else if( strcmp( q, "object_signing_ca" ) == 0 ) + opt.ns_cert_type |= NS_CERT_TYPE_OBJECT_SIGNING_CA; + else + goto usage; + + q = r; + } + } + else + goto usage; + } + + printf("\n"); + + /* + * 0. Seed the PRNG + */ + printf( " . Seeding the random number generator..." ); + fflush( stdout ); + + entropy_init( &entropy ); + if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy, + (const unsigned char *) pers, + strlen( pers ) ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! ctr_drbg_init returned %d - %s\n", ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + // Parse serial to MPI + // + printf( " . Reading serial number..." ); + fflush( stdout ); + + if( ( ret = mpi_read_string( &serial, 10, opt.serial ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! mpi_read_string returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + // Parse issuer certificate if present + // + if( !opt.selfsign && strlen( opt.issuer_crt ) ) + { + /* + * 1.0.a. Load the certificates + */ + printf( " . Loading the issuer certificate ..." ); + fflush( stdout ); + + if( ( ret = x509parse_crtfile( &issuer_crt, opt.issuer_crt ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509parse_crtfile returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + ret = x509parse_dn_gets( issuer_name, sizeof(issuer_name), + &issuer_crt.issuer ); + if( ret < 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509parse_dn_gets returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + opt.issuer_name = issuer_name; + + printf( " ok\n" ); + } + + // Parse certificate request if present + // + if( !opt.selfsign && strlen( opt.request_file ) ) + { + /* + * 1.0.b. Load the CSR + */ + printf( " . Loading the certificate request ..." ); + fflush( stdout ); + + if( ( ret = x509parse_csrfile( &csr, opt.request_file ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509parse_csrfile returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + ret = x509parse_dn_gets( subject_name, sizeof(subject_name), + &csr.subject ); + if( ret < 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509parse_dn_gets returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + opt.subject_name = subject_name; + subject_key = &csr.pk; + + printf( " ok\n" ); + } + + /* + * 1.1. Load the keys + */ + if( !opt.selfsign && !strlen( opt.request_file ) ) + { + printf( " . Loading the subject key ..." ); + fflush( stdout ); + + ret = x509parse_keyfile( &loaded_subject_key, opt.subject_key, + opt.subject_pwd ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509parse_keyfile returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + } + + printf( " . Loading the issuer key ..." ); + fflush( stdout ); + + ret = x509parse_keyfile( &loaded_issuer_key, opt.issuer_key, + opt.issuer_pwd ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509parse_keyfile returned -x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + // Check if key and issuer certificate match + // + if( strlen( opt.issuer_crt ) ) + { + if( !pk_can_do( &issuer_crt.pk, POLARSSL_PK_RSA ) || + mpi_cmp_mpi( &pk_rsa( issuer_crt.pk )->N, + &pk_rsa( *issuer_key )->N ) != 0 || + mpi_cmp_mpi( &pk_rsa( issuer_crt.pk )->E, + &pk_rsa( *issuer_key )->E ) != 0 ) + { + printf( " failed\n ! issuer_key does not match issuer certificate\n\n" ); + ret = -1; + goto exit; + } + } + + printf( " ok\n" ); + + if( opt.selfsign ) + { + opt.issuer_name = opt.subject_name; + subject_key = issuer_key; + } + + x509write_crt_set_subject_key( &crt, subject_key ); + x509write_crt_set_issuer_key( &crt, issuer_key ); + + /* + * 1.0. Check the names for validity + */ + if( ( ret = x509write_crt_set_subject_name( &crt, opt.subject_name ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_subject_name returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + if( ( ret = x509write_crt_set_issuer_name( &crt, opt.issuer_name ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_issuer_name returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " . Setting certificate values ..." ); + fflush( stdout ); + + ret = x509write_crt_set_serial( &crt, &serial ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_serial returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + ret = x509write_crt_set_validity( &crt, opt.not_before, opt.not_after ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_validity returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + printf( " . Adding the Basic Constraints extension ..." ); + fflush( stdout ); + + ret = x509write_crt_set_basic_constraints( &crt, opt.is_ca, + opt.max_pathlen ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_basic_contraints returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + printf( " . Adding the Subject Key Identifier ..." ); + fflush( stdout ); + + ret = x509write_crt_set_subject_key_identifier( &crt ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_subject_key_identifier returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + printf( " . Adding the Authority Key Identifier ..." ); + fflush( stdout ); + + ret = x509write_crt_set_authority_key_identifier( &crt ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_authority_key_identifier returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + + if( opt.key_usage ) + { + printf( " . Adding the Key Usage extension ..." ); + fflush( stdout ); + + ret = x509write_crt_set_key_usage( &crt, opt.key_usage ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_key_usage returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + } + + if( opt.ns_cert_type ) + { + printf( " . Adding the NS Cert Type extension ..." ); + fflush( stdout ); + + ret = x509write_crt_set_ns_cert_type( &crt, opt.ns_cert_type ); + if( ret != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! x509write_crt_set_ns_cert_type returned -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + } + + /* + * 1.2. Writing the request + */ + printf( " . Writing the certificate..." ); + fflush( stdout ); + + if( ( ret = write_certificate( &crt, opt.output_file, + ctr_drbg_random, &ctr_drbg ) ) != 0 ) + { + error_strerror( ret, buf, 1024 ); + printf( " failed\n ! write_certifcate -0x%02x - %s\n\n", -ret, buf ); + goto exit; + } + + printf( " ok\n" ); + +exit: + x509write_crt_free( &crt ); + pk_free( &loaded_subject_key ); + pk_free( &loaded_issuer_key ); + mpi_free( &serial ); + +#if defined(_WIN32) + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +#endif /* POLARSSL_X509_WRITE_C && POLARSSL_X509_PARSE_C && POLARSSL_FS_IO && + POLARSSL_ENTROPY_C && POLARSSL_CTR_DRBG_C && + POLARSSL_ERROR_C */ diff --git a/programs/x509/crl_app.c b/programs/x509/crl_app.c index b98e743dd0..c9c3ef0d86 100644 --- a/programs/x509/crl_app.c +++ b/programs/x509/crl_app.c @@ -35,6 +35,19 @@ #include "polarssl/x509.h" +#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ + !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " + "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); + return( 0 ); +} +#else + #define DFL_FILENAME "crl.pem" #define DFL_DEBUG_LEVEL 0 @@ -52,18 +65,6 @@ struct options " filename=%%s default: crl.pem\n" \ "\n" -#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) -int main( int argc, char *argv[] ) -{ - ((void) argc); - ((void) argv); - - printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " - "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); - return( 0 ); -} -#else int main( int argc, char *argv[] ) { int ret = 0; diff --git a/programs/x509/req_app.c b/programs/x509/req_app.c new file mode 100644 index 0000000000..e2faab43b5 --- /dev/null +++ b/programs/x509/req_app.c @@ -0,0 +1,153 @@ +/* + * Certificate request reading application + * + * 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. + */ + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include + +#include "polarssl/config.h" + +#include "polarssl/x509.h" + +#if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ + !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) +int main( int argc, char *argv[] ) +{ + ((void) argc); + ((void) argv); + + printf("POLARSSL_BIGNUM_C and/or POLARSSL_RSA_C and/or " + "POLARSSL_X509_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); + return( 0 ); +} +#else + +#define DFL_FILENAME "cert.req" +#define DFL_DEBUG_LEVEL 0 + +/* + * global options + */ +struct options +{ + const char *filename; /* filename of the certificate request */ +} opt; + +#define USAGE \ + "\n usage: req_app param=<>...\n" \ + "\n acceptable parameters:\n" \ + " filename=%%s default: cert.req\n" \ + "\n" + +int main( int argc, char *argv[] ) +{ + int ret = 0; + unsigned char buf[100000]; + x509_csr csr; + int i, j, n; + char *p, *q; + + /* + * Set to sane values + */ + memset( &csr, 0, sizeof( x509_csr ) ); + + if( argc == 0 ) + { + usage: + printf( USAGE ); + goto exit; + } + + opt.filename = DFL_FILENAME; + + for( i = 1; i < argc; i++ ) + { + n = strlen( argv[i] ); + + for( j = 0; j < n; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + p = argv[i]; + if( ( q = strchr( p, '=' ) ) == NULL ) + goto usage; + *q++ = '\0'; + + if( strcmp( p, "filename" ) == 0 ) + opt.filename = q; + else + goto usage; + } + + /* + * 1.1. Load the CSR + */ + printf( "\n . Loading the CSR ..." ); + fflush( stdout ); + + ret = x509parse_csrfile( &csr, opt.filename ); + + if( ret != 0 ) + { + printf( " failed\n ! x509parse_csr returned %d\n\n", ret ); + x509_csr_free( &csr ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.2 Print the CSR + */ + printf( " . CSR information ...\n" ); + ret = x509parse_csr_info( (char *) buf, sizeof( buf ) - 1, " ", &csr ); + if( ret == -1 ) + { + printf( " failed\n ! x509parse_csr_info returned %d\n\n", ret ); + x509_csr_free( &csr ); + goto exit; + } + + printf( "%s\n", buf ); + +exit: + x509_csr_free( &csr ); + +#if defined(_WIN32) + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +} +#endif /* POLARSSL_BIGNUM_C && POLARSSL_RSA_C && POLARSSL_X509_PARSE_C && + POLARSSL_FS_IO */ diff --git a/tests/data_files/server1.pubkey b/tests/data_files/server1.pubkey new file mode 100644 index 0000000000..93c669c616 --- /dev/null +++ b/tests/data_files/server1.pubkey @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQIfPUBq1VVTi/027oJl +LhVhXom/uOhFkNvuiBZS0/FDUEeWEllkh2v9K+BG+XO+3c+S4ZFb7Wagb4kpeUWA +0INq1UFDd185fAkER4KwVzlw7aPsFRkeqDMIR8EFQqn9TMO0390GH00QUUBncxMP +QPhtgSVfCrFTxjB+FTms+Vruf5KepgVb5xOXhbUjktnUJAbVCSWJdQfdphqPPwkZ +vq1lLGTrlZvc/kFeF6babFtpzAK6FCwWJJxK3M3Q91Jnc/EtoCP9fvQxyi1wyokL +BNsupk9wbp7OvViJ4lNZnm5akmXiiD8MlBmj3eXonZUT7Snbq3AS3FrKaxerUoJU +sQIDAQAB +-----END PUBLIC KEY----- diff --git a/tests/suites/test_suite_x509write.data b/tests/suites/test_suite_x509write.data index 7490b7c171..fc9bb92a3a 100644 --- a/tests/suites/test_suite_x509write.data +++ b/tests/suites/test_suite_x509write.data @@ -25,3 +25,23 @@ x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD4:"data_files/server1.req. Certificate Request check Server1 MD5 depends_on:POLARSSL_MD5_C:POLARSSL_RSA_C:POLARSSL_PKCS1_V15 x509_csr_check:"data_files/server1.key":POLARSSL_MD_MD5:"data_files/server1.req.md5" + +Certificate write check Server1 SHA1 +depends_on:POLARSSL_SHA1_C:POLARSSL_RSA_C:POLARSSL_PKCS1_V15 +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 d3c801a1d3..9352c9ea2f 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -14,46 +14,174 @@ void x509_csr_check( char *key_file, int md_type, char *cert_req_check_file ) { - rsa_context rsa; + pk_context key; pem_context pem; - x509_csr req; + x509write_csr req; unsigned char *c; unsigned char buf[4000]; unsigned char check_buf[4000]; int ret; - size_t olen = 2000; + size_t olen = sizeof( check_buf ); FILE *f; char *subject_name = "C=NL,O=PolarSSL,CN=PolarSSL Server 1"; + rnd_pseudo_info rnd_info; - memset( &rsa, 0, sizeof(rsa_context) ); - ret = x509parse_keyfile_rsa( &rsa, key_file, NULL ); - TEST_ASSERT( ret == 0 ); - if( ret != 0 ) - return; + memset( &rnd_info, 0x2a, sizeof( rnd_pseudo_info ) ); + + pk_init( &key ); + TEST_ASSERT( x509parse_keyfile( &key, key_file, NULL ) == 0 ); x509write_csr_init( &req ); x509write_csr_set_md_alg( &req, md_type ); - x509write_csr_set_rsa_key( &req, &rsa ); + x509write_csr_set_key( &req, &key ); TEST_ASSERT( x509write_csr_set_subject_name( &req, subject_name ) == 0 ); - ret = x509write_csr_der( &req, buf, 4000 ); + ret = x509write_csr_der( &req, buf, sizeof( buf ), + rnd_pseudo_rand, &rnd_info ); TEST_ASSERT( ret >= 0 ); - c = buf + 3999 - ret; + c = buf + sizeof( buf ) - ret; f = fopen( cert_req_check_file, "r" ); TEST_ASSERT( f != NULL ); - fread( check_buf, 1, 4000, f ); + fread( check_buf, 1, sizeof( check_buf ), f ); fclose( f ); pem_init( &pem ); pem_read_buffer( &pem, "-----BEGIN CERTIFICATE REQUEST-----", "-----END CERTIFICATE REQUEST-----", check_buf, NULL, 0, &olen ); - TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 ); TEST_ASSERT( pem.buflen == (size_t) ret ); + TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 ); x509write_csr_free( &req ); - rsa_free( &rsa ); pem_free( &pem ); + pk_free( &key ); +} +/* END_CASE */ + +/* BEGIN_CASE */ +void x509_crt_check( char *subject_key_file, char *subject_pwd, + char *subject_name, char *issuer_key_file, + char *issuer_pwd, char *issuer_name, + char *serial_str, char *not_before, char *not_after, + int md_type, char *cert_check_file ) +{ + pk_context subject_key, issuer_key; + pem_context pem; + x509write_cert crt; + unsigned char *c; + unsigned char buf[4000]; + unsigned char check_buf[5000]; + mpi serial; + int ret; + size_t olen = sizeof( check_buf ); + FILE *f; + rnd_pseudo_info rnd_info; + + memset( &rnd_info, 0x2a, sizeof( rnd_pseudo_info ) ); + mpi_init( &serial ); + pk_init( &subject_key ); + pk_init( &issuer_key ); + + TEST_ASSERT( x509parse_keyfile( &subject_key, subject_key_file, + subject_pwd ) == 0 ); + TEST_ASSERT( x509parse_keyfile( &issuer_key, issuer_key_file, + issuer_pwd ) == 0 ); + TEST_ASSERT( mpi_read_string( &serial, 10, serial_str ) == 0 ); + + x509write_crt_init( &crt ); + x509write_crt_set_serial( &crt, &serial ); + TEST_ASSERT( x509write_crt_set_validity( &crt, not_before, + not_after ) == 0 ); + x509write_crt_set_md_alg( &crt, md_type ); + TEST_ASSERT( x509write_crt_set_issuer_name( &crt, issuer_name ) == 0 ); + TEST_ASSERT( x509write_crt_set_subject_name( &crt, subject_name ) == 0 ); + x509write_crt_set_subject_key( &crt, &subject_key ); + x509write_crt_set_issuer_key( &crt, &issuer_key ); + + TEST_ASSERT( x509write_crt_set_basic_constraints( &crt, 0, 0 ) == 0 ); + TEST_ASSERT( x509write_crt_set_subject_key_identifier( &crt ) == 0 ); + TEST_ASSERT( x509write_crt_set_authority_key_identifier( &crt ) == 0 ); + + ret = x509write_crt_der( &crt, buf, sizeof(buf), + rnd_pseudo_rand, &rnd_info ); + TEST_ASSERT( ret >= 0 ); + + c = buf + sizeof( buf ) - ret; + + f = fopen( cert_check_file, "r" ); + TEST_ASSERT( f != NULL ); + TEST_ASSERT( fread( check_buf, 1, sizeof(check_buf), f ) < sizeof(check_buf) ); + fclose( f ); + + pem_init( &pem ); + TEST_ASSERT( pem_read_buffer( &pem, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----", check_buf, NULL, 0, &olen ) >= 0 ); + + TEST_ASSERT( pem.buflen == (size_t) ret ); + TEST_ASSERT( memcmp( c, pem.buf, pem.buflen ) == 0 ); + + x509write_crt_free( &crt ); + pk_free( &issuer_key ); + pk_free( &subject_key ); + pem_free( &pem ); + 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( x509parse_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( x509parse_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 */