From 7c6b2c320e2cfe22d85699dc6da0fa68607a367c Mon Sep 17 00:00:00 2001 From: Paul Bakker Date: Mon, 16 Sep 2013 13:49:26 +0200 Subject: [PATCH] Split up X509 files into smaller modules --- include/polarssl/config.h | 146 +- include/polarssl/debug.h | 4 +- include/polarssl/oid.h | 4 +- include/polarssl/ssl.h | 34 +- include/polarssl/ssl_cache.h | 2 +- include/polarssl/x509.h | 418 +---- include/polarssl/x509_crl.h | 151 ++ include/polarssl/{x509write.h => x509_crt.h} | 357 ++-- include/polarssl/x509_csr.h | 269 +++ library/CMakeLists.txt | 13 +- library/debug.c | 4 +- library/oid.c | 6 +- library/ssl_cache.c | 20 +- library/ssl_srv.c | 18 +- library/ssl_tls.c | 22 +- library/x509.c | 798 ++++++++ library/x509_create.c | 267 +++ library/x509_crl.c | 740 ++++++++ library/{x509parse.c => x509_crt.c} | 1705 +----------------- library/x509_crt_write.c | 426 +++++ library/x509_csr.c | 439 +++++ library/x509_csr_write.c | 244 +++ library/x509write.c | 869 --------- programs/pkey/key_app_writer.c | 6 +- programs/x509/cert_app.c | 16 +- programs/x509/cert_req.c | 8 +- programs/x509/cert_write.c | 9 +- programs/x509/crl_app.c | 6 +- programs/x509/req_app.c | 6 +- tests/suites/test_suite_x509parse.function | 33 +- tests/suites/test_suite_x509write.function | 10 +- 31 files changed, 3838 insertions(+), 3212 deletions(-) create mode 100644 include/polarssl/x509_crl.h rename include/polarssl/{x509write.h => x509_crt.h} (53%) create mode 100644 include/polarssl/x509_csr.h create mode 100644 library/x509.c create mode 100644 library/x509_create.c create mode 100644 library/x509_crl.c rename library/{x509parse.c => x509_crt.c} (53%) create mode 100644 library/x509_crt_write.c create mode 100644 library/x509_csr.c create mode 100644 library/x509_csr_write.c delete mode 100644 library/x509write.c diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 36697bd0e..3c9f1c1a6 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -287,7 +287,7 @@ * * Enable the RSA-PSK based ciphersuite modes in SSL / TLS * (NOT YET IMPLEMENTED) - * Requires: POLARSSL_RSA_C, POLARSSL_X509_PARSE_C, POLARSSL_PKCS1_V15 + * Requires: POLARSSL_RSA_C, POLARSSL_X509_CRT_PARSE_C, POLARSSL_PKCS1_V15 * * This enables the following ciphersuites (if other requisites are * enabled as well): @@ -307,7 +307,7 @@ * * Enable the RSA-only based ciphersuite modes in SSL / TLS * - * Requires: POLARSSL_RSA_C, POLARSSL_X509_PARSE_C, POLARSSL_PKCS1_V15 + * Requires: POLARSSL_RSA_C, POLARSSL_X509_CRT_PARSE_C, POLARSSL_PKCS1_V15 * * This enables the following ciphersuites (if other requisites are * enabled as well): @@ -332,7 +332,7 @@ * * Enable the DHE-RSA based ciphersuite modes in SSL / TLS * - * Requires: POLARSSL_DHM_C, POLARSSL_RSA_C, POLARSSL_X509_PARSE_C, + * Requires: POLARSSL_DHM_C, POLARSSL_RSA_C, POLARSSL_X509_CRT_PARSE_C, * POLARSSL_PKCS1_V15 * * This enables the following ciphersuites (if other requisites are @@ -354,7 +354,7 @@ * * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS * - * Requires: POLARSSL_ECDH_C, POLARSSL_RSA_C, POLARSSL_X509_PARSE_C, + * Requires: POLARSSL_ECDH_C, POLARSSL_RSA_C, POLARSSL_X509_CRT_PARSE_C, * POLARSSL_PKCS1_V15 * * This enables the following ciphersuites (if other requisites are @@ -377,7 +377,7 @@ * * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS * - * Requires: POLARSSL_ECDH_C, POLARSSL_ECDSA_C, POLARSSL_X509_PARSE_C + * Requires: POLARSSL_ECDH_C, POLARSSL_ECDSA_C, POLARSSL_X509_CRT_PARSE_C * * This enables the following ciphersuites (if other requisites are * enabled as well): @@ -1413,34 +1413,104 @@ #define POLARSSL_VERSION_C /** - * \def POLARSSL_X509_PARSE_C + * \def POLARSSL_X509_USE_C * - * Enable X.509 certificate parsing. + * Enable X.509 core for using certificates * - * Module: library/x509parse.c - * Caller: library/ssl_cli.c - * library/ssl_srv.c - * library/ssl_tls.c + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c * * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_OID_C, * POLARSSL_PK_PARSE_C * - * This module is required for X.509 certificate parsing. + * This module is required for the X.509 parsing modules. */ -#define POLARSSL_X509_PARSE_C +#define POLARSSL_X509_USE_C /** - * \def POLARSSL_X509_WRITE_C + * \def POLARSSL_X509_CRT_PARSE_C * - * Enable X.509 buffer writing. + * Enable X.509 certificate parsing. * - * Module: library/x509write.c + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define POLARSSL_X509_CRT_PARSE_C + +/** + * \def POLARSSL_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define POLARSSL_X509_CRL_PARSE_C + +/** + * \def POLARSSL_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define POLARSSL_X509_CSR_PARSE_C + +/** + * \def POLARSSL_X509_CREATE_C + * + * Enable X.509 core for creating certificates + * + * Module: library/x509_create.c * * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_WRITE_C * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define POLARSSL_X509_CREATE_C + +/** + * \def POLARSSL_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: POLARSSL_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define POLARSSL_X509_CRT_WRITE_C + +/** + * \def POLARSSL_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR) + * + * Module: library/x509_csr_write.c + * + * Requires: POLARSSL_CREATE_C + * * This module is required for X.509 certificate request writing. */ -#define POLARSSL_X509_WRITE_C +#define POLARSSL_X509_CSR_WRITE_C /** * \def POLARSSL_XTEA_C @@ -1566,30 +1636,30 @@ #if defined(POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ ( !defined(POLARSSL_DHM_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_PKCS1_V15) ) + !defined(POLARSSL_X509_CRT_PARSE_C) || !defined(POLARSSL_PKCS1_V15) ) #error "POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites" #endif #if defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ ( !defined(POLARSSL_ECDH_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_PKCS1_V15) ) + !defined(POLARSSL_X509_CRT_PARSE_C) || !defined(POLARSSL_PKCS1_V15) ) #error "POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites" #endif #if defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ ( !defined(POLARSSL_ECDH_C) || !defined(POLARSSL_ECDSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) ) + !defined(POLARSSL_X509_CRT_PARSE_C) ) #error "POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites" #endif #if defined(POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ - ( !defined(POLARSSL_RSA_C) || !defined(POLARSSL_X509_PARSE_C) || \ + ( !defined(POLARSSL_RSA_C) || !defined(POLARSSL_X509_CRT_PARSE_C) ||\ !defined(POLARSSL_PKCS1_V15) ) #error "POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites" #endif #if defined(POLARSSL_KEY_EXCHANGE_RSA_ENABLED) && \ - ( !defined(POLARSSL_RSA_C) || !defined(POLARSSL_X509_PARSE_C) || \ + ( !defined(POLARSSL_RSA_C) || !defined(POLARSSL_X509_CRT_PARSE_C) ||\ !defined(POLARSSL_PKCS1_V15) ) #error "POLARSSL_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites" #endif @@ -1668,16 +1738,36 @@ #error "POLARSSL_SSL_SESSION_TICKETS_C defined, but not all prerequisites" #endif -#if defined(POLARSSL_X509_PARSE_C) && ( !defined(POLARSSL_BIGNUM_C) || \ +#if defined(POLARSSL_X509_USE_C) && ( !defined(POLARSSL_BIGNUM_C) || \ !defined(POLARSSL_OID_C) || !defined(POLARSSL_ASN1_PARSE_C) || \ !defined(POLARSSL_PK_PARSE_C) ) -#error "POLARSSL_X509_PARSE_C defined, but not all prerequisites" +#error "POLARSSL_X509_USE_C defined, but not all prerequisites" #endif -#if defined(POLARSSL_X509_WRITE_C) && ( !defined(POLARSSL_BIGNUM_C) || \ - !defined(POLARSSL_OID_C) || !defined(POLARSSL_ASN1_WRITE_C) || \ - !defined(POLARSSL_RSA_C) || !defined(POLARSSL_PK_WRITE_C) ) -#error "POLARSSL_X509_WRITE_C defined, but not all prerequisites" +#if defined(POLARSSL_X509_CREATE_C) && ( !defined(POLARSSL_BIGNUM_C) || \ + !defined(POLARSSL_OID_C) || !defined(POLARSSL_ASN1_WRITE_C) || \ + !defined(POLARSSL_PK_WRITE_C) ) +#error "POLARSSL_X509_CREATE_C defined, but not all prerequisites" +#endif + +#if defined(POLARSSL_X509_CRT_PARSE_C) && ( !defined(POLARSSL_X509_USE_C) ) +#error "POLARSSL_X509_CRT_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(POLARSSL_X509_CRL_PARSE_C) && ( !defined(POLARSSL_X509_USE_C) ) +#error "POLARSSL_X509_CRL_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(POLARSSL_X509_CSR_PARSE_C) && ( !defined(POLARSSL_X509_USE_C) ) +#error "POLARSSL_X509_CSR_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(POLARSSL_X509_CRT_WRITE_C) && ( !defined(POLARSSL_X509_CREATE_C) ) +#error "POLARSSL_X509_CRT_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(POLARSSL_X509_CSR_WRITE_C) && ( !defined(POLARSSL_X509_CREATE_C) ) +#error "POLARSSL_X509_CSR_WRITE_C defined, but not all prerequisites" #endif #endif /* config.h */ diff --git a/include/polarssl/debug.h b/include/polarssl/debug.h index fdd36273e..935a2fcec 100644 --- a/include/polarssl/debug.h +++ b/include/polarssl/debug.h @@ -54,7 +54,7 @@ debug_print_ecp( ssl, level, __FILE__, __LINE__, text, X ); #endif -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) #define SSL_DEBUG_CRT( level, text, crt ) \ debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ); #endif @@ -99,7 +99,7 @@ void debug_print_ecp( const ssl_context *ssl, int level, const char *text, const ecp_point *X ); #endif -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) void debug_print_crt( const ssl_context *ssl, int level, const char *file, int line, const char *text, const x509_cert *crt ); diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h index ba0ce7d39..20bacae1b 100644 --- a/include/polarssl/oid.h +++ b/include/polarssl/oid.h @@ -39,7 +39,7 @@ #include "md.h" #endif -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C) #include "x509.h" #endif @@ -337,7 +337,7 @@ typedef struct { */ int oid_get_numeric_string( char *buf, size_t size, const asn1_buf *oid ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C) /** * \brief Translate an X.509 extension OID into local values * diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index cc60a4ebe..48ffc1ecb 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -54,8 +54,12 @@ #include "aes.h" #endif -#if defined(POLARSSL_X509_PARSE_C) -#include "x509.h" +#if defined(POLARSSL_X509_CRT_PARSE_C) +#include "x509_crt.h" +#endif + +#if defined(POLARSSL_X509_CRL_PARSE_C) +#include "x509_crl.h" #endif #if defined(POLARSSL_DHM_C) @@ -406,9 +410,9 @@ struct _ssl_session unsigned char id[32]; /*!< session identifier */ unsigned char master[48]; /*!< the master secret */ -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) x509_cert *peer_cert; /*!< peer X.509 cert chain */ -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ int verify_result; /*!< verification result */ #if defined(POLARSSL_SSL_SESSION_TICKETS) @@ -579,7 +583,7 @@ struct _ssl_context void *p_sni; /*!< context for SNI extension */ #endif -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) int (*f_vrfy)(void *, x509_cert *, int, int *); void *p_vrfy; /*!< context for verification */ #endif @@ -642,12 +646,14 @@ struct _ssl_context pk_context *pk_key; /*!< own private key */ int pk_key_own_alloc; /*!< did we allocate pk_key? */ -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) x509_cert *own_cert; /*!< own X.509 certificate */ x509_cert *ca_chain; /*!< own trusted CA chain */ - x509_crl *ca_crl; /*!< trusted CA CRLs */ const char *peer_cn; /*!< expected peer CN */ -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ +#if defined(POLARSSL_X509_CRL_PARSE_C) + x509_crl *ca_crl; /*!< trusted CA CRLs */ +#endif /* POLARSSL_X509_CRL_PARSE_C */ #if defined(POLARSSL_SSL_SESSION_TICKETS) /* @@ -806,7 +812,7 @@ void ssl_set_endpoint( ssl_context *ssl, int endpoint ); */ void ssl_set_authmode( ssl_context *ssl, int authmode ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) /** * \brief Set the verification callback (Optional). * @@ -821,7 +827,7 @@ void ssl_set_authmode( ssl_context *ssl, int authmode ); void ssl_set_verify( ssl_context *ssl, int (*f_vrfy)(void *, x509_cert *, int, int *), void *p_vrfy ); -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ /** * \brief Set the random number generator callback @@ -941,7 +947,7 @@ void ssl_set_ciphersuites_for_version( ssl_context *ssl, const int *ciphersuites, int major, int minor ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) /** * \brief Set the data required to verify peer certificate * @@ -1011,7 +1017,7 @@ int ssl_set_own_cert_alt( ssl_context *ssl, x509_cert *own_cert, rsa_decrypt_func rsa_decrypt, rsa_sign_func rsa_sign, rsa_key_len_func rsa_key_len ); -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ #if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED) /** @@ -1272,7 +1278,7 @@ const char *ssl_get_ciphersuite( const ssl_context *ssl ); */ const char *ssl_get_version( const ssl_context *ssl ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) /** * \brief Return the peer certificate from the current connection * @@ -1288,7 +1294,7 @@ const char *ssl_get_version( const ssl_context *ssl ); * \return the current peer certificate */ const x509_cert *ssl_get_peer_cert( const ssl_context *ssl ); -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ /** * \brief Save session in order to resume it later (client-side only) diff --git a/include/polarssl/ssl_cache.h b/include/polarssl/ssl_cache.h index 979dc14f7..3c5ef8b1c 100644 --- a/include/polarssl/ssl_cache.h +++ b/include/polarssl/ssl_cache.h @@ -50,7 +50,7 @@ struct _ssl_cache_entry time_t timestamp; /*!< entry timestamp */ #endif ssl_session session; /*!< entry session */ -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) x509_buf peer_cert; /*!< entry peer_cert */ #endif ssl_cache_entry *next; /*!< chain pointer */ diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index 2fa00f6c6..4a5c994f9 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -1,7 +1,7 @@ /** * \file x509.h * - * \brief X.509 certificate and private key decoding + * \brief X.509 generic defines and structures * * Copyright (C) 2006-2013, Brainspark B.V. * @@ -30,16 +30,18 @@ #include "config.h" #include "asn1.h" -#include "dhm.h" -#include "md.h" #include "pk.h" -/** +#if defined(POLARSSL_RSA_C) +#include "rsa.h" +#endif + +/** * \addtogroup x509_module - * \{ + * \{ */ - -/** + +/** * \name X509 Error codes * \{ */ @@ -61,6 +63,9 @@ #define POLARSSL_ERR_X509_INVALID_INPUT -0x2800 /**< Input invalid. */ #define POLARSSL_ERR_X509_MALLOC_FAILED -0x2880 /**< Allocation of memory failed. */ #define POLARSSL_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */ +#define POLARSSL_ERR_X509WRITE_UNKNOWN_OID -0x5F80 /**< Requested OID is unknown. */ +#define POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA -0x5F00 /**< Failed to allocate memory. */ +#define POLARSSL_ERR_X509WRITE_MALLOC_FAILED -0x5E80 /**< Failed to allocate memory. */ /* \} name */ /** @@ -174,124 +179,6 @@ typedef struct _x509_time } x509_time; -/** - * Container for an X.509 certificate. The certificate may be chained. - */ -typedef struct _x509_cert -{ - x509_buf raw; /**< The raw certificate data (DER). */ - x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ - - int version; /**< The X.509 version. (0=v1, 1=v2, 2=v3) */ - x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ - x509_buf sig_oid1; /**< Signature algorithm, e.g. sha1RSA */ - - x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ - x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ - - x509_name issuer; /**< The parsed issuer data (named information object). */ - x509_name subject; /**< The parsed subject data (named information object). */ - - x509_time valid_from; /**< Start time of certificate validity. */ - x509_time valid_to; /**< End time of certificate validity. */ - - pk_context pk; /**< Container for the public key context. */ - - x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ - x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ - x509_buf v3_ext; /**< Optional X.509 v3 extensions. Only Basic Contraints are supported at this time. */ - x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ - - int ext_types; /**< Bit string containing detected and parsed extensions */ - int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ - int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ - - unsigned char key_usage; /**< Optional key usage extension value: See the values below */ - - x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ - - unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values below */ - - x509_buf sig_oid2; /**< Signature algorithm. Must match sig_oid1. */ - x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ - 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. */ -} -x509_cert; - -/** - * Certificate revocation list entry. - * Contains the CA-specific serial numbers and revocation dates. - */ -typedef struct _x509_crl_entry -{ - x509_buf raw; - - x509_buf serial; - - x509_time revocation_date; - - x509_buf entry_ext; - - struct _x509_crl_entry *next; -} -x509_crl_entry; - -/** - * Certificate revocation list structure. - * Every CRL may have multiple entries. - */ -typedef struct _x509_crl -{ - x509_buf raw; /**< The raw certificate data (DER). */ - x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ - - int version; - x509_buf sig_oid1; - - x509_buf issuer_raw; /**< The raw issuer data (DER). */ - - x509_name issuer; /**< The parsed issuer data (named information object). */ - - x509_time this_update; - x509_time next_update; - - x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ - - x509_buf crl_ext; - - x509_buf sig_oid2; - 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 */; - - struct _x509_crl *next; -} -x509_crl; - -/** - * 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 */ @@ -300,119 +187,6 @@ x509_csr; * \{ */ -/** \ingroup x509_module */ -/** - * \brief Parse a single DER formatted certificate and add it - * to the chained list. - * - * \param chain points to the start of the chain - * \param buf buffer holding the certificate DER data - * \param buflen size of the buffer - * - * \return 0 if successful, or a specific X509 or PEM error code - */ -int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, size_t buflen ); - -/** - * \brief Parse one or more certificates and add them - * to the chained list. Parses permissively. If some - * certificates can be parsed, the result is the number - * of failed certificates it encountered. If none complete - * correctly, the first error is returned. - * - * \param chain points to the start of the chain - * \param buf buffer holding the certificate data - * \param buflen size of the buffer - * - * \return 0 if all certificates parsed successfully, a positive number - * if partly successful or a specific X509 or PEM error code - */ -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 - * to the chained list. Parses permissively. If some - * certificates can be parsed, the result is the number - * of failed certificates it encountered. If none complete - * correctly, the first error is returned. - * - * \param chain points to the start of the chain - * \param path filename to read the certificates from - * - * \return 0 if all certificates parsed successfully, a positive number - * if partly successful or a specific X509 or PEM error code - */ -int x509parse_crtfile( x509_cert *chain, const char *path ); - -/** \ingroup x509_module */ -/** - * \brief Load one or more certificate files from a path and add them - * to the chained list. Parses permissively. If some - * certificates can be parsed, the result is the number - * of failed certificates it encountered. If none complete - * correctly, the first error is returned. - * - * \param chain points to the start of the chain - * \param path directory / folder to read the certificate files from - * - * \return 0 if all certificates parsed successfully, a positive number - * 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 */ -/** - * \brief Parse one or more CRLs and add them - * to the chained list - * - * \param chain points to the start of the chain - * \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_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 - * to the chained list - * - * \param chain points to the start of the chain - * \param path filename to read the CRLs from - * - * \return 0 if successful, or a specific X509 or PEM error code - */ -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 */ /** @@ -500,51 +274,6 @@ int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ); */ int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ); -/** - * \brief Returns an informational string about the - * certificate. - * - * \param buf Buffer to write to - * \param size Maximum size of buffer - * \param prefix A line prefix - * \param crt The X509 certificate to represent - * - * \return The amount of data written to the buffer, or -1 in - * case of an error. - */ -int x509parse_cert_info( char *buf, size_t size, const char *prefix, - const x509_cert *crt ); - -/** - * \brief Returns an informational string about the - * CRL. - * - * \param buf Buffer to write to - * \param size Maximum size of buffer - * \param prefix A line prefix - * \param crl The X509 CRL to represent - * - * \return The amount of data written to the buffer, or -1 in - * case of an error. - */ -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. * @@ -579,99 +308,6 @@ int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ); */ int x509parse_time_expired( const x509_time *time ); -/** - * \name Functions to verify a certificate - * \{ - */ -/** \ingroup x509_module */ -/** - * \brief Verify the certificate signature - * - * The verify callback is a user-supplied callback that - * can clear / modify / add flags for a certificate. If set, - * the verification callback is called for each - * certificate in the chain (from the trust-ca down to the - * presented crt). The parameters for the callback are: - * (void *parameter, x509_cert *crt, int certificate_depth, - * int *flags). With the flags representing current flags for - * that specific certificate and the certificate depth from - * the bottom (Peer cert depth = 0). - * - * All flags left after returning from the callback - * are also returned to the application. The function should - * return 0 for anything but a fatal error. - * - * \param crt a certificate to be verified - * \param trust_ca the trusted CA chain - * \param ca_crl the CRL chain for trusted CA's - * \param cn expected Common Name (can be set to - * NULL if the CN must not be verified) - * \param flags result of the verification - * \param f_vrfy verification function - * \param p_vrfy verification parameter - * - * \return 0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED, - * in which case *flags will have one or more of - * the following values set: - * BADCERT_EXPIRED -- - * BADCERT_REVOKED -- - * BADCERT_CN_MISMATCH -- - * BADCERT_NOT_TRUSTED - * or another error in case of a fatal error encountered - * during the verification process. - */ -int x509parse_verify( x509_cert *crt, - x509_cert *trust_ca, - x509_crl *ca_crl, - const char *cn, int *flags, - int (*f_vrfy)(void *, x509_cert *, int, int *), - void *p_vrfy ); - -/** - * \brief Verify the certificate signature - * - * \param crt a certificate to be verified - * \param crl the CRL to verify against - * - * \return 1 if the certificate is revoked, 0 otherwise - * - */ -int x509parse_revoked( const x509_cert *crt, const x509_crl *crl ); - -/** \} name Functions to verify a certificate */ - - - -/** - * \name Functions to clear a certificate, CRL or private RSA key - * \{ - */ -/** \ingroup x509_module */ -/** - * \brief Unallocate all certificate data - * - * \param crt Certificate chain to free - */ -void x509_free( x509_cert *crt ); - -/** \ingroup x509_module */ -/** - * \brief Unallocate all CRL data - * - * \param crl CRL chain to free - */ -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 */ - - /** * \brief Checkup routine * @@ -679,8 +315,32 @@ void x509_csr_free( x509_csr *csr ); */ int x509_self_test( int verbose ); -#ifdef __cplusplus -} -#endif +/* + * Internal module functions + */ +int x509_get_name( unsigned char **p, const unsigned char *end, + x509_name *cur ); +int x509_get_alg_null( unsigned char **p, const unsigned char *end, + x509_buf *alg ); +int x509_get_sig( unsigned char **p, const unsigned char *end, x509_buf *sig ); +int x509_get_sig_alg( const x509_buf *sig_oid, md_type_t *md_alg, + pk_type_t *pk_alg ); +int x509_load_file( const char *path, unsigned char **buf, size_t *n ); +int x509_key_size_helper( char *buf, size_t size, const char *name ); +int x509_get_time( unsigned char **p, const unsigned char *end, + x509_time *time ); +int x509_get_serial( unsigned char **p, const unsigned char *end, + x509_buf *serial ); +int x509_get_ext( unsigned char **p, const unsigned char *end, + x509_buf *ext, int tag ); +int x509write_string_to_names( asn1_named_data **head, char *name ); +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 ); +int x509_write_extensions( unsigned char **p, unsigned char *start, + asn1_named_data *first ); +int x509_write_names( unsigned char **p, unsigned char *start, + asn1_named_data *first ); +int x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); #endif /* x509.h */ diff --git a/include/polarssl/x509_crl.h b/include/polarssl/x509_crl.h new file mode 100644 index 000000000..bae81823e --- /dev/null +++ b/include/polarssl/x509_crl.h @@ -0,0 +1,151 @@ +/** + * \file x509_crl.h + * + * \brief X.509 certificate revocation list parsing + * + * 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 POLARSSL_X509_CRL_H +#define POLARSSL_X509_CRL_H + +#include "config.h" + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for parsing CRLs + * \{ + */ + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct _x509_crl_entry +{ + x509_buf raw; + + x509_buf serial; + + x509_time revocation_date; + + x509_buf entry_ext; + + struct _x509_crl_entry *next; +} +x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct _x509_crl +{ + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; + x509_buf sig_oid1; + + x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + + x509_time this_update; + x509_time next_update; + + x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + x509_buf crl_ext; + + x509_buf sig_oid2; + 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 */; + + struct _x509_crl *next; +} +x509_crl; + +/** + * \brief Parse one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \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_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Load one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crlfile( x509_crl *chain, const char *path ); +#endif /* POLARSSL_FS_IO */ + +/** + * \brief Returns an informational string about the + * CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_crl_info( char *buf, size_t size, const char *prefix, + const x509_crl *crl ); + +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void x509_crl_free( x509_crl *crl ); + +/* \} name */ +/* \} addtogroup x509_module */ + +#ifdef __cplusplus +} +#endif + +#endif /* x509_crl.h */ diff --git a/include/polarssl/x509write.h b/include/polarssl/x509_crt.h similarity index 53% rename from include/polarssl/x509write.h rename to include/polarssl/x509_crt.h index 72014a68f..55042ec53 100644 --- a/include/polarssl/x509write.h +++ b/include/polarssl/x509_crt.h @@ -1,7 +1,7 @@ /** - * \file x509write.h + * \file x509_crt.h * - * \brief X509 buffer writing functionality + * \brief X.509 certificate parsing and writing * * Copyright (C) 2006-2013, Brainspark B.V. * @@ -24,30 +24,15 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef POLARSSL_X509_WRITE_H -#define POLARSSL_X509_WRITE_H +#ifndef POLARSSL_X509_CRT_H +#define POLARSSL_X509_CRT_H #include "config.h" #include "x509.h" -/** - * \addtogroup x509_module - * \{ - */ - -/** - * \name X509 Write Error codes - * \{ - */ -#define POLARSSL_ERR_X509WRITE_UNKNOWN_OID -0x5F80 /**< Requested OID is unknown. */ -#define POLARSSL_ERR_X509WRITE_BAD_INPUT_DATA -0x5F00 /**< Failed to allocate memory. */ -#define POLARSSL_ERR_X509WRITE_MALLOC_FAILED -0x5E80 /**< Failed to allocate memory. */ -/* \} name */ -/* \} addtogroup x509_module */ - -#ifdef __cplusplus -extern "C" { +#if defined(POLARSSL_X509_CRL_PARSE_C) +#include "x509_crl.h" #endif /** @@ -55,22 +40,61 @@ extern "C" { * \{ */ +#ifdef __cplusplus +extern "C" { +#endif + /** - * \name Structures for writing X.509 CSRs (Certificate Signing Request) + * \name Structures and functions for parsing and writing X.509 certificates * \{ */ /** - * Container for a CSR + * Container for an X.509 certificate. The certificate may be chained. */ -typedef struct _x509write_csr +typedef struct _x509_cert { - pk_context *key; - asn1_named_data *subject; - md_type_t md_alg; - asn1_named_data *extensions; + x509_buf raw; /**< The raw certificate data (DER). */ + x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (0=v1, 1=v2, 2=v3) */ + x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + x509_buf sig_oid1; /**< Signature algorithm, e.g. sha1RSA */ + + x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + x509_name issuer; /**< The parsed issuer data (named information object). */ + x509_name subject; /**< The parsed subject data (named information object). */ + + x509_time valid_from; /**< Start time of certificate validity. */ + x509_time valid_to; /**< End time of certificate validity. */ + + pk_context pk; /**< Container for the public key context. */ + + x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + x509_buf v3_ext; /**< Optional X.509 v3 extensions. Only Basic Contraints are supported at this time. */ + x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ + + unsigned char key_usage; /**< Optional key usage extension value: See the values below */ + + x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values below */ + + x509_buf sig_oid2; /**< Signature algorithm. Must match sig_oid1. */ + x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + 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. */ } -x509write_csr; +x509_cert; #define X509_CRT_VERSION_1 0 #define X509_CRT_VERSION_2 1 @@ -97,93 +121,151 @@ typedef struct _x509write_cert } x509write_cert; +#if defined(POLARSSL_X509_CRT_PARSE_C) +/** + * \brief Parse a single DER formatted certificate and add it + * to the chained list. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate DER data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int x509parse_crt_der( x509_cert *chain, const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data + * \param buflen size of the buffer + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ); + +#if defined(POLARSSL_FS_IO) +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crtfile( x509_cert *chain, const char *path ); + +/** + * \brief Load one or more certificate files from a path and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path directory / folder to read the certificate files from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int x509parse_crtpath( x509_cert *chain, const char *path ); +#endif /* POLARSSL_FS_IO */ + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The amount of data written to the buffer, or -1 in + * case of an error. + */ +int x509parse_cert_info( char *buf, size_t size, const char *prefix, + const x509_cert *crt ); + +/** + * \brief Verify the certificate signature + * + * The verify callback is a user-supplied callback that + * can clear / modify / add flags for a certificate. If set, + * the verification callback is called for each + * certificate in the chain (from the trust-ca down to the + * presented crt). The parameters for the callback are: + * (void *parameter, x509_cert *crt, int certificate_depth, + * int *flags). With the flags representing current flags for + * that specific certificate and the certificate depth from + * the bottom (Peer cert depth = 0). + * + * All flags left after returning from the callback + * are also returned to the application. The function should + * return 0 for anything but a fatal error. + * + * \param crt a certificate to be verified + * \param trust_ca the trusted CA chain + * \param ca_crl the CRL chain for trusted CA's + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED, + * in which case *flags will have one or more of + * the following values set: + * BADCERT_EXPIRED -- + * BADCERT_REVOKED -- + * BADCERT_CN_MISMATCH -- + * BADCERT_NOT_TRUSTED + * or another error in case of a fatal error encountered + * during the verification process. + */ +int x509parse_verify( x509_cert *crt, + x509_cert *trust_ca, + x509_crl *ca_crl, + const char *cn, int *flags, + int (*f_vrfy)(void *, x509_cert *, int, int *), + void *p_vrfy ); + +#if defined(POLARSSL_X509_CRL_PARSE_C) +/** + * \brief Verify the certificate signature + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int x509parse_revoked( const x509_cert *crt, const x509_crl *crl ); +#endif /* POLARSSL_X509_CRL_PARSE_C */ + +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void x509_crt_free( x509_cert *crt ); +#endif /* POLARSSL_X509_CRT_PARSE_C */ + /* \} name */ /* \} addtogroup x509_module */ -/** - * \brief Initialize a CSR context - * - * \param ctx CSR context to initialize - */ -void x509write_csr_init( x509write_csr *ctx ); - -/** - * \brief Set the subject name for a CSR - * 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 CSR 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_csr_set_subject_name( x509write_csr *ctx, char *subject_name ); - -/** - * \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 key Asymetric key to include - */ -void x509write_csr_set_key( x509write_csr *ctx, pk_context *key ); - -/** - * \brief Set the MD algorithm to use for the signature - * (e.g. POLARSSL_MD_SHA1) - * - * \param ctx CSR context to use - * \param md_alg MD algorithm to use - */ -void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg ); - -/** - * \brief Set the Key Usage Extension flags - * (e.g. KU_DIGITAL_SIGNATURE | KU_KEY_CERT_SIGN) - * - * \param ctx CSR context to use - * \param key_usage key usage flags to set - * - * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED - */ -int x509write_csr_set_key_usage( x509write_csr *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 CSR 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_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 - * - * \param ctx CSR context to use - * \param oid OID of the extension - * \param oid_len length of the OID - * \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_csr_set_extension( x509write_csr *ctx, - const char *oid, size_t oid_len, - const unsigned char *val, size_t val_len ); - -/** - * \brief Free the contents of a CSR context - * - * \param ctx CSR context to free - */ -void x509write_csr_free( x509write_csr *ctx ); - +#if defined(POLARSSL_X509_CRT_WRITE_C) /** * \brief Initialize a CRT writing context * @@ -389,31 +471,6 @@ int x509write_crt_der( x509write_cert *ctx, unsigned char *buf, size_t size, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); -/** - * \brief Write a CSR (Certificate Signing Request) 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 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( x509write_csr *ctx, unsigned char *buf, size_t size, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); - #if defined(POLARSSL_PEM_WRITE_C) /** * \brief Write a built up certificate to a X509 PEM string @@ -434,31 +491,11 @@ int x509write_csr_der( x509write_csr *ctx, 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 CSR (Certificate Signing Request) to a - * PEM string - * - * \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( x509write_csr *ctx, unsigned char *buf, size_t size, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ); #endif /* POLARSSL_PEM_WRITE_C */ +#endif /* POLARSSL_X509_CRT_WRITE_C */ #ifdef __cplusplus } #endif -#endif /* POLARSSL_X509_WRITE_H */ +#endif /* x509_crt.h */ diff --git a/include/polarssl/x509_csr.h b/include/polarssl/x509_csr.h new file mode 100644 index 000000000..32befdb4c --- /dev/null +++ b/include/polarssl/x509_csr.h @@ -0,0 +1,269 @@ +/** + * \file x509_csr.h + * + * \brief X.509 certificate signing request parsing and writing + * + * 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 POLARSSL_X509_CSR_H +#define POLARSSL_X509_CSR_H + +#include "config.h" + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for X.509 Certificate Signing Requests (CSR) + * \{ + */ + +/** + * 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; + +/** + * Container for writing a CSR + */ +typedef struct _x509write_csr +{ + pk_context *key; + asn1_named_data *subject; + md_type_t md_alg; + asn1_named_data *extensions; +} +x509write_csr; + +#if defined(POLARSSL_X509_CSR_PARSE_C) +/** + * \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) +/** + * \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 */ + +/** + * \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 Unallocate all CSR data + * + * \param csr CSR to free + */ +void x509_csr_free( x509_csr *csr ); +#endif /* POLARSSL_X509_CSR_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(POLARSSL_X509_CSR_WRITE_C) +/** + * \brief Initialize a CSR context + * + * \param ctx CSR context to initialize + */ +void x509write_csr_init( x509write_csr *ctx ); + +/** + * \brief Set the subject name for a CSR + * 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 CSR 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_csr_set_subject_name( x509write_csr *ctx, char *subject_name ); + +/** + * \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 key Asymetric key to include + */ +void x509write_csr_set_key( x509write_csr *ctx, pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. POLARSSL_MD_SHA1) + * + * \param ctx CSR context to use + * \param md_alg MD algorithm to use + */ +void x509write_csr_set_md_alg( x509write_csr *ctx, md_type_t md_alg ); + +/** + * \brief Set the Key Usage Extension flags + * (e.g. KU_DIGITAL_SIGNATURE | KU_KEY_CERT_SIGN) + * + * \param ctx CSR context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or POLARSSL_ERR_X509WRITE_MALLOC_FAILED + */ +int x509write_csr_set_key_usage( x509write_csr *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 CSR 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_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 + * + * \param ctx CSR context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \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_csr_set_extension( x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ); + +/** + * \brief Free the contents of a CSR context + * + * \param ctx CSR context to free + */ +void x509write_csr_free( x509write_csr *ctx ); + +/** + * \brief Write a CSR (Certificate Signing Request) 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 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( x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(POLARSSL_PEM_WRITE_C) +/** + * \brief Write a CSR (Certificate Signing Request) to a + * PEM string + * + * \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( x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* POLARSSL_PEM_WRITE_C */ +#endif /* POLARSSL_X509_CSR_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* x509_csr.h */ diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt index e839beaba..b601e4467 100644 --- a/library/CMakeLists.txt +++ b/library/CMakeLists.txt @@ -49,13 +49,18 @@ set(src sha512.c ssl_cache.c ssl_ciphersuites.c - ssl_cli.c - ssl_srv.c + ssl_cli.c + ssl_srv.c ssl_tls.c timing.c version.c - x509parse.c - x509write.c + x509.c + x509_crt.c + x509_crl.c + x509_csr.c + x509_create.c + x509_crt_write.c + x509_csr_write.c xtea.c ) diff --git a/library/debug.c b/library/debug.c index 5522fb643..1c7eeb6ef 100644 --- a/library/debug.c +++ b/library/debug.c @@ -224,7 +224,7 @@ void debug_print_mpi( const ssl_context *ssl, int level, } #endif /* POLARSSL_BIGNUM_C */ -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) static void debug_print_pk( const ssl_context *ssl, int level, const char *file, int line, const char *text, const pk_context *pk ) @@ -288,6 +288,6 @@ void debug_print_crt( const ssl_context *ssl, int level, crt = crt->next; } } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ #endif diff --git a/library/oid.c b/library/oid.c index 0386ba1d4..485fd4cc1 100644 --- a/library/oid.c +++ b/library/oid.c @@ -32,7 +32,7 @@ #include "polarssl/oid.h" #include "polarssl/rsa.h" -#if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C) +#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C) #include "polarssl/x509.h" #endif @@ -207,7 +207,7 @@ static const oid_x520_attr_t oid_x520_attr_type[] = FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type); FN_OID_GET_ATTR1(oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name); -#if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C) +#if defined(POLARSSL_X509_USE_C) || defined(POLARSSL_X509_CREATE_C) /* * For X509 extensions */ @@ -260,7 +260,7 @@ static const oid_descriptor_t oid_ext_key_usage[] = FN_OID_TYPED_FROM_ASN1(oid_descriptor_t, ext_key_usage, oid_ext_key_usage); FN_OID_GET_ATTR1(oid_get_extended_key_usage, oid_descriptor_t, ext_key_usage, const char *, description); -#endif /* POLARSSL_X509_PARSE_C || POLARSSL_X509_WRITE_C */ +#endif /* POLARSSL_X509_USE_C || POLARSSL_X509_CREATE_C */ #if defined(POLARSSL_MD_C) /* diff --git a/library/ssl_cache.c b/library/ssl_cache.c index 7c7da4b17..3090dc062 100644 --- a/library/ssl_cache.c +++ b/library/ssl_cache.c @@ -85,7 +85,7 @@ int ssl_cache_get( void *data, ssl_session *session ) session->verify_result = entry->session.verify_result; -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) /* * Restore peer certificate (without rest of the original chain) */ @@ -104,7 +104,7 @@ int ssl_cache_get( void *data, ssl_session *session ) return( 1 ); } } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ return( 0 ); } @@ -163,13 +163,13 @@ int ssl_cache_set( void *data, const ssl_session *session ) { cur = old; memset( &cur->session, 0, sizeof(ssl_session) ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) if( cur->peer_cert.p != NULL ) { polarssl_free( cur->peer_cert.p ); memset( &cur->peer_cert, 0, sizeof(x509_buf) ); } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ } #else /* POLARSSL_HAVE_TIME */ /* @@ -184,13 +184,13 @@ int ssl_cache_set( void *data, const ssl_session *session ) cur = cache->chain; cache->chain = cur->next; -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) if( cur->peer_cert.p != NULL ) { polarssl_free( cur->peer_cert.p ); memset( &cur->peer_cert, 0, sizeof(x509_buf) ); } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ memset( cur, 0, sizeof(ssl_cache_entry) ); prv->next = cur; @@ -217,7 +217,7 @@ int ssl_cache_set( void *data, const ssl_session *session ) memcpy( &cur->session, session, sizeof( ssl_session ) ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) /* * Store peer certificate */ @@ -233,7 +233,7 @@ int ssl_cache_set( void *data, const ssl_session *session ) cur->session.peer_cert = NULL; } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ return( 0 ); } @@ -267,10 +267,10 @@ void ssl_cache_free( ssl_cache_context *cache ) ssl_session_free( &prv->session ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) if( prv->peer_cert.p != NULL ) polarssl_free( prv->peer_cert.p ); -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ polarssl_free( prv ); } diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 0ffe886b5..28d3a6c76 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -62,9 +62,9 @@ static int ssl_save_session( const ssl_session *session, { unsigned char *p = buf; size_t left = buf_len; -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) size_t cert_len; -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ if( left < sizeof( ssl_session ) ) return( -1 ); @@ -73,7 +73,7 @@ static int ssl_save_session( const ssl_session *session, p += sizeof( ssl_session ); left -= sizeof( ssl_session ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) ((ssl_session *) buf)->peer_cert = NULL; if( session->peer_cert == NULL ) @@ -92,7 +92,7 @@ static int ssl_save_session( const ssl_session *session, memcpy( p, session->peer_cert->raw.p, cert_len ); p += cert_len; -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ *olen = p - buf; @@ -107,9 +107,9 @@ static int ssl_load_session( ssl_session *session, { const unsigned char *p = buf; const unsigned char * const end = buf + len; -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) size_t cert_len; -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ if( p + sizeof( ssl_session ) > end ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); @@ -117,7 +117,7 @@ static int ssl_load_session( ssl_session *session, memcpy( session, p, sizeof( ssl_session ) ); p += sizeof( ssl_session ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) if( p + 3 > end ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); @@ -144,7 +144,7 @@ static int ssl_load_session( ssl_session *session, if( ( ret = x509parse_crt( session->peer_cert, p, cert_len ) ) != 0 ) { - x509_free( session->peer_cert ); + x509_crt_free( session->peer_cert ); polarssl_free( session->peer_cert ); session->peer_cert = NULL; return( ret ); @@ -152,7 +152,7 @@ static int ssl_load_session( ssl_session *session, p += cert_len; } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ if( p != end ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 24cee1c31..d0534afec 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -75,7 +75,7 @@ static int ssl_session_copy( ssl_session *dst, const ssl_session *src ) ssl_session_free( dst ); memcpy( dst, src, sizeof( ssl_session ) ); -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) if( src->peer_cert != NULL ) { int ret; @@ -93,7 +93,7 @@ static int ssl_session_copy( ssl_session *dst, const ssl_session *src ) return( ret ); } } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ #if defined(POLARSSL_SSL_SESSION_TICKETS) if( src->ticket != NULL ) @@ -2482,7 +2482,7 @@ int ssl_parse_certificate( ssl_context *ssl ) /* In case we tried to reuse a session but it failed */ if( ssl->session_negotiate->peer_cert != NULL ) { - x509_free( ssl->session_negotiate->peer_cert ); + x509_crt_free( ssl->session_negotiate->peer_cert ); polarssl_free( ssl->session_negotiate->peer_cert ); } @@ -3377,7 +3377,7 @@ void ssl_set_authmode( ssl_context *ssl, int authmode ) ssl->authmode = authmode; } -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) void ssl_set_verify( ssl_context *ssl, int (*f_vrfy)(void *, x509_cert *, int, int *), void *p_vrfy ) @@ -3385,7 +3385,7 @@ void ssl_set_verify( ssl_context *ssl, ssl->f_vrfy = f_vrfy; ssl->p_vrfy = p_vrfy; } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ void ssl_set_rng( ssl_context *ssl, int (*f_rng)(void *, unsigned char *, size_t), @@ -3463,7 +3463,7 @@ void ssl_set_ciphersuites_for_version( ssl_context *ssl, const int *ciphersuites ssl->ciphersuite_list[minor] = ciphersuites; } -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, x509_crl *ca_crl, const char *peer_cn ) { @@ -3523,7 +3523,7 @@ int ssl_set_own_cert_alt( ssl_context *ssl, x509_cert *own_cert, return( pk_init_ctx_rsa_alt( ssl->pk_key, rsa_key, rsa_decrypt, rsa_sign, rsa_key_len ) ); } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ #if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED) void ssl_set_psk( ssl_context *ssl, const unsigned char *psk, size_t psk_len, @@ -3730,7 +3730,7 @@ const char *ssl_get_version( const ssl_context *ssl ) return( "unknown" ); } -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) const x509_cert *ssl_get_peer_cert( const ssl_context *ssl ) { if( ssl == NULL || ssl->session == NULL ) @@ -3738,7 +3738,7 @@ const x509_cert *ssl_get_peer_cert( const ssl_context *ssl ) return ssl->session->peer_cert; } -#endif /* POLARSSL_X509_PARSE_C */ +#endif /* POLARSSL_X509_CRT_PARSE_C */ int ssl_get_session( const ssl_context *ssl, ssl_session *dst ) { @@ -4076,10 +4076,10 @@ void ssl_handshake_free( ssl_handshake_params *handshake ) void ssl_session_free( ssl_session *session ) { -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) if( session->peer_cert != NULL ) { - x509_free( session->peer_cert ); + x509_crt_free( session->peer_cert ); polarssl_free( session->peer_cert ); } #endif diff --git a/library/x509.c b/library/x509.c new file mode 100644 index 000000000..40ee1803e --- /dev/null +++ b/library/x509.c @@ -0,0 +1,798 @@ +/* + * X.509 certificate and private key decoding + * + * 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. + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc3279.txt + * http://www.ietf.org/rfc/rfc3280.txt + * + * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_X509_USE_C) + +#include "polarssl/x509.h" +#include "polarssl/asn1.h" +#include "polarssl/oid.h" +#if defined(POLARSSL_PEM_PARSE_C) +#include "polarssl/pem.h" +#endif + +#if defined(POLARSSL_MEMORY_C) +#include "polarssl/memory.h" +#else +#define polarssl_malloc malloc +#define polarssl_free free +#endif + +#include +#include +#if defined(_WIN32) +#include +#else +#include +#endif + +#if defined(POLARSSL_FS_IO) +#include +#if !defined(_WIN32) +#include +#include +#include +#endif +#endif + +/* + * CertificateSerialNumber ::= INTEGER + */ +int x509_get_serial( unsigned char **p, const unsigned char *end, + x509_buf *serial ) +{ + int ret; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) && + **p != ASN1_INTEGER ) + return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + serial->tag = *(*p)++; + + if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + ret ); + + serial->p = *p; + *p += serial->len; + + return( 0 ); +} + +/* Get an algorithm identifier without parameters (eg for signatures) + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +int x509_get_alg_null( unsigned char **p, const unsigned char *end, + x509_buf *alg ) +{ + int ret; + + if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); + + return( 0 ); +} + +/* + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_attr_type_value( unsigned char **p, + const unsigned char *end, + x509_name *cur ) +{ + int ret; + size_t len; + x509_buf *oid; + x509_buf *val; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + oid = &cur->oid; + oid->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + oid->p = *p; + *p += oid->len; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING && + **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING && + **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); + + val = &cur->val; + val->tag = *(*p)++; + + if( ( ret = asn1_get_len( p, end, &val->len ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + val->p = *p; + *p += val->len; + + cur->next = NULL; + + return( 0 ); +} + +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +int x509_get_name( unsigned char **p, const unsigned char *end, + x509_name *cur ) +{ + int ret; + size_t len; + const unsigned char *end2; + x509_name *use; + + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); + + end2 = end; + end = *p + len; + use = cur; + + do + { + if( ( ret = x509_get_attr_type_value( p, end, use ) ) != 0 ) + return( ret ); + + if( *p != end ) + { + use->next = (x509_name *) polarssl_malloc( + sizeof( x509_name ) ); + + if( use->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memset( use->next, 0, sizeof( x509_name ) ); + + use = use->next; + } + } + while( *p != end ); + + /* + * recurse until end of SEQUENCE is reached + */ + if( *p == end2 ) + return( 0 ); + + cur->next = (x509_name *) polarssl_malloc( + sizeof( x509_name ) ); + + if( cur->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + memset( cur->next, 0, sizeof( x509_name ) ); + + return( x509_get_name( p, end2, cur->next ) ); +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +int x509_get_time( unsigned char **p, const unsigned char *end, + x509_time *time ) +{ + int ret; + size_t len; + char date[64]; + unsigned char tag; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + + if ( tag == ASN1_UTC_TIME ) + { + (*p)++; + ret = asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); + + memset( date, 0, sizeof( date ) ); + memcpy( date, *p, ( len < sizeof( date ) - 1 ) ? + len : sizeof( date ) - 1 ); + + if( sscanf( date, "%2d%2d%2d%2d%2d%2d", + &time->year, &time->mon, &time->day, + &time->hour, &time->min, &time->sec ) < 5 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); + + time->year += 100 * ( time->year < 50 ); + time->year += 1900; + + *p += len; + + return( 0 ); + } + else if ( tag == ASN1_GENERALIZED_TIME ) + { + (*p)++; + ret = asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); + + memset( date, 0, sizeof( date ) ); + memcpy( date, *p, ( len < sizeof( date ) - 1 ) ? + len : sizeof( date ) - 1 ); + + if( sscanf( date, "%4d%2d%2d%2d%2d%2d", + &time->year, &time->mon, &time->day, + &time->hour, &time->min, &time->sec ) < 5 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); + + *p += len; + + return( 0 ); + } + else + return( POLARSSL_ERR_X509_CERT_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); +} + +int x509_get_sig( unsigned char **p, const unsigned char *end, x509_buf *sig ) +{ + int ret; + size_t len; + + if( ( end - *p ) < 1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + + POLARSSL_ERR_ASN1_OUT_OF_DATA ); + + sig->tag = **p; + + if( ( ret = asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + ret ); + + sig->len = len; + sig->p = *p; + + *p += len; + + return( 0 ); +} + +int x509_get_sig_alg( const x509_buf *sig_oid, md_type_t *md_alg, + pk_type_t *pk_alg ) +{ + int ret = oid_get_sig_alg( sig_oid, md_alg, pk_alg ); + + if( ret != 0 ) + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG + ret ); + + return( 0 ); +} + +/* + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed! + */ +int x509_get_ext( unsigned char **p, const unsigned char *end, + x509_buf *ext, int tag ) +{ + int ret; + size_t len; + + if( *p == end ) + return( 0 ); + + ext->tag = **p; + + if( ( ret = asn1_get_tag( p, end, &ext->len, + ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | tag ) ) != 0 ) + return( ret ); + + ext->p = *p; + end = *p + ext->len; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + if( end != *p + len ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Load all data from a file into a given buffer. + */ +int x509_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = (unsigned char *) polarssl_malloc( *n + 1 ) ) == NULL ) + { + fclose( f ); + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + polarssl_free( *buf ); + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + return( 0 ); +} + +#if defined(POLARSSL_RSA_C) +/* + * Load and parse a private RSA key + */ +int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, const char *pwd ) +{ + int ret; + pk_context pk; + + pk_init( &pk ); + + ret = pk_parse_keyfile( &pk, path, pwd ); + + if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) + ret = POLARSSL_ERR_PK_TYPE_MISMATCH; + + if( ret == 0 ) + rsa_copy( rsa, pk_rsa( pk ) ); + else + rsa_free( rsa ); + + pk_free( &pk ); + + return( ret ); +} + +/* + * Load and parse a public RSA key + */ +int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path ) +{ + int ret; + pk_context pk; + + pk_init( &pk ); + + ret = pk_parse_public_keyfile( &pk, path ); + + if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) + ret = POLARSSL_ERR_PK_TYPE_MISMATCH; + + if( ret == 0 ) + rsa_copy( rsa, pk_rsa( pk ) ); + else + rsa_free( rsa ); + + pk_free( &pk ); + + return( ret ); +} +#endif /* POLARSSL_RSA_C */ +#endif /* POLARSSL_FS_IO */ + +#if defined(POLARSSL_RSA_C) +/* + * Parse a private RSA key + */ +int x509parse_key_rsa( rsa_context *rsa, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + pk_context pk; + + pk_init( &pk ); + + ret = pk_parse_key( &pk, key, keylen, pwd, pwdlen ); + + if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) + ret = POLARSSL_ERR_PK_TYPE_MISMATCH; + + if( ret == 0 ) + rsa_copy( rsa, pk_rsa( pk ) ); + else + rsa_free( rsa ); + + pk_free( &pk ); + + return( ret ); +} + +/* + * Parse a public RSA key + */ +int x509parse_public_key_rsa( rsa_context *rsa, + const unsigned char *key, size_t keylen ) +{ + int ret; + pk_context pk; + + pk_init( &pk ); + + ret = pk_parse_public_key( &pk, key, keylen ); + + if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) + ret = POLARSSL_ERR_PK_TYPE_MISMATCH; + + if( ret == 0 ) + rsa_copy( rsa, pk_rsa( pk ) ); + else + rsa_free( rsa ); + + pk_free( &pk ); + + return( ret ); +} +#endif /* POLARSSL_RSA_C */ + +#if defined _MSC_VER && !defined snprintf +#include + +#if !defined vsnprintf +#define vsnprintf _vsnprintf +#endif // vsnprintf + +/* + * Windows _snprintf and _vsnprintf are not compatible to linux versions. + * Result value is not size of buffer needed, but -1 if no fit is possible. + * + * This fuction tries to 'fix' this by at least suggesting enlarging the + * size by 20. + */ +static int compat_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int res = -1; + + va_start( ap, format ); + + res = vsnprintf( str, size, format, ap ); + + va_end( ap ); + + // No quick fix possible + if ( res < 0 ) + return( (int) size + 20 ); + + return res; +} + +#define snprintf compat_snprintf +#endif + +#define POLARSSL_ERR_DEBUG_BUF_TOO_SMALL -2 + +#define SAFE_SNPRINTF() \ +{ \ + if( ret == -1 ) \ + return( -1 ); \ + \ + if ( (unsigned int) ret > n ) { \ + p[n - 1] = '\0'; \ + return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;\ + } \ + \ + n -= (unsigned int) ret; \ + p += (unsigned int) ret; \ +} + +/* + * Store the name in printable form into buf; no more + * than size characters will be written + */ +int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ) +{ + int ret; + size_t i, n; + unsigned char c; + const x509_name *name; + const char *short_name = NULL; + char s[128], *p; + + memset( s, 0, sizeof( s ) ); + + name = dn; + p = buf; + n = size; + + while( name != NULL ) + { + if( !name->oid.p ) + { + name = name->next; + continue; + } + + if( name != dn ) + { + ret = snprintf( p, n, ", " ); + SAFE_SNPRINTF(); + } + + ret = oid_get_attr_short_name( &name->oid, &short_name ); + + if( ret == 0 ) + ret = snprintf( p, n, "%s=", short_name ); + else + ret = snprintf( p, n, "\?\?=" ); + SAFE_SNPRINTF(); + + for( i = 0; i < name->val.len; i++ ) + { + if( i >= sizeof( s ) - 1 ) + break; + + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; + } + s[i] = '\0'; + ret = snprintf( p, n, "%s", s ); + SAFE_SNPRINTF(); + name = name->next; + } + + return( (int) ( size - n ) ); +} + +/* + * Store the serial in printable form into buf; no more + * than size characters will be written + */ +int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ) +{ + int ret; + size_t i, n, nr; + char *p; + + p = buf; + n = size; + + nr = ( serial->len <= 32 ) + ? serial->len : 28; + + for( i = 0; i < nr; i++ ) + { + if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) + continue; + + ret = snprintf( p, n, "%02X%s", + serial->p[i], ( i < nr - 1 ) ? ":" : "" ); + SAFE_SNPRINTF(); + } + + if( nr != serial->len ) + { + ret = snprintf( p, n, "...." ); + SAFE_SNPRINTF(); + } + + return( (int) ( size - n ) ); +} + +/* + * Helper for writing "RSA key size", "EC key size", etc + */ +int x509_key_size_helper( char *buf, size_t size, const char *name ) +{ + char *p = buf; + size_t n = size; + int ret; + + if( strlen( name ) + sizeof( " key size" ) > size ) + return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL; + + ret = snprintf( p, n, "%s key size", name ); + SAFE_SNPRINTF(); + + return( 0 ); +} + +/* + * Return an informational string describing the given OID + */ +const char *x509_oid_get_description( x509_buf *oid ) +{ + const char *desc = NULL; + int ret; + + ret = oid_get_extended_key_usage( oid, &desc ); + + if( ret != 0 ) + return( NULL ); + + return( desc ); +} + +/* Return the x.y.z.... style numeric string for the given OID */ +int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ) +{ + return oid_get_numeric_string( buf, size, oid ); +} + +/* + * Return 0 if the x509_time is still valid, or 1 otherwise. + */ +#if defined(POLARSSL_HAVE_TIME) +int x509parse_time_expired( const x509_time *to ) +{ + int year, mon, day; + int hour, min, sec; + +#if defined(_WIN32) + SYSTEMTIME st; + + GetLocalTime(&st); + + year = st.wYear; + mon = st.wMonth; + day = st.wDay; + hour = st.wHour; + min = st.wMinute; + sec = st.wSecond; +#else + struct tm *lt; + time_t tt; + + tt = time( NULL ); + lt = localtime( &tt ); + + year = lt->tm_year + 1900; + mon = lt->tm_mon + 1; + day = lt->tm_mday; + hour = lt->tm_hour; + min = lt->tm_min; + sec = lt->tm_sec; +#endif + + if( year > to->year ) + return( 1 ); + + if( year == to->year && + mon > to->mon ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day > to->day ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day == to->day && + hour > to->hour ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day == to->day && + hour == to->hour && + min > to->min ) + return( 1 ); + + if( year == to->year && + mon == to->mon && + day == to->day && + hour == to->hour && + min == to->min && + sec > to->sec ) + return( 1 ); + + return( 0 ); +} +#else /* POLARSSL_HAVE_TIME */ +int x509parse_time_expired( const x509_time *to ) +{ + ((void) to); + return( 0 ); +} +#endif /* POLARSSL_HAVE_TIME */ + +#endif /* POLARSSL_X509_USE_C */ diff --git a/library/x509_create.c b/library/x509_create.c new file mode 100644 index 000000000..699116119 --- /dev/null +++ b/library/x509_create.c @@ -0,0 +1,267 @@ +/* + * X.509 base functions for creating certificates / CSRs + * + * Copyright (C) 2006-2013, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_X509_CREATE_C) + +#include "polarssl/x509.h" +#include "polarssl/asn1write.h" +#include "polarssl/oid.h" + +int x509write_string_to_names( asn1_named_data **head, char *name ) +{ + int ret = 0; + char *s = name, *c = s; + char *end = s + strlen( s ); + char *oid = NULL; + int in_tag = 1; + asn1_named_data *cur; + + /* Clear existing chain if present */ + asn1_free_named_data_list( head ); + + while( c <= end ) + { + if( in_tag && *c == '=' ) + { + if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 ) + oid = OID_AT_CN; + else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 ) + oid = OID_AT_COUNTRY; + else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 ) + oid = OID_AT_ORGANIZATION; + else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 ) + oid = OID_AT_LOCALITY; + else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 ) + oid = OID_PKCS9_EMAIL; + else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 ) + oid = OID_AT_ORG_UNIT; + else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 ) + oid = OID_AT_STATE; + else + { + ret = POLARSSL_ERR_X509WRITE_UNKNOWN_OID; + goto exit; + } + + s = c + 1; + in_tag = 0; + } + + if( !in_tag && ( *c == ',' || c == end ) ) + { + if( ( cur = asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) s, + c - s ) ) == NULL ) + { + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); + } + + while( c < end && *(c + 1) == ' ' ) + c++; + + s = c + 1; + in_tag = 1; + } + c++; + } + +exit: + + return( ret ); +} + +/* The first byte of the value in the asn1_named_data structure is reserved + * to store the critical boolean for us + */ +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_store_named_data( head, oid, oid_len, + NULL, val_len + 1 ) ) == NULL ) + { + return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); + } + + cur->val.p[0] = critical; + memcpy( cur->val.p + 1, val, val_len ); + + return( 0 ); +} + +/* + * 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 len = 0; + + // Write PrintableString for all except OID_PKCS9_EMAIL + // + if( OID_SIZE( OID_PKCS9_EMAIL ) == oid_len && + memcmp( oid, OID_PKCS9_EMAIL, oid_len ) == 0 ) + { + ASN1_CHK_ADD( len, asn1_write_ia5_string( p, start, + (const char *) name, + name_len ) ); + } + else + { + ASN1_CHK_ADD( len, asn1_write_printable_string( p, start, + (const char *) name, + name_len ) ); + } + + // Write OID + // + ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_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 ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SET ) ); + + return( len ); +} + +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 ); +} + +int x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ) +{ + int ret; + size_t len = 0; + + if( *p - start < (int) size + 1 ) + return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, sig, len ); + + *--(*p) = 0; + len += 1; + + ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); + ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) ); + + // Write OID + // + ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid, + oid_len, 0 ) ); + + 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 + * } + */ +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 ); +} + +#endif /* POLARSSL_X509_CREATE_C */ diff --git a/library/x509_crl.c b/library/x509_crl.c new file mode 100644 index 000000000..3f1e17566 --- /dev/null +++ b/library/x509_crl.c @@ -0,0 +1,740 @@ +/* + * X.509 certificate and private key decoding + * + * 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. + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc3279.txt + * http://www.ietf.org/rfc/rfc3280.txt + * + * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_X509_CRL_PARSE_C) + +#include "polarssl/x509_crl.h" +#include "polarssl/oid.h" +#if defined(POLARSSL_PEM_PARSE_C) +#include "polarssl/pem.h" +#endif + +#if defined(POLARSSL_MEMORY_C) +#include "polarssl/memory.h" +#else +#define polarssl_malloc malloc +#define polarssl_free free +#endif + +#include +#include +#if defined(_WIN32) +#include +#else +#include +#endif + +#if defined(POLARSSL_FS_IO) +#include +#endif + +/* + * Version ::= INTEGER { v1(0), v2(1) } + */ +static int x509_crl_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 ); +} + +/* + * X.509 CRL v2 extensions (no extensions parsed yet.) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* Get explicit tag */ + if( ( ret = x509_get_ext( p, end, ext, 0) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 entry extensions (no extensions parsed yet.) + */ +static int x509_get_crl_entry_ext( unsigned char **p, + const unsigned char *end, + x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* OPTIONAL */ + if (end <= *p) + return( 0 ); + + ext->tag = **p; + ext->p = *p; + + /* + * Get CRL-entry extension sequence header + * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 + */ + if( ( ret = asn1_get_tag( p, end, &ext->len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + { + ext->p = NULL; + return( 0 ); + } + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + } + + end = *p + ext->len; + + if( end != *p + ext->len ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + const unsigned char *end, + x509_crl_entry *entry ) +{ + int ret; + size_t entry_len; + x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + if( ( ret = asn1_get_tag( p, end, &entry_len, + ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + end = *p + entry_len; + + while( *p < end ) + { + size_t len2; + const unsigned char *end2; + + if( ( ret = asn1_get_tag( p, end, &len2, + ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) + { + return( ret ); + } + + cur_entry->raw.tag = **p; + cur_entry->raw.p = *p; + cur_entry->raw.len = len2; + end2 = *p + len2; + + if( ( ret = x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_time( p, end2, &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_entry_ext( p, end2, &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if ( *p < end ) + { + cur_entry->next = polarssl_malloc( sizeof( x509_crl_entry ) ); + + if( cur_entry->next == NULL ) + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + + cur_entry = cur_entry->next; + memset( cur_entry, 0, sizeof( x509_crl_entry ) ); + } + } + + return( 0 ); +} + +/* + * Parse one or more CRLs and add them to the chained list + */ +int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + x509_crl *crl; +#if defined(POLARSSL_PEM_PARSE_C) + size_t use_len; + pem_context pem; +#endif + + crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( POLARSSL_ERR_X509_INVALID_INPUT ); + + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + /* + * Add new CRL on the end of the chain if needed. + */ + if ( crl->version != 0 && crl->next == NULL) + { + crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); + + if( crl->next == NULL ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + } + + crl = crl->next; + memset( crl, 0, sizeof( x509_crl ) ); + } + +#if defined(POLARSSL_PEM_PARSE_C) + pem_init( &pem ); + ret = pem_read_buffer( &pem, + "-----BEGIN X509 CRL-----", + "-----END X509 CRL-----", + 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; + } + + crl->raw.p = p; + crl->raw.len = len; + end = p + len; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = x509_get_alg_null( &p, end, &crl->sig_oid1 ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + crl->version++; + + if( crl->version > 2 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); + } + + if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_md, + &crl->sig_pk ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); + } + + if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = x509_get_time( &p, end, &crl->this_update ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) + { + if ( ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && + ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE + + POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) + { + x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = x509_get_alg_null( &p, end, &crl->sig_oid2 ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( crl->sig_oid1.len != crl->sig_oid2.len || + memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH ); + } + + if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( buflen > 0 ) + { + crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); + + if( crl->next == NULL ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_MALLOC_FAILED ); + } + + crl = crl->next; + memset( crl, 0, sizeof( x509_crl ) ); + + return( x509parse_crl( crl, buf, buflen ) ); + } + + return( 0 ); +} + +#if defined(POLARSSL_FS_IO) +/* + * Load one or more CRLs and add them to the chained list + */ +int x509parse_crlfile( x509_crl *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( ( ret = x509_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_crl( chain, buf, n ); + + memset( buf, 0, n + 1 ); + polarssl_free( buf ); + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +#if defined _MSC_VER && !defined snprintf +#include + +#if !defined vsnprintf +#define vsnprintf _vsnprintf +#endif // vsnprintf + +/* + * Windows _snprintf and _vsnprintf are not compatible to linux versions. + * Result value is not size of buffer needed, but -1 if no fit is possible. + * + * This fuction tries to 'fix' this by at least suggesting enlarging the + * size by 20. + */ +static int compat_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int res = -1; + + va_start( ap, format ); + + res = vsnprintf( str, size, format, ap ); + + va_end( ap ); + + // No quick fix possible + if ( res < 0 ) + return( (int) size + 20 ); + + return res; +} + +#define snprintf compat_snprintf +#endif + +#define POLARSSL_ERR_DEBUG_BUF_TOO_SMALL -2 + +#define SAFE_SNPRINTF() \ +{ \ + if( ret == -1 ) \ + return( -1 ); \ + \ + if ( (unsigned int) ret > n ) { \ + p[n - 1] = '\0'; \ + return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;\ + } \ + \ + n -= (unsigned int) ret; \ + p += (unsigned int) ret; \ +} + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CRL. + */ +int x509parse_crl_info( char *buf, size_t size, const char *prefix, + const x509_crl *crl ) +{ + int ret; + size_t n; + char *p; + const char *desc; + const x509_crl_entry *entry; + + p = buf; + n = size; + + ret = snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sissuer name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crl->issuer ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + SAFE_SNPRINTF(); + + entry = &crl->entry; + + ret = snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + SAFE_SNPRINTF(); + + while( entry != NULL && entry->raw.len != 0 ) + { + ret = snprintf( p, n, "\n%sserial number: ", + prefix ); + SAFE_SNPRINTF(); + + ret = x509parse_serial_gets( p, n, &entry->serial); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + SAFE_SNPRINTF(); + + entry = entry->next; + } + + ret = snprintf( p, n, "\n%ssigned using : ", prefix ); + SAFE_SNPRINTF(); + + ret = oid_get_sig_alg_desc( &crl->sig_oid1, &desc ); + if( ret != 0 ) + ret = snprintf( p, n, "???" ); + else + ret = snprintf( p, n, "%s", desc ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n" ); + SAFE_SNPRINTF(); + + return( (int) ( size - n ) ); +} + +/* + * Unallocate all CRL data + */ +void x509_crl_free( x509_crl *crl ) +{ + x509_crl *crl_cur = crl; + x509_crl *crl_prv; + x509_name *name_cur; + x509_name *name_prv; + x509_crl_entry *entry_cur; + x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { + name_cur = crl_cur->issuer.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 ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + memset( entry_prv, 0, sizeof( x509_crl_entry ) ); + polarssl_free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + memset( crl_cur->raw.p, 0, crl_cur->raw.len ); + polarssl_free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + memset( crl_prv, 0, sizeof( x509_crl ) ); + if( crl_prv != crl ) + polarssl_free( crl_prv ); + } + while( crl_cur != NULL ); +} + +#endif diff --git a/library/x509parse.c b/library/x509_crt.c similarity index 53% rename from library/x509parse.c rename to library/x509_crt.c index 331c8a066..3c88b5ed8 100644 --- a/library/x509parse.c +++ b/library/x509_crt.c @@ -36,20 +36,13 @@ #include "polarssl/config.h" -#if defined(POLARSSL_X509_PARSE_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) -#include "polarssl/x509.h" -#include "polarssl/asn1.h" +#include "polarssl/x509_crt.h" #include "polarssl/oid.h" #if defined(POLARSSL_PEM_PARSE_C) #include "polarssl/pem.h" #endif -#if defined(POLARSSL_PKCS5_C) -#include "polarssl/pkcs5.h" -#endif -#if defined(POLARSSL_PKCS12_C) -#include "polarssl/pkcs12.h" -#endif #if defined(POLARSSL_MEMORY_C) #include "polarssl/memory.h" @@ -109,293 +102,6 @@ static int x509_get_version( unsigned char **p, return( 0 ); } -/* - * Version ::= INTEGER { v1(0), v2(1) } - */ -static int x509_crl_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 ); -} - -/* - * 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 - */ -static int x509_get_serial( unsigned char **p, - const unsigned char *end, - x509_buf *serial ) -{ - int ret; - - if( ( end - *p ) < 1 ) - return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + - POLARSSL_ERR_ASN1_OUT_OF_DATA ); - - if( **p != ( ASN1_CONTEXT_SPECIFIC | ASN1_PRIMITIVE | 2 ) && - **p != ASN1_INTEGER ) - return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + - POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); - - serial->tag = *(*p)++; - - if( ( ret = asn1_get_len( p, end, &serial->len ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_SERIAL + ret ); - - serial->p = *p; - *p += serial->len; - - return( 0 ); -} - -/* Get an algorithm identifier without parameters (eg for signatures) - * - * AlgorithmIdentifier ::= SEQUENCE { - * algorithm OBJECT IDENTIFIER, - * parameters ANY DEFINED BY algorithm OPTIONAL } - */ -static int x509_get_alg_null( unsigned char **p, const unsigned char *end, - x509_buf *alg ) -{ - int ret; - - if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret ); - - return( 0 ); -} - -/* - * AttributeTypeAndValue ::= SEQUENCE { - * type AttributeType, - * value AttributeValue } - * - * AttributeType ::= OBJECT IDENTIFIER - * - * AttributeValue ::= ANY DEFINED BY AttributeType - */ -static int x509_get_attr_type_value( unsigned char **p, - const unsigned char *end, - x509_name *cur ) -{ - int ret; - size_t len; - x509_buf *oid; - x509_buf *val; - - if( ( ret = asn1_get_tag( p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); - - if( ( end - *p ) < 1 ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + - POLARSSL_ERR_ASN1_OUT_OF_DATA ); - - oid = &cur->oid; - oid->tag = **p; - - if( ( ret = asn1_get_tag( p, end, &oid->len, ASN1_OID ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); - - oid->p = *p; - *p += oid->len; - - if( ( end - *p ) < 1 ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + - POLARSSL_ERR_ASN1_OUT_OF_DATA ); - - if( **p != ASN1_BMP_STRING && **p != ASN1_UTF8_STRING && - **p != ASN1_T61_STRING && **p != ASN1_PRINTABLE_STRING && - **p != ASN1_IA5_STRING && **p != ASN1_UNIVERSAL_STRING ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + - POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); - - val = &cur->val; - val->tag = *(*p)++; - - if( ( ret = asn1_get_len( p, end, &val->len ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); - - val->p = *p; - *p += val->len; - - cur->next = NULL; - - return( 0 ); -} - -/* - * RelativeDistinguishedName ::= - * SET OF AttributeTypeAndValue - * - * AttributeTypeAndValue ::= SEQUENCE { - * type AttributeType, - * value AttributeValue } - * - * AttributeType ::= OBJECT IDENTIFIER - * - * AttributeValue ::= ANY DEFINED BY AttributeType - */ -static int x509_get_name( unsigned char **p, - const unsigned char *end, - x509_name *cur ) -{ - int ret; - size_t len; - const unsigned char *end2; - x509_name *use; - - if( ( ret = asn1_get_tag( p, end, &len, - ASN1_CONSTRUCTED | ASN1_SET ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_NAME + ret ); - - end2 = end; - end = *p + len; - use = cur; - - do - { - if( ( ret = x509_get_attr_type_value( p, end, use ) ) != 0 ) - return( ret ); - - if( *p != end ) - { - use->next = (x509_name *) polarssl_malloc( - sizeof( x509_name ) ); - - if( use->next == NULL ) - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - - memset( use->next, 0, sizeof( x509_name ) ); - - use = use->next; - } - } - while( *p != end ); - - /* - * recurse until end of SEQUENCE is reached - */ - if( *p == end2 ) - return( 0 ); - - cur->next = (x509_name *) polarssl_malloc( - sizeof( x509_name ) ); - - if( cur->next == NULL ) - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - - memset( cur->next, 0, sizeof( x509_name ) ); - - return( x509_get_name( p, end2, cur->next ) ); -} - -/* - * Time ::= CHOICE { - * utcTime UTCTime, - * generalTime GeneralizedTime } - */ -static int x509_get_time( unsigned char **p, - const unsigned char *end, - x509_time *time ) -{ - int ret; - size_t len; - char date[64]; - unsigned char tag; - - if( ( end - *p ) < 1 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE + - POLARSSL_ERR_ASN1_OUT_OF_DATA ); - - tag = **p; - - if ( tag == ASN1_UTC_TIME ) - { - (*p)++; - ret = asn1_get_len( p, end, &len ); - - if( ret != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); - - memset( date, 0, sizeof( date ) ); - memcpy( date, *p, ( len < sizeof( date ) - 1 ) ? - len : sizeof( date ) - 1 ); - - if( sscanf( date, "%2d%2d%2d%2d%2d%2d", - &time->year, &time->mon, &time->day, - &time->hour, &time->min, &time->sec ) < 5 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); - - time->year += 100 * ( time->year < 50 ); - time->year += 1900; - - *p += len; - - return( 0 ); - } - else if ( tag == ASN1_GENERALIZED_TIME ) - { - (*p)++; - ret = asn1_get_len( p, end, &len ); - - if( ret != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE + ret ); - - memset( date, 0, sizeof( date ) ); - memcpy( date, *p, ( len < sizeof( date ) - 1 ) ? - len : sizeof( date ) - 1 ); - - if( sscanf( date, "%4d%2d%2d%2d%2d%2d", - &time->year, &time->mon, &time->day, - &time->hour, &time->min, &time->sec ) < 5 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); - - *p += len; - - return( 0 ); - } - else - return( POLARSSL_ERR_X509_CERT_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ); -} - - /* * Validity ::= SEQUENCE { * notBefore Time, @@ -428,30 +134,6 @@ static int x509_get_dates( unsigned char **p, return( 0 ); } -static int x509_get_sig( unsigned char **p, - const unsigned char *end, - x509_buf *sig ) -{ - int ret; - size_t len; - - if( ( end - *p ) < 1 ) - return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + - POLARSSL_ERR_ASN1_OUT_OF_DATA ); - - sig->tag = **p; - - if( ( ret = asn1_get_bitstring_null( p, end, &len ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_SIGNATURE + ret ); - - sig->len = len; - sig->p = *p; - - *p += len; - - return( 0 ); -} - /* * X.509 v2/v3 unique identifier (not parsed) */ @@ -481,137 +163,6 @@ static int x509_get_uid( unsigned char **p, return( 0 ); } -/* - * X.509 Extensions (No parsing of extensions, pointer should - * be either manually updated or extensions should be parsed! - */ -static int x509_get_ext( unsigned char **p, - const unsigned char *end, - x509_buf *ext, int tag ) -{ - int ret; - size_t len; - - if( *p == end ) - return( 0 ); - - ext->tag = **p; - - if( ( ret = asn1_get_tag( p, end, &ext->len, - ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | tag ) ) != 0 ) - return( ret ); - - ext->p = *p; - end = *p + ext->len; - - /* - * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension - * - * Extension ::= SEQUENCE { - * extnID OBJECT IDENTIFIER, - * critical BOOLEAN DEFAULT FALSE, - * extnValue OCTET STRING } - */ - if( ( ret = asn1_get_tag( p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); - - if( end != *p + len ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - - return( 0 ); -} - -/* - * X.509 CRL v2 extensions (no extensions parsed yet.) - */ -static int x509_get_crl_ext( unsigned char **p, - const unsigned char *end, - x509_buf *ext ) -{ - int ret; - size_t len = 0; - - /* Get explicit tag */ - if( ( ret = x509_get_ext( p, end, ext, 0) ) != 0 ) - { - if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) - return( 0 ); - - return( ret ); - } - - while( *p < end ) - { - if( ( ret = asn1_get_tag( p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); - - *p += len; - } - - if( *p != end ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - - return( 0 ); -} - -/* - * X.509 CRL v2 entry extensions (no extensions parsed yet.) - */ -static int x509_get_crl_entry_ext( unsigned char **p, - const unsigned char *end, - x509_buf *ext ) -{ - int ret; - size_t len = 0; - - /* OPTIONAL */ - if (end <= *p) - return( 0 ); - - ext->tag = **p; - ext->p = *p; - - /* - * Get CRL-entry extension sequence header - * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 - */ - if( ( ret = asn1_get_tag( p, end, &ext->len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - { - if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) - { - ext->p = NULL; - return( 0 ); - } - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); - } - - end = *p + ext->len; - - if( end != *p + ext->len ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - - while( *p < end ) - { - if( ( ret = asn1_get_tag( p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + ret ); - - *p += len; - } - - if( *p != end ) - return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - - return( 0 ); -} - static int x509_get_basic_constraints( unsigned char **p, const unsigned char *end, int *ca_istrue, @@ -961,82 +512,6 @@ static int x509_get_crt_ext( unsigned char **p, return( 0 ); } -/* - * X.509 CRL Entries - */ -static int x509_get_entries( unsigned char **p, - const unsigned char *end, - x509_crl_entry *entry ) -{ - int ret; - size_t entry_len; - x509_crl_entry *cur_entry = entry; - - if( *p == end ) - return( 0 ); - - if( ( ret = asn1_get_tag( p, end, &entry_len, - ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) - { - if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) - return( 0 ); - - return( ret ); - } - - end = *p + entry_len; - - while( *p < end ) - { - size_t len2; - const unsigned char *end2; - - if( ( ret = asn1_get_tag( p, end, &len2, - ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) - { - return( ret ); - } - - cur_entry->raw.tag = **p; - cur_entry->raw.p = *p; - cur_entry->raw.len = len2; - end2 = *p + len2; - - if( ( ret = x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) - return( ret ); - - if( ( ret = x509_get_time( p, end2, &cur_entry->revocation_date ) ) != 0 ) - return( ret ); - - if( ( ret = x509_get_crl_entry_ext( p, end2, &cur_entry->entry_ext ) ) != 0 ) - return( ret ); - - if ( *p < end ) - { - cur_entry->next = polarssl_malloc( sizeof( x509_crl_entry ) ); - - if( cur_entry->next == NULL ) - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - - cur_entry = cur_entry->next; - memset( cur_entry, 0, sizeof( x509_crl_entry ) ); - } - } - - return( 0 ); -} - -static int x509_get_sig_alg( const x509_buf *sig_oid, md_type_t *md_alg, - pk_type_t *pk_alg ) -{ - int ret = oid_get_sig_alg( sig_oid, md_alg, pk_alg ); - - if( ret != 0 ) - return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG + ret ); - - return( 0 ); -} - /* * Parse and fill a single X.509 certificate in DER format */ @@ -1075,13 +550,13 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); } if( len > (size_t) ( end - p ) ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } @@ -1095,7 +570,7 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); } @@ -1113,7 +588,7 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, ( ret = x509_get_serial( &p, end, &crt->serial ) ) != 0 || ( ret = x509_get_alg_null( &p, end, &crt->sig_oid1 ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } @@ -1121,14 +596,14 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, if( crt->version > 3 ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); } if( ( ret = x509_get_sig_alg( &crt->sig_oid1, &crt->sig_md, &crt->sig_pk ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } @@ -1140,13 +615,13 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); } if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } @@ -1161,7 +636,7 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, if( ( ret = x509_get_dates( &p, end, &crt->valid_from, &crt->valid_to ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } @@ -1173,13 +648,13 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); } if( len && ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } @@ -1190,7 +665,7 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, */ if( ( ret = pk_parse_get_pubkey( &p, end, &crt->pk ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } @@ -1207,7 +682,7 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); if( ret != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } } @@ -1217,7 +692,7 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); if( ret != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } } @@ -1227,14 +702,14 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, ret = x509_get_crt_ext( &p, end, crt); if( ret != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } } if( p != end ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } @@ -1250,26 +725,26 @@ static int x509parse_crt_der_core( x509_cert *crt, const unsigned char *buf, */ if( ( ret = x509_get_alg_null( &p, end, &crt->sig_oid2 ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } if( crt->sig_oid1.len != crt->sig_oid2.len || memcmp( crt->sig_oid1.p, crt->sig_oid2.p, crt->sig_oid1.len ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH ); } if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 ) { - x509_free( crt ); + x509_crt_free( crt ); return( ret ); } if( p != end ) { - x509_free( crt ); + x509_crt_free( crt ); return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } @@ -1431,530 +906,7 @@ 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_PARSE_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_PARSE_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 = pk_parse_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 - */ -int x509parse_crl( x509_crl *chain, const unsigned char *buf, size_t buflen ) -{ - int ret; - size_t len; - unsigned char *p, *end; - x509_crl *crl; -#if defined(POLARSSL_PEM_PARSE_C) - size_t use_len; - pem_context pem; -#endif - - crl = chain; - - /* - * Check for valid input - */ - if( crl == NULL || buf == NULL ) - return( POLARSSL_ERR_X509_INVALID_INPUT ); - - while( crl->version != 0 && crl->next != NULL ) - crl = crl->next; - - /* - * Add new CRL on the end of the chain if needed. - */ - if ( crl->version != 0 && crl->next == NULL) - { - crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); - - if( crl->next == NULL ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - } - - crl = crl->next; - memset( crl, 0, sizeof( x509_crl ) ); - } - -#if defined(POLARSSL_PEM_PARSE_C) - pem_init( &pem ); - ret = pem_read_buffer( &pem, - "-----BEGIN X509 CRL-----", - "-----END X509 CRL-----", - 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; - } - - crl->raw.p = p; - crl->raw.len = len; - end = p + len; - - /* - * CertificateList ::= SEQUENCE { - * tbsCertList TBSCertList, - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING } - */ - if( ( ret = asn1_get_tag( &p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); - } - - if( len != (size_t) ( end - p ) ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - } - - /* - * TBSCertList ::= SEQUENCE { - */ - crl->tbs.p = p; - - if( ( ret = asn1_get_tag( &p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); - } - - end = p + len; - crl->tbs.len = end - crl->tbs.p; - - /* - * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } - * -- if present, MUST be v2 - * - * signature AlgorithmIdentifier - */ - if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || - ( ret = x509_get_alg_null( &p, end, &crl->sig_oid1 ) ) != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - - crl->version++; - - if( crl->version > 2 ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); - } - - if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_md, - &crl->sig_pk ) ) != 0 ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); - } - - /* - * issuer Name - */ - crl->issuer_raw.p = p; - - if( ( ret = asn1_get_tag( &p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret ); - } - - if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - - crl->issuer_raw.len = p - crl->issuer_raw.p; - - /* - * thisUpdate Time - * nextUpdate Time OPTIONAL - */ - if( ( ret = x509_get_time( &p, end, &crl->this_update ) ) != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - - if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) - { - if ( ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE + - POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && - ret != ( POLARSSL_ERR_X509_CERT_INVALID_DATE + - POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) - { - x509_crl_free( crl ); - return( ret ); - } - } - - /* - * revokedCertificates SEQUENCE OF SEQUENCE { - * userCertificate CertificateSerialNumber, - * revocationDate Time, - * crlEntryExtensions Extensions OPTIONAL - * -- if present, MUST be v2 - * } OPTIONAL - */ - if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - - /* - * crlExtensions EXPLICIT Extensions OPTIONAL - * -- if present, MUST be v2 - */ - if( crl->version == 2 ) - { - ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); - - if( ret != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - } - - if( p != end ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - } - - end = crl->raw.p + crl->raw.len; - - /* - * signatureAlgorithm AlgorithmIdentifier, - * signatureValue BIT STRING - */ - if( ( ret = x509_get_alg_null( &p, end, &crl->sig_oid2 ) ) != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - - if( crl->sig_oid1.len != crl->sig_oid2.len || - memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH ); - } - - if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 ) - { - x509_crl_free( crl ); - return( ret ); - } - - if( p != end ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + - POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); - } - - if( buflen > 0 ) - { - crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); - - if( crl->next == NULL ) - { - x509_crl_free( crl ); - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - } - - crl = crl->next; - memset( crl, 0, sizeof( x509_crl ) ); - - return( x509parse_crl( crl, buf, buflen ) ); - } - - return( 0 ); -} - #if defined(POLARSSL_FS_IO) -/* - * Load all data from a file into a given buffer. - */ -static int load_file( const char *path, unsigned char **buf, size_t *n ) -{ - FILE *f; - long size; - - if( ( f = fopen( path, "rb" ) ) == NULL ) - return( POLARSSL_ERR_X509_FILE_IO_ERROR ); - - fseek( f, 0, SEEK_END ); - if( ( size = ftell( f ) ) == -1 ) - { - fclose( f ); - return( POLARSSL_ERR_X509_FILE_IO_ERROR ); - } - fseek( f, 0, SEEK_SET ); - - *n = (size_t) size; - - if( *n + 1 == 0 || - ( *buf = (unsigned char *) polarssl_malloc( *n + 1 ) ) == NULL ) - { - fclose( f ); - return( POLARSSL_ERR_X509_MALLOC_FAILED ); - } - - if( fread( *buf, 1, *n, f ) != *n ) - { - fclose( f ); - polarssl_free( *buf ); - return( POLARSSL_ERR_X509_FILE_IO_ERROR ); - } - - fclose( f ); - - (*buf)[*n] = '\0'; - - return( 0 ); -} - /* * Load one or more certificates and add them to the chained list */ @@ -1964,7 +916,7 @@ int x509parse_crtfile( x509_cert *chain, const char *path ) size_t n; unsigned char *buf; - if ( ( ret = load_file( path, &buf, &n ) ) != 0 ) + if ( ( ret = x509_load_file( path, &buf, &n ) ) != 0 ) return( ret ); ret = x509parse_crt( chain, buf, n ); @@ -2071,155 +1023,8 @@ 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 - */ -int x509parse_crlfile( x509_crl *chain, const char *path ) -{ - int ret; - size_t n; - unsigned char *buf; - - if ( ( ret = load_file( path, &buf, &n ) ) != 0 ) - return( ret ); - - ret = x509parse_crl( chain, buf, n ); - - memset( buf, 0, n + 1 ); - polarssl_free( buf ); - - return( ret ); -} - -#if defined(POLARSSL_RSA_C) -/* - * Load and parse a private RSA key - */ -int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, const char *pwd ) -{ - int ret; - pk_context pk; - - pk_init( &pk ); - - ret = pk_parse_keyfile( &pk, path, pwd ); - - if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) - ret = POLARSSL_ERR_PK_TYPE_MISMATCH; - - if( ret == 0 ) - rsa_copy( rsa, pk_rsa( pk ) ); - else - rsa_free( rsa ); - - pk_free( &pk ); - - return( ret ); -} - -/* - * Load and parse a public RSA key - */ -int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path ) -{ - int ret; - pk_context pk; - - pk_init( &pk ); - - ret = pk_parse_public_keyfile( &pk, path ); - - if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) - ret = POLARSSL_ERR_PK_TYPE_MISMATCH; - - if( ret == 0 ) - rsa_copy( rsa, pk_rsa( pk ) ); - else - rsa_free( rsa ); - - pk_free( &pk ); - - return( ret ); -} -#endif /* POLARSSL_RSA_C */ #endif /* POLARSSL_FS_IO */ -#if defined(POLARSSL_RSA_C) -/* - * Parse a private RSA key - */ -int x509parse_key_rsa( rsa_context *rsa, - const unsigned char *key, size_t keylen, - const unsigned char *pwd, size_t pwdlen ) -{ - int ret; - pk_context pk; - - pk_init( &pk ); - - ret = pk_parse_key( &pk, key, keylen, pwd, pwdlen ); - - if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) - ret = POLARSSL_ERR_PK_TYPE_MISMATCH; - - if( ret == 0 ) - rsa_copy( rsa, pk_rsa( pk ) ); - else - rsa_free( rsa ); - - pk_free( &pk ); - - return( ret ); -} - -/* - * Parse a public RSA key - */ -int x509parse_public_key_rsa( rsa_context *rsa, - const unsigned char *key, size_t keylen ) -{ - int ret; - pk_context pk; - - pk_init( &pk ); - - ret = pk_parse_public_key( &pk, key, keylen ); - - if( ret == 0 && ! pk_can_do( &pk, POLARSSL_PK_RSA ) ) - ret = POLARSSL_ERR_PK_TYPE_MISMATCH; - - if( ret == 0 ) - rsa_copy( rsa, pk_rsa( pk ) ); - else - rsa_free( rsa ); - - pk_free( &pk ); - - return( ret ); -} -#endif /* POLARSSL_RSA_C */ - #if defined _MSC_VER && !defined snprintf #include @@ -2248,7 +1053,7 @@ static int compat_snprintf(char *str, size_t size, const char *format, ...) // No quick fix possible if ( res < 0 ) return( (int) size + 20 ); - + return res; } @@ -2271,119 +1076,6 @@ static int compat_snprintf(char *str, size_t size, const char *format, ...) p += (unsigned int) ret; \ } -/* - * Store the name in printable form into buf; no more - * than size characters will be written - */ -int x509parse_dn_gets( char *buf, size_t size, const x509_name *dn ) -{ - int ret; - size_t i, n; - unsigned char c; - const x509_name *name; - const char *short_name = NULL; - char s[128], *p; - - memset( s, 0, sizeof( s ) ); - - name = dn; - p = buf; - n = size; - - while( name != NULL ) - { - if( !name->oid.p ) - { - name = name->next; - continue; - } - - if( name != dn ) - { - ret = snprintf( p, n, ", " ); - SAFE_SNPRINTF(); - } - - ret = oid_get_attr_short_name( &name->oid, &short_name ); - - if( ret == 0 ) - ret = snprintf( p, n, "%s=", short_name ); - else - ret = snprintf( p, n, "\?\?=" ); - SAFE_SNPRINTF(); - - for( i = 0; i < name->val.len; i++ ) - { - if( i >= sizeof( s ) - 1 ) - break; - - c = name->val.p[i]; - if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) - s[i] = '?'; - else s[i] = c; - } - s[i] = '\0'; - ret = snprintf( p, n, "%s", s ); - SAFE_SNPRINTF(); - name = name->next; - } - - return( (int) ( size - n ) ); -} - -/* - * Store the serial in printable form into buf; no more - * than size characters will be written - */ -int x509parse_serial_gets( char *buf, size_t size, const x509_buf *serial ) -{ - int ret; - size_t i, n, nr; - char *p; - - p = buf; - n = size; - - nr = ( serial->len <= 32 ) - ? serial->len : 28; - - for( i = 0; i < nr; i++ ) - { - if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) - continue; - - ret = snprintf( p, n, "%02X%s", - serial->p[i], ( i < nr - 1 ) ? ":" : "" ); - SAFE_SNPRINTF(); - } - - if( nr != serial->len ) - { - ret = snprintf( p, n, "...." ); - SAFE_SNPRINTF(); - } - - return( (int) ( size - n ) ); -} - -/* - * Helper for writing "RSA key size", "EC key size", etc - */ -static int x509_key_size_helper( char *buf, size_t size, const char *name ) -{ - char *p = buf; - size_t n = size; - int ret; - - if( strlen( name ) + sizeof( " key size" ) > size ) - return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL; - - ret = snprintf( p, n, "%s key size", name ); - SAFE_SNPRINTF(); - - return( 0 ); -} - /* * Return an informational string about the certificate. */ @@ -2458,232 +1150,7 @@ int x509parse_cert_info( char *buf, size_t size, const char *prefix, return( (int) ( size - n ) ); } -/* - * Return an informational string describing the given OID - */ -const char *x509_oid_get_description( x509_buf *oid ) -{ - const char *desc = NULL; - int ret; - - ret = oid_get_extended_key_usage( oid, &desc ); - - if( ret != 0 ) - return( NULL ); - - return( desc ); -} - -/* Return the x.y.z.... style numeric string for the given OID */ -int x509_oid_get_numeric_string( char *buf, size_t size, x509_buf *oid ) -{ - return oid_get_numeric_string( buf, size, oid ); -} - -/* - * Return an informational string about the CRL. - */ -int x509parse_crl_info( char *buf, size_t size, const char *prefix, - const x509_crl *crl ) -{ - int ret; - size_t n; - char *p; - const char *desc; - const x509_crl_entry *entry; - - p = buf; - n = size; - - ret = snprintf( p, n, "%sCRL version : %d", - prefix, crl->version ); - SAFE_SNPRINTF(); - - ret = snprintf( p, n, "\n%sissuer name : ", prefix ); - SAFE_SNPRINTF(); - ret = x509parse_dn_gets( p, n, &crl->issuer ); - SAFE_SNPRINTF(); - - ret = snprintf( p, n, "\n%sthis update : " \ - "%04d-%02d-%02d %02d:%02d:%02d", prefix, - crl->this_update.year, crl->this_update.mon, - crl->this_update.day, crl->this_update.hour, - crl->this_update.min, crl->this_update.sec ); - SAFE_SNPRINTF(); - - ret = snprintf( p, n, "\n%snext update : " \ - "%04d-%02d-%02d %02d:%02d:%02d", prefix, - crl->next_update.year, crl->next_update.mon, - crl->next_update.day, crl->next_update.hour, - crl->next_update.min, crl->next_update.sec ); - SAFE_SNPRINTF(); - - entry = &crl->entry; - - ret = snprintf( p, n, "\n%sRevoked certificates:", - prefix ); - SAFE_SNPRINTF(); - - while( entry != NULL && entry->raw.len != 0 ) - { - ret = snprintf( p, n, "\n%sserial number: ", - prefix ); - SAFE_SNPRINTF(); - - ret = x509parse_serial_gets( p, n, &entry->serial); - SAFE_SNPRINTF(); - - ret = snprintf( p, n, " revocation date: " \ - "%04d-%02d-%02d %02d:%02d:%02d", - entry->revocation_date.year, entry->revocation_date.mon, - entry->revocation_date.day, entry->revocation_date.hour, - entry->revocation_date.min, entry->revocation_date.sec ); - SAFE_SNPRINTF(); - - entry = entry->next; - } - - ret = snprintf( p, n, "\n%ssigned using : ", prefix ); - SAFE_SNPRINTF(); - - ret = oid_get_sig_alg_desc( &crl->sig_oid1, &desc ); - if( ret != 0 ) - ret = snprintf( p, n, "???" ); - else - ret = snprintf( p, n, "%s", desc ); - SAFE_SNPRINTF(); - - ret = snprintf( p, n, "\n" ); - SAFE_SNPRINTF(); - - 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. - */ -#if defined(POLARSSL_HAVE_TIME) -int x509parse_time_expired( const x509_time *to ) -{ - int year, mon, day; - int hour, min, sec; - -#if defined(_WIN32) - SYSTEMTIME st; - - GetLocalTime(&st); - - year = st.wYear; - mon = st.wMonth; - day = st.wDay; - hour = st.wHour; - min = st.wMinute; - sec = st.wSecond; -#else - struct tm *lt; - time_t tt; - - tt = time( NULL ); - lt = localtime( &tt ); - - year = lt->tm_year + 1900; - mon = lt->tm_mon + 1; - day = lt->tm_mday; - hour = lt->tm_hour; - min = lt->tm_min; - sec = lt->tm_sec; -#endif - - if( year > to->year ) - return( 1 ); - - if( year == to->year && - mon > to->mon ) - return( 1 ); - - if( year == to->year && - mon == to->mon && - day > to->day ) - return( 1 ); - - if( year == to->year && - mon == to->mon && - day == to->day && - hour > to->hour ) - return( 1 ); - - if( year == to->year && - mon == to->mon && - day == to->day && - hour == to->hour && - min > to->min ) - return( 1 ); - - if( year == to->year && - mon == to->mon && - day == to->day && - hour == to->hour && - min == to->min && - sec > to->sec ) - return( 1 ); - - return( 0 ); -} -#else /* POLARSSL_HAVE_TIME */ -int x509parse_time_expired( const x509_time *to ) -{ - ((void) to); - return( 0 ); -} -#endif /* POLARSSL_HAVE_TIME */ - +#if defined(POLARSSL_X509_CRL_PARSE_C) /* * Return 1 if the certificate is revoked, or 0 otherwise. */ @@ -2778,6 +1245,7 @@ static int x509parse_verifycrl(x509_cert *crt, x509_cert *ca, } return flags; } +#endif /* POLARSSL_X509_CRL_PARSE_C */ // Equal == 0, inequal == 1 static int x509_name_cmp( const void *s1, const void *s2, size_t len ) @@ -2915,8 +1383,10 @@ static int x509parse_verify_top( memcmp( child->subject_raw.p, trust_ca->subject_raw.p, child->issuer_raw.len ) != 0 ) ) { +#if defined(POLARSSL_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the chain's top crt */ *flags |= x509parse_verifycrl( child, trust_ca, ca_crl ); +#endif if( x509parse_time_expired( &trust_ca->valid_to ) ) ca_flags |= BADCERT_EXPIRED; @@ -2975,8 +1445,10 @@ static int x509parse_verify_child( } } +#if defined(POLARSSL_X509_CRL_PARSE_C) /* Check trusted CA's CRL for the given crt */ *flags |= x509parse_verifycrl(child, parent, ca_crl); +#endif grandparent = parent->next; @@ -3116,7 +1588,7 @@ int x509parse_verify( x509_cert *crt, ret = x509parse_verify_child( crt, parent, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy ); if( ret != 0 ) return( ret ); - } + } else { ret = x509parse_verify_top( crt, trust_ca, ca_crl, pathlen, flags, f_vrfy, p_vrfy ); @@ -3133,7 +1605,7 @@ int x509parse_verify( x509_cert *crt, /* * Unallocate all certificate data */ -void x509_free( x509_cert *crt ) +void x509_crt_free( x509_cert *crt ) { x509_cert *cert_cur = crt; x509_cert *cert_prv; @@ -3208,95 +1680,6 @@ void x509_free( x509_cert *crt ) while( cert_cur != NULL ); } -/* - * Unallocate all CRL data - */ -void x509_crl_free( x509_crl *crl ) -{ - x509_crl *crl_cur = crl; - x509_crl *crl_prv; - x509_name *name_cur; - x509_name *name_prv; - x509_crl_entry *entry_cur; - x509_crl_entry *entry_prv; - - if( crl == NULL ) - return; - - do - { - name_cur = crl_cur->issuer.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 ); - } - - entry_cur = crl_cur->entry.next; - while( entry_cur != NULL ) - { - entry_prv = entry_cur; - entry_cur = entry_cur->next; - memset( entry_prv, 0, sizeof( x509_crl_entry ) ); - polarssl_free( entry_prv ); - } - - if( crl_cur->raw.p != NULL ) - { - memset( crl_cur->raw.p, 0, crl_cur->raw.len ); - polarssl_free( crl_cur->raw.p ); - } - - crl_cur = crl_cur->next; - } - while( crl_cur != NULL ); - - crl_cur = crl; - do - { - crl_prv = crl_cur; - crl_cur = crl_cur->next; - - memset( crl_prv, 0, sizeof( x509_crl ) ); - if( crl_prv != crl ) - polarssl_free( crl_prv ); - } - 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" @@ -3340,26 +1723,6 @@ int x509_self_test( int verbose ) return( ret ); } -#if defined(POLARSSL_MD5_C) && defined(POLARSSL_CIPHER_MODE_CBC) && \ - defined(POLARSSL_DES_C) && defined(POLARSSL_AES_C) - if( verbose != 0 ) - printf( "passed\n X.509 private key load: " ); - - pk_init( &pkey ); - - if( ( ret = pk_parse_key( &pkey, - (const unsigned char *) test_ca_key, - strlen( test_ca_key ), - (const unsigned char *) test_ca_pwd, - strlen( test_ca_pwd ) ) ) != 0 ) - { - if( verbose != 0 ) - printf( "failed\n" ); - - return( ret ); - } -#endif - if( verbose != 0 ) printf( "passed\n X.509 signature verify: "); @@ -3377,8 +1740,8 @@ int x509_self_test( int verbose ) if( verbose != 0 ) printf( "passed\n\n"); - x509_free( &cacert ); - x509_free( &clicert ); + x509_crt_free( &cacert ); + x509_crt_free( &clicert ); pk_free( &pkey ); return( 0 ); diff --git a/library/x509_crt_write.c b/library/x509_crt_write.c new file mode 100644 index 000000000..577097d9d --- /dev/null +++ b/library/x509_crt_write.c @@ -0,0 +1,426 @@ +/* + * X.509 certificate writing + * + * 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. + */ +/* + * 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_CRT_WRITE_C) + +#include "polarssl/x509_crt.h" +#include "polarssl/oid.h" +#include "polarssl/asn1write.h" +#include "polarssl/sha1.h" + +#if defined(POLARSSL_PEM_WRITE_C) +#include "polarssl/pem.h" +#endif /* POLARSSL_PEM_WRITE_C */ + +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_cert) ); +} + +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; + + 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; + + memset( buf, 0, sizeof(buf) ); + + 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, pk_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, pk_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 ); +} + +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 ); +} + +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, pk_write_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" + +#if defined(POLARSSL_PEM_WRITE_C) +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]; + size_t olen = 0; + + if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* POLARSSL_PEM_WRITE_C */ + +#endif /* POLARSSL_X509_CRT_WRITE_C */ diff --git a/library/x509_csr.c b/library/x509_csr.c new file mode 100644 index 000000000..e4b05174c --- /dev/null +++ b/library/x509_csr.c @@ -0,0 +1,439 @@ +/* + * X.509 Certificate Signing Request (CSR) parsing + * + * 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. + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc3279.txt + * http://www.ietf.org/rfc/rfc3280.txt + * + * ftp://ftp.rsasecurity.com/pub/pkcs/ascii/pkcs-1v2.asc + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_X509_CSR_PARSE_C) + +#include "polarssl/x509_csr.h" +#include "polarssl/oid.h" +#if defined(POLARSSL_PEM_PARSE_C) +#include "polarssl/pem.h" +#endif +#if defined(POLARSSL_ASN1_WRITE_C) +#include "polarssl/asn1write.h" +#endif + +#if defined(POLARSSL_MEMORY_C) +#include "polarssl/memory.h" +#else +#define polarssl_malloc malloc +#define polarssl_free free +#endif + +#include +#include + +#if defined(POLARSSL_FS_IO) +#include +#endif + +/* + * 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 ); +} + +/* + * 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_PARSE_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_PARSE_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 = pk_parse_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 ); +} + +#if defined(POLARSSL_FS_IO) +/* + * 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 = x509_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = x509parse_csr( csr, buf, n ); + + memset( buf, 0, n + 1 ); + polarssl_free( buf ); + + return( ret ); +} +#endif /* POLARSSL_FS_IO */ + +#if defined _MSC_VER && !defined snprintf +#include + +#if !defined vsnprintf +#define vsnprintf _vsnprintf +#endif // vsnprintf + +/* + * Windows _snprintf and _vsnprintf are not compatible to linux versions. + * Result value is not size of buffer needed, but -1 if no fit is possible. + * + * This fuction tries to 'fix' this by at least suggesting enlarging the + * size by 20. + */ +static int compat_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int res = -1; + + va_start( ap, format ); + + res = vsnprintf( str, size, format, ap ); + + va_end( ap ); + + // No quick fix possible + if ( res < 0 ) + return( (int) size + 20 ); + + return res; +} + +#define snprintf compat_snprintf +#endif + +#define POLARSSL_ERR_DEBUG_BUF_TOO_SMALL -2 + +#define SAFE_SNPRINTF() \ +{ \ + if( ret == -1 ) \ + return( -1 ); \ + \ + if ( (unsigned int) ret > n ) { \ + p[n - 1] = '\0'; \ + return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;\ + } \ + \ + n -= (unsigned int) ret; \ + p += (unsigned int) ret; \ +} + +#define BEFORE_COLON 14 +#define BC "14" +/* + * 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 ) ); +} + +/* + * 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 ) ); +} + +#endif /* POLARSSL_X509_CSR_PARSE_C */ diff --git a/library/x509_csr_write.c b/library/x509_csr_write.c new file mode 100644 index 000000000..b744300ab --- /dev/null +++ b/library/x509_csr_write.c @@ -0,0 +1,244 @@ +/* + * X.509 Certificate Signing Request writing + * + * 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. + */ +/* + * References: + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#include "polarssl/config.h" + +#if defined(POLARSSL_X509_CSR_WRITE_C) + +#include "polarssl/x509_csr.h" +#include "polarssl/oid.h" +#include "polarssl/asn1write.h" + +#if defined(POLARSSL_PEM_WRITE_C) +#include "polarssl/pem.h" +#endif + +#include +#include + +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 ); +} + +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; + int ret; + + c = buf + 4; + + if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) + return( ret ); + + ret = x509write_csr_set_extension( ctx, OID_KEY_USAGE, + OID_SIZE( OID_KEY_USAGE ), + buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int x509write_csr_set_ns_cert_type( x509write_csr *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_csr_set_extension( ctx, OID_NS_CERT_TYPE, + OID_SIZE( OID_NS_CERT_TYPE ), + buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +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 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 ); + + ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + + if( len ) + { + 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_CONSTRUCTED | ASN1_SET ) ); + + 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 ) ); + } + + 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, pk_write_pubkey_der( ctx->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 ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + ASN1_CHK_ADD( len, asn1_write_int( &c, tmp_buf, 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 ) ); + + /* + * Prepare signature + */ + md( md_info_from_type( ctx->md_alg ), c, len, hash ); + + pk_alg = pk_get_type( ctx->key ); + if( pk_alg == POLARSSL_PK_ECKEY ) + pk_alg = POLARSSL_PK_ECDSA; + + 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 ); + } + + /* + * 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_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" +#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" + +#if defined(POLARSSL_PEM_WRITE_C) +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]; + size_t olen = 0; + + if( ( ret = x509write_csr_der( ctx, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* POLARSSL_PEM_WRITE_C */ + +#endif /* POLARSSL_X509_CSR_WRITE_C */ diff --git a/library/x509write.c b/library/x509write.c deleted file mode 100644 index f020b9e03..000000000 --- a/library/x509write.c +++ /dev/null @@ -1,869 +0,0 @@ -/* - * X509 buffer writing functionality - * - * 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. - */ - -/* - * 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) - -#include "polarssl/asn1write.h" -#include "polarssl/x509write.h" -#include "polarssl/x509.h" -#include "polarssl/md.h" -#include "polarssl/oid.h" - -#include "polarssl/sha1.h" - -#if defined(POLARSSL_PEM_WRITE_C) -#include "polarssl/pem.h" -#endif - -#if defined(POLARSSL_MEMORY_C) -#include "polarssl/memory.h" -#else -#include -#define polarssl_malloc malloc -#define polarssl_free free -#endif - -static int x509write_string_to_names( asn1_named_data **head, char *name ) -{ - int ret = 0; - char *s = name, *c = s; - char *end = s + strlen( s ); - char *oid = NULL; - int in_tag = 1; - asn1_named_data *cur; - - /* Clear existing chain if present */ - asn1_free_named_data_list( head ); - - while( c <= end ) - { - if( in_tag && *c == '=' ) - { - if( memcmp( s, "CN", 2 ) == 0 && c - s == 2 ) - oid = OID_AT_CN; - else if( memcmp( s, "C", 1 ) == 0 && c - s == 1 ) - oid = OID_AT_COUNTRY; - else if( memcmp( s, "O", 1 ) == 0 && c - s == 1 ) - oid = OID_AT_ORGANIZATION; - else if( memcmp( s, "L", 1 ) == 0 && c - s == 1 ) - oid = OID_AT_LOCALITY; - else if( memcmp( s, "R", 1 ) == 0 && c - s == 1 ) - oid = OID_PKCS9_EMAIL; - else if( memcmp( s, "OU", 2 ) == 0 && c - s == 2 ) - oid = OID_AT_ORG_UNIT; - else if( memcmp( s, "ST", 2 ) == 0 && c - s == 2 ) - oid = OID_AT_STATE; - else - { - ret = POLARSSL_ERR_X509WRITE_UNKNOWN_OID; - goto exit; - } - - s = c + 1; - in_tag = 0; - } - - if( !in_tag && ( *c == ',' || c == end ) ) - { - if( ( cur = asn1_store_named_data( head, oid, strlen( oid ), - (unsigned char *) s, - c - s ) ) == NULL ) - { - return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); - } - - while( c < end && *(c + 1) == ' ' ) - c++; - - s = c + 1; - in_tag = 1; - } - c++; - } - -exit: - - return( ret ); -} - -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_store_named_data( head, oid, oid_len, - NULL, val_len + 1 ) ) == NULL ) - { - return( POLARSSL_ERR_X509WRITE_MALLOC_FAILED ); - } - - cur->val.p[0] = critical; - memcpy( cur->val.p + 1, val, val_len ); - - return( 0 ); -} - -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; - int ret; - - c = buf + 4; - - if( ( ret = asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) - return( ret ); - - ret = x509write_csr_set_extension( ctx, OID_KEY_USAGE, - OID_SIZE( OID_KEY_USAGE ), - buf, 4 ); - if( ret != 0 ) - return( ret ); - - return( 0 ); -} - -int x509write_csr_set_ns_cert_type( x509write_csr *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_csr_set_extension( ctx, OID_NS_CERT_TYPE, - OID_SIZE( OID_NS_CERT_TYPE ), - buf, 4 ); - if( ret != 0 ) - return( ret ); - - return( 0 ); -} - -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; - - 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; - - memset( buf, 0, sizeof(buf) ); - - 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, pk_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, pk_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 ); -} - -/* - * 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 len = 0; - - // Write PrintableString for all except OID_PKCS9_EMAIL - // - if( OID_SIZE( OID_PKCS9_EMAIL ) == oid_len && - memcmp( oid, OID_PKCS9_EMAIL, oid_len ) == 0 ) - { - ASN1_CHK_ADD( len, asn1_write_ia5_string( p, start, - (const char *) name, - name_len ) ); - } - else - { - ASN1_CHK_ADD( len, asn1_write_printable_string( p, start, - (const char *) name, - name_len ) ); - } - - // Write OID - // - ASN1_CHK_ADD( len, asn1_write_oid( p, start, oid, oid_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 ) ); - ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_CONSTRUCTED | ASN1_SET ) ); - - 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, size_t oid_len, - unsigned char *sig, size_t size ) -{ - int ret; - size_t len = 0; - - if( *p - start < (int) size + 1 ) - return( POLARSSL_ERR_ASN1_BUF_TOO_SMALL ); - - len = size; - (*p) -= len; - memcpy( *p, sig, len ); - - *--(*p) = 0; - len += 1; - - ASN1_CHK_ADD( len, asn1_write_len( p, start, len ) ); - ASN1_CHK_ADD( len, asn1_write_tag( p, start, ASN1_BIT_STRING ) ); - - // Write OID - // - ASN1_CHK_ADD( len, asn1_write_algorithm_identifier( p, start, oid, - oid_len, 0 ) ); - - return( len ); -} - -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 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 ); - - ASN1_CHK_ADD( len, x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); - - if( len ) - { - 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_CONSTRUCTED | ASN1_SET ) ); - - 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 ) ); - } - - 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, pk_write_pubkey_der( ctx->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 ) ); - - /* - * Version ::= INTEGER { v1(0), v2(1), v3(2) } - */ - ASN1_CHK_ADD( len, asn1_write_int( &c, tmp_buf, 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 ) ); - - /* - * Prepare signature - */ - md( md_info_from_type( ctx->md_alg ), c, len, hash ); - - pk_alg = pk_get_type( ctx->key ); - if( pk_alg == POLARSSL_PK_ECKEY ) - pk_alg = POLARSSL_PK_ECDSA; - - 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 ); - } - - /* - * 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 ); -} - -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, pk_write_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" - -#if defined(POLARSSL_PEM_WRITE_C) -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]; - size_t olen = 0; - - if( ( ret = x509write_crt_der( crt, output_buf, sizeof(output_buf), - f_rng, p_rng ) ) < 0 ) - { - return( ret ); - } - - if( ( ret = pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT, - output_buf + sizeof(output_buf) - ret, - ret, buf, size, &olen ) ) != 0 ) - { - return( ret ); - } - - return( 0 ); -} - -int x509write_csr_pem( x509write_csr *ctx, unsigned char *buf, size_t size, - int (*f_rng)(void *, unsigned char *, size_t), - void *p_rng ) -{ - int ret; - unsigned char output_buf[4096]; - size_t olen = 0; - - if( ( ret = x509write_csr_der( ctx, output_buf, sizeof(output_buf), - f_rng, p_rng ) ) < 0 ) - { - return( ret ); - } - - if( ( ret = pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, - output_buf + sizeof(output_buf) - ret, - ret, buf, size, &olen ) ) != 0 ) - { - return( ret ); - } - - return( 0 ); -} -#endif /* POLARSSL_BASE64_C */ - -#endif diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c index 3661341d4..3257635e7 100644 --- a/programs/pkey/key_app_writer.c +++ b/programs/pkey/key_app_writer.c @@ -33,16 +33,16 @@ #include "polarssl/config.h" -#include "polarssl/x509write.h" +#include "polarssl/pk.h" #include "polarssl/error.h" -#if !defined(POLARSSL_X509_WRITE_C) || !defined(POLARSSL_FS_IO) +#if !defined(POLARSSL_PK_WRITE_C) || !defined(POLARSSL_FS_IO) int main( int argc, char *argv[] ) { ((void) argc); ((void) argv); - printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_FS_IO not defined.\n" ); + printf( "POLARSSL_PK_WRITE_C and/or POLARSSL_FS_IO not defined.\n" ); return( 0 ); } #else diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c index eb6414d9c..9bfbdbfd4 100644 --- a/programs/x509/cert_app.c +++ b/programs/x509/cert_app.c @@ -42,7 +42,7 @@ #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_X509_CRT_PARSE_C) || !defined(POLARSSL_FS_IO) || \ !defined(POLARSSL_CTR_DRBG_C) int main( int argc, char *argv[] ) { @@ -52,7 +52,7 @@ int main( int argc, char *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_X509_CRT_PARSE_C and/or POLARSSL_FS_IO and/or " "POLARSSL_CTR_DRBG_C not defined.\n"); return( 0 ); } @@ -282,14 +282,14 @@ int main( int argc, char *argv[] ) if( ret < 0 ) { printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); - x509_free( &crt ); + x509_crt_free( &crt ); goto exit; } if( opt.permissive == 0 && ret > 0 ) { printf( " failed\n ! x509parse_crt failed to parse %d certificates\n\n", ret ); - x509_free( &crt ); + x509_crt_free( &crt ); goto exit; } @@ -305,7 +305,7 @@ int main( int argc, char *argv[] ) if( ret == -1 ) { printf( " failed\n ! x509parse_cert_info returned %d\n\n", ret ); - x509_free( &crt ); + x509_crt_free( &crt ); goto exit; } @@ -344,7 +344,7 @@ int main( int argc, char *argv[] ) printf( " ok\n" ); } - x509_free( &crt ); + x509_crt_free( &crt ); } else if( opt.mode == MODE_SSL ) { @@ -447,8 +447,8 @@ exit: if( server_fd ) net_close( server_fd ); - x509_free( &cacert ); - x509_free( &clicert ); + x509_crt_free( &cacert ); + x509_crt_free( &clicert ); pk_free( &pkey ); #if defined(_WIN32) diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c index f4b139e3b..ff651980a 100644 --- a/programs/x509/cert_req.c +++ b/programs/x509/cert_req.c @@ -33,21 +33,19 @@ #include "polarssl/config.h" -#include "polarssl/x509write.h" +#include "polarssl/x509_csr.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) || \ +#if !defined(POLARSSL_X509_CSR_WRITE_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 " + printf( "POLARSSL_X509_CSR_WRITE_C and/or POLARSSL_FS_IO and/or " "POLARSSL_ENTROPY_C and/or POLARSSL_CTR_DRBG_C " "not defined.\n"); return( 0 ); diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c index 0b52bb186..0cc6482aa 100644 --- a/programs/x509/cert_write.c +++ b/programs/x509/cert_write.c @@ -33,13 +33,14 @@ #include "polarssl/config.h" -#include "polarssl/x509write.h" +#include "polarssl/x509_crt.h" +#include "polarssl/x509_csr.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) || \ +#if !defined(POLARSSL_X509_CRT_WRITE_C) || \ + !defined(POLARSSL_X509_CRT_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[] ) @@ -47,7 +48,7 @@ int main( int argc, char *argv[] ) ((void) argc); ((void) argv); - printf( "POLARSSL_X509_WRITE_C and/or POLARSSL_X509_PARSE_C and/or " + printf( "POLARSSL_X509_CRT_WRITE_C and/or POLARSSL_X509_CRT_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"); diff --git a/programs/x509/crl_app.c b/programs/x509/crl_app.c index c9c3ef0d8..98edb2d45 100644 --- a/programs/x509/crl_app.c +++ b/programs/x509/crl_app.c @@ -33,17 +33,17 @@ #include "polarssl/config.h" -#include "polarssl/x509.h" +#include "polarssl/x509_crl.h" #if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) + !defined(POLARSSL_X509_CRL_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"); + "POLARSSL_X509_CRL_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); return( 0 ); } #else diff --git a/programs/x509/req_app.c b/programs/x509/req_app.c index e2faab43b..a3f762c40 100644 --- a/programs/x509/req_app.c +++ b/programs/x509/req_app.c @@ -33,17 +33,17 @@ #include "polarssl/config.h" -#include "polarssl/x509.h" +#include "polarssl/x509_csr.h" #if !defined(POLARSSL_BIGNUM_C) || !defined(POLARSSL_RSA_C) || \ - !defined(POLARSSL_X509_PARSE_C) || !defined(POLARSSL_FS_IO) + !defined(POLARSSL_X509_CSR_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"); + "POLARSSL_X509_CSR_PARSE_C and/or POLARSSL_FS_IO not defined.\n"); return( 0 ); } #else diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index fcacaefe2..0d15211a8 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ -#include +#include +#include #include #include @@ -26,11 +27,11 @@ int verify_all( void *data, x509_cert *crt, int certificate_depth, int *flags ) /* END_HEADER */ /* BEGIN_DEPENDENCIES - * depends_on:POLARSSL_X509_PARSE_C:POLARSSL_BIGNUM_C + * depends_on:POLARSSL_BIGNUM_C * END_DEPENDENCIES */ -/* BEGIN_CASE depends_on:POLARSSL_FS_IO */ +/* BEGIN_CASE depends_on:POLARSSL_FS_IO:POLARSSL_X509_CRT_PARSE_C */ void x509_cert_info( char *crt_file, char *result_str ) { x509_cert crt; @@ -43,7 +44,7 @@ void x509_cert_info( char *crt_file, char *result_str ) TEST_ASSERT( x509parse_crtfile( &crt, crt_file ) == 0 ); res = x509parse_cert_info( buf, 2000, "", &crt ); - x509_free( &crt ); + x509_crt_free( &crt ); TEST_ASSERT( res != -1 ); TEST_ASSERT( res != -2 ); @@ -52,7 +53,7 @@ void x509_cert_info( char *crt_file, char *result_str ) } /* END_CASE */ -/* BEGIN_CASE depends_on:POLARSSL_FS_IO */ +/* BEGIN_CASE depends_on:POLARSSL_FS_IO:POLARSSL_X509_CRL_PARSE_C */ void x509_crl_info( char *crl_file, char *result_str ) { x509_crl crl; @@ -74,7 +75,7 @@ void x509_crl_info( char *crl_file, char *result_str ) } /* END_CASE */ -/* BEGIN_CASE depends_on:POLARSSL_FS_IO */ +/* BEGIN_CASE depends_on:POLARSSL_FS_IO:POLARSSL_X509_CRT_PARSE_C */ void x509_verify( char *crt_file, char *ca_file, char *crl_file, char *cn_name_str, int result, int flags_result, char *verify_callback ) @@ -109,8 +110,8 @@ void x509_verify( char *crt_file, char *ca_file, char *crl_file, res = x509parse_verify( &crt, &ca, &crl, cn_name, &flags, f_vrfy, NULL ); - x509_free( &crt ); - x509_free( &ca ); + x509_crt_free( &crt ); + x509_crt_free( &ca ); x509_crl_free( &crl ); TEST_ASSERT( res == ( result ) ); @@ -118,7 +119,7 @@ void x509_verify( char *crt_file, char *ca_file, char *crl_file, } /* END_CASE */ -/* BEGIN_CASE depends_on:POLARSSL_FS_IO */ +/* BEGIN_CASE depends_on:POLARSSL_FS_IO:POLARSSL_X509_USE_C */ void x509_dn_gets( char *crt_file, char *entity, char *result_str ) { x509_cert crt; @@ -136,7 +137,7 @@ void x509_dn_gets( char *crt_file, char *entity, char *result_str ) else TEST_ASSERT( "Unknown entity" == 0 ); - x509_free( &crt ); + x509_crt_free( &crt ); TEST_ASSERT( res != -1 ); TEST_ASSERT( res != -2 ); @@ -145,7 +146,7 @@ void x509_dn_gets( char *crt_file, char *entity, char *result_str ) } /* END_CASE */ -/* BEGIN_CASE depends_on:POLARSSL_FS_IO */ +/* BEGIN_CASE depends_on:POLARSSL_FS_IO:POLARSSL_X509_USE_C */ void x509_time_expired( char *crt_file, char *entity, int result ) { x509_cert crt; @@ -161,11 +162,11 @@ void x509_time_expired( char *crt_file, char *entity, int result ) else TEST_ASSERT( "Unknown entity" == 0 ); - x509_free( &crt ); + x509_crt_free( &crt ); } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:POLARSSL_X509_CRT_PARSE_C */ void x509parse_crt( char *crt_data, char *result_str, int result ) { x509_cert crt; @@ -190,11 +191,11 @@ void x509parse_crt( char *crt_data, char *result_str, int result ) TEST_ASSERT( strcmp( (char *) output, result_str ) == 0 ); } - x509_free( &crt ); + x509_crt_free( &crt ); } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:POLARSSL_X509_CRL_PARSE_C */ void x509parse_crl( char *crl_data, char *result_str, int result ) { x509_crl crl; @@ -223,7 +224,7 @@ void x509parse_crl( char *crl_data, char *result_str, int result ) } /* END_CASE */ -/* BEGIN_CASE */ +/* BEGIN_CASE depends_on:POLARSSL_X509_CRT_PARSE_C */ void x509_selftest() { TEST_ASSERT( x509_self_test( 0 ) == 0 ); diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function index 6af5555bc..323361784 100644 --- a/tests/suites/test_suite_x509write.function +++ b/tests/suites/test_suite_x509write.function @@ -1,16 +1,16 @@ /* BEGIN_HEADER */ -#include -#include +#include +#include #include #include /* END_HEADER */ /* BEGIN_DEPENDENCIES - * depends_on:POLARSSL_X509_WRITE_C:POLARSSL_BIGNUM_C:POLARSSL_FS_IO + * depends_on:POLARSSL_BIGNUM_C:POLARSSL_FS_IO:POLARSSL_PK_PARSE_C * END_DEPENDENCIES */ -/* BEGIN_CASE depends_on:POLARSSL_PEM_C */ +/* BEGIN_CASE depends_on:POLARSSL_PEM_WRITE_C:POLARSSL_X509_CSR_WRITE_C */ void x509_csr_check( char *key_file, int md_type, char *cert_req_check_file ) { @@ -53,7 +53,7 @@ void x509_csr_check( char *key_file, int md_type, } /* END_CASE */ -/* BEGIN_CASE depends_on:POLARSSL_PEM_C */ +/* BEGIN_CASE depends_on:POLARSSL_PEM_WRITE_C:POLARSSL_X509_CRT_WRITE_C */ void x509_crt_check( char *subject_key_file, char *subject_pwd, char *subject_name, char *issuer_key_file, char *issuer_pwd, char *issuer_name,