Most of the code build atop OpenSSL 0.9.x or OpenSSL 1.0.x needs significant modification to be compiled against OpenSSL 1.1 due to API changes and structures being opaque. This document is an attempt to aid such transition.
Note: The examples below omits error checks. For production code, check return of the function and bail accordingly.
Copycat of this page without credit is also available, if you prefer more eyecandy.
$Id: migrate2openssl-1.1.html,v 1.2 2021-10-22 21:15:54+09 kabe Exp $
BIGNUM dh_pub; - if (dh_pub->neg) + if (BN_is_negative(dh_pub)) - BN_num_bits(key->rsa->n) + RSA_bits(key->rsa)
DH *dh; - BN_sub(tmp, dh->p, BN_value_one()); + const BIGNUM *p; + DH_get0_pqg(dh, &p, NULL, NULL); + BN_sub(tmp, p, BN_value_one()); - dh->length = MINIMUM(need * 2, pbits - 1); + DH_set_length(dh, MIN(need * 2, pbits - 1)) - if (!dh_pub_is_valid(dh, dh->pub_key))) ... + BIGNUM *pub_key, *priv_key; + DH_get0_key(dh, &pub_key, &priv_key); + if (!dh_pub_is_valid(dh, pub_key)) ...*_get0_*() functions does not increment the reference count of the BIGNUM, so do NOT
BN_free()
the values returned.
Zero means they don't increment refcount.
BIGNUM *modulus, *gen; ... - dh->p = modulus; - dh->g = gen; + DH_set0_pqg(dh, modulus, NULL, gen);*_set0_*() functions takes ownership of the passed in BIGNUM*, so you should allocate it by
BN_new()
,
and not free them after passing them in (except if *set0*() failed).
Most of the *_set0_* functions just stashes the passed parameters to internal structures, but some does parameter checking and could fail. You must check the return.
RSA *key; - if (BN_num_bits(key->e) < 2) ... - olen = BN_num_bytes(key->n); + const BIGNUM *e, *n; + RSA_get0_key(key, &n, &e, NULL); + if (BN_num_bits(e) < 2)... + olen = BN_num_bytes(n); - BN_num_bytes(key->n) + RSA_size(key) RSA *rsa; - ... rsa->p, rsa->q, rsa->d, ... + const BIGNUM *q, *d, *p; + RSA_get0_key(rsa, NULL, NULL, &d); + RSA_get0_factors(rsa, &p, &q); + ... p, q, d, ... BIGNUM *dmq1, *dmp1; ... - rsa->dmq1 = dmq1; - rsa->dmp1 = dmp1; + RSA_set0_crt_params(rsa, dmp1, dmq1, NULL); /* receives data from buffer */ - buffer_get_bignum_bits(b, rsa->d); - buffer_get_bignum_bits(b, rsa->n); - buffer_get_bignum_bits(b, rsa->iqmp); - buffer_get_bignum_bits(b, rsa->q); - buffer_get_bignum_bits(b, rsa->p); + BIGNUM *d=NULL, *n=NULL, *iqmp=NULL, *q=NULL, *p=NULL; + BIGNUM *dmp1=NULL, *dmq1=NULL; /* dummy input to set in RSA_set0_crt_params */ + d=BN_new(); n=BN_new(); iqmp=BN_new(); + q=BN_new(); p=BN_new(); + buffer_get_bignum_bits(b, d); + buffer_get_bignum_bits(b, n); + buffer_get_bignum_bits(b, iqmp); + buffer_get_bignum_bits(b, q); + buffer_get_bignum_bits(b, p); + RSA_set0_key(rsa, n, rsa_e, d); + RSA_set0_factors(rsa, p, q); + /* dmp1, dmq1 should not be NULL for initial set0 */ + dmp1=BN_new(); BN_clear(dmp1); + dmq1=BN_new(); BN_clear(dmq1); + RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp);
struct sshkey *key; - if (BN_num_bits(key->rsa->n) < SSH_RSA_MINIMUM_MODULUS_SIZE) + if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE)
- RSA_METHOD helper_rsa; + RSA_METHOD *helper_rsa; - memcpy(&helper_rsa, RSA_get_default_method(), sizeof(helper_rsa)); + helper_rsa = RSA_meth_dup(RSA_get_default_method()); - helper_rsa.name = "ssh-pkcs11-helper"; - helper_rsa.rsa_priv_enc = pkcs11_rsa_private_encrypt; + RSA_meth_set1_name(helper_rsa, "ssh-pkcs11-helper"); + RSA_meth_set_priv_enc(helper_rsa, pkcs11_rsa_private_encrypt); - RSA_METHOD rsa_method; + RSA_METHOD *rsa_method; const RSA_METHOD *def = RSA_get_default_method(); RSA *rsa; ... - ... = def->finish; + ... = RSA_meth_get_finish(def); - memcpy(&rsa_method, def, sizeof(k11->rsa_method)); - rsa_method.name = "pkcs11"; - rsa_method.rsa_priv_enc = pkcs11_rsa_private_encrypt; - rsa_method.rsa_priv_dec = pkcs11_rsa_private_decrypt; - rsa_method.finish = pkcs11_rsa_finish; + rsa_method = RSA_meth_new("pkcs11", RSA_meth_get_flags(def)); + RSA_meth_set_priv_enc(rsa_method, pkcs11_rsa_private_encrypt); + RSA_meth_set_priv_dec(rsa_method, pkcs11_rsa_private_decrypt); + RSA_meth_set_finish(rsa_method, pkcs11_rsa_finish);
- EVP_CIPHER_CTX evp; + EVP_CIPHER_CTX *evpEvery EVP_* functions manipulating on EVP_CIPHER_CTX should be passing opaque pointer, not a reference of real struct.
- EVP_CIPHER_CTX_init(&evp); + evp = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_free(evp); /* do not forget to free after usage or error */ - EVP_CipherInit(&evp, EVP_des_cbc(), k1, NULL, enc) + EVP_CipherInit(evp, EVP_des_cbc(), k1, NULL, enc) - EVP_Cipher(&evp, dest, (u_char *)src, len); + EVP_Cipher(evp, dest, (u_char *)src, len) - EVP_CIPHER_CTX_cleanup(&evp); + EVP_CIPHER_CTX_free(evp); - memcpy(evp.iv, iv, 8); /* direct write to Initial Vector */ + memcpy(EVP_CIPHER_CTX_iv_noconst(evp), iv, 8) /* use accessor */ - memcpy(iv, evp.iv, len); /* direct read from Initial Vector */ + memcpy(iv, EVP_CIPHER_CTX_iv(evp), len); - ... = (evp)->cipher_data; + ... = EVP_CIPHER_CTX_get_cipher_data(evp) - ... = (evp)->cipher->ctx_size; + ... = EVP_CIPHER_impl_ctx_size(EVP_CIPHER_CTX_cipher(evp))
- static EVP_CIPHER ssh1_3des; - memset(&ssh1_3des, 0, sizeof(ssh1_3des)); - ssh1_3des.nid = NID_undef; - ssh1_3des.block_size = 8; - ssh1_3des.iv_len = 0; - ssh1_3des.key_len = 16; - ssh1_3des.init = ssh1_3des_init; - ssh1_3des.cleanup = ssh1_3des_cleanup; - ssh1_3des.do_cipher = ssh1_3des_cbc; - ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH; + static EVP_CIPHER *ssh1_3des_p; + ssh1_3des_p = EVP_CIPHER_meth_new(NID_undef, /*block_size*/8, /*key_len*/16); + EVP_CIPHER_meth_set_iv_length(ssh1_3des_p, 0); + EVP_CIPHER_meth_set_init(ssh1_3des_p, ssh1_3des_init); + EVP_CIPHER_meth_set_cleanup(ssh1_3des_p, ssh1_3des_cleanup); + EVP_CIPHER_meth_set_do_cipher(ssh1_3des_p, ssh1_3des_cbc); + EVP_CIPHER_meth_set_flags(ssh1_3des_p, EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH); - static EVP_CIPHER ssh1_bf; + static EVP_CIPHER *ssh1_bfp; - memcpy(&ssh1_bf, EVP_bf_cbc(), sizeof(EVP_CIPHER)); - orig_bf = ssh1_bf.do_cipher; - ssh1_bf.key_len = 32; + orig_bf = EVP_CIPHER_meth_get_do_cipher(EVP_bf_cbc()); + ssh1_bfp = EVP_CIPHER_meth_new(NID_undef, /*block_size*/8, /*key_len*/32); - ssh1_bf.do_cipher = bf_ssh1_cipher; + EVP_CIPHER_meth_set_do_cipher(ssh1_bfp, bf_ssh1_cipher); + /* set remaining members of new ssh1_bfp */ + EVP_CIPHER_meth_set_iv_length(ssh1_bfp, 8); + EVP_CIPHER_meth_set_flags(ssh1_bfp, EVP_CIPH_VARIABLE_LENGTH | EVP_CIPH_CBC_MODE); + EVP_CIPHER_meth_set_init(ssh1_bfp, EVP_CIPHER_meth_get_init(EVP_bf_cbc())); + EVP_CIPHER_meth_set_cleanup(ssh1_bfp, EVP_CIPHER_meth_get_cleanup(EVP_bf_cbc())); + EVP_CIPHER_meth_set_impl_ctx_size(ssh1_bfp, /*sizeof(EVP_BF_KEY) == */sizeof(BF_KEY)); + EVP_CIPHER_meth_set_set_asn1_params(ssh1_bfp, EVP_CIPHER_set_asn1_iv); + EVP_CIPHER_meth_set_get_asn1_params(ssh1_bfp, EVP_CIPHER_get_asn1_iv); + EVP_CIPHER_meth_set_ctrl(ssh1_bfp, NULL); + /*app_data = NULL*/
- EVP_MD_CTX mdctx; + EVP_MD_CTX *mdctx; - EVP_MD_CTX_init(&mdctx); + mdctx = EVP_MD_CTX_new(); - EVP_MD_CTX_cleanup(&mdctx); + EVP_MD_CTX_free(mdctx);
- switch (EVP_PKEY_type(pubkey->type)) { + switch (EVP_PKEY_type(EVP_PKEY_id(pubkey))) { - evp->pkey.rsa + EVP_PKEY_get0_RSA(evp)
DSA *dsa; - dsa->p = BN_new(); - dsa->q = BN_new(); - dsa->g = BN_new(); - dsa->pub_key = BN_new(); + BIGNUM *p=NULL, *q=NULL, *g=NULL, *pubkey=NULL; + p=BN_new(); q=BN_new(); g=BN_new(); pub_key=BN_new(); + DSA_set0_pqg(dsa, p, q, g); + DSA_set0_key(dsa, pubkey, NULL); - BN_cmp(a->dsa->p, b->dsa->p) == 0 && - BN_cmp(a->dsa->q, b->dsa->q) == 0 && ... + const BIGNUM *a_p, *a_q, *a_g, ... + const BIGNUM *b_p, *b_q, *b_g, ... + DSA_get0_pqg(a->dsa, &a_p, &a_q, &a_g); + DSA_get0_pqg(b->dsa, &b_p, &b_q, &b_g); + BN_cmp(a_p, b_p) == 0 && + BN_cmp(a_q, b_q) == 0 && ...
DSA_SIG *sig; ... - rlen = BN_num_bytes(sig->r); - slen = BN_num_bytes(sig->s); const BIGNUM *r, *s; + DSA_SIG_get0(sig, &r, &s); + rlen = BN_num_bytes(r); + slen = BN_num_bytes(s); - sig->r = r; - sig->s = s; + DSA_SIG_set0(sig, r, s);
ECDSA_SIG *sig; - ... sig->r, sig->s, ... + const BIGNUM *r, *s; + ECDSA_SIG_get0(sig, &r, &s); + ... r, s, ... /* this assigns sig->r, sig->s */ - if (sshbuf_get_bignum2(sigbuf, sig->r) != 0 || - sshbuf_get_bignum2(sigbuf, sig->s) != 0) ... + BIGNUM *r=NULL, *s=NULL; + r = BN_new(); s = BN_new(); + if (sshbuf_get_bignum2(sigbuf, r) != 0 || + sshbuf_get_bignum2(sigbuf, s) != 0) ... + ECDSA_SIG_set0(sig, r, s);
- bio = BIO_new(&BioMethods); - bio->ptr = (char*)statePtr; - bio->init = 1; - bio->shutdown = flags; + bio = BIO_new(BIO_s_tcl()); + BIO_set_data(bio, (void*)statePtr); + BIO_set_init(bio, 1); + BIO_set_shutdown(bio, flags); -static BIO_METHOD BioMethods = { - BIO_TYPE_TCL, "tcl", - BioWrite, - BioRead, - BioPuts, - NULL, /* BioGets */ - BioCtrl, - BioNew, - BioFree, -}; BIO_METHOD * BIO_s_tcl() { - return &BioMethods; + static BIO_METHOD *biom = NULL; + if (!biom) { + biom = BIO_meth_new(BIO_TYPE_TCL, "tcl"); + BIO_meth_set_write(biom, BioWrite); + BIO_meth_set_read(biom, BioRead); + BIO_meth_set_puts(biom, BioPuts); + BIO_meth_set_ctrl(biom, BioCtrl); + BIO_meth_set_create(biom, BioNew); + BIO_meth_set_destroy(biom, BioFree); + } + return biom; } BIO bio; - Tcl_Channel chan = Tls_GetParent((State*)(bio->ptr)); + Tcl_Channel chan = Tls_GetParent((State*)BIO_get_data(bio)); - bio->ptr = *((char **)ptr); - bio->shutdown = (int)num; - bio->init = 1; + BIO_set_data(bio, *((char **)ptr)); + BIO_set_shutdown(bio, (int)num); + BIO_set_init(bio, 1); - ret = bio->num; + ret = BIO_get_fd(bio, ptr); - ret = bio->shutdown; + ret = BIO_get_shutdown(bio); - bio->shutdown = (int)num; + BIO_set_shutdown(bio, (int)num); - bio->flags = 0; + BIO_clear_flags(bio, ~0);bio->num (file descripter) could be set by
BIO_set_fd()
,
but since this callbacks the routine set by
BIO_meth_set_ctrl(biom, BioCtrl)
, beware of infinite loops.
Recommend to not touch bio->num member and leave it alone.
SSL *handle; ... - handle->options |= SSL_OP_NO_TLSv1; +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + SSL_set_min_proto_version(handle, TLS1_1_VERSION); +#else + SSL_set_options(handle, SSL_OP_NO_TLSv1); +#endif
EVP_CipherInit()
has semantics changed to clear all previous settings,
so you may want to replace it with EVP_CipherInit_ex()
, if the original code
is building parameters by multiple EVP_CipherInit()
calls.
- EVP_CipherInit(cc->evp, NULL, (u_char *)key, NULL, -1); + /* in OpenSSL 1.1.0, EVP_CipherInit clears all previous setups; + use EVP_CipherInit_ex for augmenting */ + EVP_CipherInit_ex(cc->evp, NULL, NULL, (u_char *)key, NULL, -1);
X509_STORE_CTX_get_app_data()
has changed semantics.
Compilers wouldn't catch this change; not replacing this will
likely cause Segmentation Fault.
- SSL *ssl = (SSL*)X509_STORE_CTX_get_app_data(ctx); + SSL *ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());