From 2cedd593849a344c403e59fb25f5ef88e2845731 Mon Sep 17 00:00:00 2001 From: cameronrich Date: Wed, 23 Sep 2009 12:38:23 +0000 Subject: [PATCH] Added SAN ("Subject Alternative Name" support git-svn-id: svn://svn.code.sf.net/p/axtls/code/trunk@159 9a5d90b5-6617-0410-8a86-bb477d3ed2e3 --- ssl/asn1.c | 54 +++++++++++++++++++++++++++++++++++++++++++- ssl/crypto_misc.h | 10 ++++++++- ssl/ssl.h | 17 ++++++++++++++ ssl/tls1.c | 34 ++++++++++++++++++++++++---- ssl/x509.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++- www/index.html | 2 +- 6 files changed, 166 insertions(+), 8 deletions(-) diff --git a/ssl/asn1.c b/ssl/asn1.c index 4f2e6db24..ee474f4c1 100644 --- a/ssl/asn1.c +++ b/ssl/asn1.c @@ -42,6 +42,7 @@ #define SIG_OID_PREFIX_SIZE 8 #define SIG_IIS6_OID_SIZE 5 +#define SIG_SUBJECT_ALT_NAME_SIZE 3 /* Must be an RSA algorithm with either SHA1 or MD5 for verifying to work */ static const uint8_t sig_oid_prefix[SIG_OID_PREFIX_SIZE] = @@ -54,6 +55,11 @@ static const uint8_t sig_iis6_oid[SIG_IIS6_OID_SIZE] = 0x2b, 0x0e, 0x03, 0x02, 0x1d }; +static const uint8_t sig_subject_alt_name[SIG_SUBJECT_ALT_NAME_SIZE] = +{ + 0x55, 0x1d, 0x11 +}; + /* CN, O, OU */ static const uint8_t g_dn_types[] = { 3, 10, 11 }; @@ -284,6 +290,7 @@ static int asn1_get_printable_str(const uint8_t *buf, int *offset, char **str) /* some certs have this awful crud in them for some reason */ if (buf[*offset] != ASN1_PRINTABLE_STR && + buf[*offset] != ASN1_PRINTABLE_STR2 && buf[*offset] != ASN1_TELETEX_STR && buf[*offset] != ASN1_IA5_STR && buf[*offset] != ASN1_UNICODE_STR) @@ -471,7 +478,52 @@ int asn1_compare_dn(char * const dn1[], char * const dn2[]) return 0; /* all good */ } -#endif +int asn1_find_oid(const uint8_t* cert, int* offset, + const uint8_t* oid, int oid_length) +{ + int seqlen; + if ((seqlen = asn1_next_obj(cert, offset, ASN1_SEQUENCE))> 0) + { + int end = *offset + seqlen; + + while (*offset < end) + { + int type = cert[(*offset)++]; + int length = get_asn1_length(cert, offset); + int noffset = *offset + length; + + if (type == ASN1_SEQUENCE) + { + type = cert[(*offset)++]; + length = get_asn1_length(cert, offset); + + if (type == ASN1_OID && length == oid_length && + memcmp(cert + *offset, oid, oid_length) == 0) + { + *offset += oid_length; + return 1; + } + } + + *offset = noffset; + } + } + + return 0; +} + +int asn1_find_subjectaltname(const uint8_t* cert, int offset) +{ + if (asn1_find_oid(cert, &offset, sig_subject_alt_name, + SIG_SUBJECT_ALT_NAME_SIZE)) + { + return offset; + } + + return 0; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ /** * Read the signature type of the certificate. We only support RSA-MD5 and diff --git a/ssl/crypto_misc.h b/ssl/crypto_misc.h index 97cb0f2d2..1fd514eeb 100644 --- a/ssl/crypto_misc.h +++ b/ssl/crypto_misc.h @@ -68,6 +68,7 @@ struct _x509_ctx { char *ca_cert_dn[X509_NUM_DN_TYPES]; char *cert_dn[X509_NUM_DN_TYPES]; + char **subject_alt_dnsnames; time_t not_before; time_t not_after; uint8_t *signature; @@ -104,16 +105,22 @@ const char * x509_display_error(int error); #define ASN1_BIT_STRING 0x03 #define ASN1_OCTET_STRING 0x04 #define ASN1_NULL 0x05 +#define ASN1_PRINTABLE_STR2 0x0C #define ASN1_OID 0x06 +#define ASN1_PRINTABLE_STR2 0x0C #define ASN1_PRINTABLE_STR 0x13 #define ASN1_TELETEX_STR 0x14 #define ASN1_IA5_STR 0x16 #define ASN1_UTC_TIME 0x17 #define ASN1_UNICODE_STR 0x1e #define ASN1_SEQUENCE 0x30 +#define ASN1_CONTEXT_DNSNAME 0x82 #define ASN1_SET 0x31 +#define ASN1_V3_DATA 0xa3 #define ASN1_IMPLICIT_TAG 0x80 +#define ASN1_CONTEXT_DNSNAME 0x82 #define ASN1_EXPLICIT_TAG 0xa0 +#define ASN1_V3_DATA 0xa3 #define SIG_TYPE_MD2 0x02 #define SIG_TYPE_MD5 0x04 @@ -130,8 +137,9 @@ int asn1_name(const uint8_t *cert, int *offset, char *dn[]); int asn1_public_key(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); #ifdef CONFIG_SSL_CERT_VERIFICATION int asn1_signature(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); +int asn1_find_subjectaltname(const uint8_t* cert, int offset); int asn1_compare_dn(char * const dn1[], char * const dn2[]); -#endif +#endif /* CONFIG_SSL_CERT_VERIFICATION */ int asn1_signature_type(const uint8_t *cert, int *offset, X509_CTX *x509_ctx); diff --git a/ssl/ssl.h b/ssl/ssl.h index 539d0a305..9fc8d0e0f 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -384,6 +384,23 @@ EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl); */ EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component); + +/** + * @brief Retrieve a Subject Alternative DNSName + * + * When a handshake is complete and a certificate has been exchanged, then the + * details of the remote certificate can be retrieved. + * + * This will usually be used by a client to check that the server's common + * name matches the URL. + * + * @param ssl [in] An SSL object reference. + * @param index [in] The index of the DNS name to retrieve. + * @return The appropriate string (or null if not defined) + * @note Verification build mode must be enabled. + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int dnsindex); + /** * @brief Force the client to perform its handshake again. * diff --git a/ssl/tls1.c b/ssl/tls1.c index 658c2c15d..9a469d7fe 100755 --- a/ssl/tls1.c +++ b/ssl/tls1.c @@ -419,6 +419,7 @@ error: return ret; } + /* * Retrieve an X.509 distinguished name component */ @@ -452,7 +453,27 @@ EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) } } -#endif +/* + * Retrieve a "Subject Alternative Name" from a v3 certificate + */ +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, + int dnsindex) +{ + int i; + + if (ssl->x509_ctx == NULL || ssl->x509_ctx->subject_alt_dnsnames == NULL) + return NULL; + + for (i = 0; i < dnsindex; ++i) + { + if (ssl->x509_ctx->subject_alt_dnsnames[i] == NULL) + return NULL; + } + + return ssl->x509_ctx->subject_alt_dnsnames[dnsindex]; +} + +#endif /* CONFIG_SSL_CERT_VERIFICATION */ /* * Find an ssl object based on the client's file descriptor. @@ -879,7 +900,6 @@ static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt) return (void *)aes_ctx; } - break; case SSL_RC4_128_MD5: #endif @@ -889,7 +909,6 @@ static void *crypt_new(SSL *ssl, uint8_t *key, uint8_t *iv, int is_decrypt) RC4_setup(rc4_ctx, key, 16); return (void *)rc4_ctx; } - break; } return NULL; /* its all gone wrong */ @@ -1505,7 +1524,7 @@ void disposable_free(SSL *ssl) { if (ssl->dc) { - free(ssl->dc->key_block); + free(ssl->dc->key_block); memset(ssl->dc, 0, sizeof(DISPOSABLE_CTX)); free(ssl->dc); ssl->dc = NULL; @@ -2045,12 +2064,19 @@ EXP_FUNC int STDCALL ssl_verify_cert(const SSL *ssl) return -1; } + EXP_FUNC const char * STDCALL ssl_get_cert_dn(const SSL *ssl, int component) { printf(unsupported_str); return NULL; } +EXP_FUNC const char * STDCALL ssl_get_cert_subject_alt_dnsname(const SSL *ssl, int index) +{ + printf(unsupported_str); + return NULL; +} + #endif /* CONFIG_SSL_CERT_VERIFICATION */ #endif /* CONFIG_BINDINGS */ diff --git a/ssl/x509.c b/ssl/x509.c index 37db7f4e8..d2e8ccbb4 100644 --- a/ssl/x509.c +++ b/ssl/x509.c @@ -147,7 +147,53 @@ int x509_new(const uint8_t *cert, int *len, X509_CTX **ctx) x509_ctx->digest = bi_import(bi_ctx, md2_dgst, MD2_SIZE); } - offset = end_tbs; /* skip the v3 data */ + if (cert[offset] == ASN1_V3_DATA) + { + int suboffset; + + ++offset; + get_asn1_length(cert, &offset); + + if ((suboffset = asn1_find_subjectaltname(cert, offset)) > 0) + { + if (asn1_next_obj(cert, &suboffset, ASN1_OCTET_STRING) > 0) + { + int altlen; + + if ((altlen = asn1_next_obj(cert, + &suboffset, ASN1_SEQUENCE)) > 0) + { + int endalt = suboffset + altlen; + int totalnames = 0; + + while (suboffset < endalt) + { + int type = cert[suboffset++]; + int dnslen = get_asn1_length(cert, &suboffset); + + if (type == ASN1_CONTEXT_DNSNAME) + { + x509_ctx->subject_alt_dnsnames = (char**) + realloc(x509_ctx->subject_alt_dnsnames, + (totalnames + 2) * sizeof(char*)); + x509_ctx->subject_alt_dnsnames[totalnames] = + (char*)malloc(dnslen + 1); + x509_ctx->subject_alt_dnsnames[totalnames+1] = NULL; + memcpy(x509_ctx->subject_alt_dnsnames[totalnames], + cert + suboffset, dnslen); + x509_ctx->subject_alt_dnsnames[ + totalnames][dnslen] = 0; + ++totalnames; + } + + suboffset += dnslen; + } + } + } + } + } + + offset = end_tbs; /* skip the rest of v3 data */ if (asn1_skip_obj(cert, &offset, ASN1_SEQUENCE) || asn1_signature(cert, &offset, x509_ctx)) goto end_cert; @@ -188,6 +234,7 @@ void x509_free(X509_CTX *x509_ctx) free(x509_ctx->cert_dn[i]); } + free(x509_ctx->signature); #ifdef CONFIG_SSL_CERT_VERIFICATION @@ -195,6 +242,14 @@ void x509_free(X509_CTX *x509_ctx) { bi_free(x509_ctx->rsa_ctx->bi_ctx, x509_ctx->digest); } + + if (x509_ctx->subject_alt_dnsnames) + { + for (i = 0; x509_ctx->subject_alt_dnsnames[i]; ++i) + free(x509_ctx->subject_alt_dnsnames[i]); + + free(x509_ctx->subject_alt_dnsnames); + } #endif RSA_free(x509_ctx->rsa_ctx); diff --git a/www/index.html b/www/index.html index 25cd2e69b..6170143e3 100755 --- a/www/index.html +++ b/www/index.html @@ -7087,7 +7087,7 @@ if (useJavaSaver)
changes, notes and errata
Type the text for 'YourName'
-
@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.1@@\n\n!!__SSL Library__\n* Certificate verification now works for Firefox.\n* Extended the openssl API.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.0@@\n\n!!__SSL Library__\n* A self-signed certificate will be verified as ok provided that that it is on the certificate authority list.\n* Certificates are not verified when added as certificate authorities (since self-signed and expired certificates can be added to browsers etc)\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.9@@\n\n!!__SSL Library__\n* Now support MS IIS resource kit certificates (thanks to Carsten Sørensen).\n* Fixed a memory leak when freeing more than one CA certificate.\n* The bigint library had a problem with squaring which affected classical reduction (thanks to Manuel Klimek).\n\n!!__axhttpd__\n* Brought back setuid()/setgid() as an option.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.8@@\n\n!!__SSL Library__\n* Now using a BSD style license.\n* Self-signed certificates can now be automatically generated (the keys still need to be provided).\n* A new API call //ssl_x509_create()// can be used to programatically create the certificate.\n* Certificate/keys can be loaded automatically given a file location.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.7@@\n\n!!__SSL Library__\n\n* Variable sized session id's is now better handled for session caching. It has meant a new API call //ssl_get_session_id_size()// and a change to //ssl_client_new()// to define the session id size.\n* Muliple records with a single header are now better supported (thanks to Hervé Sibert).\n* ~MD2 added for Verisign root cert verification (thanks to Byron Rakitzis).\n* The ~MD5/~SHA1 digests are calculated incrementally to reduce memory (thanks to Byron Rakitzis).\n* The bigint cache is now cleared regularly to reduce memory.\n\n!!__axhttpd__\n\n* Improved the POST handling (thanks to Christian Melki).\n* CSS files now work properly.\n* Lua's CGI launcher location is configurable.\n* //vfork()// is now used for CGI for performance reasons.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.6@@\n\n!!__SSL Library__\n\n* ~RC4 speed improvements\n* Lua samples/bindings now work properly\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.5@@\n\n!!__SSL Library__\n\n* Session id's can now be variable lengths in server hello messages.\n* 0 length client certificates are now supported.\n* ssl_version() now returns just the version and not the date.\n* ssl_write() was not sending complete packets under load.\n\n!!__axhttpd__\n\n* Completely updated the CGI code.\n* Lua now integrated - Lua scripts and Lua Pages now run.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.4@@\n\n!!__SSL Library__\n\n* Fixed a Win32 crypto library issue with non-Administrator users\n* Removed compiler warnings that showed up in ~FC6.\n* GNU TLS certificates are now accepted.\n* Separated the send/receive headers for HMAC calculations.\n* Fixed a compilation problem with swig/perl/~FC6.\n* Fixed an issue with loading PEM CA certificates.\n\n!!__axhttpd__\n\n* Made //setuid()/setgid()// call an mconf option.\n* Made //chroot()// an mconf option. Default to //chdir()// instead.\n* Removed optional permissions checking.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.1@@\n\n!!__SSL Library__\n\n* AES should now work on 16bit processors (there was an alignment problem).\n* Various freed objects are cleared before freeing.\n* Header files now installed in ///usr/local/include/axTLS//.\n* -DCYGWIN replaced with -~DCONFIG_PLATFORM_CYGWIN (and the same for Solaris).\n* removed "-noextern" option in Swig. Fixed some other warnings in Win32.\n* SSLCTX changed to ~SSL_CTX (to be consistent with openssl). SSLCTX still exists for backwards compatibility.\n* malloc() and friends call abort() on failure.\n* Fixed a memory leak in directory listings.\n* Added openssl() compatibility functions.\n* Fixed Cygwin 'make install' issue.\n\n!!__axhttpd__\n\n* main.c now becomes axhttpd.c.\n* Header file issue fixed (in mime_types.c).\n* //chroot()// now used for better security.\n* Basic authentication implemented (via .htpasswd).\n* SSL access/denial protection implemented (via .htaccess).\n* Directory access protection implemented (via .htaccess).\n* Can now have more than one CGI file extension in mconf.\n* "~If-Modified-Since" request now handled properly.\n* Performance tweaks to remove //ssl_find()//.
+
@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.2@@\n\n!!__axhttpd__\n* File uploads over 1kB (but under MAXPOSTDATASIZE) are now supported.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.1@@\n\n!!__SSL Library__\n* Certificate verification now works for Firefox.\n* Extended the openssl API.\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.2.0@@\n\n!!__SSL Library__\n* A self-signed certificate will be verified as ok provided that that it is on the certificate authority list.\n* Certificates are not verified when added as certificate authorities (since self-signed and expired certificates can be added to browsers etc)\n\n@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.9@@\n\n!!__SSL Library__\n* Now support MS IIS resource kit certificates (thanks to Carsten Sørensen).\n* Fixed a memory leak when freeing more than one CA certificate.\n* The bigint library had a problem with squaring which affected classical reduction (thanks to Manuel Klimek).\n\n!!__axhttpd__\n* Brought back setuid()/setgid() as an option.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.8@@\n\n!!__SSL Library__\n* Now using a BSD style license.\n* Self-signed certificates can now be automatically generated (the keys still need to be provided).\n* A new API call //ssl_x509_create()// can be used to programatically create the certificate.\n* Certificate/keys can be loaded automatically given a file location.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.7@@\n\n!!__SSL Library__\n\n* Variable sized session id's is now better handled for session caching. It has meant a new API call //ssl_get_session_id_size()// and a change to //ssl_client_new()// to define the session id size.\n* Muliple records with a single header are now better supported (thanks to Hervé Sibert).\n* ~MD2 added for Verisign root cert verification (thanks to Byron Rakitzis).\n* The ~MD5/~SHA1 digests are calculated incrementally to reduce memory (thanks to Byron Rakitzis).\n* The bigint cache is now cleared regularly to reduce memory.\n\n!!__axhttpd__\n\n* Improved the POST handling (thanks to Christian Melki).\n* CSS files now work properly.\n* Lua's CGI launcher location is configurable.\n* //vfork()// is now used for CGI for performance reasons.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.6@@\n\n!!__SSL Library__\n\n* ~RC4 speed improvements\n* Lua samples/bindings now work properly\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.5@@\n\n!!__SSL Library__\n\n* Session id's can now be variable lengths in server hello messages.\n* 0 length client certificates are now supported.\n* ssl_version() now returns just the version and not the date.\n* ssl_write() was not sending complete packets under load.\n\n!!__axhttpd__\n\n* Completely updated the CGI code.\n* Lua now integrated - Lua scripts and Lua Pages now run.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.4@@\n\n!!__SSL Library__\n\n* Fixed a Win32 crypto library issue with non-Administrator users\n* Removed compiler warnings that showed up in ~FC6.\n* GNU TLS certificates are now accepted.\n* Separated the send/receive headers for HMAC calculations.\n* Fixed a compilation problem with swig/perl/~FC6.\n* Fixed an issue with loading PEM CA certificates.\n\n!!__axhttpd__\n\n* Made //setuid()/setgid()// call an mconf option.\n* Made //chroot()// an mconf option. Default to //chdir()// instead.\n* Removed optional permissions checking.\n\n!@@bgcolor(#ff0000):color(#ffffff):Changes for 1.1.1@@\n\n!!__SSL Library__\n\n* AES should now work on 16bit processors (there was an alignment problem).\n* Various freed objects are cleared before freeing.\n* Header files now installed in ///usr/local/include/axTLS//.\n* -DCYGWIN replaced with -~DCONFIG_PLATFORM_CYGWIN (and the same for Solaris).\n* removed "-noextern" option in Swig. Fixed some other warnings in Win32.\n* SSLCTX changed to ~SSL_CTX (to be consistent with openssl). SSLCTX still exists for backwards compatibility.\n* malloc() and friends call abort() on failure.\n* Fixed a memory leak in directory listings.\n* Added openssl() compatibility functions.\n* Fixed Cygwin 'make install' issue.\n\n!!__axhttpd__\n\n* main.c now becomes axhttpd.c.\n* Header file issue fixed (in mime_types.c).\n* //chroot()// now used for better security.\n* Basic authentication implemented (via .htpasswd).\n* SSL access/denial protection implemented (via .htaccess).\n* Directory access protection implemented (via .htaccess).\n* Can now have more than one CGI file extension in mconf.\n* "~If-Modified-Since" request now handled properly.\n* Performance tweaks to remove //ssl_find()//.
[[Read Me]]
axTLS uses a BSD style license:\n\nCopyright (c) 2008, Cameron Rich All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\nRedistributions of source code must retain the above copyright notice, this\nlist of conditions and the following disclaimer. Redistributions in binary\nform must reproduce the above copyright notice, this list of conditions and\nthe following disclaimer in the documentation and/or other materials\nprovided with the distribution. Neither the name of the axTLS Project nor\nthe names of its contributors may be used to endorse or promote products\nderived from this software without specific prior written permission. \n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\nLIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\nOUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH\nDAMAGE.
[[Read Me]] \n[[Changelog]]\n[[axhttpd]]\n[[License]]