diff --git a/ChangeLog b/ChangeLog index b24009b9a..4fbd4b664 100644 --- a/ChangeLog +++ b/ChangeLog @@ -19,6 +19,7 @@ Features * Added support for Hardware Acceleration hooking in SSL/TLS * Added OpenSSL / PolarSSL compatibility script (tests/compat.sh) and example application (programs/ssl/o_p_test) (Requires OpenSSL) + * Added X509 CA Path support Changes * Removed redundant POLARSSL_DEBUG_MSG define diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index 2cd883fb4..e0a2776e9 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -455,6 +455,22 @@ int x509parse_crt( x509_cert *chain, const unsigned char *buf, size_t buflen ); */ 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 ); + /** \ingroup x509_module */ /** * \brief Parse one or more CRLs and add them diff --git a/library/x509parse.c b/library/x509parse.c index f1e98b31e..4234dfc06 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -60,6 +60,10 @@ #if defined(POLARSSL_FS_IO) #include +#if !defined(_WIN32) +#include +#include +#endif #endif /* @@ -1860,6 +1864,68 @@ int x509parse_crtfile( x509_cert *chain, const char *path ) return( ret ); } +int x509parse_crtpath( x509_cert *chain, const char *path ) +{ + int ret = 0; +#if defined(_WIN32) + int t_ret; + TCHAR szDir[MAX_PATH]; + WIN32_FIND_DATA file_data; + HANDLE hFind; + DWORD dwError = 0; + + StringCchCopy(szDir, MAX_PATH, path); + StringCchCat(szDir, MAX_PATH, TEXT("\\*")); + + hFind = FindFirstFile( szDir, &file_data ); + if (hFind == INVALID_HANDLE_VALUE) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + do + { + if( file_data.dwAttributes & FILE_ATTRIBUTE_DIRECTORY ) + continue; + + t_ret = x509parse_crtfile( chain, entry_name ); + if( t_ret < 0 ) + return( t_ret ); + + ret += t_ret; + } + while( FindNextFile( hFind, &file_data ) != 0 ); + + dwError = GetLastError(); + if (dwError != ERROR_NO_MORE_FILES) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + FindClose( hFind ); +#else + int t_ret; + struct dirent *entry; + char entry_name[255]; + DIR *dir = opendir( path ); + + if( dir == NULL) + return( POLARSSL_ERR_X509_FILE_IO_ERROR ); + + while( ( entry = readdir( dir ) ) != NULL ) + { + if( entry->d_type != DT_REG ) + continue; + + snprintf( entry_name, sizeof(entry_name), "%s/%s", path, entry->d_name ); + t_ret = x509parse_crtfile( chain, entry_name ); + if( t_ret < 0 ) + return( t_ret ); + + ret += t_ret; + } + closedir( dir ); +#endif + + return( ret ); +} + /* * Load one or more CRLs and add them to the chained list */ diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index f82abe6be..8c0a94df0 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -46,6 +46,7 @@ #define DFL_REQUEST_PAGE "/" #define DFL_DEBUG_LEVEL 0 #define DFL_CA_FILE "" +#define DFL_CA_PATH "" #define DFL_CRT_FILE "" #define DFL_KEY_FILE "" #define DFL_FORCE_CIPHER 0 @@ -62,6 +63,7 @@ struct options int debug_level; /* level of debugging */ char *request_page; /* page on server to request */ char *ca_file; /* the file with the CA certificate(s) */ + char *ca_path; /* the path with the CA certificate(s) reside */ char *crt_file; /* the file with the client certificate */ char *key_file; /* the file with the client key */ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */ @@ -79,6 +81,7 @@ void my_debug( void *ctx, int level, const char *str ) #if defined(POLARSSL_FS_IO) #define USAGE_IO \ " ca_file=%%s default: \"\" (pre-loaded)\n" \ + " ca_path=%%s default: \"\" (pre-loaded) (overrides ca_file)\n" \ " crt_file=%%s default: \"\" (pre-loaded)\n" \ " key_file=%%s default: \"\" (pre-loaded)\n" #else @@ -164,6 +167,7 @@ int main( int argc, char *argv[] ) opt.debug_level = DFL_DEBUG_LEVEL; opt.request_page = DFL_REQUEST_PAGE; opt.ca_file = DFL_CA_FILE; + opt.ca_path = DFL_CA_PATH; opt.crt_file = DFL_CRT_FILE; opt.key_file = DFL_KEY_FILE; opt.force_ciphersuite[0]= DFL_FORCE_CIPHER; @@ -201,6 +205,8 @@ int main( int argc, char *argv[] ) opt.request_page = q; else if( strcmp( p, "ca_file" ) == 0 ) opt.ca_file = q; + else if( strcmp( p, "ca_path" ) == 0 ) + opt.ca_path = q; else if( strcmp( p, "crt_file" ) == 0 ) opt.crt_file = q; else if( strcmp( p, "key_file" ) == 0 ) @@ -245,7 +251,9 @@ int main( int argc, char *argv[] ) fflush( stdout ); #if defined(POLARSSL_FS_IO) - if( strlen( opt.ca_file ) ) + if( strlen( opt.ca_path ) ) + ret = x509parse_crtpath( &cacert, opt.ca_path ); + else if( strlen( opt.ca_file ) ) ret = x509parse_crtfile( &cacert, opt.ca_file ); else #endif