Создание запроса подписи сертификата OpenSSL в iOS с сохраненными ключами Keychain
Я пытаюсь создать CSR в iOS. Поскольку, по-видимому, инфраструктура безопасности Apple для iOS не включает методы генерации CSR, мне пришлось скомпилировать исходный код OpenSSL для моего проекта.
Теперь я хочу знать, как использовать эти методы с ключами, которые я создал в Keychain ранее. То есть мне нужно преобразовать тип SecKeyRef в типы OpenSSL, такие как EVP_PKEY. Это позволит мне вызвать метод OpenSSL X509_REQ_set_pubkey.
Кто-нибудь знает, как это достичь?
Ответы
Ответ 1
Нашел решение самостоятельно.
Прежде всего вам нужно извлечь ключ из Keychain как NSData.
- (NSData *) getKeyDataWithIdentifier:(NSString *) identifier
{
NSData * keyBits = nil;
NSMutableDictionary * keyQuery = [[NSMutableDictionary alloc] init];
NSData * encodedId = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[keyQuery setObject:encodedId forKey:kSecAttrApplicationTag];
[keyQuery setObject:kSecClassKey forKey:kSecClass];
[keyQuery setObject:[NSNumber numberWithBool:YES] forKey:kSecReturnData];
[keyQuery setObject:kSecAttrKeyTypeRSA forKey:kSecAttrKeyType];
OSStatus sanityCheck = SecItemCopyMatching((CFDictionaryRef)keyQuery, (CFTypeRef *)&keyBits);
if (sanityCheck != noErr) {
NSLog(@"Error: %ld", sanityCheck);
}
return keyBits;
}
Теперь нам нужно передать эти данные как unsigned char и передать их методу d2i_RSAPublicKey
- (void) generateCSR:(NSData *) keyData
{
X509_REQ *req = NULL;
X509_NAME *name= NULL;
EVP_PKEY *key;
const unsigned char * bits = (unsigned char *) [keyData bytes];
int length = [keyData length];
if ((req=X509_REQ_new()) == NULL) {
NSLog(@"big error");
return;
}
RSA * rsa = NULL;
key=EVP_PKEY_new();
d2i_RSAPublicKey(&rsa, &bits, length);
EVP_PKEY_assign_RSA(key,rsa);
name = X509_REQ_get_subject_name(req);
X509_REQ_set_pubkey(req, key);
/* This function creates and adds the entry, working out the
* correct string type and performing checks on its length.
* Normally we'd check the return value for errors...
*/
X509_NAME_add_entry_by_txt(name,"CN",
MBSTRING_ASC, "My certificate request", -1, -1, 0);
X509_REQ_print_fp(stdout, req);
}
Это создает простой CSR в OpenSSL (не подписан) с открытым ключом и общим именем и выводит его на стандартный вывод.
Ответ 2
Ну, материал хранилища ключей не подходит для нас, поэтому мы сгенерировали их и сохранили в виде файлов. Если кому-то это понадобится, я оставлю его здесь.
+ (void)generateCsrAndKeyAtPath:(NSString *)csrPath KeyPath:(NSString *)keyPath Username:(NSString *)username {
int i;
RSA *rsakey;
X509_REQ *req;
X509_NAME *subj;
EVP_PKEY *pkey;
EVP_MD *digest;
FILE *fp;
structentry[ENTRIES - 1].value = [username UTF8String];
// standard set up for OpenSSL
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
// Generate the RSA key; we don't assign a callback to monitor progress
// since generating keys is fast enough these days
rsakey = RSA_generate_key(2048, RSA_F4, NULL, NULL);
// Create evp obj to hold our rsakey
if (!(pkey = EVP_PKEY_new()))
NSLog(@"Could not create EVP object");
if (!(EVP_PKEY_set1_RSA(pkey, rsakey)))
NSLog(@"Could not assign RSA key to EVP object");
// create request object
if (!(req = X509_REQ_new()))
NSLog(@"Failed to create X509_REQ object");
X509_REQ_set_pubkey(req, pkey);
// create and fill in subject object
if (!(subj = X509_NAME_new()))
NSLog(@"Failed to create X509_NAME object");
for (i = 0; i < ENTRIES; i++) {
int nid; // ASN numeric identifier
X509_NAME_ENTRY *ent;
if ((nid = OBJ_txt2nid(structentry[i].key)) == NID_undef) {
fprintf(stderr, "Error finding NID for %s\n", structentry[i].key);
NSLog(@"Error on lookup");
}
if (!(ent = X509_NAME_ENTRY_create_by_NID(NULL, nid, MBSTRING_ASC,
structentry[i].value, -1)))
NSLog(@"Error creating Name fewfwefewf from NID");
if (X509_NAME_add_entry(subj, ent, -1, 0) != 1)
NSLog(@"Error adding fewfwefewf to Name");
}
if (X509_REQ_set_subject_name(req, subj) != 1)
NSLog(@"Error adding subject to request");
// request is filled in and contains our generated public key;
// now sign it
digest = (EVP_MD *) EVP_sha1();
if (!(X509_REQ_sign(req, pkey, digest)))
NSLog(@"Error signing request");
// write output files
if (!(fp = fopen([csrPath UTF8String], "wb")))
NSLog(@"Error writing to request file");
if (PEM_write_X509_REQ(fp, req) != 1)
NSLog(@"Error while writing request");
fclose(fp);
if (!(fp = fopen([keyPath UTF8String], "w")))
NSLog(@"Error writing to private key file");
if (PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, 0, NULL) != 1)
NSLog(@"Error while writing private key");
fclose(fp);
EVP_PKEY_free(pkey);
X509_REQ_free(req);
}