Skip to content

Commit

Permalink
improve keychain integration
Browse files Browse the repository at this point in the history
- use proper key size
- apple: need to store pubkey back to keychain
- apple: do not attempt to generate key with existing tag
  • Loading branch information
ekoby committed Jul 26, 2024
1 parent 734ffe9 commit f39b19b
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 33 deletions.
1 change: 1 addition & 0 deletions include/tlsuv/keychain.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct keychain_s {
int (*rem_key)(const char *name);

enum keychain_key_type (*key_type)(keychain_key_t k);
int (*key_bits)(keychain_key_t);
int (*key_public)(keychain_key_t k, char *buf, size_t *len);
int (*key_sign)(keychain_key_t k, const uint8_t * data, size_t datalen,
uint8_t *sig, size_t *siglen, int p);
Expand Down
81 changes: 62 additions & 19 deletions src/apple/keychain.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "../keychain.h"
#include "um_debug.h"

static SecKeyRef find_private_key(const char *name, OSStatus *code);

static const char* keychain_strerror(OSStatus s) {
static char err[1024];
CFStringRef e = SecCopyErrorMessageString(s, NULL);
Expand Down Expand Up @@ -39,8 +41,15 @@ static const char* keychain_errmsg(CFErrorRef err) {
}

static int gen_key(keychain_key_t *pk, enum keychain_key_type type, const char *name) {
UM_LOG(DEBG, "generating key %s", name);
static int32_t ec_size = 256;
SecKeyRef existing = find_private_key(name, NULL);
if (existing != NULL) {
UM_LOG(WARN, "key[%s] already exists", name);
CFRelease(existing);
return EEXIST;
}

UM_LOG(DEBG, "generating key[%s]", name);
static int32_t ec_size = 521;
static int rsa_size = 4096;

CFNumberRef bits = NULL;
Expand All @@ -52,12 +61,12 @@ static int gen_key(keychain_key_t *pk, enum keychain_key_type type, const char *
bits = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &rsa_size);
cf_key_type = kSecAttrKeyTypeRSA;
} else {
return -1;
return EINVAL;
}

CFDataRef tag = CFDataCreate(kCFAllocatorDefault, (const uint8_t *)name, (CFIndex) strlen(name));
CFStringRef label = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingUTF8);

CFMutableDictionaryRef params = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
CFDictionaryAddValue(params, kSecAttrKeyClass, kSecAttrKeyClassPrivate);
CFDictionaryAddValue(params, kSecReturnRef, kCFBooleanTrue);
Expand All @@ -70,7 +79,24 @@ static int gen_key(keychain_key_t *pk, enum keychain_key_type type, const char *

CFErrorRef error = NULL;
SecKeyRef key = SecKeyCreateRandomKey(params, &error);
SecKeyRef pub = SecKeyCopyPublicKey(key);

// store public key back so that pubkey data can be loaded after
// https://forums.developer.apple.com/forums/thread/8030
CFMutableDictionaryRef pubparams = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
CFDictionaryAddValue(pubparams, kSecAttrApplicationTag, tag);
CFDictionaryAddValue(pubparams, kSecAttrLabel, label);
CFDictionarySetValue(pubparams, kSecAttrIsExtractable, kCFBooleanTrue);
CFDictionaryAddValue(pubparams, kSecAttrIsPermanent, kCFBooleanTrue);
CFDictionarySetValue(pubparams, kSecValueRef, pub);

OSStatus pubadd = SecItemAdd(pubparams, NULL);
if (pubadd != errSecSuccess) {
UM_LOG(WARN, "failed to store pubkey to keychain: %s", keychain_strerror(pubadd));
}

CFRelease(pubparams);
CFRelease(pub);
CFRelease(params);
CFRelease(tag);
CFRelease(label);
Expand All @@ -89,6 +115,8 @@ static int key_size(keychain_key_t k) {
CFNumberRef num = CFDictionaryGetValue(atts, kSecAttrKeySizeInBits);
int val = 0;
CFNumberGetValue(num, kCFNumberNSIntegerType, &val);
CFRelease(num);
CFRelease(atts);
return val;
}

Expand Down Expand Up @@ -124,7 +152,7 @@ static int key_public(keychain_key_t k, char *buf, size_t *len) {
if (err != NULL) {
UM_LOG(ERR, "failed to retrieve public key: %s", keychain_errmsg(err));
CFRelease(pub);
return -1;
return (int)CFErrorGetCode(err);
}

CFIndex publen = CFDataGetLength(d);
Expand Down Expand Up @@ -152,11 +180,15 @@ static int key_sign(keychain_key_t k,
algorithm = kSecKeyAlgorithmECDSASignatureDigestX962SHA256;
break;
case keychain_key_rsa:
algorithm = kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw;
if (p == 1) { // RSA_PKCS1_PADDING
algorithm = kSecKeyAlgorithmRSASignatureDigestPKCS1v15Raw;
} else if (p == 3) { // RSA_NO_PADDING
algorithm = kSecKeyAlgorithmRSASignatureRaw;
}
break;
default:
UM_LOG(ERR, "unsupported key type");
return -1;
return EINVAL;
};

CFDataRef d = CFDataCreate(kCFAllocatorDefault, data, (CFIndex)datalen);
Expand All @@ -174,7 +206,7 @@ static int key_sign(keychain_key_t k,
}

UM_LOG(WARN, "failed to sign data: %s", keychain_errmsg(err));
return -1;
return (int) CFErrorGetCode(err);
}

static void free_key(keychain_key_t k) {
Expand Down Expand Up @@ -204,9 +236,7 @@ static int rem_key(const char *name) {
return 0;
}

static int load_key(keychain_key_t *k, const char *name) {
UM_LOG(INFO, "loading key %s", name);

static SecKeyRef find_private_key(const char *name, OSStatus *code) {
CFDataRef tag = CFDataCreate(kCFAllocatorDefault, (const uint8_t *)name, (CFIndex) strlen(name));

CFMutableDictionaryRef q = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL);
Expand All @@ -220,19 +250,31 @@ static int load_key(keychain_key_t *k, const char *name) {
CFRelease(q);
CFRelease(tag);

if (code) *code = r;

if (r == errSecSuccess) {
assert(ref != NULL);
*k = (keychain_key_t) ref;
return 0;
assert(CFGetTypeID(ref) == SecKeyGetTypeID());
return (SecKeyRef)ref;
}

return NULL;
}

if (ref) {
CFRelease(ref);
}
static int load_key(keychain_key_t *k, const char *name) {
UM_LOG(INFO, "loading key %s", name);

OSStatus r;
SecKeyRef key = find_private_key(name, &r);

*k = NULL;
UM_LOG(ERR, "failed to load key[%s]: %s", name, keychain_strerror(r));
return -1;
if (k != NULL) {
*k = (keychain_key_t) key;
}
if (r != errSecSuccess) {
UM_LOG(ERR, "failed to load key[%s]: %s", name, keychain_strerror(r));
return ENOENT;
}
return 0;
}

static keychain_t apple_keychain = {
Expand All @@ -241,6 +283,7 @@ static keychain_t apple_keychain = {
.free_key = free_key,
.rem_key = rem_key,
.key_type = key_type,
.key_bits = key_size,
.key_public = key_public,
.key_sign = key_sign,
};
Expand Down
2 changes: 1 addition & 1 deletion src/openssl/engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ goto on_error; \
}}while(0)

ssl_check(X509_REQ_set_pubkey(req, pk));
ssl_check(X509_REQ_sign(req, pk, EVP_sha1()));
ssl_check(X509_REQ_sign(req, pk, EVP_sha256()));
ssl_check(PEM_write_bio_X509_REQ(b, req));

on_error:
Expand Down
31 changes: 18 additions & 13 deletions src/openssl/keys.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,15 +500,16 @@ int gen_pkcs11_key(tlsuv_private_key_t *key, const char *pkcs11driver, const cha

int load_kc_key(EVP_PKEY **pkey, keychain_key_t k) {
uv_once(&init_once, init);
const keychain_t *keychain = tlsuv_keychain();
assert(keychain);

int rc = 0;
EVP_PKEY_CTX *pkey_ctx = NULL;
char pub[1024];
char pub[8 * 1024];
size_t publen = sizeof(pub);
if (keychain_key_public(k, pub, &publen) != 0) {
UM_LOG(WARN, "failed to load public key from keychain");
rc = -1;
goto error;
return -1;
}

// check if pub key is ASN.1 SubjectPublicKeyInfo format
Expand Down Expand Up @@ -538,15 +539,20 @@ int load_kc_key(EVP_PKEY **pkey, keychain_key_t k) {
}

if (keychain_key_type(k) == keychain_key_ec) {
int bits = keychain->key_bits(k);
if (bits < 0) {
UM_LOG(ERR, "invalid key size");
return -1;
}

const char *group = NULL;
size_t keysize = (publen/2) * 8;
if (keysize == 256) {
group = SN_X9_62_prime256v1;
} else if (keysize == 384) {
group = SN_secp384r1;
} else if (keysize == 1042) {
group = SN_secp521r1;
switch(bits) {
case 256: group = SN_X9_62_prime256v1; break;
case 384: group = SN_secp384r1; break;
case 521: group = SN_secp521r1; break;
default:
UM_LOG(ERR, "unsupported EC key size[%d]", bits);
return -1;
}

pkey_ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
Expand Down Expand Up @@ -581,15 +587,14 @@ int load_kc_key(EVP_PKEY **pkey, keychain_key_t k) {
if(r != 1) {
unsigned long err = ERR_get_error();
UM_LOG(ERR, "failed to set RSA pubkey for key id[%s] label[%s]: %ld/%s", "id", "label", err, ERR_lib_error_string(err));
rc = -1;
goto error;
}
}

return rc;

error:
if (pkey_ctx) EVP_PKEY_CTX_free(pkey_ctx);
return -1;
return rc;
}

int gen_keychain_key(tlsuv_private_key_t *key, const char *name) {
Expand Down

0 comments on commit f39b19b

Please sign in to comment.