int ssl_ca_certificate(struct ssl_t *ssl, const char *cafile, int depth) { STACK_OF(X509_NAME) *list; SSL_CTX_set_verify(ssl->ctx, SSL_VERIFY_PEER, ssl_verify_callback); SSL_CTX_set_verify_depth(ssl->ctx, depth); if (SSL_CTX_load_verify_locations(ssl->ctx, cafile, NULL) == 0) { hlog(LOG_ERR, "Failed to load trusted CA list from \"%s\"", cafile); ssl_error(LOG_ERR, "SSL_CTX_load_verify_locations"); return -1; } list = SSL_load_client_CA_file(cafile); if (list == NULL) { hlog(LOG_ERR, "Failed to load client CA file from \"%s\"", cafile); ssl_error(LOG_ERR, "SSL_load_client_CA_file"); return -1; } /* * before 0.9.7h and 0.9.8 SSL_load_client_CA_file() * always leaved an error in the error queue */ ERR_clear_error(); SSL_CTX_set_client_CA_list(ssl->ctx, list); ssl->validate = 1; return 0; }
void ssl_set_ecdh_curve(SSL_CTX *ctx, const char *curve) { #if OPENSSL_VERSION_NUMBER >= 0x0090800fL #ifndef OPENSSL_NO_ECDH int nid; EC_KEY *ecdh; if (curve == NULL) curve = SSL_ECDH_CURVE; if ((nid = OBJ_sn2nid(curve)) == 0) { ssl_error("ssl_set_ecdh_curve"); fatal("ssl_set_ecdh_curve: unknown curve name %s", curve); } if ((ecdh = EC_KEY_new_by_curve_name(nid)) == NULL) { ssl_error("ssl_set_ecdh_curve"); fatal("ssl_set_ecdh_curve: unable to create curve %s", curve); } SSL_CTX_set_tmp_ecdh(ctx, ecdh); SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE); EC_KEY_free(ecdh); #endif #endif }
static value dgst_sign(value data, value key, value alg){ const mbedtls_md_info_t *md; int r = -1; size_t olen = 0; value out; unsigned char *buf; unsigned char hash[32]; val_check(data, string); val_check_kind(key, k_pkey); val_check(alg, string); md = mbedtls_md_info_from_string(val_string(alg)); if( md == NULL ){ val_throw(alloc_string("Invalid hash algorithm")); return val_null; } if( (r = mbedtls_md( md, (const unsigned char *)val_string(data), val_strlen(data), hash )) != 0 ) return ssl_error(r); out = alloc_empty_string(MBEDTLS_MPI_MAX_SIZE); buf = (unsigned char *)val_string(out); if( (r = mbedtls_pk_sign( val_pkey(key), mbedtls_md_get_type(md), hash, 0, buf, &olen, mbedtls_ctr_drbg_random, &ctr_drbg )) != 0 ) return ssl_error(r); buf[olen] = 0; val_set_size(out, olen); return out; }
// Dynamically load SSL library. Set up ctx->ssl_ctx pointer. static int set_ssl_option(struct mg_context *ctx) { int i, size; const char *pem; // If PEM file is not specified and the init_ssl callback // is not specified, skip SSL initialization. if ((pem = ctx->config[SSL_CERTIFICATE]) == NULL) { // MG_INIT_SSL // ctx->callbacks.init_ssl == NULL) { return 1; } #if !defined(NO_SSL_DL) if (!load_dll(ctx, SSL_LIB, ssl_sw) || !load_dll(ctx, CRYPTO_LIB, crypto_sw)) { return 0; } #endif // NO_SSL_DL // Initialize SSL library SSL_library_init(); SSL_load_error_strings(); if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) { cry(fc(ctx), "SSL_CTX_new (server) error: %s", ssl_error()); return 0; } // If user callback returned non-NULL, that means that user callback has // set up certificate itself. In this case, skip sertificate setting. // MG_INIT_SSL if (SSL_CTX_use_certificate_file(ctx->ssl_ctx, pem, 1) == 0 || SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, pem, 1) == 0) { cry(fc(ctx), "%s: cannot open %s: %s", __func__, pem, ssl_error()); return 0; } if (pem != NULL) { (void) SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, pem); } // Initialize locking callbacks, needed for thread safety. // http://www.openssl.org/support/faq.html#PROG1 size = sizeof(pthread_mutex_t) * CRYPTO_num_locks(); if ((ssl_mutexes = (pthread_mutex_t *) malloc((size_t)size)) == NULL) { cry(fc(ctx), "%s: cannot allocate mutexes: %s", __func__, ssl_error()); return 0; } for (i = 0; i < CRYPTO_num_locks(); i++) { pthread_mutex_init(&ssl_mutexes[i], NULL); } CRYPTO_set_locking_callback(&ssl_locking_callback); CRYPTO_set_id_callback(&ssl_id_callback); return 1; }
int ssl_setup(SSL_CTX **ctxp, struct pki *pki, int (*sni_cb)(SSL *,int *,void *), const char *ciphers) { SSL_CTX *ctx; uint8_t sid[SSL_MAX_SID_CTX_LENGTH]; ctx = ssl_ctx_create(pki->pki_name, pki->pki_cert, pki->pki_cert_len, ciphers); /* * Set session ID context to a random value. We don't support * persistent caching of sessions so it is OK to set a temporary * session ID context that is valid during run time. */ arc4random_buf(sid, sizeof(sid)); if (!SSL_CTX_set_session_id_context(ctx, sid, sizeof(sid))) goto err; if (sni_cb) SSL_CTX_set_tlsext_servername_callback(ctx, sni_cb); SSL_CTX_set_dh_auto(ctx, pki->pki_dhe); SSL_CTX_set_ecdh_auto(ctx, 1); *ctxp = ctx; return 1; err: SSL_CTX_free(ctx); ssl_error("ssl_setup"); return 0; }
int ssl_setup(SSL_CTX **ctxp, struct pki *pki) { DH *dh; SSL_CTX *ctx; ctx = ssl_ctx_create(pki->pki_name, pki->pki_cert, pki->pki_cert_len); if (!SSL_CTX_set_session_id_context(ctx, (const unsigned char *)pki->pki_name, strlen(pki->pki_name) + 1)) goto err; if (pki->pki_dhparams_len == 0) dh = get_dh1024(); else dh = get_dh_from_memory(pki->pki_dhparams, pki->pki_dhparams_len); ssl_set_ephemeral_key_exchange(ctx, dh); DH_free(dh); ssl_set_ecdh_curve(ctx, SSL_ECDH_CURVE); *ctxp = ctx; return 1; err: SSL_CTX_free(ctx); ssl_error("ssl_setup"); return 0; }
// add_key_from_file: adds an RSA key from a file location, returns // KSSL_ERROR_NONE if successful, or a KSSL_ERROR_* if a problem // occurs. Adds the private key to the list if successful. kssl_error_code add_key_from_file(const char *path, // Path to file containing key pk_list list) { // Array of private keys from new_pk_list int rc; BIO *bp; kssl_error_code err = KSSL_ERROR_NONE; bp = BIO_new(BIO_s_file()); if (bp == NULL) { ssl_error(); } rc = BIO_read_filename(bp, path); if (!rc) { write_log(1, "Failed to open private key file %s", path); return KSSL_ERROR_INTERNAL; } err = add_key_from_bio(bp, list); if (err != KSSL_ERROR_NONE) { write_log(1, "Private RSA key from file %s is not valid", path); BIO_free(bp); return KSSL_ERROR_INTERNAL; } BIO_free(bp); return KSSL_ERROR_NONE; }
// add_key_from_bio: adds an RSA key from a BIO pointer, returns // KSSL_ERROR_NONE if successful, or a KSSL_ERROR_* if a problem // occurs. Adds the private key to the list if successful. static kssl_error_code add_key_from_bio(BIO *key_bp, // BIO Key value in PEM format pk_list list) { // Array of private keys RSA *local_key; local_key = PEM_read_bio_RSAPrivateKey(key_bp, 0, 0, 0); if (local_key == NULL) { ssl_error(); } if (list->current >= list->allocated) { write_log(1, "Private key list maximum reached"); return KSSL_ERROR_INTERNAL; } if (RSA_check_key(local_key) != 1) { return KSSL_ERROR_INTERNAL; } list->privates[list->current].key = local_key; digest_public_modulus(local_key, list->privates[list->current].digest); list->current++; return KSSL_ERROR_NONE; }
// add_key_from_buffer: adds an RSA key from a pointer, returns // KSSL_ERROR_NONE if successful, or a KSSL_ERROR_* if a problem // occurs. Adds the private key to the list if successful. kssl_error_code add_key_from_buffer(const char *key, // Key value in PEM format int key_len, // Length of key in bytes pk_list list) { // Array of private keys BIO *bp; kssl_error_code err = KSSL_ERROR_NONE; if (!list) { write_log(1, "Assigning to NULL"); return KSSL_ERROR_INTERNAL; } bp = BIO_new_mem_buf((void*)key, key_len); if (bp == NULL) { ssl_error(); } err = add_key_from_bio(bp, list); if (err != KSSL_ERROR_NONE) { write_log(1, "Private RSA key is not valid"); BIO_free(bp); return KSSL_ERROR_INTERNAL; } BIO_free(bp); return KSSL_ERROR_NONE; }
static value key_from_pem(value data, value pub, value pass){ mbedtls_pk_context *pk; int r, len; value v; unsigned char *buf; val_check(data, string); val_check(pub, bool); if (!val_is_null(pass)) val_check(pass, string); len = val_strlen(data)+1; buf = (unsigned char *)alloc(len); memcpy(buf, val_string(data), len-1); buf[len-1] = '\0'; pk = (mbedtls_pk_context *)alloc(sizeof(mbedtls_pk_context)); mbedtls_pk_init(pk); if( val_bool(pub) ) r = mbedtls_pk_parse_public_key( pk, buf, len ); else if( val_is_null(pass) ) r = mbedtls_pk_parse_key( pk, buf, len, NULL, 0 ); else r = mbedtls_pk_parse_key( pk, buf, len, (const unsigned char*)val_string(pass), val_strlen(pass) ); if( r != 0 ){ mbedtls_pk_free(pk); return ssl_error(r); } v = alloc_abstract(k_pkey,pk); val_gc(v,free_pkey); return v; }
int C_SecureSocketClient::_secure_mode() { int L_result, L_ret ; m_ssl = SSL_new(m_ssl_ctx); SSL_set_connect_state(m_ssl) ; if ((m_bio = BIO_new_socket(m_socket_id, BIO_CLOSE)) == NULL ) { SOCKET_ERROR(0, "Unable to create the BIO- client in New TLS connection"); } SSL_set_bio(m_ssl,m_bio,m_bio); L_result = SSL_connect(m_ssl) ; if ( L_result < 0 ) { if (SSL_get_error(m_ssl, L_result) == SSL_ERROR_WANT_READ) { m_state = E_SOCKET_STATE_INPROGESS ; L_ret = 0 ; } else { ssl_error(L_result); L_ret = -1 ; } } else { L_ret = 0 ; } return (L_ret); }
int io_start_tls(struct io *io, void *ssl) { int mode; mode = io->flags & IO_RW; if (mode == 0 || mode == IO_RW) errx(1, "io_start_tls(): full-duplex or unset"); if (io->ssl) errx(1, "io_start_tls(): SSL already started"); io->ssl = ssl; if (SSL_set_fd(io->ssl, io->sock) == 0) { ssl_error("io_start_ssl:SSL_set_fd"); return (-1); } if (mode == IO_WRITE) { io->state = IO_STATE_CONNECT_SSL; SSL_set_connect_state(io->ssl); io_reset(io, EV_WRITE, io_dispatch_connect_ssl); } else { io->state = IO_STATE_ACCEPT_SSL; SSL_set_accept_state(io->ssl); io_reset(io, EV_READ, io_dispatch_accept_ssl); } return (0); }
void ssl_set_ephemeral_key_exchange(SSL_CTX *ctx, DH *dh) { if (dh == NULL || !SSL_CTX_set_tmp_dh(ctx, dh)) { ssl_error("ssl_set_ephemeral_key_exchange"); fatal("ssl_set_ephemeral_key_exchange: cannot set tmp dh"); } }
static void ssl_clear_error(void) { while (ERR_peek_error()) { ssl_error(LOG_INFO, "Ignoring stale SSL error"); } ERR_clear_error(); }
int C_SecureSocketClient::_call_write(unsigned char* P_data, size_t P_size) { int L_result = 0 ; L_result = SSL_write(m_ssl,P_data,P_size); if (L_result < 0) ssl_error(L_result) ; return (L_result) ; }
static value ssl_set_hostname( value ssl, value hostname ){ int ret; val_check_kind(ssl,k_ssl); val_check(hostname,string); if( (ret = mbedtls_ssl_set_hostname(val_ssl(ssl), val_string(hostname))) != 0 ) return ssl_error(ret); return val_true; }
SSL_CTX * ssl_ctx_create(const char *pkiname, char *cert, off_t cert_len, const char *ciphers) { SSL_CTX *ctx; size_t pkinamelen = 0; ctx = SSL_CTX_new(SSLv23_method()); if (ctx == NULL) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: could not create SSL context"); } SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_timeout(ctx, SSL_SESSION_TIMEOUT); SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TICKET); SSL_CTX_set_options(ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); SSL_CTX_set_options(ctx, SSL_OP_NO_CLIENT_RENEGOTIATION); SSL_CTX_set_options(ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); if (ciphers == NULL) ciphers = SSL_CIPHERS; if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: could not set cipher list"); } if (cert != NULL) { if (pkiname != NULL) pkinamelen = strlen(pkiname) + 1; if (!SSL_CTX_use_certificate_chain_mem(ctx, cert, cert_len)) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: invalid certificate chain"); } else if (!ssl_ctx_fake_private_key(ctx, pkiname, pkinamelen, cert, cert_len, NULL, NULL)) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: could not fake private key"); } else if (!SSL_CTX_check_private_key(ctx)) { ssl_error("ssl_ctx_create"); fatal("ssl_ctx_create: invalid private key"); } } return (ctx); }
//get some characters from the bio int get_char_buf(BIO* bio, const void *buf, int size) { int messlen = BIO_read(bio, buf, size); if(messlen < 0) { ssl_error("Error while getting message\n"); } //printf("GOT %d bytes from stream\n",messlen); return messlen; }
int C_SecureSocketClient::_call_read() { int L_result = 0 ; L_result = SSL_read(m_ssl, m_read_buf, m_read_buf_size); if (L_result < 0) ssl_error(L_result) ; return (L_result) ; }
void ca_engine_init(void) { ENGINE *e; const char *errstr, *name; if ((e = ENGINE_get_default_RSA()) == NULL) { if ((e = ENGINE_new()) == NULL) { errstr = "ENGINE_new"; goto fail; } if (!ENGINE_set_name(e, rsae_method.name)) { errstr = "ENGINE_set_name"; goto fail; } if ((rsa_default = RSA_get_default_method()) == NULL) { errstr = "RSA_get_default_method"; goto fail; } } else if ((rsa_default = ENGINE_get_RSA(e)) == NULL) { errstr = "ENGINE_get_RSA"; goto fail; } if ((name = ENGINE_get_name(e)) == NULL) name = "unknown RSA engine"; log_debug("debug: %s: using %s", __func__, name); if (rsa_default->flags & RSA_FLAG_SIGN_VER) fatalx("unsupported RSA engine"); if (rsa_default->rsa_mod_exp == NULL) rsae_method.rsa_mod_exp = NULL; if (rsa_default->bn_mod_exp == NULL) rsae_method.bn_mod_exp = NULL; if (rsa_default->rsa_keygen == NULL) rsae_method.rsa_keygen = NULL; rsae_method.flags = rsa_default->flags | RSA_METHOD_FLAG_NO_CHECK; rsae_method.app_data = rsa_default->app_data; if (!ENGINE_set_RSA(e, &rsae_method)) { errstr = "ENGINE_set_RSA"; goto fail; } if (!ENGINE_set_default_RSA(e)) { errstr = "ENGINE_set_default_RSA"; goto fail; } return; fail: ssl_error(errstr); fatalx("%s", errstr); }
void ssl_connect(int s, short event, void *arg) { struct ctl_tcp_event *cte = arg; int retry_flag = 0; int tls_err = 0; int ret; if (event == EV_TIMEOUT) { cte->host->up = HOST_DOWN; hce_notify_done(cte->host, HCE_TLS_CONNECT_TIMEOUT); ssl_cleanup(cte); return; } ret = SSL_connect(cte->ssl); if (ret <= 0) { tls_err = SSL_get_error(cte->ssl, ret); switch (tls_err) { case SSL_ERROR_WANT_READ: retry_flag = EV_READ; goto retry; case SSL_ERROR_WANT_WRITE: retry_flag = EV_WRITE; goto retry; default: cte->host->up = HOST_DOWN; ssl_error(cte->host->conf.name, "cannot connect"); hce_notify_done(cte->host, HCE_TLS_CONNECT_FAIL); ssl_cleanup(cte); return; } } if (cte->table->conf.check == CHECK_TCP) { cte->host->up = HOST_UP; hce_notify_done(cte->host, HCE_TLS_CONNECT_OK); ssl_cleanup(cte); return; } if (cte->table->sendbuf != NULL) { event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_write, &cte->tv_start, &cte->table->conf.timeout, cte); return; } if ((cte->buf = ibuf_dynamic(SMALL_READ_BUF_SIZE, UINT_MAX)) == NULL) fatalx("ssl_connect: cannot create dynamic buffer"); event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_READ, ssl_read, &cte->tv_start, &cte->table->conf.timeout, cte); return; retry: event_again(&cte->ev, s, EV_TIMEOUT|retry_flag, ssl_connect, &cte->tv_start, &cte->table->conf.timeout, cte); }
static value conf_set_cert( value config, value cert, value key ) { int r; val_check_kind(config,k_ssl_conf); val_check_kind(cert,k_cert); val_check_kind(key,k_pkey); if( (r = mbedtls_ssl_conf_own_cert(val_conf(config), val_cert(cert), val_pkey(key))) != 0 ) return ssl_error(r); return val_true; }
static value ssl_new( value config ) { int ret; mbedtls_ssl_context *ssl; val_check_kind(config,k_ssl_conf); ssl = (mbedtls_ssl_context *)alloc(sizeof(mbedtls_ssl_context)); mbedtls_ssl_init(ssl); if( (ret = mbedtls_ssl_setup(ssl, val_conf(config))) != 0 ){ mbedtls_ssl_free(ssl); return ssl_error(ret); } return alloc_abstract( k_ssl, ssl ); }
static value ssl_handshake( value ssl ) { int r; val_check_kind(ssl,k_ssl); POSIX_LABEL(handshake_again); r = mbedtls_ssl_handshake( val_ssl(ssl) ); if( r == SOCKET_ERROR ) { HANDLE_EINTR(handshake_again); return block_error(); }else if( r != 0 ) return ssl_error(r); return val_true; }
SSL_CTX * ssl_ctx_create(struct relayd *env) { SSL_CTX *ctx; ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { ssl_error("ssl_ctx_create", "cannot create context"); fatal("could not create SSL context"); } return (ctx); }
char * ssl_load_key(struct relayd *env, const char *name, off_t *len, char *pass) { FILE *fp; EVP_PKEY *key = NULL; BIO *bio = NULL; long size; char *data, *buf = NULL; /* Initialize SSL library once */ ssl_init(env); /* * Read (possibly) encrypted key from file */ if ((fp = fopen(name, "r")) == NULL) return (NULL); key = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, pass); fclose(fp); if (key == NULL) goto fail; /* * Write unencrypted key to memory buffer */ if ((bio = BIO_new(BIO_s_mem())) == NULL) goto fail; if (!PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) goto fail; if ((size = BIO_get_mem_data(bio, &data)) <= 0) goto fail; if ((buf = calloc(1, size)) == NULL) goto fail; memcpy(buf, data, size); BIO_free_all(bio); EVP_PKEY_free(key); *len = (off_t)size; return (buf); fail: ssl_error(__func__, name); free(buf); if (bio != NULL) BIO_free_all(bio); if (key != NULL) EVP_PKEY_free(key); return (NULL); }
//Experiment encryption function similar to that for files but for character buffers instead. //Was to be used as an alternative to signing the token verification with the public key //but also couldn't get it working. Not used in the end char* decrypt_encrypt_buffer(char *inbuf, int inlen, int *len, unsigned char *key, int do_crypt) { unsigned char *outbuf = malloc(1024 + EVP_MAX_BLOCK_LENGTH); int outlen; unsigned char iv[] = "0"; EVP_CIPHER_CTX ctx; EVP_CIPHER_CTX_init(&ctx); EVP_CipherInit_ex(&ctx, EVP_des_ede3_cbc(), NULL, key, iv, do_crypt); //do_crypt 1 for enc, 0 for dec if(!EVP_CipherUpdate(&ctx, outbuf, &outlen, inbuf, inlen)) { fprintf(stderr, "Cipher Update on buffer\n"); ssl_error("Cipher update"); return NULL; } if(!EVP_CipherFinal_ex(&ctx, outbuf, &outlen)) { ssl_error("cipher final"); return NULL; } *len = outlen; return outbuf; }
int ssl_create_connection(struct ssl_t *ssl, struct client_t *c, int i_am_client) { struct ssl_connection_t *sc; sc = hmalloc(sizeof(*sc)); sc->connection = SSL_new(ssl->ctx); if (sc->connection == NULL) { ssl_error(LOG_ERR, "SSL_new failed"); hfree(sc); return -1; } if (SSL_set_fd(sc->connection, c->fd) == 0) { ssl_error(LOG_ERR, "SSL_set_fd failed"); SSL_free(sc->connection); hfree(sc); return -1; } if (i_am_client) { SSL_set_connect_state(sc->connection); } else { SSL_set_accept_state(sc->connection); } if (SSL_set_ex_data(sc->connection, ssl_connection_index, c) == 0) { ssl_error(LOG_ERR, "SSL_set_ex_data failed"); SSL_free(sc->connection); hfree(sc); return -1; } sc->validate = ssl->validate; c->ssl_con = sc; return 0; }
void ssl_transaction(struct ctl_tcp_event *cte) { if (cte->ssl == NULL) { cte->ssl = SSL_new(cte->table->ssl_ctx); if (cte->ssl == NULL) { ssl_error(cte->host->conf.name, "cannot create object"); fatal("cannot create SSL object"); } } if (SSL_set_fd(cte->ssl, cte->s) == 0) { cte->host->up = HOST_UNKNOWN; ssl_error(cte->host->conf.name, "cannot set fd"); ssl_cleanup(cte); hce_notify_done(cte->host, HCE_TLS_CONNECT_ERROR); return; } SSL_set_connect_state(cte->ssl); event_again(&cte->ev, cte->s, EV_TIMEOUT|EV_WRITE, ssl_connect, &cte->tv_start, &cte->table->conf.timeout, cte); }
static value cert_load_path(value path){ int r; mbedtls_x509_crt *x; value v; val_check(path,string); x = (mbedtls_x509_crt *)alloc(sizeof(mbedtls_x509_crt)); mbedtls_x509_crt_init( x ); if( (r = mbedtls_x509_crt_parse_path(x, val_string(path))) != 0 ){ return ssl_error(r); } v = alloc_abstract(k_cert, x); val_gc(v,free_cert); return v; }