Skip to content

Instantly share code, notes, and snippets.

@dmaclach
Created April 23, 2025 02:27
Show Gist options
  • Save dmaclach/a0f51212e871e19165c6b970bc7158fb to your computer and use it in GitHub Desktop.
Save dmaclach/a0f51212e871e19165c6b970bc7158fb to your computer and use it in GitHub Desktop.
Code snippet for converting between OpenSSL types and SecKeyRefs. Hacky, but it worked for my needs.
uint8_t get_EC_curve(const EC_key_t ec)
{
int nid;
nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
return get_ec_curve_type(nid);
}
static EC_KEY *SecKeyToOpenSSLKey(SecKeyRef secKey, int public) {
CFErrorRef error;
CFDataRef data = SecKeyCopyExternalRepresentation(secKey, &error);
if (!data) {
fprintf(stderr, "unable to copy external representation");
return NULL;
}
EC_KEY *ec;
if ((ec = EC_KEY_new_by_curve_name(
get_ec_curve_nid(get_EC_curve_darwin(secKey)))) == NULL) {
log_ssl_err("EC_KEY_new_by_curve_name failed");
return NULL;
}
CFIndex keylen = CFDataGetLength(data);
const unsigned char *buf = CFDataGetBytePtr(data);
if (public) {
if (!o2i_ECPublicKey(&ec, &buf, keylen)) {
fprintf(stderr, "o2i_ECPublicKey failed");
EC_KEY_free(ec);
return NULL;
}
} else {
CFDataRef derData;
OSStatus status = SecItemExport(secKey, kSecFormatOpenSSL, 0, NULL, &derData);
if (status != noErr) {
fprintf(stderr, "unable to export: %d", status);
return NULL;
}
unsigned char *defBuf = CFDataGetBytePtr(derData);
if (!d2i_ECPrivateKey(&ec, &defBuf, CFDataGetLength(derData))) {
fprintf(stderr, "d2i_ECPrivateKey failed");
EC_KEY_free(ec);
CFRelease(derData);
return NULL;
}
CFRelease(derData);
}
if (!EC_KEY_check_key(ec)) {
fprintf(stderr, "Conversion Failed");
EC_KEY_free(ec);
}
return ec;
}
static SecKeyRef OpenSSLKeyToSecKey(EC_KEY *key, int public) {
if (public) {
size_t keylen;
if ((keylen = i2o_ECPublicKey(key, NULL)) == 0) {
log0(0, 0, 0, "error getting size of EC key");
return 0;
}
unsigned char *buf = safe_malloc(keylen);
unsigned char *tmp = buf;
// After this call, tmp points to (buf + keylen),
// but the exported key lives at buf
if (!i2o_ECPublicKey(key, &tmp)) {
fprintf(stderr, "i2o_ECPublicKey failed");
free(buf);
return NULL;
}
CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, buf, keylen, kCFAllocatorMalloc);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks , &kCFTypeDictionaryValueCallBacks);
CFDictionaryAddValue(dict, kSecAttrKeyType, kSecAttrKeyTypeECDSA);
CFDictionaryAddValue(dict, kSecAttrKeyClass, kSecAttrKeyClassPublic);
CFErrorRef error;
SecKeyRef key = SecKeyCreateWithData(data, dict, &error);
CFRelease(data);
CFRelease(dict);
return key;
} else {
size_t keylen;
if ((keylen = i2d_ECPrivateKey(key, NULL)) == 0) {
fprintf(stderr, "error getting size of EC key");
return 0;
}
unsigned char *buf = safe_malloc(keylen);
unsigned char *tmp = buf;
// After this call, tmp points to (buf + keylen),
// but the exported key lives at buf
if (!i2d_ECPrivateKey(key, &tmp)) {
fprintf(stderr, "i2o_ECPublicKey failed");
free(buf);
return NULL;
}
CFDataRef data = CFDataCreateWithBytesNoCopy(NULL, buf, keylen, kCFAllocatorMalloc);
CFArrayRef array;
SecItemImportExportKeyParameters params;
bzero(&params, sizeof(params));
params.keyAttributes = CFArrayCreate(NULL, &kSecAttrIsExtractable, 1, &kCFTypeArrayCallBacks);
OSStatus status = SecItemImport(data, NULL, NULL, NULL, 0, &params, NULL, &array);
CFRelease(params.keyAttributes);
if (status != noErr) {
fprintf(stderr, "SecItemImport failed %d", status);
return NULL;
}
SecKeyRef key = CFArrayGetValueAtIndex(array, 0);
CFRetain(key);
CFRelease(array);
return key;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment