Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generating an OpenSSL Certificate Signing Request in iOS with Keychain stored keys

I'm trying to generate a CSR in iOS. Since apparently the Apple security framework for iOS doesn't include methods for CSR generation I had to compile the OpenSSL source code for my project.

Now I want to know how to use these methods with the keys I've generated in the Keychain previously. That is, I need to convert SecKeyRef type into OpenSSL types like EVP_PKEY. That will allow me to call the OpenSSL method X509_REQ_set_pubkey.

Does anyone know a way to achieve this?

like image 362
anavarroma Avatar asked Nov 19 '12 14:11

anavarroma


People also ask

How do I create a certificate signing request in iOS?

Here's a basic outline of the CSR process: You run Keychain Access and choose Certificate Assistant > Request a Certificate from a Certificate Authority. You run through the workflow as described in Developer Account Help > Create certificates > Create a certificate signing request.

How do I create a certificate signing request on a Mac?

Keychain Access on your Mac allows you to create a certificate signing request (CSR). Launch Keychain Access located in /Applications/Utilities . Choose Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority.


1 Answers

Found the solution myself.

First of all you need to extract the key from the Keychain as 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;
}

Now we need to cast this data as unsigned char and give it to the method 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);
}

That generates a simple CSR in OpenSSL (not signed) with a public key and a common name and prints it to the standard out.

like image 166
anavarroma Avatar answered Sep 26 '22 02:09

anavarroma