struct asymmetric_key {
RSA *rsa;
+ EVP_PKEY *pkey;
+ EVP_PKEY_CTX *ctx;
};
static int openssl_perror(const char *pfx)
return bnsize + 4;
}
-static int read_public_key(const unsigned char *blob, int blen,
- struct asymmetric_key *result)
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+/*
+ * Convert bignumns e and n to a pkey and context.
+ */
+static int generate_public_pkey(struct asymmetric_key *pub,
+ const BIGNUM *e, const BIGNUM *n)
{
- int ret;
- RSA *rsa;
- BIGNUM *n, *e;
+ unsigned char *ebuf, *nbuf;
+ int ret, ebytes = BN_num_bytes(e), nbytes = BN_num_bytes(n);
+ OSSL_PARAM params[3];
+
+ /* Convert e and n to a buffer for OSSL_PARAM_construct_BN() */
+ ebuf = alloc(ebytes);
+ assert(BN_bn2nativepad(e, ebuf, ebytes) > 0);
+ nbuf = alloc(nbytes);
+ assert(BN_bn2nativepad(n, nbuf, nbytes) > 0);
+ /* Init params[] with {e,n}buf and create the pkey from it */
+ params[0] = OSSL_PARAM_construct_BN("e", ebuf, ebytes);
+ params[1] = OSSL_PARAM_construct_BN("n", nbuf, nbytes);
+ params[2] = OSSL_PARAM_construct_end();
+ pub->ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+ assert(pub->ctx);
+ assert(EVP_PKEY_fromdata_init(pub->ctx) > 0);
+ ret = EVP_PKEY_fromdata(pub->ctx, &pub->pkey, EVP_PKEY_PUBLIC_KEY,
+ params);
+ free(nbuf);
+ free(ebuf);
+ if (ret <= 0) {
+ EVP_PKEY_CTX_free(pub->ctx);
+ return openssl_perror("EVP_PKEY_fromdata()");
+ }
+ assert(pub->pkey);
+ return nbytes * 8;
+}
+#endif /* HAVE_OSSL_PARAM */
+
+static int read_public_key(const unsigned char *blob, size_t blen,
+ struct asymmetric_key *pub)
+{
+ int ret, bits;
const unsigned char *p = blob, *end = blob + blen;
+ BIGNUM *e, *n;
- assert((rsa = RSA_new()));
ret = read_bignum(p, end - p, &e);
if (ret < 0)
- goto free_rsa;
+ return ret;
p += ret;
ret = read_bignum(p, end - p, &n);
- if (ret < 0)
- goto free_e;
-#ifdef HAVE_RSA_SET0_KEY
- RSA_set0_key(rsa, n, e, NULL);
-#else
- rsa->n = n;
- rsa->e = e;
-#endif
- result->rsa = rsa;
- return 1;
-free_e:
+ if (ret < 0) {
+ BN_free(e);
+ return ret;
+ }
+ bits = BN_num_bytes(n) * 8;
+ PARA_DEBUG_LOG("modulus: %d bits\n", bits);
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+ ret = generate_public_pkey(pub, e, n);
BN_free(e);
-free_rsa:
- RSA_free(rsa);
- return ret;
+ BN_free(n);
+ if (ret < 0)
+ return ret;
+#else /* openssl < 3.0 */
+ pub->rsa = RSA_new();
+ assert(pub->rsa);
+ #if HAVE_RSA_SET0_KEY /* openssl-1.1 */
+ RSA_set0_key(pub->rsa, n, e, NULL);
+ #else /* openssl-1.0 */
+ pub->rsa->n = n;
+ pub->rsa->e = e;
+ #endif
+ /* e and n are now owned by openssl */
+#endif /* HAVE_OSSL_PARAM */
+ return bits;
}
static int read_pem_private_key(const char *path, struct asymmetric_key *priv)
unsigned char *blob;
size_t decoded_size;
int ret;
- struct asymmetric_key *pub = alloc(sizeof(*pub));
+ struct asymmetric_key *pub;
ret = decode_public_key(key_file, &blob, &decoded_size);
if (ret < 0)
- goto out;
+ return ret;
+ pub = zalloc(sizeof(*pub)); /* ->pkey needs to start out zeroed */
ret = read_public_key(blob + ret, decoded_size - ret, pub);
- if (ret < 0)
- goto free_blob;
- ret = RSA_size(pub->rsa);
- assert(ret > 0);
- *result = pub;
-free_blob:
free(blob);
-out:
if (ret < 0) {
free(pub);
*result = NULL;
PARA_ERROR_LOG("can not load key %s\n", key_file);
+ return ret;
}
- return ret;
+ PARA_NOTICE_LOG("loaded %d bit key from %s\n", ret, key_file);
+ *result = pub;
+ return ret / 8;
}
void apc_free_pubkey(struct asymmetric_key *pub)
{
if (!pub)
return;
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+ EVP_PKEY_CTX_free(pub->ctx);
+ EVP_PKEY_free(pub->pkey);
+#else
RSA_free(pub->rsa);
+#endif
free(pub);
}
int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
unsigned len, unsigned char **outbuf)
{
- int ret, flen = len; /* RSA_public_encrypt expects a signed int */
+ int ret;
+#ifdef HAVE_OSSL_PARAM /* openssl-3 */
+ EVP_PKEY_CTX *ctx;
+ size_t outlen;
*outbuf = NULL;
- if (flen < 0)
- return -E_ENCRYPT;
+ assert((ctx = EVP_PKEY_CTX_new(pub->pkey, NULL)));
+ assert((EVP_PKEY_encrypt_init(ctx) > 0));
+ assert((EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) > 0));
+ if (EVP_PKEY_encrypt(ctx, NULL, &outlen, inbuf, len) <= 0) {
+ ret = openssl_perror("EVP_PKEY_encrypt()");
+ goto free_ctx;
+ }
+ *outbuf = alloc(outlen);
+ assert((EVP_PKEY_encrypt(ctx, *outbuf, &outlen, inbuf, len) > 0));
+ PARA_INFO_LOG("wrote %zu encrypted data bytes\n", outlen);
+ ret = outlen;
+free_ctx:
+ EVP_PKEY_CTX_free(ctx);
+ return ret;
+#else /* openssl < 3.0 */
*outbuf = alloc(RSA_size(pub->rsa));
- ret = RSA_public_encrypt(flen, inbuf, *outbuf, pub->rsa,
+ ret = RSA_public_encrypt((int)len, inbuf, *outbuf, pub->rsa,
RSA_PKCS1_OAEP_PADDING);
if (ret < 0) {
free(*outbuf);
return -E_ENCRYPT;
}
return ret;
+#endif /* HAVE_OSSL_PARAM */
}
struct stream_cipher {