📄 ne_openssl.c
字号:
}/* Callback invoked when the SSL server requests a client certificate. */static int provide_client_cert(SSL *ssl, X509 **cert, EVP_PKEY **pkey){ ne_ssl_context *ctx = SSL_get_app_data(ssl); ne_session *sess = SSL_CTX_get_app_data(ctx->ctx); if (!sess->client_cert && sess->ssl_provide_fn) { ne_ssl_dname **dnames = NULL; int n, count = 0; STACK_OF(X509_NAME) *ca_list = SSL_get_client_CA_list(ssl); count = ca_list ? sk_X509_NAME_num(ca_list) : 0; if (count > 0) { dnames = ne_malloc(count * sizeof(ne_ssl_dname *)); for (n = 0; n < count; n++) { dnames[n] = ne_malloc(sizeof(ne_ssl_dname)); dnames[n]->dn = sk_X509_NAME_value(ca_list, n); } } NE_DEBUG(NE_DBG_SSL, "Calling client certificate provider...\n"); sess->ssl_provide_fn(sess->ssl_provide_ud, sess, (const ne_ssl_dname *const *)dnames, count); if (count) { for (n = 0; n < count; n++) ne_free(dnames[n]); ne_free(dnames); } } if (sess->client_cert) { ne_ssl_client_cert *const cc = sess->client_cert; NE_DEBUG(NE_DBG_SSL, "Supplying client certificate.\n"); cc->pkey->references++; cc->cert.subject->references++; *cert = cc->cert.subject; *pkey = cc->pkey; return 1; } else { NE_DEBUG(NE_DBG_SSL, "No client certificate supplied.\n"); return 0; }}void ne_ssl_set_clicert(ne_session *sess, const ne_ssl_client_cert *cc){ sess->client_cert = dup_client_cert(cc);}ne_ssl_context *ne_ssl_context_create(void){ ne_ssl_context *ctx = ne_malloc(sizeof *ctx); ctx->ctx = SSL_CTX_new(SSLv23_client_method()); ctx->sess = NULL; /* set client cert callback. */ SSL_CTX_set_client_cert_cb(ctx->ctx, provide_client_cert); /* enable workarounds for buggy SSL server implementations */ SSL_CTX_set_options(ctx->ctx, SSL_OP_ALL); return ctx;}void ne_ssl_context_destroy(ne_ssl_context *ctx){ SSL_CTX_free(ctx->ctx); if (ctx->sess) SSL_SESSION_free(ctx->sess); ne_free(ctx);}/* For internal use only. */int ne_negotiate_ssl(ne_request *req){ ne_session *sess = ne_get_session(req); ne_ssl_context *ctx = sess->ssl_context; ne_ssl_socket *sock; STACK_OF(X509) *chain; int freechain = 0; /* non-zero if chain should be free'd. */ NE_DEBUG(NE_DBG_SSL, "Doing SSL negotiation.\n"); /* Rather a hack: link the ssl_context back to the ne_session, so * provide_client_cert can get to the ne_session. */ SSL_CTX_set_app_data(ctx->ctx, sess); if (ne_sock_connect_ssl(sess->socket, ctx)) { if (ctx->sess) { /* remove cached session. */ SSL_SESSION_free(ctx->sess); ctx->sess = NULL; } ne_set_error(sess, _("SSL negotiation failed: %s"), ne_sock_error(sess->socket)); return NE_ERROR; } sock = ne_sock_sslsock(sess->socket); chain = SSL_get_peer_cert_chain(sock->ssl); /* For an SSLv2 connection, the cert chain will always be NULL. */ if (chain == NULL) { X509 *cert = SSL_get_peer_certificate(sock->ssl); if (cert) { chain = sk_X509_new_null(); sk_X509_push(chain, cert); } } if (chain == NULL || sk_X509_num(chain) == 0) { ne_set_error(sess, _("SSL server did not present certificate")); return NE_ERROR; } if (sess->server_cert) { int diff = X509_cmp(sk_X509_value(chain, 0), sess->server_cert->subject); if (freechain) sk_X509_free(chain); /* no longer need the chain */ if (diff) { /* This could be a MITM attack: fail the request. */ ne_set_error(sess, _("Server certificate changed: " "connection intercepted?")); return NE_ERROR; } /* certificate has already passed verification: no need to * verify it again. */ } else { /* new connection: create the chain. */ ne_ssl_certificate *cert = make_chain(chain); if (freechain) sk_X509_free(chain); /* no longer need the chain */ if (check_certificate(sess, sock->ssl, cert)) { NE_DEBUG(NE_DBG_SSL, "SSL certificate checks failed: %s\n", sess->error); ne_ssl_cert_free(cert); return NE_ERROR; } /* remember the chain. */ sess->server_cert = cert; } if (!ctx->sess) { /* store the session. */ ctx->sess = SSL_get1_session(sock->ssl); } if (sess->notify_cb) { sess->notify_cb(sess->notify_ud, ne_conn_secure, SSL_get_version(sock->ssl)); } return NE_OK;}const ne_ssl_dname *ne_ssl_cert_issuer(const ne_ssl_certificate *cert){ return &cert->issuer_dn;}const ne_ssl_dname *ne_ssl_cert_subject(const ne_ssl_certificate *cert){ return &cert->subj_dn;}const ne_ssl_certificate *ne_ssl_cert_signedby(const ne_ssl_certificate *cert){ return cert->issuer;}const char *ne_ssl_cert_identity(const ne_ssl_certificate *cert){ return cert->identity;}void ne_ssl_ctx_trustcert(ne_ssl_context *ctx, const ne_ssl_certificate *cert){ X509_STORE *store = SSL_CTX_get_cert_store(ctx->ctx); X509_STORE_add_cert(store, cert->subject);}void ne_ssl_trust_default_ca(ne_session *sess){ X509_STORE *store = SSL_CTX_get_cert_store(sess->ssl_context->ctx); X509_STORE_set_default_paths(store);}/* Find a friendly name in a PKCS12 structure the hard way, without * decrypting the parts which are encrypted.. */static char *find_friendly_name(PKCS12 *p12){ STACK_OF(PKCS7) *safes = PKCS12_unpack_authsafes(p12); int n, m; char *name = NULL; if (safes == NULL) return NULL; /* Iterate over the unpacked authsafes: */ for (n = 0; n < sk_PKCS7_num(safes) && !name; n++) { PKCS7 *safe = sk_PKCS7_value(safes, n); STACK_OF(PKCS12_SAFEBAG) *bags; /* Only looking for unencrypted authsafes. */ if (OBJ_obj2nid(safe->type) != NID_pkcs7_data) continue; bags = PKCS12_unpack_p7data(safe); if (!bags) continue; /* Iterate through the bags, picking out a friendly name */ for (m = 0; m < sk_PKCS12_SAFEBAG_num(bags) && !name; m++) { PKCS12_SAFEBAG *bag = sk_PKCS12_SAFEBAG_value(bags, m); name = PKCS12_get_friendlyname(bag); } sk_PKCS12_SAFEBAG_pop_free(bags, PKCS12_SAFEBAG_free); } sk_PKCS7_pop_free(safes, PKCS7_free); return name;}ne_ssl_client_cert *ne_ssl_clicert_read(const char *filename){ PKCS12 *p12; FILE *fp; X509 *cert; EVP_PKEY *pkey; ne_ssl_client_cert *cc; fp = fopen(filename, "rb"); if (fp == NULL) return NULL; p12 = d2i_PKCS12_fp(fp, NULL); fclose(fp); if (p12 == NULL) { ERR_clear_error(); return NULL; } /* Try parsing with no password. */ if (PKCS12_parse(p12, NULL, &pkey, &cert, NULL) == 1) { /* Success - no password needed for decryption. */ unsigned int len = 0; unsigned char *name = X509_alias_get0(cert, &len); cc = ne_calloc(sizeof *cc); cc->pkey = pkey; cc->decrypted = 1; if (name && len) cc->friendly_name = ne_strndup((char *)name, len); populate_cert(&cc->cert, cert); PKCS12_free(p12); return cc; } else { /* Failed to parse the file */ int err = ERR_get_error(); ERR_clear_error(); if (ERR_GET_LIB(err) == ERR_LIB_PKCS12 && ERR_GET_REASON(err) == PKCS12_R_MAC_VERIFY_FAILURE) { /* Decryption error due to bad password. */ cc = ne_calloc(sizeof *cc); cc->friendly_name = find_friendly_name(p12); cc->p12 = p12; return cc; } else { /* Some parse error, give up. */ PKCS12_free(p12); return NULL; } }}int ne_ssl_clicert_encrypted(const ne_ssl_client_cert *cc){ return !cc->decrypted;}int ne_ssl_clicert_decrypt(ne_ssl_client_cert *cc, const char *password){ X509 *cert; EVP_PKEY *pkey; if (PKCS12_parse(cc->p12, password, &pkey, &cert, NULL) != 1) { ERR_clear_error(); return -1; } PKCS12_free(cc->p12); populate_cert(&cc->cert, cert); cc->pkey = pkey; cc->decrypted = 1; cc->p12 = NULL; return 0;}const ne_ssl_certificate *ne_ssl_clicert_owner(const ne_ssl_client_cert *cc){ return &cc->cert;}const char *ne_ssl_clicert_name(ne_ssl_client_cert *ccert){ return ccert->friendly_name;}ne_ssl_certificate *ne_ssl_cert_read(const char *filename){ FILE *fp = fopen(filename, "r"); X509 *cert; if (fp == NULL) return NULL; cert = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if (cert == NULL) { NE_DEBUG(NE_DBG_SSL, "d2i_X509_fp failed: %s\n", ERR_reason_error_string(ERR_get_error())); ERR_clear_error(); return NULL; } return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), cert);}int ne_ssl_cert_write(const ne_ssl_certificate *cert, const char *filename){ FILE *fp = fopen(filename, "w"); if (fp == NULL) return -1; if (PEM_write_X509(fp, cert->subject) != 1) { ERR_clear_error(); fclose(fp); return -1; } if (fclose(fp) != 0) return -1; return 0;}void ne_ssl_cert_free(ne_ssl_certificate *cert){ X509_free(cert->subject); if (cert->issuer) ne_ssl_cert_free(cert->issuer); if (cert->identity) ne_free(cert->identity); ne_free(cert);}int ne_ssl_cert_cmp(const ne_ssl_certificate *c1, const ne_ssl_certificate *c2){ return X509_cmp(c1->subject, c2->subject);}/* The certificate import/export format is the base64 encoding of the * raw DER; PEM without the newlines and wrapping. */ne_ssl_certificate *ne_ssl_cert_import(const char *data){ unsigned char *der, *p; size_t len; X509 *x5; /* decode the base64 to get the raw DER representation */ len = ne_unbase64(data, &der); if (len == 0) return NULL; p = der; x5 = d2i_X509(NULL, &p, len); /* p is incremented */ ne_free(der); if (x5 == NULL) { ERR_clear_error(); return NULL; } return populate_cert(ne_calloc(sizeof(struct ne_ssl_certificate_s)), x5);}char *ne_ssl_cert_export(const ne_ssl_certificate *cert){ int len; unsigned char *der, *p; /* find the length of the DER encoding. */ len = i2d_X509(cert->subject, NULL); p = der = ne_malloc(len); i2d_X509(cert->subject, &p); /* p is incremented */ p = ne_base64(der, len); ne_free(der); return p;}#if SHA_DIGEST_LENGTH != 20# error SHA digest length is not 20 bytes#endifint ne_ssl_cert_digest(const ne_ssl_certificate *cert, char *digest){ unsigned char sha1[EVP_MAX_MD_SIZE]; unsigned int len, j; char *p; if (!X509_digest(cert->subject, EVP_sha1(), sha1, &len) || len != 20) { ERR_clear_error(); return -1; } for (j = 0, p = digest; j < 20; j++) { *p++ = NE_HEX2ASC((sha1[j] >> 4) & 0x0f); *p++ = NE_HEX2ASC(sha1[j] & 0x0f); *p++ = ':'; } *--p = '\0'; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -