在iOS中使用钥匙串存储的密钥生成OpenSSL证书签名请求

我正在尝试在iOS中生成CSR。 由于显然iOS的Apple安全框架不包括用于生成CSR的方法,所以我不得不为我的项目编译OpenSSL源代码。

现在我想知道如何使用我以前在Keychain中生成的密钥来使用这些方法。 也就是说,我需要将SecKeyReftypes转换为像EVP_PKEY这样的OpenSSLtypes。 这将允许我调用OpenSSL方法X509_REQ_set_pubkey。

有没有人知道一个方法来实现这一目标?

自己find解决scheme。

首先你需要从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; } 

现在我们需要将这些数据转换为无符号字符并将其赋予方法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); } 

这在OpenSSL(未签名)中使用公钥和通用名称生成一个简单的CSR,并将其输出到标准输出。

那么,密钥库的东西并不适合我们,所以我们生成它们并将它们存储为文件。 如果有人需要这个,我会把它留在这里。

 + (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); }