Lines 202-207
struct serf_ssl_certificate_t {
Link Here
|
202 |
}; |
202 |
}; |
203 |
|
203 |
|
204 |
static void disable_compression(serf_ssl_context_t *ssl_ctx); |
204 |
static void disable_compression(serf_ssl_context_t *ssl_ctx); |
|
|
205 |
static char * |
206 |
pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool); |
205 |
|
207 |
|
206 |
#if SSL_VERBOSE |
208 |
#if SSL_VERBOSE |
207 |
/* Log all ssl alerts that we receive from the server. */ |
209 |
/* Log all ssl alerts that we receive from the server. */ |
Lines 427-432
static BIO_METHOD bio_file_method = {
Link Here
|
427 |
#endif |
429 |
#endif |
428 |
}; |
430 |
}; |
429 |
|
431 |
|
|
|
432 |
typedef enum san_copy_t { |
433 |
EscapeNulAndCopy = 0, |
434 |
ErrorOnNul = 1, |
435 |
} san_copy_t; |
436 |
|
437 |
|
438 |
static apr_status_t |
439 |
get_subject_alt_names(apr_array_header_t **san_arr, X509 *ssl_cert, |
440 |
san_copy_t copy_action, apr_pool_t *pool) |
441 |
{ |
442 |
STACK_OF(GENERAL_NAME) *names; |
443 |
|
444 |
/* assert: copy_action == ErrorOnNul || (san_arr && pool) */ |
445 |
|
446 |
if (san_arr) { |
447 |
*san_arr = NULL; |
448 |
} |
449 |
|
450 |
/* Get subjectAltNames */ |
451 |
names = X509_get_ext_d2i(ssl_cert, NID_subject_alt_name, NULL, NULL); |
452 |
if (names) { |
453 |
int names_count = sk_GENERAL_NAME_num(names); |
454 |
int name_idx; |
455 |
|
456 |
if (san_arr) |
457 |
*san_arr = apr_array_make(pool, names_count, sizeof(char*)); |
458 |
for (name_idx = 0; name_idx < names_count; name_idx++) { |
459 |
char *p = NULL; |
460 |
GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, name_idx); |
461 |
|
462 |
switch (nm->type) { |
463 |
case GEN_DNS: |
464 |
if (copy_action == ErrorOnNul && |
465 |
strlen(nm->d.ia5->data) != nm->d.ia5->length) |
466 |
return SERF_ERROR_SSL_CERT_FAILED; |
467 |
if (san_arr && *san_arr) |
468 |
p = pstrdup_escape_nul_bytes((const char *)nm->d.ia5->data, |
469 |
nm->d.ia5->length, |
470 |
pool); |
471 |
break; |
472 |
default: |
473 |
/* Don't know what to do - skip. */ |
474 |
break; |
475 |
} |
476 |
|
477 |
if (p) { |
478 |
APR_ARRAY_PUSH(*san_arr, char*) = p; |
479 |
} |
480 |
} |
481 |
sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); |
482 |
} |
483 |
|
484 |
return APR_SUCCESS; |
485 |
} |
486 |
|
487 |
static apr_status_t validate_cert_hostname(X509 *server_cert, apr_pool_t *pool) |
488 |
{ |
489 |
char buf[1024]; |
490 |
int length; |
491 |
apr_status_t ret; |
492 |
|
493 |
ret = get_subject_alt_names(NULL, server_cert, ErrorOnNul, NULL); |
494 |
if (ret) { |
495 |
return ret; |
496 |
} else { |
497 |
/* Fail if the subject's CN field contains \0 characters. */ |
498 |
X509_NAME *subject = X509_get_subject_name(server_cert); |
499 |
if (!subject) |
500 |
return SERF_ERROR_SSL_CERT_FAILED; |
501 |
|
502 |
length = X509_NAME_get_text_by_NID(subject, NID_commonName, buf, 1024); |
503 |
if (length != -1) |
504 |
if (strlen(buf) != length) |
505 |
return SERF_ERROR_SSL_CERT_FAILED; |
506 |
} |
507 |
|
508 |
return APR_SUCCESS; |
509 |
} |
510 |
|
430 |
static int |
511 |
static int |
431 |
validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx) |
512 |
validate_server_certificate(int cert_valid, X509_STORE_CTX *store_ctx) |
432 |
{ |
513 |
{ |
Lines 435-440
validate_server_certificate(int cert_valid, X509_S
Link Here
|
435 |
X509 *server_cert; |
516 |
X509 *server_cert; |
436 |
int err, depth; |
517 |
int err, depth; |
437 |
int failures = 0; |
518 |
int failures = 0; |
|
|
519 |
apr_status_t status; |
438 |
|
520 |
|
439 |
ssl = X509_STORE_CTX_get_ex_data(store_ctx, |
521 |
ssl = X509_STORE_CTX_get_ex_data(store_ctx, |
440 |
SSL_get_ex_data_X509_STORE_CTX_idx()); |
522 |
SSL_get_ex_data_X509_STORE_CTX_idx()); |
Lines 475-480
validate_server_certificate(int cert_valid, X509_S
Link Here
|
475 |
} |
557 |
} |
476 |
} |
558 |
} |
477 |
|
559 |
|
|
|
560 |
/* Validate hostname */ |
561 |
status = validate_cert_hostname(server_cert, ctx->pool); |
562 |
if (status) |
563 |
failures |= SERF_SSL_CERT_UNKNOWN_FAILURE; |
564 |
|
478 |
/* Check certificate expiry dates. */ |
565 |
/* Check certificate expiry dates. */ |
479 |
if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) { |
566 |
if (X509_cmp_current_time(X509_get_notBefore(server_cert)) >= 0) { |
480 |
failures |= SERF_SSL_CERT_NOTYETVALID; |
567 |
failures |= SERF_SSL_CERT_NOTYETVALID; |
Lines 485-491
validate_server_certificate(int cert_valid, X509_S
Link Here
|
485 |
|
572 |
|
486 |
if (ctx->server_cert_callback && |
573 |
if (ctx->server_cert_callback && |
487 |
(depth == 0 || failures)) { |
574 |
(depth == 0 || failures)) { |
488 |
apr_status_t status; |
|
|
489 |
serf_ssl_certificate_t *cert; |
575 |
serf_ssl_certificate_t *cert; |
490 |
apr_pool_t *subpool; |
576 |
apr_pool_t *subpool; |
491 |
|
577 |
|
Lines 512-518
validate_server_certificate(int cert_valid, X509_S
Link Here
|
512 |
|
598 |
|
513 |
if (ctx->server_cert_chain_callback |
599 |
if (ctx->server_cert_chain_callback |
514 |
&& (depth == 0 || failures)) { |
600 |
&& (depth == 0 || failures)) { |
515 |
apr_status_t status; |
|
|
516 |
STACK_OF(X509) *chain; |
601 |
STACK_OF(X509) *chain; |
517 |
const serf_ssl_certificate_t **certs; |
602 |
const serf_ssl_certificate_t **certs; |
518 |
int certs_len; |
603 |
int certs_len; |
Lines 1461-1467
serf_ssl_context_t *serf_bucket_ssl_encrypt_contex
Link Here
|
1461 |
|
1546 |
|
1462 |
/* Functions to read a serf_ssl_certificate structure. */ |
1547 |
/* Functions to read a serf_ssl_certificate structure. */ |
1463 |
|
1548 |
|
1464 |
/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). */ |
1549 |
/* Takes a counted length string and escapes any NUL bytes so that |
|
|
1550 |
* it can be used as a C string. NUL bytes are escaped as 3 characters |
1551 |
* "\00" (that's a literal backslash). |
1552 |
* The returned string is allocated in POOL. |
1553 |
*/ |
1554 |
static char * |
1555 |
pstrdup_escape_nul_bytes(const char *buf, int len, apr_pool_t *pool) |
1556 |
{ |
1557 |
int i, nul_count = 0; |
1558 |
char *ret; |
1559 |
|
1560 |
/* First determine if there are any nul bytes in the string. */ |
1561 |
for (i = 0; i < len; i++) { |
1562 |
if (buf[i] == '\0') |
1563 |
nul_count++; |
1564 |
} |
1565 |
|
1566 |
if (nul_count == 0) { |
1567 |
/* There aren't so easy case to just copy the string */ |
1568 |
ret = apr_pstrdup(pool, buf); |
1569 |
} else { |
1570 |
/* There are so we have to replace nul bytes with escape codes |
1571 |
* Proper length is the length of the original string, plus |
1572 |
* 2 times the number of nulls (for two digit hex code for |
1573 |
* the value) + the trailing null. */ |
1574 |
char *pos; |
1575 |
ret = pos = apr_palloc(pool, len + 2 * nul_count + 1); |
1576 |
for (i = 0; i < len; i++) { |
1577 |
if (buf[i] != '\0') { |
1578 |
*(pos++) = buf[i]; |
1579 |
} else { |
1580 |
*(pos++) = '\\'; |
1581 |
*(pos++) = '0'; |
1582 |
*(pos++) = '0'; |
1583 |
} |
1584 |
} |
1585 |
*pos = '\0'; |
1586 |
} |
1587 |
|
1588 |
return ret; |
1589 |
} |
1590 |
|
1591 |
/* Creates a hash_table with keys (E, CN, OU, O, L, ST and C). Any NUL bytes in |
1592 |
these fields in the certificate will be escaped as \00. */ |
1465 |
static apr_hash_t * |
1593 |
static apr_hash_t * |
1466 |
convert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool) |
1594 |
convert_X509_NAME_to_table(X509_NAME *org, apr_pool_t *pool) |
1467 |
{ |
1595 |
{ |
Lines 1474-1510
convert_X509_NAME_to_table(X509_NAME *org, apr_poo
Link Here
|
1474 |
NID_commonName, |
1602 |
NID_commonName, |
1475 |
buf, 1024); |
1603 |
buf, 1024); |
1476 |
if (ret != -1) |
1604 |
if (ret != -1) |
1477 |
apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1605 |
apr_hash_set(tgt, "CN", APR_HASH_KEY_STRING, |
|
|
1606 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1478 |
ret = X509_NAME_get_text_by_NID(org, |
1607 |
ret = X509_NAME_get_text_by_NID(org, |
1479 |
NID_pkcs9_emailAddress, |
1608 |
NID_pkcs9_emailAddress, |
1480 |
buf, 1024); |
1609 |
buf, 1024); |
1481 |
if (ret != -1) |
1610 |
if (ret != -1) |
1482 |
apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1611 |
apr_hash_set(tgt, "E", APR_HASH_KEY_STRING, |
|
|
1612 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1483 |
ret = X509_NAME_get_text_by_NID(org, |
1613 |
ret = X509_NAME_get_text_by_NID(org, |
1484 |
NID_organizationalUnitName, |
1614 |
NID_organizationalUnitName, |
1485 |
buf, 1024); |
1615 |
buf, 1024); |
1486 |
if (ret != -1) |
1616 |
if (ret != -1) |
1487 |
apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1617 |
apr_hash_set(tgt, "OU", APR_HASH_KEY_STRING, |
|
|
1618 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1488 |
ret = X509_NAME_get_text_by_NID(org, |
1619 |
ret = X509_NAME_get_text_by_NID(org, |
1489 |
NID_organizationName, |
1620 |
NID_organizationName, |
1490 |
buf, 1024); |
1621 |
buf, 1024); |
1491 |
if (ret != -1) |
1622 |
if (ret != -1) |
1492 |
apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1623 |
apr_hash_set(tgt, "O", APR_HASH_KEY_STRING, |
|
|
1624 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1493 |
ret = X509_NAME_get_text_by_NID(org, |
1625 |
ret = X509_NAME_get_text_by_NID(org, |
1494 |
NID_localityName, |
1626 |
NID_localityName, |
1495 |
buf, 1024); |
1627 |
buf, 1024); |
1496 |
if (ret != -1) |
1628 |
if (ret != -1) |
1497 |
apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1629 |
apr_hash_set(tgt, "L", APR_HASH_KEY_STRING, |
|
|
1630 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1498 |
ret = X509_NAME_get_text_by_NID(org, |
1631 |
ret = X509_NAME_get_text_by_NID(org, |
1499 |
NID_stateOrProvinceName, |
1632 |
NID_stateOrProvinceName, |
1500 |
buf, 1024); |
1633 |
buf, 1024); |
1501 |
if (ret != -1) |
1634 |
if (ret != -1) |
1502 |
apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1635 |
apr_hash_set(tgt, "ST", APR_HASH_KEY_STRING, |
|
|
1636 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1503 |
ret = X509_NAME_get_text_by_NID(org, |
1637 |
ret = X509_NAME_get_text_by_NID(org, |
1504 |
NID_countryName, |
1638 |
NID_countryName, |
1505 |
buf, 1024); |
1639 |
buf, 1024); |
1506 |
if (ret != -1) |
1640 |
if (ret != -1) |
1507 |
apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, apr_pstrdup(pool, buf)); |
1641 |
apr_hash_set(tgt, "C", APR_HASH_KEY_STRING, |
|
|
1642 |
pstrdup_escape_nul_bytes(buf, ret, pool)); |
1508 |
|
1643 |
|
1509 |
return tgt; |
1644 |
return tgt; |
1510 |
} |
1645 |
} |
Lines 1550-1556
apr_hash_t *serf_ssl_cert_certificate(
Link Here
|
1550 |
unsigned int md_size, i; |
1685 |
unsigned int md_size, i; |
1551 |
unsigned char md[EVP_MAX_MD_SIZE]; |
1686 |
unsigned char md[EVP_MAX_MD_SIZE]; |
1552 |
BIO *bio; |
1687 |
BIO *bio; |
1553 |
STACK_OF(GENERAL_NAME) *names; |
1688 |
apr_array_header_t *san_arr; |
1554 |
|
1689 |
|
1555 |
/* sha1 fingerprint */ |
1690 |
/* sha1 fingerprint */ |
1556 |
if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) { |
1691 |
if (X509_digest(cert->ssl_cert, EVP_sha1(), md, &md_size)) { |
Lines 1595-1627
apr_hash_t *serf_ssl_cert_certificate(
Link Here
|
1595 |
BIO_free(bio); |
1730 |
BIO_free(bio); |
1596 |
|
1731 |
|
1597 |
/* Get subjectAltNames */ |
1732 |
/* Get subjectAltNames */ |
1598 |
names = X509_get_ext_d2i(cert->ssl_cert, NID_subject_alt_name, NULL, NULL); |
1733 |
if (!get_subject_alt_names(&san_arr, cert->ssl_cert, EscapeNulAndCopy, pool)) |
1599 |
if (names) { |
|
|
1600 |
int names_count = sk_GENERAL_NAME_num(names); |
1601 |
|
1602 |
apr_array_header_t *san_arr = apr_array_make(pool, names_count, |
1603 |
sizeof(char*)); |
1604 |
apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr); |
1734 |
apr_hash_set(tgt, "subjectAltName", APR_HASH_KEY_STRING, san_arr); |
1605 |
for (i = 0; i < names_count; i++) { |
|
|
1606 |
char *p = NULL; |
1607 |
GENERAL_NAME *nm = sk_GENERAL_NAME_value(names, i); |
1608 |
|
1735 |
|
1609 |
switch (nm->type) { |
|
|
1610 |
case GEN_DNS: |
1611 |
p = apr_pstrmemdup(pool, (const char *)nm->d.ia5->data, |
1612 |
nm->d.ia5->length); |
1613 |
break; |
1614 |
default: |
1615 |
/* Don't know what to do - skip. */ |
1616 |
break; |
1617 |
} |
1618 |
if (p) { |
1619 |
APR_ARRAY_PUSH(san_arr, char*) = p; |
1620 |
} |
1621 |
} |
1622 |
sk_GENERAL_NAME_pop_free(names, GENERAL_NAME_free); |
1623 |
} |
1624 |
|
1625 |
return tgt; |
1736 |
return tgt; |
1626 |
} |
1737 |
} |
1627 |
|
1738 |
|