Fossil SCM

Rework the SSL cert exception mechanism so that it remembers the SHA3 hash of the cert that failed to verify, rather than the PEM of the complete cert. Simplify the error prompts. Always verify the cert hash before accepting the exception.

drh 2020-04-27 16:53 trunk
Commit 3c194e2b893134b12156196639c67b0384b672371d5640f8ef0202f70e24d74c
1 file changed +105 -115
+105 -115
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -46,11 +46,15 @@
4646
static int sslIsInit = 0; /* True after global initialization */
4747
static BIO *iBio = 0; /* OpenSSL I/O abstraction */
4848
static char *sslErrMsg = 0; /* Text of most recent OpenSSL error */
4949
static SSL_CTX *sslCtx; /* SSL context */
5050
static SSL *ssl;
51
-
51
+static struct { /* Accept this SSL cert for this session only */
52
+ char *zHost; /* Subject or host name */
53
+ char *zHash; /* SHA3 hash of the cert */
54
+} sException;
55
+static int sslNoCertVerify = 0; /* Do not verify SSL certs */
5256
5357
/*
5458
** Clear the SSL error message
5559
*/
5660
static void ssl_clear_errmsg(void){
@@ -224,10 +228,21 @@
224228
}while(!done);
225229
sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
226230
blob_reset(&reply);
227231
return rc;
228232
}
233
+
234
+/*
235
+** Invoke this routine to disable SSL cert verification. After
236
+** this call is made, any SSL cert that the server provides will
237
+** be accepted. Communication will still be encrypted, but the
238
+** client has no way of knowing whether it is talking to the
239
+** real server or a man-in-the-middle imposter.
240
+*/
241
+int ssl_disable_cert_verification(void){
242
+ sslNoCertVerify = 1;
243
+}
229244
230245
/*
231246
** Open an SSL connection. The identify of the server is determined
232247
** as follows:
233248
**
@@ -237,26 +252,13 @@
237252
**
238253
** Return the number of errors.
239254
*/
240255
int ssl_open(UrlData *pUrlData){
241256
X509 *cert;
242
- int hasSavedCertificate = 0;
243
- int trusted = 0;
244257
unsigned long e;
245258
246259
ssl_global_init();
247
-
248
- /* Get certificate for current server from global config and
249
- * (if we have it in config) add it to certificate store.
250
- */
251
- cert = ssl_get_certificate(pUrlData, &trusted);
252
- if ( cert!=NULL ){
253
- X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
254
- X509_free(cert);
255
- hasSavedCertificate = 1;
256
- }
257
-
258260
if( pUrlData->useProxy ){
259261
int rc;
260262
char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
261263
BIO *sBio = BIO_new_connect(connStr);
262264
free(connStr);
@@ -326,70 +328,65 @@
326328
ssl_set_errmsg("No SSL certificate was presented by the peer");
327329
ssl_close();
328330
return 1;
329331
}
330332
331
- if( trusted<=0 && (e = SSL_get_verify_result(ssl)) != X509_V_OK ){
333
+ if( !sslNoCertVerify && SSL_get_verify_result(ssl)!=X509_V_OK ){
332334
char *desc, *prompt;
333
- const char *warning = "";
334335
Blob ans;
335336
char cReply;
336337
BIO *mem;
337338
unsigned char md[32];
338
- unsigned int mdLength = 31;
339
-
340
- mem = BIO_new(BIO_s_mem());
341
- X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE);
342
- BIO_puts(mem, "\n\nIssued By:\n\n");
343
- X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE);
344
- BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n ");
345
- if(X509_digest(cert, EVP_sha1(), md, &mdLength)){
346
- int j;
347
- for( j = 0; j < mdLength; ++j ) {
348
- BIO_printf(mem, " %02x", md[j]);
349
- }
350
- }
351
- BIO_write(mem, "", 1); /* nul-terminate mem buffer */
352
- BIO_get_mem_data(mem, &desc);
353
-
354
- if( hasSavedCertificate ){
355
- warning = "WARNING: Certificate doesn't match the "
356
- "saved certificate for this host!";
357
- }
358
- prompt = mprintf("\nSSL verification failed: %s\n"
359
- "Certificate received: \n\n%s\n\n%s\n"
360
- "Either:\n"
361
- " * verify the certificate is correct using the "
362
- "SHA1 fingerprint above\n"
363
- " * use the global ssl-ca-location setting to specify your CA root\n"
364
- " certificates list\n\n"
365
- "If you are not expecting this message, answer no and "
366
- "contact your server\nadministrator.\n\n"
367
- "Accept certificate for host %s (a=always/y/N)? ",
368
- X509_verify_cert_error_string(e), desc, warning,
369
- pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
370
- BIO_free(mem);
371
-
372
- prompt_user(prompt, &ans);
373
- free(prompt);
374
- cReply = blob_str(&ans)[0];
375
- blob_reset(&ans);
376
- if( cReply!='y' && cReply!='Y' && cReply!='a' && cReply!='A') {
377
- X509_free(cert);
378
- ssl_set_errmsg("SSL certificate declined");
379
- ssl_close();
380
- return 1;
381
- }
382
- if( cReply=='a' || cReply=='A') {
383
- if ( trusted==0 ){
384
- prompt_user("\nSave this certificate as fully trusted (a=always/N)? ",
385
- &ans);
386
- cReply = blob_str(&ans)[0];
387
- trusted = ( cReply=='a' || cReply=='A' );
388
- blob_reset(&ans);
389
- }
390
- ssl_save_certificate(pUrlData, cert, trusted);
339
+ char zHash[32*2+1];
340
+ unsigned int mdLength = (int)sizeof(md);
341
+
342
+ memset(md, 0, sizeof(md));
343
+ zHash[0] = 0;
344
+ if( X509_digest(cert, EVP_sha3_256(), md, &mdLength) ){
345
+ int j;
346
+ for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
347
+ zHash[j*2] = "0123456789abcdef"[md[j]>>4];
348
+ zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
349
+ }
350
+ zHash[j*2] = 0;
351
+ }
352
+
353
+ if( ssl_certificate_exception_exists(pUrlData, zHash) ){
354
+ /* Ignore the failure because an exception exists */
355
+ ssl_one_time_exception(pUrlData, zHash);
356
+ }else{
357
+ /* Tell the user about the failure and ask what to do */
358
+ mem = BIO_new(BIO_s_mem());
359
+ BIO_puts(mem, " subject: ");
360
+ X509_NAME_print_ex(mem, X509_get_subject_name(cert), 0, XN_FLAG_ONELINE);
361
+ BIO_puts(mem, "\n issuer: ");
362
+ X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 0, XN_FLAG_ONELINE);
363
+ BIO_printf(mem, "\n sha256: %s", zHash);
364
+ BIO_get_mem_data(mem, &desc);
365
+
366
+ prompt = mprintf("Unable to verify SSL cert from %s\n%s\n"
367
+ "accept this cert and continue (y/N)? ",
368
+ pUrlData->name, desc);
369
+ BIO_free(mem);
370
+
371
+ prompt_user(prompt, &ans);
372
+ free(prompt);
373
+ cReply = blob_str(&ans)[0];
374
+ blob_reset(&ans);
375
+ if( cReply!='y' && cReply!='Y' ){
376
+ X509_free(cert);
377
+ ssl_set_errmsg("SSL cert declined");
378
+ ssl_close();
379
+ return 1;
380
+ }
381
+ ssl_one_time_exception(pUrlData, zHash);
382
+ prompt_user("remember this exception (y/N)? ", &ans);
383
+ cReply = blob_str(&ans)[0];
384
+ if( cReply=='y' || cReply=='Y') {
385
+ ssl_remember_certificate_exception(pUrlData, zHash);
386
+ }
387
+ blob_reset(&ans);
391388
}
392389
}
393390
394391
/* Set the Global.zIpAddr variable to the server we are talking to.
395392
** This is used to populate the ipaddr column of the rcvfrom table,
@@ -416,60 +413,53 @@
416413
X509_free(cert);
417414
return 0;
418415
}
419416
420417
/*
421
-** Save certificate to global config.
422
-*/
423
-void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
424
- BIO *mem;
425
- char *zCert, *zHost;
426
-
427
- mem = BIO_new(BIO_s_mem());
428
- PEM_write_bio_X509(mem, cert);
429
- BIO_write(mem, "", 1); /* nul-terminate mem buffer */
430
- BIO_get_mem_data(mem, &zCert);
431
- zHost = mprintf("cert:%s",
432
- pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
433
- db_set(zHost, zCert, 1);
434
- free(zHost);
435
- zHost = mprintf("trusted:%s",
436
- pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
437
- db_set_int(zHost, trusted, 1);
438
- free(zHost);
439
- BIO_free(mem);
418
+** Remember that the cert with the given hash is a acceptable for
419
+** use with pUrlData->name.
420
+*/
421
+LOCAL void ssl_remember_certificate_exception(
422
+ UrlData *pUrlData,
423
+ const char *zHash
424
+){
425
+ char *zName = mprintf("cert:%s", pUrlData->name);
426
+ db_set(zName, zHash, 1);
427
+ fossil_free(zName);
428
+}
429
+
430
+/*
431
+** Return true if the there exists a certificate exception for
432
+** pUrlData->name that matches the hash.
433
+*/
434
+LOCAL int ssl_certificate_exception_exists(
435
+ UrlData *pUrlData,
436
+ const char *zHash
437
+){
438
+ char *zName, *zValue;
439
+ if( fossil_strcmp(sException.zHost,pUrlData->name)==0
440
+ && fossil_strcmp(sException.zHash,zHash)==0
441
+ ){
442
+ return 1;
443
+ }
444
+ zName = mprintf("cert:%s", pUrlData->name);
445
+ zValue = db_get(zName,0);
446
+ fossil_free(zName);
447
+ return zValue!=0 && strcmp(zHash,zValue)==0;
440448
}
441449
442450
/*
443
-** Get certificate for pUrlData->urlName from global config.
444
-** Return NULL if no certificate found.
451
+** Remember zHash as an acceptable certificate for this session only.
445452
*/
446
-X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
447
- char *zHost, *zCert;
448
- BIO *mem;
449
- X509 *cert;
450
-
451
- zHost = mprintf("cert:%s",
452
- pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
453
- zCert = db_get(zHost, NULL);
454
- free(zHost);
455
- if ( zCert==NULL )
456
- return NULL;
457
-
458
- if ( pTrusted!=0 ){
459
- zHost = mprintf("trusted:%s",
460
- pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
461
- *pTrusted = db_get_int(zHost, 0);
462
- free(zHost);
463
- }
464
-
465
- mem = BIO_new(BIO_s_mem());
466
- BIO_puts(mem, zCert);
467
- cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
468
- free(zCert);
469
- BIO_free(mem);
470
- return cert;
453
+LOCAL int ssl_one_time_exception(
454
+ UrlData *pUrlData,
455
+ const char *zHash
456
+){
457
+ fossil_free(sException.zHost);
458
+ sException.zHost = fossil_strdup(pUrlData->name);
459
+ fossil_free(sException.zHash);
460
+ sException.zHost = fossil_strdup(zHash);
471461
}
472462
473463
/*
474464
** Send content out over the SSL connection.
475465
*/
476466
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -46,11 +46,15 @@
46 static int sslIsInit = 0; /* True after global initialization */
47 static BIO *iBio = 0; /* OpenSSL I/O abstraction */
48 static char *sslErrMsg = 0; /* Text of most recent OpenSSL error */
49 static SSL_CTX *sslCtx; /* SSL context */
50 static SSL *ssl;
51
 
 
 
 
52
53 /*
54 ** Clear the SSL error message
55 */
56 static void ssl_clear_errmsg(void){
@@ -224,10 +228,21 @@
224 }while(!done);
225 sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
226 blob_reset(&reply);
227 return rc;
228 }
 
 
 
 
 
 
 
 
 
 
 
229
230 /*
231 ** Open an SSL connection. The identify of the server is determined
232 ** as follows:
233 **
@@ -237,26 +252,13 @@
237 **
238 ** Return the number of errors.
239 */
240 int ssl_open(UrlData *pUrlData){
241 X509 *cert;
242 int hasSavedCertificate = 0;
243 int trusted = 0;
244 unsigned long e;
245
246 ssl_global_init();
247
248 /* Get certificate for current server from global config and
249 * (if we have it in config) add it to certificate store.
250 */
251 cert = ssl_get_certificate(pUrlData, &trusted);
252 if ( cert!=NULL ){
253 X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
254 X509_free(cert);
255 hasSavedCertificate = 1;
256 }
257
258 if( pUrlData->useProxy ){
259 int rc;
260 char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
261 BIO *sBio = BIO_new_connect(connStr);
262 free(connStr);
@@ -326,70 +328,65 @@
326 ssl_set_errmsg("No SSL certificate was presented by the peer");
327 ssl_close();
328 return 1;
329 }
330
331 if( trusted<=0 && (e = SSL_get_verify_result(ssl)) != X509_V_OK ){
332 char *desc, *prompt;
333 const char *warning = "";
334 Blob ans;
335 char cReply;
336 BIO *mem;
337 unsigned char md[32];
338 unsigned int mdLength = 31;
339
340 mem = BIO_new(BIO_s_mem());
341 X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE);
342 BIO_puts(mem, "\n\nIssued By:\n\n");
343 X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE);
344 BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n ");
345 if(X509_digest(cert, EVP_sha1(), md, &mdLength)){
346 int j;
347 for( j = 0; j < mdLength; ++j ) {
348 BIO_printf(mem, " %02x", md[j]);
349 }
350 }
351 BIO_write(mem, "", 1); /* nul-terminate mem buffer */
352 BIO_get_mem_data(mem, &desc);
353
354 if( hasSavedCertificate ){
355 warning = "WARNING: Certificate doesn't match the "
356 "saved certificate for this host!";
357 }
358 prompt = mprintf("\nSSL verification failed: %s\n"
359 "Certificate received: \n\n%s\n\n%s\n"
360 "Either:\n"
361 " * verify the certificate is correct using the "
362 "SHA1 fingerprint above\n"
363 " * use the global ssl-ca-location setting to specify your CA root\n"
364 " certificates list\n\n"
365 "If you are not expecting this message, answer no and "
366 "contact your server\nadministrator.\n\n"
367 "Accept certificate for host %s (a=always/y/N)? ",
368 X509_verify_cert_error_string(e), desc, warning,
369 pUrlData->useProxy?pUrlData->hostname:pUrlData->name);
370 BIO_free(mem);
371
372 prompt_user(prompt, &ans);
373 free(prompt);
374 cReply = blob_str(&ans)[0];
375 blob_reset(&ans);
376 if( cReply!='y' && cReply!='Y' && cReply!='a' && cReply!='A') {
377 X509_free(cert);
378 ssl_set_errmsg("SSL certificate declined");
379 ssl_close();
380 return 1;
381 }
382 if( cReply=='a' || cReply=='A') {
383 if ( trusted==0 ){
384 prompt_user("\nSave this certificate as fully trusted (a=always/N)? ",
385 &ans);
386 cReply = blob_str(&ans)[0];
387 trusted = ( cReply=='a' || cReply=='A' );
388 blob_reset(&ans);
389 }
390 ssl_save_certificate(pUrlData, cert, trusted);
391 }
392 }
393
394 /* Set the Global.zIpAddr variable to the server we are talking to.
395 ** This is used to populate the ipaddr column of the rcvfrom table,
@@ -416,60 +413,53 @@
416 X509_free(cert);
417 return 0;
418 }
419
420 /*
421 ** Save certificate to global config.
422 */
423 void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
424 BIO *mem;
425 char *zCert, *zHost;
426
427 mem = BIO_new(BIO_s_mem());
428 PEM_write_bio_X509(mem, cert);
429 BIO_write(mem, "", 1); /* nul-terminate mem buffer */
430 BIO_get_mem_data(mem, &zCert);
431 zHost = mprintf("cert:%s",
432 pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
433 db_set(zHost, zCert, 1);
434 free(zHost);
435 zHost = mprintf("trusted:%s",
436 pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
437 db_set_int(zHost, trusted, 1);
438 free(zHost);
439 BIO_free(mem);
 
 
 
 
 
 
 
 
 
 
 
440 }
441
442 /*
443 ** Get certificate for pUrlData->urlName from global config.
444 ** Return NULL if no certificate found.
445 */
446 X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
447 char *zHost, *zCert;
448 BIO *mem;
449 X509 *cert;
450
451 zHost = mprintf("cert:%s",
452 pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
453 zCert = db_get(zHost, NULL);
454 free(zHost);
455 if ( zCert==NULL )
456 return NULL;
457
458 if ( pTrusted!=0 ){
459 zHost = mprintf("trusted:%s",
460 pUrlData->useProxy ? pUrlData->hostname : pUrlData->name);
461 *pTrusted = db_get_int(zHost, 0);
462 free(zHost);
463 }
464
465 mem = BIO_new(BIO_s_mem());
466 BIO_puts(mem, zCert);
467 cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
468 free(zCert);
469 BIO_free(mem);
470 return cert;
471 }
472
473 /*
474 ** Send content out over the SSL connection.
475 */
476
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -46,11 +46,15 @@
46 static int sslIsInit = 0; /* True after global initialization */
47 static BIO *iBio = 0; /* OpenSSL I/O abstraction */
48 static char *sslErrMsg = 0; /* Text of most recent OpenSSL error */
49 static SSL_CTX *sslCtx; /* SSL context */
50 static SSL *ssl;
51 static struct { /* Accept this SSL cert for this session only */
52 char *zHost; /* Subject or host name */
53 char *zHash; /* SHA3 hash of the cert */
54 } sException;
55 static int sslNoCertVerify = 0; /* Do not verify SSL certs */
56
57 /*
58 ** Clear the SSL error message
59 */
60 static void ssl_clear_errmsg(void){
@@ -224,10 +228,21 @@
228 }while(!done);
229 sscanf(bbuf, "HTTP/1.%d %d", &httpVerMin, &rc);
230 blob_reset(&reply);
231 return rc;
232 }
233
234 /*
235 ** Invoke this routine to disable SSL cert verification. After
236 ** this call is made, any SSL cert that the server provides will
237 ** be accepted. Communication will still be encrypted, but the
238 ** client has no way of knowing whether it is talking to the
239 ** real server or a man-in-the-middle imposter.
240 */
241 int ssl_disable_cert_verification(void){
242 sslNoCertVerify = 1;
243 }
244
245 /*
246 ** Open an SSL connection. The identify of the server is determined
247 ** as follows:
248 **
@@ -237,26 +252,13 @@
252 **
253 ** Return the number of errors.
254 */
255 int ssl_open(UrlData *pUrlData){
256 X509 *cert;
 
 
257 unsigned long e;
258
259 ssl_global_init();
 
 
 
 
 
 
 
 
 
 
 
260 if( pUrlData->useProxy ){
261 int rc;
262 char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
263 BIO *sBio = BIO_new_connect(connStr);
264 free(connStr);
@@ -326,70 +328,65 @@
328 ssl_set_errmsg("No SSL certificate was presented by the peer");
329 ssl_close();
330 return 1;
331 }
332
333 if( !sslNoCertVerify && SSL_get_verify_result(ssl)!=X509_V_OK ){
334 char *desc, *prompt;
 
335 Blob ans;
336 char cReply;
337 BIO *mem;
338 unsigned char md[32];
339 char zHash[32*2+1];
340 unsigned int mdLength = (int)sizeof(md);
341
342 memset(md, 0, sizeof(md));
343 zHash[0] = 0;
344 if( X509_digest(cert, EVP_sha3_256(), md, &mdLength) ){
345 int j;
346 for(j=0; j<mdLength && j*2+1<sizeof(zHash); ++j){
347 zHash[j*2] = "0123456789abcdef"[md[j]>>4];
348 zHash[j*2+1] = "0123456789abcdef"[md[j]&0xf];
349 }
350 zHash[j*2] = 0;
351 }
352
353 if( ssl_certificate_exception_exists(pUrlData, zHash) ){
354 /* Ignore the failure because an exception exists */
355 ssl_one_time_exception(pUrlData, zHash);
356 }else{
357 /* Tell the user about the failure and ask what to do */
358 mem = BIO_new(BIO_s_mem());
359 BIO_puts(mem, " subject: ");
360 X509_NAME_print_ex(mem, X509_get_subject_name(cert), 0, XN_FLAG_ONELINE);
361 BIO_puts(mem, "\n issuer: ");
362 X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 0, XN_FLAG_ONELINE);
363 BIO_printf(mem, "\n sha256: %s", zHash);
364 BIO_get_mem_data(mem, &desc);
365
366 prompt = mprintf("Unable to verify SSL cert from %s\n%s\n"
367 "accept this cert and continue (y/N)? ",
368 pUrlData->name, desc);
369 BIO_free(mem);
370
371 prompt_user(prompt, &ans);
372 free(prompt);
373 cReply = blob_str(&ans)[0];
374 blob_reset(&ans);
375 if( cReply!='y' && cReply!='Y' ){
376 X509_free(cert);
377 ssl_set_errmsg("SSL cert declined");
378 ssl_close();
379 return 1;
380 }
381 ssl_one_time_exception(pUrlData, zHash);
382 prompt_user("remember this exception (y/N)? ", &ans);
383 cReply = blob_str(&ans)[0];
384 if( cReply=='y' || cReply=='Y') {
385 ssl_remember_certificate_exception(pUrlData, zHash);
386 }
387 blob_reset(&ans);
 
 
 
 
388 }
389 }
390
391 /* Set the Global.zIpAddr variable to the server we are talking to.
392 ** This is used to populate the ipaddr column of the rcvfrom table,
@@ -416,60 +413,53 @@
413 X509_free(cert);
414 return 0;
415 }
416
417 /*
418 ** Remember that the cert with the given hash is a acceptable for
419 ** use with pUrlData->name.
420 */
421 LOCAL void ssl_remember_certificate_exception(
422 UrlData *pUrlData,
423 const char *zHash
424 ){
425 char *zName = mprintf("cert:%s", pUrlData->name);
426 db_set(zName, zHash, 1);
427 fossil_free(zName);
428 }
429
430 /*
431 ** Return true if the there exists a certificate exception for
432 ** pUrlData->name that matches the hash.
433 */
434 LOCAL int ssl_certificate_exception_exists(
435 UrlData *pUrlData,
436 const char *zHash
437 ){
438 char *zName, *zValue;
439 if( fossil_strcmp(sException.zHost,pUrlData->name)==0
440 && fossil_strcmp(sException.zHash,zHash)==0
441 ){
442 return 1;
443 }
444 zName = mprintf("cert:%s", pUrlData->name);
445 zValue = db_get(zName,0);
446 fossil_free(zName);
447 return zValue!=0 && strcmp(zHash,zValue)==0;
448 }
449
450 /*
451 ** Remember zHash as an acceptable certificate for this session only.
 
452 */
453 LOCAL int ssl_one_time_exception(
454 UrlData *pUrlData,
455 const char *zHash
456 ){
457 fossil_free(sException.zHost);
458 sException.zHost = fossil_strdup(pUrlData->name);
459 fossil_free(sException.zHash);
460 sException.zHost = fossil_strdup(zHash);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
461 }
462
463 /*
464 ** Send content out over the SSL connection.
465 */
466

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button