0

I'm working on app in which I need to create CSR, by using objective c or Swift this doesn't easy. So I choosed OpenSSL to created CSR and I created successfully code is shown following, but my one more core requirement is to store keys in secure enclave but this not possible in OpenSSL as I searched online. Now I want to create keypair in objective c in secure enclave and then export these public key (with data) and private key (with reference) to openSSL (EC_KEY) and then create CSR from. I found this this link to export key but there is no way to export private key (not possible with data but with reference).

I need some guidance how to do that.

    - (void)genCSRX509ForEC
{
    int             ret = 0;
    DSA             *r = NULL;
    BIGNUM          *bne = NULL;


int             nVersion = 1;

unsigned long   e = RSA_F4;

X509_REQ        *x509_req = NULL;
X509_NAME       *x509_name = NULL;
EVP_PKEY        *pKey = NULL;
BIO             *out = NULL;

const char      *szCountry = "USA";
const char      *szProvince = "MA";
const char      *szCity = "Boston";
const char      *szOrganization = "MyComp";
const char      *szCommon = "MYC";

const char      *szPath = "x509Req.pem";

// 1. generate rsa key
bne = BN_new();
ret = BN_set_word(bne,e);
if(ret != 1){
    goto free_all;
}

r = DSA_new();
//    
//    EC_KEY* _ec_key = EC_KEY_new();
//    EC_GROUP* ec_group_new = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
//    const EC_GROUP* ec_group = ec_group_new;
//    if (!EC_KEY_set_group(_ec_key,ec_group))
//        NSLog(@"Error in initializeCrypto, EC_KEY_set_group failed!");

    // Segfault at this position


    //////////////////////////// CREATE KEYPAIR /////////////////////////////////////

    EC_KEY* _ec_key = EC_KEY_new();
    EC_GROUP* ec_group_new = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
    const EC_GROUP* ec_group = ec_group_new;
    if (!EC_KEY_set_group(_ec_key,ec_group))
        NSLog(@"Error in initializeCrypto, EC_KEY_set_group failed!");

    EC_KEY_generate_key(_ec_key);

    ret = EC_KEY_check_key(_ec_key);
    if (ret != 1){
        goto free_all;
    }

      const BIGNUM *privateKey = EC_KEY_get0_private_key(_ec_key);
      const EC_POINT *publicKey = EC_KEY_get0_public_key(_ec_key);

      privateKeySize = i2d_ECPrivateKey(_ec_key,NULL);
      unsigned char *privateKeyBuf = OPENSSL_malloc(privateKeySize);
      memset(privateKeyBuf, 0, privateKeySize);
      int status = i2d_ECPrivateKey(_ec_key,&privateKeyBuf);
      if (!ret){
        NSLog(@"Private key to DER failed\n");
        return;
      }
      else {
        NSLog(@"Private key %s",privateKeyBuf);
      }
    privateKeyUnsignedChar = privateKeyBuf;

      publicKeySize = i2o_ECPublicKey(_ec_key,NULL);
      unsigned char *publicKeyBuf = OPENSSL_malloc(privateKeySize);
      memset(publicKeyBuf, 0, privateKeySize);
      ret = i2o_ECPublicKey(_ec_key,&publicKeyBuf);
      if (!ret){
        NSLog(@"Public key to octed failed\n");
        return;
      }
      else {
        NSLog(@"Public key %s",publicKeyBuf);
      }
    publicKeyUnsignedChar = publicKeyBuf;
    NSLog(@"key generation generated");

    //////////////////////////// CREATE KEYPAIR END /////////////////////////////////////


    // 2. set version of x509 req
    x509_req = X509_REQ_new();
    ret = X509_REQ_set_version(x509_req, nVersion);
    if (ret != 1){
        goto free_all;
    }

    // 3. set subject of x509 req
    x509_name = X509_REQ_get_subject_name(x509_req);

    ret = X509_NAME_add_entry_by_txt(x509_name,"C", MBSTRING_ASC, (const unsigned char*)szCountry, -1, -1, 0);
    if (ret != 1){
        goto free_all;
    }

    ret = X509_NAME_add_entry_by_txt(x509_name,"ST", MBSTRING_ASC, (const unsigned char*)szProvince, -1, -1, 0);
    if (ret != 1){
        goto free_all;
    }

    ret = X509_NAME_add_entry_by_txt(x509_name,"L", MBSTRING_ASC, (const unsigned char*)szCity, -1, -1, 0);
    if (ret != 1){
        goto free_all;
    }

    ret = X509_NAME_add_entry_by_txt(x509_name,"O", MBSTRING_ASC, (const unsigned char*)szOrganization, -1, -1, 0);
    if (ret != 1){
        goto free_all;
    }

    ret = X509_NAME_add_entry_by_txt(x509_name,"CN", MBSTRING_ASC, (const unsigned char*)szCommon, -1, -1, 0);
    if (ret != 1){
        goto free_all;
    }

    // 4. set public key of x509 req
    pKey = EVP_PKEY_new();
    EVP_PKEY_assign_EC_KEY(pKey, _ec_key);
    r = NULL;   // will be free rsa when EVP_PKEY_free(pKey)

    ret = X509_REQ_set_pubkey(x509_req, pKey);
    if (ret != 1){
        goto free_all;
    }

    // 5. set sign key of x509 req
    ret = X509_REQ_sign(x509_req, pKey, EVP_sha256());    // return x509_req->signature->length
    if (ret <= 0){
        goto free_all;
    }

    out = BIO_new_file(szPath,"w");
    ret = PEM_write_bio_X509_REQ(out, x509_req);
    X509_REQ_print_fp(stdout, x509_req);


    [self createFileForPEM:x509_req];

    //    PEM_write_X509_REQ(pemFile, certSigningRequest);
    // 6. free
free_all:
    X509_REQ_free(x509_req);
    BIO_free_all(out);

    EVP_PKEY_free(pKey);
//    BN_free(bne);


}
Aleem
  • 3,173
  • 5
  • 33
  • 71
  • For interoperability, you should also set the `OPENSSL_EC_NAMED_CURVE` flag on the key. Also see [Elliptic Curve Cryptography | Named Curves](https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography#Named_Curves) on the OpenSSL wiki. – jww Dec 14 '16 at 06:40
  • @jww By this we can interact with keys which is generated from OpenSSL but how can I store private key in secure enclave which is doing in objective c using this "kSecAttrTokenIDSecureEnclave" ? will this possible using OpenSSL – Aleem Dec 14 '16 at 07:03

1 Answers1

0

Refer https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html and https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivateKey.html

You can call i2d_ECPrivateKey to convert it into DER format in the given unsigned char array and then convert it into Base64 and write to file.

//int i2d_ECPrivateKey(EC_KEY *key, unsigned char **out);
int len = -1;
unsigned char outbuf[2000]; /*large enough to hold the key.*/
len = i2d_ECPrivateKey(_ec_key, outbuf);
/*Now, you have outbuf with len bytes*/
/*Write it to file with in DER format and you can use d2i_ECPrivateKey to import it. */
doptimusprime
  • 9,115
  • 6
  • 52
  • 90