wi_boolean_t wi_cipher_decrypt_bytes(wi_cipher_t *cipher, const void *encrypted_buffer, wi_uinteger_t encrypted_length, void **out_buffer, wi_uinteger_t *out_length) { void *decrypted_buffer; int decrypted_length, padded_length; decrypted_buffer = wi_malloc(encrypted_length + EVP_CIPHER_block_size(cipher->cipher)); if(EVP_DecryptUpdate(&cipher->decrypt_ctx, decrypted_buffer, &decrypted_length, encrypted_buffer, encrypted_length) != 1) { wi_error_set_openssl_error(); wi_free(decrypted_buffer); return false; } if(EVP_DecryptFinal_ex(&cipher->decrypt_ctx, decrypted_buffer + decrypted_length, &padded_length) != 1) { wi_error_set_openssl_error(); wi_free(decrypted_buffer); return false; } if(EVP_DecryptInit_ex(&cipher->decrypt_ctx, NULL, NULL, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_free(decrypted_buffer); return false; } *out_buffer = decrypted_buffer; *out_length = decrypted_length + padded_length; return true; }
void wi_error_set_openssl_ssl_error_with_result(void *ssl, int result) { wi_error_t *error; int code; code = SSL_get_error(ssl, result); if(code == SSL_ERROR_SYSCALL) { if(ERR_peek_error() == 0) { if(result == 0) wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); else wi_error_set_errno(errno); } else { wi_error_set_openssl_error(); } } else if(code == SSL_ERROR_SSL) { wi_error_set_openssl_error(); } else { error = _wi_error_get_error(); error->domain = WI_ERROR_DOMAIN_OPENSSL_SSL; error->code = code; wi_release(error->string); switch(error->code) { case SSL_ERROR_NONE: error->string = wi_retain(WI_STR("SSL: No error")); break; case SSL_ERROR_ZERO_RETURN: error->string = wi_retain(WI_STR("SSL: Zero return")); break; case SSL_ERROR_WANT_READ: error->string = wi_retain(WI_STR("SSL: Want read")); break; case SSL_ERROR_WANT_WRITE: error->string = wi_retain(WI_STR("SSL: Want write")); break; case SSL_ERROR_WANT_CONNECT: error->string = wi_retain(WI_STR("SSL: Want connect")); break; case SSL_ERROR_WANT_ACCEPT: error->string = wi_retain(WI_STR("SSL: Want accept")); break; case SSL_ERROR_WANT_X509_LOOKUP: error->string = wi_retain(WI_STR("SSL: Want X509 lookup")); break; } } ERR_clear_error(); }
void wi_error_set_openssl_ssl_error_with_result(void *ssl, int result) { wi_string_t *string; int code; code = SSL_get_error(ssl, result); if(code == SSL_ERROR_SYSCALL) { if(ERR_peek_error() == 0) { if(result == 0) wi_error_set_libwired_error(WI_ERROR_SOCKET_EOF); else wi_error_set_errno(errno); } else { wi_error_set_openssl_error(); } } else if(code == SSL_ERROR_SSL) { wi_error_set_openssl_error(); } else { switch(code) { case SSL_ERROR_NONE: string = WI_STR("SSL: No error"); break; case SSL_ERROR_ZERO_RETURN: string = WI_STR("SSL: Zero return"); break; case SSL_ERROR_WANT_READ: string = WI_STR("SSL: Want read"); break; case SSL_ERROR_WANT_WRITE: string = WI_STR("SSL: Want write"); break; case SSL_ERROR_WANT_CONNECT: string = WI_STR("SSL: Want connect"); break; case SSL_ERROR_WANT_ACCEPT: string = WI_STR("SSL: Want accept"); break; case SSL_ERROR_WANT_X509_LOOKUP: string = WI_STR("SSL: Want X509 lookup"); break; default: string = NULL; break; } wi_error_set_error_with_string(WI_ERROR_DOMAIN_OPENSSL_SSL, code, string); } ERR_clear_error(); }
wi_cipher_t * wi_cipher_init_with_key(wi_cipher_t *cipher, wi_cipher_type_t type, wi_data_t *key, wi_data_t *iv) { unsigned char *key_buffer, *iv_buffer; cipher->type = type; cipher->cipher = _wi_cipher_cipher(cipher); key_buffer = (unsigned char *) wi_data_bytes(key); iv_buffer = iv ? (unsigned char *) wi_data_bytes(iv) : NULL; if(EVP_EncryptInit(&cipher->encrypt_ctx, cipher->cipher, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(EVP_DecryptInit(&cipher->decrypt_ctx, cipher->cipher, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } _wi_cipher_configure_cipher(cipher); if(EVP_EncryptInit(&cipher->encrypt_ctx, cipher->cipher, key_buffer, iv_buffer) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(EVP_DecryptInit(&cipher->decrypt_ctx, cipher->cipher, key_buffer, iv_buffer) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } cipher->key = wi_retain(key); cipher->iv = wi_retain(iv); return cipher; }
wi_x509_t * wi_x509_init_with_pem_file(wi_x509_t *x509, wi_string_t *path) { FILE *fp; fp = fopen(wi_string_cstring(path), "r"); if(!fp) { wi_error_set_errno(errno); wi_release(x509); return NULL; } x509->x509 = PEM_read_X509(fp, NULL, NULL, NULL); fclose(fp); if(!x509->x509) { wi_error_set_openssl_error(); wi_release(x509); return NULL; } return x509; }
wi_rsa_t * wi_rsa_init_with_pem_file(wi_rsa_t *rsa, wi_string_t *path) { FILE *fp; fp = fopen(wi_string_cstring(path), "r"); if(!fp) { wi_error_set_errno(errno); wi_release(rsa); return NULL; } rsa->rsa = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL); fclose(fp); if(!rsa->rsa) { wi_error_set_openssl_error(); wi_release(rsa); return NULL; } return rsa; }
wi_socket_tls_t * wi_socket_tls_init_with_type(wi_socket_tls_t *tls, wi_socket_tls_type_t type) { SSL_METHOD *method; switch(type) { default: case WI_SOCKET_TLS_CLIENT: method = TLSv1_client_method(); break; case WI_SOCKET_TLS_SERVER: method = TLSv1_server_method(); break; } tls->ssl_ctx = SSL_CTX_new(method); if(!tls->ssl_ctx) { wi_error_set_openssl_error(); wi_release(NULL); return NULL; } SSL_CTX_set_mode(tls->ssl_ctx, SSL_MODE_AUTO_RETRY); SSL_CTX_set_quiet_shutdown(tls->ssl_ctx, 1); return tls; }
wi_boolean_t wi_socket_tls_set_certificate(wi_socket_tls_t *tls, wi_x509_t *x509) { if(SSL_CTX_use_certificate(tls->ssl_ctx, wi_x509_x509(x509)) != 1) { wi_error_set_openssl_error(); return false; } return true; }
wi_rsa_t * wi_socket_ssl_public_key(wi_socket_t *socket) { #ifdef HAVE_OPENSSL_SSL_H RSA *rsa = NULL; X509 *x509 = NULL; EVP_PKEY *pkey = NULL; x509 = SSL_get_peer_certificate(socket->ssl); if(!x509) { wi_error_set_openssl_error(); goto end; } pkey = X509_get_pubkey(x509); if(!pkey) { wi_error_set_openssl_error(); goto end; } rsa = EVP_PKEY_get1_RSA(pkey); if(!rsa) wi_error_set_openssl_error(); end: if(x509) X509_free(x509); if(pkey) EVP_PKEY_free(pkey); return wi_autorelease(wi_rsa_init_with_rsa(wi_rsa_alloc(), rsa)); #else return NULL; #endif }
wi_boolean_t wi_socket_tls_set_private_key(wi_socket_tls_t *tls, wi_rsa_t *rsa) { tls->private_key = false; if(SSL_CTX_use_RSAPrivateKey(tls->ssl_ctx, wi_rsa_rsa(rsa)) != 1) { wi_error_set_openssl_error(); return false; } tls->private_key = true; return true; }
wi_rsa_t * wi_rsa_init_with_bits(wi_rsa_t *rsa, wi_uinteger_t size) { rsa->rsa = RSA_generate_key(size, RSA_F4, NULL, NULL); if(!rsa->rsa) { wi_error_set_openssl_error(); wi_release(rsa); return NULL; } return rsa; }
wi_boolean_t wi_socket_tls_set_dh(wi_socket_tls_t *tls, const unsigned char *p, size_t p_size, const unsigned char *g, size_t g_size) { tls->dh = DH_new(); if(!tls->dh) { wi_error_set_openssl_error(); return false; } tls->dh->p = BN_bin2bn(p, p_size, NULL); tls->dh->g = BN_bin2bn(g, g_size, NULL); if(!tls->dh->p || !tls->dh->g) { wi_error_set_openssl_error(); DH_free(tls->dh); tls->dh = NULL; return false; } return true; }
wi_boolean_t wi_rsa_decrypt_bytes(wi_rsa_t *rsa, const void *encrypted_buffer, wi_uinteger_t encrypted_length, void **out_buffer, wi_uinteger_t *out_length) { void *decrypted_buffer; int32_t decrypted_length; decrypted_buffer = wi_malloc(RSA_size(rsa->rsa)); decrypted_length = RSA_private_decrypt(encrypted_length, encrypted_buffer, decrypted_buffer, rsa->rsa, RSA_PKCS1_PADDING); if(decrypted_length == -1) { wi_error_set_openssl_error(); wi_free(decrypted_buffer); return false; } *out_buffer = decrypted_buffer; *out_length = decrypted_length; return true; }
wi_data_t * wi_rsa_private_key(wi_rsa_t *rsa) { unsigned char *buffer; int length; if(!rsa->private_key) { buffer = NULL; length = i2d_RSAPrivateKey(rsa->rsa, &buffer); if(length <= 0) { wi_error_set_openssl_error(); return NULL; } rsa->private_key = wi_data_init_with_bytes(wi_data_alloc(), buffer, length); OPENSSL_free(buffer); } return rsa->private_key; }
wi_rsa_t * wi_rsa_init_with_public_key(wi_rsa_t *rsa, wi_data_t *data) { const unsigned char *buffer; long length; buffer = wi_data_bytes(data); length = wi_data_length(data); rsa->rsa = d2i_RSAPublicKey(NULL, (const unsigned char **) &buffer, length); if(!rsa->rsa) { wi_error_set_openssl_error(); wi_release(rsa); return NULL; } rsa->public_key = wi_retain(data); return rsa; }
wi_x509_t * wi_x509_init_with_common_name(wi_x509_t *x509, wi_rsa_t *rsa, wi_string_t *common_name) { X509_REQ *req; EVP_PKEY *pkey = NULL; X509_NAME *name = NULL; BIGNUM *bn = NULL; req = X509_REQ_new(); if(!req) goto err; if(X509_REQ_set_version(req, 0) != 1) goto err; name = X509_NAME_new(); if(X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC, (unsigned char *) wi_string_cstring(common_name), -1, -1, 0) != 1) goto err; if(X509_REQ_set_subject_name(req, name) != 1) goto err; pkey = EVP_PKEY_new(); EVP_PKEY_set1_RSA(pkey, wi_rsa_rsa(rsa)); if(X509_REQ_set_pubkey(req, pkey) != 1) goto err; x509->x509 = X509_new(); if(!x509->x509) goto err; bn = BN_new(); if(!bn) goto err; if(BN_pseudo_rand(bn, 64, 0, 0) != 1) goto err; if(!BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(x509->x509))) goto err; if(X509_set_issuer_name(x509->x509, X509_REQ_get_subject_name(req)) != 1) goto err; if(!X509_gmtime_adj(X509_get_notBefore(x509->x509), 0)) goto err; if(!X509_gmtime_adj(X509_get_notAfter(x509->x509), 3600 * 24 * 365)) goto err; if(X509_set_subject_name(x509->x509, X509_REQ_get_subject_name(req)) != 1) goto end; if(X509_set_pubkey(x509->x509, pkey) != 1) goto err; if(X509_sign(x509->x509, pkey, EVP_sha1()) == 0) goto err; goto end; err: wi_error_set_openssl_error(); wi_release(x509); x509 = NULL; end: if(req) X509_REQ_free(req); if(pkey) EVP_PKEY_free(pkey); if(name) X509_NAME_free(name); if(bn) BN_free(bn); return x509; }
wi_integer_t wi_cipher_decrypt_bytes(wi_cipher_t *cipher, const void *encrypted_buffer, wi_uinteger_t encrypted_length, void *decrypted_buffer) { #ifdef WI_CIPHER_OPENSSL int decrypted_length, padded_length; if(EVP_DecryptUpdate(&cipher->decrypt_ctx, decrypted_buffer, &decrypted_length, encrypted_buffer, encrypted_length) != 1) { wi_error_set_openssl_error(); return -1; } if(EVP_DecryptFinal_ex(&cipher->decrypt_ctx, decrypted_buffer + decrypted_length, &padded_length) != 1) { wi_error_set_openssl_error(); return -1; } if(EVP_DecryptInit_ex(&cipher->decrypt_ctx, NULL, NULL, NULL, NULL) != 1) { wi_error_set_openssl_error(); return -1; } return decrypted_length + padded_length; #endif #ifdef WI_CIPHER_COMMONCRYPTO CCCryptorStatus status; size_t available_length, decrypted_length, padded_length; available_length = wi_cipher_block_size(cipher) + encrypted_length; status = CCCryptorUpdate(cipher->decrypt_ref, encrypted_buffer, encrypted_length, decrypted_buffer, available_length, &decrypted_length); if(status != kCCSuccess) { wi_error_set_commoncrypto_error(status); return -1; } status = CCCryptorFinal(cipher->decrypt_ref, decrypted_buffer + decrypted_length, available_length - decrypted_length, &padded_length); if(status != kCCSuccess) { wi_error_set_commoncrypto_error(status); return -1; } status = CCCryptorReset(cipher->decrypt_ref, cipher->iv ? wi_data_bytes(cipher->iv) : NULL); if(status != kCCSuccess) { wi_error_set_commoncrypto_error(status); return -1; } return decrypted_length + padded_length; #endif }
wi_cipher_t * wi_cipher_init_with_random_key(wi_cipher_t *cipher, wi_cipher_type_t type) { unsigned char *key_buffer, *iv_buffer; int key_length, iv_length; cipher->type = type; cipher->cipher = _wi_cipher_cipher(cipher); key_length = EVP_MAX_KEY_LENGTH; key_buffer = wi_malloc(key_length); iv_length = EVP_CIPHER_iv_length(cipher->cipher); iv_buffer = (iv_length > 0) ? wi_malloc(iv_length) : NULL; if(RAND_bytes(key_buffer, key_length) <= 0) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(iv_buffer) { if(RAND_bytes(iv_buffer, iv_length) <= 0) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } } if(EVP_EncryptInit_ex(&cipher->encrypt_ctx, cipher->cipher, NULL, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(EVP_DecryptInit_ex(&cipher->decrypt_ctx, cipher->cipher, NULL, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } _wi_cipher_configure_cipher(cipher); if(EVP_EncryptInit_ex(&cipher->encrypt_ctx, cipher->cipher, NULL, key_buffer, iv_buffer) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(EVP_DecryptInit_ex(&cipher->decrypt_ctx, cipher->cipher, NULL, key_buffer, iv_buffer) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } cipher->key = wi_data_init_with_bytes_no_copy(wi_data_alloc(), key_buffer, key_length, true); cipher->iv = (iv_length > 0) ? wi_data_init_with_bytes_no_copy(wi_data_alloc(), iv_buffer, iv_length, true) : NULL; return cipher; }
wi_boolean_t wi_socket_accept_tls(wi_socket_t *socket, wi_socket_tls_t *tls, wi_time_interval_t timeout) { wi_socket_state_t state; int err, result; wi_boolean_t blocking; socket->ssl = SSL_new(tls->ssl_ctx); if(!socket->ssl) { wi_error_set_openssl_error(); return false; } if(SSL_set_fd(socket->ssl, socket->sd) != 1) { wi_error_set_openssl_error(); return false; } if(!tls->private_key && tls->dh) { if(SSL_set_tmp_dh(socket->ssl, tls->dh) != 1) { wi_error_set_openssl_error(); return false; } } if(timeout > 0.0) { blocking = wi_socket_blocking(socket); if(blocking) wi_socket_set_blocking(socket, false); result = SSL_accept(socket->ssl); if(result != 1) { do { err = SSL_get_error(socket->ssl, result); if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) { wi_error_set_openssl_ssl_error_with_result(socket->ssl, result); return false; } state = wi_socket_wait_descriptor(socket->sd, 1.0, (err == SSL_ERROR_WANT_READ), (err == SSL_ERROR_WANT_WRITE)); if(state == WI_SOCKET_ERROR) break; else if(state == WI_SOCKET_READY) { result = SSL_accept(socket->ssl); if(result == 1) break; } timeout -= 1.0; } while(timeout >= 0.0); if(state == WI_SOCKET_ERROR) return false; if(timeout <= 0.0) { wi_error_set_errno(ETIMEDOUT); return false; } } if(blocking) wi_socket_set_blocking(socket, true); } else { result = SSL_accept(socket->ssl); if(result != 1) { wi_error_set_openssl_ssl_error_with_result(socket->ssl, result); return false; } } return true; }
static wi_cipher_t * _wi_cipher_init_with_key(wi_cipher_t *cipher, wi_data_t *key, wi_data_t *iv) { #ifdef WI_CIPHER_COMMONCRYPTO CCCryptorStatus status; #endif unsigned char *key_buffer, *iv_buffer; key_buffer = (unsigned char *) wi_data_bytes(key); iv_buffer = iv ? (unsigned char *) wi_data_bytes(iv) : NULL; cipher->key = wi_retain(key); cipher->iv = wi_retain(iv); #ifdef WI_CIPHER_OPENSSL if(EVP_EncryptInit(&cipher->encrypt_ctx, cipher->cipher, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(EVP_DecryptInit(&cipher->decrypt_ctx, cipher->cipher, NULL, NULL) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } _wi_cipher_configure_cipher(cipher); if(EVP_EncryptInit(&cipher->encrypt_ctx, cipher->cipher, key_buffer, iv_buffer) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } if(EVP_DecryptInit(&cipher->decrypt_ctx, cipher->cipher, key_buffer, iv_buffer) != 1) { wi_error_set_openssl_error(); wi_release(cipher); return NULL; } #endif #ifdef WI_CIPHER_COMMONCRYPTO status = CCCryptorCreate(kCCEncrypt, cipher->algorithm, kCCOptionPKCS7Padding, key_buffer, wi_data_length(cipher->key), iv_buffer, &cipher->encrypt_ref); if(status != kCCSuccess) { wi_error_set_commoncrypto_error(status); wi_release(cipher); return NULL; } status = CCCryptorCreate(kCCDecrypt, cipher->algorithm, kCCOptionPKCS7Padding, key_buffer, wi_data_length(cipher->key), iv_buffer, &cipher->decrypt_ref); if(status != kCCSuccess) { wi_error_set_commoncrypto_error(status); wi_release(cipher); return NULL; } #endif return cipher; }