diff options
author | Nick Mathewson <nickm@torproject.org> | 2018-08-17 11:24:50 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2018-09-04 14:52:35 -0400 |
commit | 5205c7fd903cb5bd751812bddb5497ac76e1f30b (patch) | |
tree | eeb20f1e5485c32dc364d9ead768c6740c56e561 /src/lib/tls/tortls_nss.c | |
parent | c567b8fcb4e4851d6db19946cce8c4d5e75535f5 (diff) | |
download | tor-5205c7fd903cb5bd751812bddb5497ac76e1f30b.tar.gz tor-5205c7fd903cb5bd751812bddb5497ac76e1f30b.zip |
Initial NSS support for TLS.
This is enough to get a chutney network to bootstrap, though a bunch
of work remains.
Diffstat (limited to 'src/lib/tls/tortls_nss.c')
-rw-r--r-- | src/lib/tls/tortls_nss.c | 621 |
1 files changed, 487 insertions, 134 deletions
diff --git a/src/lib/tls/tortls_nss.c b/src/lib/tls/tortls_nss.c index 35dbc27d9c..d2b81ad084 100644 --- a/src/lib/tls/tortls_nss.c +++ b/src/lib/tls/tortls_nss.c @@ -12,6 +12,7 @@ #include "orconfig.h" #define TORTLS_PRIVATE +#define TOR_X509_PRIVATE #ifdef _WIN32 /*wrkard for dtls1.h >= 0.9.8m of "#include <winsock.h>"*/ #include <winsock2.h> @@ -22,6 +23,9 @@ #include "lib/crypt_ops/crypto_rand.h" #include "lib/crypt_ops/crypto_dh.h" #include "lib/crypt_ops/crypto_util.h" +#include "lib/crypt_ops/crypto_nss_mgt.h" +#include "lib/string/printf.h" + #include "lib/tls/x509.h" #include "lib/tls/x509_internal.h" #include "lib/tls/tortls.h" @@ -29,26 +33,16 @@ #include "lib/tls/tortls_internal.h" #include "lib/log/util_bug.h" -int -tor_errno_to_tls_error(int e) -{ - (void)e; - // XXXX - return -1; -} -int -tor_tls_get_error(tor_tls_t *tls, int r, int extra, - const char *doing, int severity, int domain) -{ - (void)tls; - (void)r; - (void)extra; - (void)doing; - (void)severity; - (void)domain; - // XXXX - return -1; -} +#include <prio.h> +// For access to raw sockets. +#include <private/pprio.h> +#include <ssl.h> +#include <sslt.h> +#include <sslproto.h> +#include <certt.h> + +static SECStatus always_accept_cert_cb(void *, PRFileDesc *, PRBool, PRBool); + MOCK_IMPL(void, try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, tor_x509_cert_impl_t **cert_out, @@ -57,14 +51,109 @@ try_to_extract_certs_from_tls,(int severity, tor_tls_t *tls, tor_assert(tls); tor_assert(cert_out); tor_assert(id_cert_out); - (void)severity; - // XXXX + (void) severity; + + *cert_out = *id_cert_out = NULL; + + CERTCertificate *peer = SSL_PeerCertificate(tls->ssl); + if (!peer) + return; + *cert_out = peer; /* Now owns pointer. */ + + CERTCertList *chain = SSL_PeerCertificateChain(tls->ssl); + CERTCertListNode *c = CERT_LIST_HEAD(chain); + for (; !CERT_LIST_END(c, chain); c = CERT_LIST_NEXT(c)) { + if (CERT_CompareCerts(c->cert, peer) == PR_FALSE) { + *id_cert_out = CERT_DupCertificate(c->cert); + break; + } + } + CERT_DestroyCertList(chain); +} + +static bool +we_like_ssl_cipher(SSLCipherAlgorithm ca) +{ + switch (ca) { + case ssl_calg_null: return false; + case ssl_calg_rc4: return false; + case ssl_calg_rc2: return false; + case ssl_calg_des: return false; + case ssl_calg_3des: return false; /* ???? */ + case ssl_calg_idea: return false; + case ssl_calg_fortezza: return false; + case ssl_calg_camellia: return false; + case ssl_calg_seed: return false; + + case ssl_calg_aes: return true; + case ssl_calg_aes_gcm: return true; + case ssl_calg_chacha20: return true; + default: return true; + } +} +static bool +we_like_ssl_kea(SSLKEAType kt) +{ + switch (kt) { + case ssl_kea_null: return false; + case ssl_kea_rsa: return false; /* ??? */ + case ssl_kea_fortezza: return false; + case ssl_kea_ecdh_psk: return false; + case ssl_kea_dh_psk: return false; + + case ssl_kea_dh: return true; + case ssl_kea_ecdh: return true; + case ssl_kea_tls13_any: return true; + + case ssl_kea_size: return true; /* prevent a warning. */ + default: return true; + } +} + +static bool +we_like_mac_algorithm(SSLMACAlgorithm ma) +{ + switch (ma) { + case ssl_mac_null: return false; + case ssl_mac_md5: return false; + case ssl_hmac_md5: return false; + + case ssl_mac_sha: return true; + case ssl_hmac_sha: return true; + case ssl_hmac_sha256: return true; + case ssl_mac_aead: return true; + case ssl_hmac_sha384: return true; + default: return true; + } +} + +static bool +we_like_auth_type(SSLAuthType at) +{ + switch (at) { + case ssl_auth_null: return false; + case ssl_auth_rsa_decrypt: return false; + case ssl_auth_dsa: return false; + case ssl_auth_kea: return false; + + case ssl_auth_ecdsa: return true; + case ssl_auth_ecdh_rsa: return true; + case ssl_auth_ecdh_ecdsa: return true; + case ssl_auth_rsa_sign: return true; + case ssl_auth_rsa_pss: return true; + case ssl_auth_psk: return true; + case ssl_auth_tls13_any: return true; + + case ssl_auth_size: return true; /* prevent a warning. */ + default: return true; + } } tor_tls_context_t * tor_tls_context_new(crypto_pk_t *identity, unsigned int key_lifetime, unsigned flags, int is_client) { + SECStatus s; tor_assert(identity); tor_tls_context_t *ctx = tor_malloc_zero(sizeof(tor_tls_context_t)); @@ -77,7 +166,128 @@ tor_tls_context_new(crypto_pk_t *identity, } } - // XXXX write the main body. + { + /* Create the "model" PRFileDesc that we will use to base others on. */ + PRFileDesc *tcp = PR_NewTCPSocket(); + if (!tcp) + goto err; + + ctx->ctx = SSL_ImportFD(NULL, tcp); + if (!ctx->ctx) { + PR_Close(tcp); + goto err; + } + } + + // Configure the certificate. + if (!is_client) { + s = SSL_ConfigServerCert(ctx->ctx, + ctx->my_link_cert->cert, + (SECKEYPrivateKey *) + crypto_pk_get_nss_privkey(ctx->link_key), + NULL, /* ExtraServerCertData */ + 0 /* DataLen */); + if (s != SECSuccess) + goto err; + } + + // We need a certificate from the other side. + if (is_client) { + // XXXX does this do anything? + s = SSL_OptionSet(ctx->ctx, SSL_REQUIRE_CERTIFICATE, PR_TRUE); + if (s != SECSuccess) + goto err; + } + + // Always accept other side's cert; we'll check it ourselves in goofy + // tor ways. + s = SSL_AuthCertificateHook(ctx->ctx, always_accept_cert_cb, NULL); + + // We allow simultaneous read and write. + s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_FDX, PR_TRUE); + if (s != SECSuccess) + goto err; + // XXXX SSL_ROLLBACK_DETECTION?? + // XXXX SSL_ENABLE_ALPN?? + + // Force client-mode or server_mode. + s = SSL_OptionSet(ctx->ctx, + is_client ? SSL_HANDSHAKE_AS_CLIENT : SSL_HANDSHAKE_AS_SERVER, + PR_TRUE); + if (s != SECSuccess) + goto err; + + // Disable everything before TLS 1.0; support everything else. + { + SSLVersionRange vrange; + memset(&vrange, 0, sizeof(vrange)); + s = SSL_VersionRangeGetSupported(ssl_variant_stream, &vrange); + if (s != SECSuccess) + goto err; + if (vrange.min < SSL_LIBRARY_VERSION_TLS_1_0) + vrange.min = SSL_LIBRARY_VERSION_TLS_1_0; + s = SSL_VersionRangeSet(ctx->ctx, &vrange); + if (s != SECSuccess) + goto err; + } + + // Only support strong ciphers. + { + const PRUint16 *ciphers = SSL_GetImplementedCiphers(); + const PRUint16 n_ciphers = SSL_GetNumImplementedCiphers(); + PRUint16 i; + for (i = 0; i < n_ciphers; ++i) { + SSLCipherSuiteInfo info; + memset(&info, 0, sizeof(info)); + s = SSL_GetCipherSuiteInfo(ciphers[i], &info, sizeof(info)); + if (s != SECSuccess) + goto err; + if (BUG(info.cipherSuite != ciphers[i])) + goto err; + int disable = info.effectiveKeyBits < 128 || + info.macBits < 128 || + !we_like_ssl_cipher(info.symCipher) || + !we_like_ssl_kea(info.keaType) || + !we_like_mac_algorithm(info.macAlgorithm) || + !we_like_auth_type(info.authType)/* Requires NSS 3.24 */; + + s = SSL_CipherPrefSet(ctx->ctx, ciphers[i], + disable ? PR_FALSE : PR_TRUE); + if (s != SECSuccess) + goto err; + } + } + + // Only use DH and ECDH keys once. + s = SSL_OptionSet(ctx->ctx, SSL_REUSE_SERVER_ECDHE_KEY, PR_FALSE); + if (s != SECSuccess) + goto err; + + // don't cache sessions. + s = SSL_OptionSet(ctx->ctx, SSL_NO_CACHE, PR_TRUE); + if (s != SECSuccess) + goto err; + + // Enable DH. + s = SSL_OptionSet(ctx->ctx, SSL_ENABLE_SERVER_DHE, PR_TRUE); + if (s != SECSuccess) + goto err; + + // Set DH and ECDH groups. + SSLNamedGroup groups[] = { + ssl_grp_ec_curve25519, + ssl_grp_ec_secp256r1, + ssl_grp_ec_secp224r1, + ssl_grp_ffdhe_2048, + }; + s = SSL_NamedGroupConfig(ctx->ctx, groups, ARRAY_LENGTH(groups)); + if (s != SECSuccess) + goto err; + + // These features are off by default, so we don't need to disable them: + // Session tickets + // Renegotiation + // Compression goto done; err: @@ -88,11 +298,9 @@ tor_tls_context_new(crypto_pk_t *identity, } void -tor_tls_context_impl_free(struct ssl_ctx_st *ctx) +tor_tls_context_impl_free(tor_tls_context_impl_t *ctx) { - (void)ctx; - // XXXX - // XXXX openssl type. + PR_Close(ctx); } void @@ -101,33 +309,82 @@ tor_tls_get_state_description(tor_tls_t *tls, char *buf, size_t sz) (void)tls; (void)buf; (void)sz; - // XXXX + // AFAICT, NSS doesn't expose its internal state. + buf[0]=0; } void tor_tls_init(void) { - // XXXX + /* We don't have any global setup to do yet, but that will change */ } + void tls_log_errors(tor_tls_t *tls, int severity, int domain, const char *doing) { + /* XXXX This implementation isn't right for NSS -- it logs the last error + whether anything actually failed or not. */ + (void)tls; - (void)severity; - (void)domain; - (void)doing; - // XXXX + PRErrorCode code = PORT_GetError(); + + const char *string = PORT_ErrorToString(code); + const char *name = PORT_ErrorToName(code); + char buf[16]; + if (!string) + string = "<unrecognized>"; + if (!name) { + tor_snprintf(buf, sizeof(buf), "%d", code); + name = buf; + } + + if (doing) { + log_fn(severity, domain, "TLS error %s while %s: %s", name, doing, string); + } else { + log_fn(severity, domain, "TLS error %s: %s", name, string); + } } tor_tls_t * -tor_tls_new(int sock, int is_server) +tor_tls_new(tor_socket_t sock, int is_server) { (void)sock; - (void)is_server; - // XXXX - return NULL; + tor_tls_context_t *ctx = tor_tls_context_get(is_server); + + PRFileDesc *tcp = PR_ImportTCPSocket(sock); + if (!tcp) + return NULL; + + PRFileDesc *ssl = SSL_ImportFD(ctx->ctx, tcp); + if (!ssl) { + PR_Close(tcp); + return NULL; + } + + tor_tls_t *tls = tor_malloc_zero(sizeof(tor_tls_t)); + tls->magic = TOR_TLS_MAGIC; + tls->context = ctx; + tor_tls_context_incref(ctx); + tls->ssl = ssl; + tls->socket = sock; + tls->state = TOR_TLS_ST_HANDSHAKE; + tls->isServer = !!is_server; + + if (!is_server) { + /* Set a random SNI */ + char *fake_hostname = crypto_random_hostname(4,25, "www.",".com"); + SSL_SetURL(tls->ssl, fake_hostname); + tor_free(fake_hostname); + } + SECStatus s = SSL_ResetHandshake(ssl, is_server ? PR_TRUE : PR_FALSE); + if (s != SECSuccess) { + crypto_nss_log_errors(LOG_WARN, "resetting handshake state"); + } + + return tls; } + void tor_tls_set_renegotiate_callback(tor_tls_t *tls, void (*cb)(tor_tls_t *, void *arg), @@ -136,131 +393,175 @@ tor_tls_set_renegotiate_callback(tor_tls_t *tls, tor_assert(tls); (void)cb; (void)arg; - // XXXX; + + /* We don't support renegotiation-based TLS with NSS. */ } void -tor_tls_free_(tor_tls_t *tls) +tor_tls_impl_free_(tor_tls_impl_t *tls) { - (void)tls; - // XXXX + // XXXX This will close the underlying fd, which our OpenSSL version does + // not do! + + PR_Close(tls); } int tor_tls_peer_has_cert(tor_tls_t *tls) { - (void)tls; - // XXXX - return -1; + CERTCertificate *cert = SSL_PeerCertificate(tls->ssl); + int result = (cert != NULL); + CERT_DestroyCertificate(cert); + return result; } + MOCK_IMPL(tor_x509_cert_t *, tor_tls_get_peer_cert,(tor_tls_t *tls)) { - tor_assert(tls); - // XXXX - return NULL; + CERTCertificate *cert = SSL_PeerCertificate(tls->ssl); + if (cert) + return tor_x509_cert_new(cert); + else + return NULL; } + MOCK_IMPL(tor_x509_cert_t *, tor_tls_get_own_cert,(tor_tls_t *tls)) { tor_assert(tls); - // XXXX - return NULL; -} -int -tor_tls_verify(int severity, tor_tls_t *tls, crypto_pk_t **identity) -{ - tor_assert(tls); - tor_assert(identity); - (void)severity; - // XXXX - return -1; -} -int -tor_tls_check_lifetime(int severity, - tor_tls_t *tls, time_t now, - int past_tolerance, - int future_tolerance) -{ - tor_assert(tls); - (void)severity; - (void)now; - (void)past_tolerance; - (void)future_tolerance; - // XXXX - return -1; + CERTCertificate *cert = SSL_LocalCertificate(tls->ssl); + if (cert) + return tor_x509_cert_new(cert); + else + return NULL; } + MOCK_IMPL(int, tor_tls_read, (tor_tls_t *tls, char *cp, size_t len)) { tor_assert(tls); tor_assert(cp); - (void)len; - // XXXX - return -1; + tor_assert(len < INT_MAX); + + PRInt32 rv = PR_Read(tls->ssl, cp, (int)len); + // log_debug(LD_NET, "PR_Read(%zu) returned %d", n, (int)rv); + if (rv > 0) { + tls->n_read_since_last_check += rv; + return rv; + } + if (rv == 0) + return TOR_TLS_CLOSE; + PRErrorCode err = PORT_GetError(); + if (err == PR_WOULD_BLOCK_ERROR) { + return TOR_TLS_WANTREAD; // XXXX ???? + } else { + crypto_nss_log_errors(LOG_NOTICE, "reading"); // XXXX + return TOR_TLS_ERROR_MISC; // ???? + } } + int tor_tls_write(tor_tls_t *tls, const char *cp, size_t n) { tor_assert(tls); - tor_assert(cp); - (void)n; - // XXXX - return -1; + tor_assert(cp || n == 0); + tor_assert(n < INT_MAX); + + PRInt32 rv = PR_Write(tls->ssl, cp, (int)n); + // log_debug(LD_NET, "PR_Write(%zu) returned %d", n, (int)rv); + if (rv > 0) { + tls->n_written_since_last_check += rv; + return rv; + } + if (rv == 0) + return TOR_TLS_ERROR_MISC; + PRErrorCode err = PORT_GetError(); + + if (err == PR_WOULD_BLOCK_ERROR) { + return TOR_TLS_WANTWRITE; // XXXX ???? + } else { + crypto_nss_log_errors(LOG_NOTICE, "writing"); // XXXX + return TOR_TLS_ERROR_MISC; // ???? + } } + int tor_tls_handshake(tor_tls_t *tls) { tor_assert(tls); - // XXXX - return -1; + tor_assert(tls->state == TOR_TLS_ST_HANDSHAKE); + + SECStatus s = SSL_ForceHandshake(tls->ssl); + if (s == SECSuccess) { + tls->state = TOR_TLS_ST_OPEN; + log_debug(LD_NET, "SSL handshake is supposedly complete."); + return tor_tls_finish_handshake(tls); + } + if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) + return TOR_TLS_WANTREAD; /* XXXX What about wantwrite? */ + + return TOR_TLS_ERROR_MISC; // XXXX } + int tor_tls_finish_handshake(tor_tls_t *tls) { tor_assert(tls); - // XXXX - return -1; + // We don't need to do any of the weird handshake nonsense stuff on NSS, + // since we only support recent handshakes. + return TOR_TLS_DONE; } + void tor_tls_unblock_renegotiation(tor_tls_t *tls) { tor_assert(tls); - // XXXX + /* We don't support renegotiation with NSS. */ } + void tor_tls_block_renegotiation(tor_tls_t *tls) { tor_assert(tls); - // XXXX + /* We don't support renegotiation with NSS. */ } + void tor_tls_assert_renegotiation_unblocked(tor_tls_t *tls) { tor_assert(tls); - // XXXX + /* We don't support renegotiation with NSS. */ } + int tor_tls_shutdown(tor_tls_t *tls) { tor_assert(tls); - // XXXX + /* XXXX This is not actually used, so I'm not implementing it. We can + * XXXX remove this function entirely someday. */ return -1; } + int tor_tls_get_pending_bytes(tor_tls_t *tls) { tor_assert(tls); - // XXXX - return -1; + int n = SSL_DataPending(tls->ssl); + if (n < 0) { + crypto_nss_log_errors(LOG_WARN, "Looking up pending bytes"); + return 0; + } + return (int)n; } + size_t tor_tls_get_forced_write_size(tor_tls_t *tls) { tor_assert(tls); - // XXXX + /* NSS doesn't have the same "forced write" restriction as openssl. */ return 0; } + void tor_tls_get_n_raw_bytes(tor_tls_t *tls, size_t *n_read, size_t *n_written) @@ -268,7 +569,13 @@ tor_tls_get_n_raw_bytes(tor_tls_t *tls, tor_assert(tls); tor_assert(n_read); tor_assert(n_written); - // XXXX + /* XXXX We don't curently have a way to measure this information correctly + * in NSS; we could do that with a PRIO layer, but it'll take a little + * coding. For now, we just track the number of bytes sent _in_ the TLS + * stream. Doing this will make our rate-limiting slightly inaccurate. */ + *n_read = tls->n_read_since_last_check; + *n_written = tls->n_written_since_last_check; + tls->n_read_since_last_check = tls->n_written_since_last_check = 0; } int @@ -281,54 +588,70 @@ tor_tls_get_buffer_sizes(tor_tls_t *tls, tor_assert(rbuf_bytes); tor_assert(wbuf_capacity); tor_assert(wbuf_bytes); - // XXXX + + /* This is an acceptable way to say "we can't measure this." */ return -1; } + MOCK_IMPL(double, tls_get_write_overhead_ratio, (void)) { - // XXXX - return 0.0; + /* XXX We don't currently have a way to measure this in NSS; we could do that + * XXX with a PRIO layer, but it'll take a little coding. */ + return 0.95; } int tor_tls_used_v1_handshake(tor_tls_t *tls) { tor_assert(tls); - // XXXX - return -1; -} -int -tor_tls_get_num_server_handshakes(tor_tls_t *tls) -{ - tor_assert(tls); - // XXXX - return -1; + /* We don't support or allow the V1 handshake with NSS. + */ + return 0; } + int tor_tls_server_got_renegotiate(tor_tls_t *tls) { tor_assert(tls); - // XXXX - return -1; + return 0; /* We don't support renegotiation with NSS */ } + MOCK_IMPL(int, tor_tls_cert_matches_key,(const tor_tls_t *tls, const struct tor_x509_cert_t *cert)) { tor_assert(tls); tor_assert(cert); - // XXXX - return 0; + int rv = 0; + + CERTCertificate *peercert = SSL_PeerCertificate(tls->ssl); + if (!peercert) + goto done; + CERTSubjectPublicKeyInfo *peer_info = &peercert->subjectPublicKeyInfo; + CERTSubjectPublicKeyInfo *cert_info = &cert->cert->subjectPublicKeyInfo; + rv = SECOID_CompareAlgorithmID(&peer_info->algorithm, + &cert_info->algorithm) == 0 && + SECITEM_ItemsAreEqual(&peer_info->subjectPublicKey, + &cert_info->subjectPublicKey); + + done: + if (peercert) + CERT_DestroyCertificate(peercert); + return rv; } + MOCK_IMPL(int, tor_tls_get_tlssecrets,(tor_tls_t *tls, uint8_t *secrets_out)) { tor_assert(tls); tor_assert(secrets_out); - // XXXX + + /* There's no way to get this information out of NSS. */ + return -1; } + MOCK_IMPL(int, tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, const uint8_t *context, @@ -339,42 +662,72 @@ tor_tls_export_key_material,(tor_tls_t *tls, uint8_t *secrets_out, tor_assert(secrets_out); tor_assert(context); tor_assert(label); - (void)context_len; - // XXXX - return -1; -} + tor_assert(strlen(label) <= UINT_MAX); + tor_assert(context_len <= UINT_MAX); -void -check_no_tls_errors_(const char *fname, int line) -{ - (void)fname; - (void)line; - // XXXX -} -void -tor_tls_log_one_error(tor_tls_t *tls, unsigned long err, - int severity, int domain, const char *doing) -{ - tor_assert(tls); - (void)err; - (void)severity; - (void)domain; - (void)doing; - // XXXX + SECStatus s; + s = SSL_ExportKeyingMaterial(tls->ssl, + label, (unsigned)strlen(label), + PR_TRUE, context, (unsigned)context_len, + secrets_out, DIGEST256_LEN); + + return (s == SECSuccess) ? 0 : -1; } const char * tor_tls_get_ciphersuite_name(tor_tls_t *tls) { tor_assert(tls); - // XXXX - return NULL; + + SSLChannelInfo channel_info; + SSLCipherSuiteInfo cipher_info; + + memset(&channel_info, 0, sizeof(channel_info)); + memset(&cipher_info, 0, sizeof(cipher_info)); + + SECStatus s = SSL_GetChannelInfo(tls->ssl, + &channel_info, sizeof(channel_info)); + if (s != SECSuccess) + return NULL; + + s = SSL_GetCipherSuiteInfo(channel_info.cipherSuite, + &cipher_info, sizeof(cipher_info)); + if (s != SECSuccess) + return NULL; + + return cipher_info.cipherSuiteName; } +/** The group we should use for ecdhe when none was selected. */ +#define SEC_OID_TOR_DEFAULT_ECDHE_GROUP SEC_OID_ANSIX962_EC_PRIME256V1 + int evaluate_ecgroup_for_tls(const char *ecgroup) { - (void)ecgroup; - // XXXX - return -1; + SECOidTag tag; + + if (!ecgroup) + tag = SEC_OID_TOR_DEFAULT_ECDHE_GROUP; + else if (!strcasecmp(ecgroup, "P256")) + tag = SEC_OID_ANSIX962_EC_PRIME256V1; + else if (!strcasecmp(ecgroup, "P224")) + tag = SEC_OID_SECG_EC_SECP224R1; + else + return 0; + + /* I don't think we need any additional tests here for NSS */ + (void) tag; + + return 1; +} + +static SECStatus +always_accept_cert_cb(void *arg, PRFileDesc *ssl, PRBool checkSig, + PRBool isServer) +{ + (void)arg; + (void)ssl; + (void)checkSig; + (void)isServer; + return SECSuccess; } |