4444#ifndef OPENSSL_NO_OCSP /* requires openssl 0.9.7 or later */
4545#include <openssl/ocsp.h>
4646#endif
47+ #if defined(SERF_HAVE_OSSL_STORE_OPEN_EX )
48+ #include <openssl/store.h>
49+ #include <openssl/evp.h>
50+ #include <openssl/safestack.h>
51+ #include <openssl/ui.h>
52+ #ifndef sk_EVP_PKEY_new_null
53+ DEFINE_STACK_OF (EVP_PKEY )
54+ #endif
55+ #endif
4756
4857#ifndef APR_ARRAY_PUSH
4958#define APR_ARRAY_PUSH (ary ,type ) (*((type *)apr_array_push(ary)))
117126 *
118127 */
119128
129+ static int ssl_x509_ex_data_idx = -1 ;
130+
120131typedef struct bucket_list {
121132 serf_bucket_t * bucket ;
122133 struct bucket_list * next ;
@@ -177,12 +188,20 @@ struct serf_ssl_context_t {
177188 apr_pool_t * cert_pw_cache_pool ;
178189 const char * cert_pw_success ;
179190
191+ /* Cert uri callbacks */
192+ serf_ssl_need_cert_uri_t cert_uri_callback ;
193+ void * cert_uri_userdata ;
194+ apr_pool_t * cert_uri_cache_pool ;
195+ const char * cert_uri_success ;
196+
180197 /* Server cert callbacks */
181198 serf_ssl_need_server_cert_t server_cert_callback ;
182199 serf_ssl_server_cert_chain_cb_t server_cert_chain_callback ;
183200 void * server_cert_userdata ;
184201
185202 const char * cert_path ;
203+ const char * cert_uri ;
204+ const char * cert_pw ;
186205
187206 X509 * cached_cert ;
188207 EVP_PKEY * cached_cert_pw ;
@@ -1502,6 +1521,12 @@ static apr_status_t do_init_libraries(void* baton)
15021521 OpenSSL_add_all_algorithms ();
15031522#endif
15041523
1524+ #if defined(SERF_HAVE_OSSL_STORE_OPEN_EX )
1525+ if (ssl_x509_ex_data_idx < 0 ) {
1526+ ssl_x509_ex_data_idx = X509_get_ex_new_index (0 , NULL , NULL , NULL , NULL );
1527+ }
1528+ #endif
1529+
15051530#if APR_HAS_THREADS && defined(SERF_HAVE_SSL_LOCKING_CALLBACKS )
15061531 numlocks = CRYPTO_num_locks ();
15071532 apr_pool_create (& ssl_pool , NULL );
@@ -1533,10 +1558,50 @@ static apr_status_t init_ssl_libraries(void)
15331558 return serf__init_once (& init_ctx , do_init_libraries , NULL );
15341559}
15351560
1561+ #if defined(SERF_HAVE_OSSL_STORE_OPEN_EX )
1562+
1563+ static int ssl_pass_cb (UI * ui , UI_STRING * uis )
1564+ {
1565+ serf_ssl_context_t * ctx = UI_get0_user_data (ui );
1566+
1567+ const char * password ;
1568+ apr_status_t status ;
1569+
1570+ if (ctx -> cert_pw_success ) {
1571+ status = APR_SUCCESS ;
1572+ password = ctx -> cert_pw_success ;
1573+ ctx -> cert_pw_success = NULL ;
1574+ }
1575+ else if (ctx -> cert_pw_callback ) {
1576+ status = ctx -> cert_pw_callback (ctx -> cert_pw_userdata ,
1577+ ctx -> cert_uri ,
1578+ & password );
1579+ }
1580+ else {
1581+ return 0 ;
1582+ }
1583+
1584+ UI_set_result (ui , uis , password );
1585+
1586+ ctx -> cert_pw = apr_pstrdup (ctx -> pool , password );
1587+
1588+ return 1 ;
1589+ }
1590+
1591+ #endif
1592+
15361593static int ssl_need_client_cert (SSL * ssl , X509 * * cert , EVP_PKEY * * pkey )
15371594{
15381595 serf_ssl_context_t * ctx = SSL_get_app_data (ssl );
1596+ #if defined(SERF_HAVE_OSSL_STORE_OPEN_EX )
1597+ STACK_OF (X509 ) * leaves ;
1598+ STACK_OF (X509 ) * intermediates ;
1599+ STACK_OF (EVP_PKEY ) * keys ;
1600+ X509_STORE * requests ;
1601+ UI_METHOD * ui_method ;
1602+ #endif
15391603 apr_status_t status ;
1604+ int retrying_success = 0 ;
15401605
15411606 serf__log (LOGLVL_DEBUG , LOGCOMP_SSL , __FILE__ , ctx -> config ,
15421607 "Server requests a client certificate.\n" );
@@ -1547,14 +1612,220 @@ static int ssl_need_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey)
15471612 return 1 ;
15481613 }
15491614
1615+ #if defined(SERF_HAVE_OSSL_STORE_OPEN_EX )
1616+
1617+ /* until further notice */
1618+ * cert = NULL ;
1619+ * pkey = NULL ;
1620+
1621+ leaves = sk_X509_new_null ();
1622+ intermediates = sk_X509_new_null ();
1623+ keys = sk_EVP_PKEY_new_null ();
1624+ requests = X509_STORE_new ();
1625+
1626+ ui_method = UI_create_method ("passphrase" );
1627+ UI_method_set_reader (ui_method , ssl_pass_cb );
1628+
1629+ while (ctx -> cert_uri_callback ) {
1630+ const char * cert_uri = NULL ;
1631+ OSSL_STORE_CTX * store = NULL ;
1632+ OSSL_STORE_INFO * info ;
1633+ X509 * c ;
1634+ STACK_OF (X509_NAME ) * requested ;
1635+ int type ;
1636+
1637+ retrying_success = 0 ;
1638+
1639+ if (ctx -> cert_uri_success ) {
1640+ status = APR_SUCCESS ;
1641+ cert_uri = ctx -> cert_uri_success ;
1642+ ctx -> cert_uri_success = NULL ;
1643+ retrying_success = 1 ;
1644+ } else {
1645+ status = ctx -> cert_uri_callback (ctx -> cert_uri_userdata , & cert_uri );
1646+ }
1647+
1648+ if (status || !cert_uri ) {
1649+ break ;
1650+ }
1651+
1652+ ctx -> cert_uri = cert_uri ;
1653+
1654+ /* server side request some certs? this list may be empty */
1655+ requested = SSL_get_client_CA_list (ssl );
1656+
1657+ store = OSSL_STORE_open_ex (cert_uri , NULL , NULL , ui_method , ctx , NULL ,
1658+ NULL , NULL );
1659+ if (!store ) {
1660+ int err = ERR_get_error ();
1661+ serf__log (LOGLVL_ERROR , LOGCOMP_SSL , __FILE__ , ctx -> config ,
1662+ "OpenSSL store error (%s): %d %d\n" , cert_uri ,
1663+ ERR_GET_LIB (err ), ERR_GET_REASON (err ));
1664+ break ;
1665+ }
1666+
1667+ /* walk the store, what are we working with */
1668+
1669+ while (!OSSL_STORE_eof (store )) {
1670+ info = OSSL_STORE_load (store );
1671+
1672+ if (!info ) {
1673+ break ;
1674+ }
1675+
1676+ type = OSSL_STORE_INFO_get_type (info );
1677+ if (type == OSSL_STORE_INFO_CERT ) {
1678+ X509 * c = OSSL_STORE_INFO_get1_CERT (info );
1679+
1680+ int n , i ;
1681+
1682+ int is_ca = X509_check_ca (c );
1683+
1684+ /* split into leaves and intermediate certs */
1685+ if (is_ca ) {
1686+ sk_X509_push (intermediates , c );
1687+ }
1688+ else {
1689+ sk_X509_push (leaves , c );
1690+ }
1691+
1692+ /* any cert with an issuer matching our requested CAs is also
1693+ * added to the requests list, except for leaf certs which are
1694+ * marked as requested with a flag so we can skip the chain
1695+ * check later. */
1696+ n = sk_X509_NAME_num (requested );
1697+ for (i = 0 ; i < n ; ++ i ) {
1698+ X509_NAME * name = sk_X509_NAME_value (requested , i );
1699+ if (X509_NAME_cmp (name , X509_get_issuer_name (c )) == 0 ) {
1700+ if (is_ca ) {
1701+ X509_STORE_add_cert (requests , c );
1702+ }
1703+ else {
1704+ X509_set_ex_data (c , ssl_x509_ex_data_idx ,
1705+ (void * )1 );
1706+ }
1707+ }
1708+ }
1709+
1710+ } else if (type == OSSL_STORE_INFO_PKEY ) {
1711+ EVP_PKEY * k = OSSL_STORE_INFO_get1_PKEY (info );
1712+
1713+ sk_EVP_PKEY_push (keys , k );
1714+ }
1715+
1716+ OSSL_STORE_INFO_free (info );
1717+ }
1718+
1719+ /* FIXME: openssl error checking goes here */
1720+
1721+ OSSL_STORE_close (store );
1722+
1723+ /* walk the leaf certificates, choose the best one */
1724+
1725+ while ((c = sk_X509_pop (leaves ))) {
1726+
1727+ EVP_PKEY * k = NULL ;
1728+ int i , n , found = 0 ;
1729+
1730+ /* no key, skip */
1731+ n = sk_EVP_PKEY_num (keys );
1732+ for (i = 0 ; i < n ; ++ i ) {
1733+ k = sk_EVP_PKEY_value (keys , i );
1734+ if (X509_check_private_key (c , k )) {
1735+ found = 1 ;
1736+ break ;
1737+ }
1738+ }
1739+ if (!found ) {
1740+ continue ;
1741+ }
1742+
1743+ /* CAs requested? if so, skip non matches, if not, accept all */
1744+ if (sk_X509_NAME_num (requested ) &&
1745+ !X509_get_ex_data (c , ssl_x509_ex_data_idx )) {
1746+ STACK_OF (X509 ) * chain ;
1747+
1748+ chain = X509_build_chain (c , intermediates , requests , 0 , NULL ,
1749+ NULL );
1750+
1751+ if (!chain ) {
1752+ continue ;
1753+ }
1754+
1755+ sk_X509_pop_free (chain , X509_free );
1756+ }
1757+
1758+ /* no best candidate yet? we're in first place */
1759+ if (!* cert ) {
1760+ EVP_PKEY_up_ref (k );
1761+ * cert = c ; /* don't dup, we're returning this */
1762+ * pkey = k ;
1763+ continue ;
1764+ }
1765+
1766+ /* were we issued after the previous best? */
1767+ if (ASN1_TIME_compare (X509_get0_notBefore (* cert ),
1768+ X509_get0_notBefore (c )) < 0 ) {
1769+ X509_free (* cert );
1770+ EVP_PKEY_free (* pkey );
1771+ EVP_PKEY_up_ref (k );
1772+ * cert = c ; /* don't dup, we're returning this */
1773+ * pkey = k ;
1774+ continue ;
1775+ }
1776+
1777+ X509_free (c );
1778+ }
1779+
1780+ break ;
1781+ }
1782+
1783+ sk_X509_pop_free (leaves , X509_free );
1784+ sk_X509_pop_free (intermediates , X509_free );
1785+ sk_EVP_PKEY_pop_free (keys , EVP_PKEY_free );
1786+ X509_STORE_free (requests );
1787+ UI_destroy_method (ui_method );
1788+
1789+ /* we settled on a cert and key, cache it for later */
1790+
1791+ if (* cert && * pkey ) {
1792+
1793+ ctx -> cached_cert = * cert ;
1794+ ctx -> cached_cert_pw = * pkey ;
1795+ if (!retrying_success && ctx -> cert_cache_pool ) {
1796+ const char * c ;
1797+
1798+ c = apr_pstrdup (ctx -> cert_cache_pool , ctx -> cert_uri );
1799+
1800+ apr_pool_userdata_setn (c , "serf:ssl:cert" ,
1801+ apr_pool_cleanup_null ,
1802+ ctx -> cert_cache_pool );
1803+ }
1804+
1805+ if (!retrying_success && ctx -> cert_pw_cache_pool && ctx -> cert_pw ) {
1806+ const char * pw ;
1807+
1808+ pw = apr_pstrdup (ctx -> cert_pw_cache_pool ,
1809+ ctx -> cert_pw );
1810+
1811+ apr_pool_userdata_setn (pw , "serf:ssl:certpw" ,
1812+ apr_pool_cleanup_null ,
1813+ ctx -> cert_pw_cache_pool );
1814+ }
1815+
1816+ return 1 ;
1817+ }
1818+
1819+ #endif
1820+
15501821 while (ctx -> cert_callback ) {
15511822 const char * cert_path ;
15521823 apr_file_t * cert_file ;
15531824 BIO * bio ;
15541825 BIO_METHOD * biom ;
15551826 PKCS12 * p12 ;
15561827 int i ;
1557- int retrying_success = 0 ;
1828+ retrying_success = 0 ;
15581829
15591830 if (ctx -> cert_file_success ) {
15601831 status = APR_SUCCESS ;
@@ -1704,6 +1975,22 @@ void serf_ssl_client_cert_password_set(
17041975}
17051976
17061977
1978+ void serf_ssl_cert_uri_set (
1979+ serf_ssl_context_t * context ,
1980+ serf_ssl_need_cert_uri_t callback ,
1981+ void * data ,
1982+ void * cache_pool )
1983+ {
1984+ context -> cert_uri_callback = callback ;
1985+ context -> cert_uri_userdata = data ;
1986+ context -> cert_cache_pool = cache_pool ;
1987+ if (context -> cert_cache_pool ) {
1988+ apr_pool_userdata_get ((void * * )& context -> cert_uri_success ,
1989+ "serf:ssl:certuri" , cache_pool );
1990+ }
1991+ }
1992+
1993+
17071994void serf_ssl_server_cert_callback_set (
17081995 serf_ssl_context_t * context ,
17091996 serf_ssl_need_server_cert_t callback ,
@@ -1780,6 +2067,7 @@ static serf_ssl_context_t *ssl_init_context(serf_bucket_alloc_t *allocator)
17802067
17812068 ssl_ctx -> cert_callback = NULL ;
17822069 ssl_ctx -> cert_pw_callback = NULL ;
2070+ ssl_ctx -> cert_uri_callback = NULL ;
17832071 ssl_ctx -> server_cert_callback = NULL ;
17842072 ssl_ctx -> server_cert_chain_callback = NULL ;
17852073
0 commit comments