ECDH harness¶
Key exchange with public point¶
Naming convention¶
CC_ECDH_exchange_point_<curve>
Where curve
is one of:
P192
,P224
,P256
,P384
,P521
.B163
,B223
,B283
,B409
,B571
.K163
,K223
,K283
,K409
,K571
.
Attention
OpenSSL 3.0 does not support B
or K
curves, so they are untested in harness mode.
Function signature¶
- int ECDH_exchange_point(
- uint8_t ss[512],
- size_t *ss_size,
- const uint8_t *secret,
- const size_t secret_size,
- const uint8_t *point,
- const size_t point_size,
Performs an ECDH key exchange with an encoded uncompressed point.
- Parameters:
ss – [Out] An allocated buffer to return the shared secret.
ss_size – [Out] A pointer to return the actual size of the shared secret.
secret – [In] Peer A’s secret value as a big-endian array of bytes.
secret_size – [In] The size of
secret
in bytes.point – [In] Peer B’s public key as an encoded uncompressed point.
point_size – [In] The size of
point_size
in bytes.
- Returns:
A status code.
- Return values:
1 – OK.
0 – An error occurred.
Example¶
To test that the harness integration is working correctly, we use the following OpenSSL harness:
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/obj_mac.h>
#include <openssl/objects.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int generic_exchange_point(const char *curve, uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *point, const size_t point_size);
/* Test exchange_point with P curves */
/* There are no exchange_point test vectors for secp256k1 or Brainpool curves */
/* OpenSSL 3.0 does not support NIST B or K curves */
int CC_ECDH_exchange_point_P256(uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *point, const size_t point_size) {
return generic_exchange_point("prime256v1", ss, ss_size, secret, secret_size,
point, point_size);
}
int CC_ECDH_exchange_point_P384(uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *point, const size_t point_size) {
return generic_exchange_point("secp384r1", ss, ss_size, secret, secret_size,
point, point_size);
}
int CC_ECDH_exchange_point_P521(uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *point, const size_t point_size) {
return generic_exchange_point("secp521r1", ss, ss_size, secret, secret_size,
point, point_size);
}
/**
* Generic exchange_point function
*
* Uses functions deprecated in OpenSSL 3.0.
* The fprintf statements are mostly for debugging.
*/
int generic_exchange_point(const char *curve, uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *point, const size_t point_size) {
int nid = OBJ_txt2nid(curve);
if (nid == NID_undef) {
fprintf(stderr, "Failed to get NID for %s\n", curve);
return 0;
}
EC_KEY *ec_sk = EC_KEY_new_by_curve_name(nid);
if (ec_sk == NULL) {
fprintf(stderr, "Failed to create ec_sk by curve name\n");
return 0;
}
BIGNUM *prv = BN_bin2bn(secret, secret_size, NULL);
if (prv == NULL) {
fprintf(stderr, "Failed to get BIGNUM from secret\n");
return 0;
}
if (!EC_KEY_set_private_key(ec_sk, prv)) {
fprintf(stderr, "Failed to set private key\n");
return 0;
}
EC_KEY *ec_pk = EC_KEY_new_by_curve_name(nid);
if (ec_pk == NULL) {
fprintf(stderr, "Failed to create ec_pk by curve name\n");
return 0;
}
const EC_GROUP *group = EC_KEY_get0_group(ec_pk);
if (group == NULL) {
fprintf(stderr, "Failed to get group from key\n");
return 0;
}
EC_POINT *pub = EC_POINT_new(group);
if (pub == NULL) {
fprintf(stderr, "Failed to create point from group\n");
return 0;
}
if (!EC_POINT_oct2point(group, pub, point, point_size, NULL)) {
fprintf(stderr, "Failed to convert oct to point\n");
return 0;
}
if (!EC_KEY_set_public_key(ec_pk, pub)) {
fprintf(stderr, "Failed to set public key\n");
}
EVP_PKEY *sk = EVP_PKEY_new();
if (!EVP_PKEY_set1_EC_KEY(sk, ec_sk)) {
fprintf(stderr, "Failed to set sk\n");
return 0;
}
EVP_PKEY *pk = EVP_PKEY_new();
if (!EVP_PKEY_set1_EC_KEY(pk, ec_pk)) {
fprintf(stderr, "Failed to set pk\n");
return 0;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(sk, NULL);
if (!ctx) {
return 0;
}
if (EVP_PKEY_derive_init(ctx) <= 0) {
fprintf(stderr, "Failed to derive_init\n");
return 0;
}
if (EVP_PKEY_derive_set_peer(ctx, pk) <= 0) {
fprintf(stderr, "Failed to derive_set_peer\n");
return 0;
}
if (EVP_PKEY_derive(ctx, NULL, ss_size) <= 0) {
fprintf(stderr, "Failed to get ss_size with derive\n");
return 0;
}
if (EVP_PKEY_derive(ctx, ss, ss_size) <= 0) {
fprintf(stderr, "Failed to derive\n");
return 0;
}
return 1;
}
Compile the shared library with the -lssl -lcrypto
options.
gcc -fPIC -shared ecdh_point_harness.c -o ecdh_point.so -lssl -lcrypto
Then test the harness.
crypto-condor-cli test harness ecdh_point.so
Key exchange with X.509 key¶
Naming convention¶
CC_ECDH_exchange_point_<curve>
Where curve
is one of:
P192
,P224
,P256
,P384
,P521
.brainpoolP224r1
,brainpoolP256r1
,brainpoolP320r1
,brainpoolP384r1
,brainpoolP512r1
.secp256k1
.B163
,B223
,B283
,B409
,B571
.K163
,K223
,K283
,K409
,K571
.
Attention
OpenSSL 3.0 does not support B
or K
curves, so they are untested in harness mode.
Function signature¶
- int ECDH_exchange_x509(
- uint8_t ss[512],
- size_t *ss_size,
- const uint8_t *secret,
- const size_t secret_size,
- const uint8_t *pub,
- const size_t pub_size,
Performs an ECDH key exchange with an encoded uncompressed point.
- Parameters:
ss – [Out] An allocated buffer to return the shared secret.
ss_size – [Out] A pointer to return the actual size of the shared secret.
secret – [In] Peer A’s secret value as a big-endian array of bytes.
secret_size – [In] The size of
secret
in bytes.pub – [In] Peer B’s public key as an X.509 key.
point_size – [In] The size of
pub_size
in bytes.
- Returns:
A status code.
- Return values:
1 – OK.
0 – An error occurred.
Example¶
To test that the harness integration is working correctly, we use the following OpenSSL harness:
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/obj_mac.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int generic_exchange_x509(const char *curve, uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *point, const size_t point_size);
/* Test exchange_point with P curves */
/* OpenSSL 3.0 does not support NIST B or K curves */
int CC_ECDH_exchange_x509_P256(uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *pub, const size_t pub_size) {
return generic_exchange_x509("prime256v1", ss, ss_size, secret, secret_size,
pub, pub_size);
}
int CC_ECDH_exchange_x509_P384(uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *pub, const size_t pub_size) {
return generic_exchange_x509("secp384r1", ss, ss_size, secret, secret_size,
pub, pub_size);
}
int CC_ECDH_exchange_x509_P521(uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *pub, const size_t pub_size) {
return generic_exchange_x509("secp521r1", ss, ss_size, secret, secret_size,
pub, pub_size);
}
/**
* Generic exchange_point function
*
* Uses functions deprecated in OpenSSL 3.0.
* The fprintf statements are mostly for debugging.
*/
int generic_exchange_x509(const char *curve, uint8_t ss[512], size_t *ss_size,
const uint8_t *secret, const size_t secret_size,
const uint8_t *pub, const size_t pub_size) {
int nid = OBJ_txt2nid(curve);
if (nid == NID_undef) {
fprintf(stderr, "Failed to get NID for %s\n", curve);
return 0;
}
EC_KEY *ec_sk = EC_KEY_new_by_curve_name(nid);
if (ec_sk == NULL) {
fprintf(stderr, "Failed to create ec_sk by curve name\n");
return 0;
}
BIGNUM *prv = BN_bin2bn(secret, secret_size, NULL);
if (prv == NULL) {
fprintf(stderr, "Failed to get BIGNUM from secret\n");
return 0;
}
if (!EC_KEY_set_private_key(ec_sk, prv)) {
fprintf(stderr, "Failed to set private key\n");
return 0;
}
EVP_PKEY *sk = EVP_PKEY_new();
if (!EVP_PKEY_set1_EC_KEY(sk, ec_sk)) {
fprintf(stderr, "Failed to set sk\n");
return 0;
}
EVP_PKEY *pk = d2i_PUBKEY(NULL, &pub, pub_size);
if (!pk) {
fprintf(stderr, "Failed to read pubkey from pub\n");
return 0;
}
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(sk, NULL);
if (!ctx) {
return 0;
}
if (EVP_PKEY_derive_init(ctx) <= 0) {
fprintf(stderr, "Failed to derive_init\n");
return 0;
}
if (EVP_PKEY_derive_set_peer(ctx, pk) <= 0) {
fprintf(stderr, "Failed to derive_set_peer\n");
return 0;
}
if (EVP_PKEY_derive(ctx, NULL, ss_size) <= 0) {
fprintf(stderr, "Failed to get ss_size with derive\n");
return 0;
}
if (EVP_PKEY_derive(ctx, ss, ss_size) <= 0) {
fprintf(stderr, "Failed to derive\n");
return 0;
}
return 1;
}
Compile the shared library with the -lssl -lcrypto
options.
gcc -fPIC -shared ecdh_x509_harness.c -o ecdh_x509.so -lssl -lcrypto
Then test the harness.
crypto-condor-cli test harness ecdh_x509.so