Генерация запроса на подпись сертификата OpenSSL в iOS с ключами, хранящимися в связке ключей

Я пытаюсь создать CSR в iOS. Поскольку очевидно, что структура безопасности Apple для iOS не включает методы генерации CSR, мне пришлось скомпилировать исходный код OpenSSL для моего проекта.

Теперь я хочу знать, как использовать эти методы с ключами, которые я сгенерировал ранее в цепочке ключей. То есть мне нужно преобразовать тип SecKeyRef в типы OpenSSL, такие как EVP_PKEY. Это позволит мне вызвать метод OpenSSL X509_REQ_set_pubkey.

Кто-нибудь знает способ добиться этого?


person anavarroma    schedule 19.11.2012    source источник
comment
См. также Простой протокол регистрации сертификатов (SCEP). Питер Гутманн взял на себя его техническое обслуживание в мае 2015 года, поэтому он должен двигаться вперед.   -  person jww    schedule 15.06.2015


Ответы (2)


Сам нашел решение.

Прежде всего вам нужно извлечь ключ из цепочки ключей как 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 (не подписанный) с открытым ключом и общим именем и выводит его на стандартный вывод.

person anavarroma    schedule 21.11.2012

Ну, хранилище ключей у нас не сработало, поэтому мы сгенерировали их и сохранили в виде файлов. Если кому-то это когда-нибудь понадобится, я оставлю это здесь.

+ (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);
}
person EpicPandaForce    schedule 15.06.2015