Fossil SCM
Use the dedicated certs table for server certificate cache. Only attempt to use client certificate if one was actually specified for a cert bundle. Assume client key is in same file as certificate if one wasn't explicitly specified.
Commit
c44bb083e9a10219ad8f5bc1b0ef00238abc87d0
Parent
cff102fe8594944…
1 file changed
+37
-22
+37
-22
| --- src/http_ssl.c | ||
| +++ src/http_ssl.c | ||
| @@ -238,39 +238,45 @@ | ||
| 238 | 238 | X509_free(cert); |
| 239 | 239 | return 0; |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | 242 | /* |
| 243 | -** Save certificate to global config. | |
| 243 | +** Save certificate to global certificate/key store. | |
| 244 | 244 | */ |
| 245 | 245 | void ssl_save_certificate(X509 *cert){ |
| 246 | 246 | BIO *mem; |
| 247 | - char *zCert, *zHost; | |
| 247 | + char *zCert; | |
| 248 | 248 | |
| 249 | 249 | mem = BIO_new(BIO_s_mem()); |
| 250 | 250 | PEM_write_bio_X509(mem, cert); |
| 251 | 251 | BIO_write(mem, "", 1); // null-terminate mem buffer |
| 252 | 252 | BIO_get_mem_data(mem, &zCert); |
| 253 | - zHost = mprintf("cert:%s", g.urlName); | |
| 254 | - db_set(zHost, zCert, 1); | |
| 255 | - free(zHost); | |
| 253 | + db_swap_connections(); | |
| 254 | + create_cert_table_if_not_exist(); | |
| 255 | + db_begin_transaction(); | |
| 256 | + db_multi_exec("REPLACE INTO certs(name,type,filepath) " | |
| 257 | + "VALUES(%Q,'scert',%Q)", g.urlName, zCert); | |
| 258 | + db_end_transaction(0); | |
| 259 | + db_swap_connections(); | |
| 256 | 260 | BIO_free(mem); |
| 257 | 261 | } |
| 258 | 262 | |
| 259 | 263 | /* |
| 260 | -** Get certificate for g.urlName from global config. | |
| 264 | +** Get certificate for g.urlName from global certificate/key store. | |
| 261 | 265 | ** Return NULL if no certificate found. |
| 262 | 266 | */ |
| 263 | 267 | X509 *ssl_get_certificate(void){ |
| 264 | - char *zHost, *zCert; | |
| 268 | + char *zCert; | |
| 265 | 269 | BIO *mem; |
| 266 | 270 | X509 *cert; |
| 267 | 271 | |
| 268 | - zHost = mprintf("cert:%s", g.urlName); | |
| 269 | - zCert = db_get(zHost, NULL); | |
| 270 | - free(zHost); | |
| 271 | - if ( zCert==NULL ) | |
| 272 | + db_swap_connections(); | |
| 273 | + create_cert_table_if_not_exist(); | |
| 274 | + zCert = db_text(0, "SELECT filepath FROM certs WHERE name=%Q" | |
| 275 | + " AND type='scert'", g.urlName); | |
| 276 | + db_swap_connections(); | |
| 277 | + if( zCert==NULL ) | |
| 272 | 278 | return NULL; |
| 273 | 279 | mem = BIO_new(BIO_s_mem()); |
| 274 | 280 | BIO_puts(mem, zCert); |
| 275 | 281 | cert = PEM_read_bio_X509(mem, NULL, 0, NULL); |
| 276 | 282 | free(zCert); |
| @@ -331,11 +337,11 @@ | ||
| 331 | 337 | free(zName); |
| 332 | 338 | zBundleName = strdup(g.urlCertBundle); |
| 333 | 339 | }else{ |
| 334 | 340 | db_swap_connections(); |
| 335 | 341 | zBundleName = db_text(0, "SELECT value FROM global_config" |
| 336 | - " WHERE name='certbundle:%q'", g.urlName); | |
| 342 | + " WHERE name='certbundle:%q'", g.urlName); | |
| 337 | 343 | db_swap_connections(); |
| 338 | 344 | } |
| 339 | 345 | if( !zBundleName ){ |
| 340 | 346 | /* No cert bundle specified on command line or found cached for URL */ |
| 341 | 347 | return; |
| @@ -366,23 +372,32 @@ | ||
| 366 | 372 | " AND type='ckey'", zBundleName); |
| 367 | 373 | certfile = db_text(0, "SELECT filepath FROM certs WHERE name=%Q" |
| 368 | 374 | " AND type='ccert'", zBundleName); |
| 369 | 375 | db_swap_connections(); |
| 370 | 376 | |
| 371 | - if( SSL_CTX_use_certificate_file(sslCtx, certfile, SSL_FILETYPE_PEM)<=0 ){ | |
| 372 | - fossil_fatal("SSL: Unable to open client certificate in %s.", certfile); | |
| 373 | - } | |
| 374 | - if( SSL_CTX_use_PrivateKey_file(sslCtx, keyfile, SSL_FILETYPE_PEM)<=0 ){ | |
| 375 | - fossil_fatal("SSL: Unable to open client key in %s.", keyfile); | |
| 377 | + if( certfile ){ | |
| 378 | + /* If a client certificate is explicitly specified, but a key is not, then | |
| 379 | + ** assume the key is in the same file as the certificate. | |
| 380 | + */ | |
| 381 | + if( !keyfile ){ | |
| 382 | + keyfile = certfile; | |
| 383 | + } | |
| 384 | + if( SSL_CTX_use_certificate_file(sslCtx, certfile, SSL_FILETYPE_PEM)<=0 ){ | |
| 385 | + fossil_fatal("SSL: Unable to open client certificate in %s.", certfile); | |
| 386 | + } | |
| 387 | + if( SSL_CTX_use_PrivateKey_file(sslCtx, keyfile, SSL_FILETYPE_PEM)<=0 ){ | |
| 388 | + fossil_fatal("SSL: Unable to open client key in %s.", keyfile); | |
| 389 | + } | |
| 390 | + if( certfile && keyfile && !SSL_CTX_check_private_key(sslCtx) ){ | |
| 391 | + fossil_fatal("SSL: Private key does not match the certificate public " | |
| 392 | + "key."); | |
| 393 | + } | |
| 376 | 394 | } |
| 377 | 395 | |
| 378 | - if( !SSL_CTX_check_private_key(sslCtx) ){ | |
| 379 | - fossil_fatal("SSL: Private key does not match the certificate public " | |
| 380 | - "key."); | |
| 396 | + if( keyfile != certfile ){ | |
| 397 | + free(keyfile); | |
| 381 | 398 | } |
| 382 | - | |
| 383 | - free(keyfile); | |
| 384 | 399 | free(certfile); |
| 385 | 400 | free(capath); |
| 386 | 401 | free(cafile); |
| 387 | 402 | } |
| 388 | 403 | #endif /* FOSSIL_ENABLE_SSL */ |
| 389 | 404 |
| --- src/http_ssl.c | |
| +++ src/http_ssl.c | |
| @@ -238,39 +238,45 @@ | |
| 238 | X509_free(cert); |
| 239 | return 0; |
| 240 | } |
| 241 | |
| 242 | /* |
| 243 | ** Save certificate to global config. |
| 244 | */ |
| 245 | void ssl_save_certificate(X509 *cert){ |
| 246 | BIO *mem; |
| 247 | char *zCert, *zHost; |
| 248 | |
| 249 | mem = BIO_new(BIO_s_mem()); |
| 250 | PEM_write_bio_X509(mem, cert); |
| 251 | BIO_write(mem, "", 1); // null-terminate mem buffer |
| 252 | BIO_get_mem_data(mem, &zCert); |
| 253 | zHost = mprintf("cert:%s", g.urlName); |
| 254 | db_set(zHost, zCert, 1); |
| 255 | free(zHost); |
| 256 | BIO_free(mem); |
| 257 | } |
| 258 | |
| 259 | /* |
| 260 | ** Get certificate for g.urlName from global config. |
| 261 | ** Return NULL if no certificate found. |
| 262 | */ |
| 263 | X509 *ssl_get_certificate(void){ |
| 264 | char *zHost, *zCert; |
| 265 | BIO *mem; |
| 266 | X509 *cert; |
| 267 | |
| 268 | zHost = mprintf("cert:%s", g.urlName); |
| 269 | zCert = db_get(zHost, NULL); |
| 270 | free(zHost); |
| 271 | if ( zCert==NULL ) |
| 272 | return NULL; |
| 273 | mem = BIO_new(BIO_s_mem()); |
| 274 | BIO_puts(mem, zCert); |
| 275 | cert = PEM_read_bio_X509(mem, NULL, 0, NULL); |
| 276 | free(zCert); |
| @@ -331,11 +337,11 @@ | |
| 331 | free(zName); |
| 332 | zBundleName = strdup(g.urlCertBundle); |
| 333 | }else{ |
| 334 | db_swap_connections(); |
| 335 | zBundleName = db_text(0, "SELECT value FROM global_config" |
| 336 | " WHERE name='certbundle:%q'", g.urlName); |
| 337 | db_swap_connections(); |
| 338 | } |
| 339 | if( !zBundleName ){ |
| 340 | /* No cert bundle specified on command line or found cached for URL */ |
| 341 | return; |
| @@ -366,23 +372,32 @@ | |
| 366 | " AND type='ckey'", zBundleName); |
| 367 | certfile = db_text(0, "SELECT filepath FROM certs WHERE name=%Q" |
| 368 | " AND type='ccert'", zBundleName); |
| 369 | db_swap_connections(); |
| 370 | |
| 371 | if( SSL_CTX_use_certificate_file(sslCtx, certfile, SSL_FILETYPE_PEM)<=0 ){ |
| 372 | fossil_fatal("SSL: Unable to open client certificate in %s.", certfile); |
| 373 | } |
| 374 | if( SSL_CTX_use_PrivateKey_file(sslCtx, keyfile, SSL_FILETYPE_PEM)<=0 ){ |
| 375 | fossil_fatal("SSL: Unable to open client key in %s.", keyfile); |
| 376 | } |
| 377 | |
| 378 | if( !SSL_CTX_check_private_key(sslCtx) ){ |
| 379 | fossil_fatal("SSL: Private key does not match the certificate public " |
| 380 | "key."); |
| 381 | } |
| 382 | |
| 383 | free(keyfile); |
| 384 | free(certfile); |
| 385 | free(capath); |
| 386 | free(cafile); |
| 387 | } |
| 388 | #endif /* FOSSIL_ENABLE_SSL */ |
| 389 |
| --- src/http_ssl.c | |
| +++ src/http_ssl.c | |
| @@ -238,39 +238,45 @@ | |
| 238 | X509_free(cert); |
| 239 | return 0; |
| 240 | } |
| 241 | |
| 242 | /* |
| 243 | ** Save certificate to global certificate/key store. |
| 244 | */ |
| 245 | void ssl_save_certificate(X509 *cert){ |
| 246 | BIO *mem; |
| 247 | char *zCert; |
| 248 | |
| 249 | mem = BIO_new(BIO_s_mem()); |
| 250 | PEM_write_bio_X509(mem, cert); |
| 251 | BIO_write(mem, "", 1); // null-terminate mem buffer |
| 252 | BIO_get_mem_data(mem, &zCert); |
| 253 | db_swap_connections(); |
| 254 | create_cert_table_if_not_exist(); |
| 255 | db_begin_transaction(); |
| 256 | db_multi_exec("REPLACE INTO certs(name,type,filepath) " |
| 257 | "VALUES(%Q,'scert',%Q)", g.urlName, zCert); |
| 258 | db_end_transaction(0); |
| 259 | db_swap_connections(); |
| 260 | BIO_free(mem); |
| 261 | } |
| 262 | |
| 263 | /* |
| 264 | ** Get certificate for g.urlName from global certificate/key store. |
| 265 | ** Return NULL if no certificate found. |
| 266 | */ |
| 267 | X509 *ssl_get_certificate(void){ |
| 268 | char *zCert; |
| 269 | BIO *mem; |
| 270 | X509 *cert; |
| 271 | |
| 272 | db_swap_connections(); |
| 273 | create_cert_table_if_not_exist(); |
| 274 | zCert = db_text(0, "SELECT filepath FROM certs WHERE name=%Q" |
| 275 | " AND type='scert'", g.urlName); |
| 276 | db_swap_connections(); |
| 277 | if( zCert==NULL ) |
| 278 | return NULL; |
| 279 | mem = BIO_new(BIO_s_mem()); |
| 280 | BIO_puts(mem, zCert); |
| 281 | cert = PEM_read_bio_X509(mem, NULL, 0, NULL); |
| 282 | free(zCert); |
| @@ -331,11 +337,11 @@ | |
| 337 | free(zName); |
| 338 | zBundleName = strdup(g.urlCertBundle); |
| 339 | }else{ |
| 340 | db_swap_connections(); |
| 341 | zBundleName = db_text(0, "SELECT value FROM global_config" |
| 342 | " WHERE name='certbundle:%q'", g.urlName); |
| 343 | db_swap_connections(); |
| 344 | } |
| 345 | if( !zBundleName ){ |
| 346 | /* No cert bundle specified on command line or found cached for URL */ |
| 347 | return; |
| @@ -366,23 +372,32 @@ | |
| 372 | " AND type='ckey'", zBundleName); |
| 373 | certfile = db_text(0, "SELECT filepath FROM certs WHERE name=%Q" |
| 374 | " AND type='ccert'", zBundleName); |
| 375 | db_swap_connections(); |
| 376 | |
| 377 | if( certfile ){ |
| 378 | /* If a client certificate is explicitly specified, but a key is not, then |
| 379 | ** assume the key is in the same file as the certificate. |
| 380 | */ |
| 381 | if( !keyfile ){ |
| 382 | keyfile = certfile; |
| 383 | } |
| 384 | if( SSL_CTX_use_certificate_file(sslCtx, certfile, SSL_FILETYPE_PEM)<=0 ){ |
| 385 | fossil_fatal("SSL: Unable to open client certificate in %s.", certfile); |
| 386 | } |
| 387 | if( SSL_CTX_use_PrivateKey_file(sslCtx, keyfile, SSL_FILETYPE_PEM)<=0 ){ |
| 388 | fossil_fatal("SSL: Unable to open client key in %s.", keyfile); |
| 389 | } |
| 390 | if( certfile && keyfile && !SSL_CTX_check_private_key(sslCtx) ){ |
| 391 | fossil_fatal("SSL: Private key does not match the certificate public " |
| 392 | "key."); |
| 393 | } |
| 394 | } |
| 395 | |
| 396 | if( keyfile != certfile ){ |
| 397 | free(keyfile); |
| 398 | } |
| 399 | free(certfile); |
| 400 | free(capath); |
| 401 | free(cafile); |
| 402 | } |
| 403 | #endif /* FOSSIL_ENABLE_SSL */ |
| 404 |