rsapkcs#11safenet

Importing private key in Safenet dongle 5110


I am trying to import a base64 representation of private key into safenet dongle.

Example Private key:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA3VLpIpck/ExTwh5Ac118symULpg2KjgO4AgwtPeQa3XvayPJlY
jBmrj7ZMjzdMu4YKQt8E9j7lcs8m2nDfV0Uloy840JKHdCpSm6HJf8xBqxds4KyC3m
horNk+NvOYrWf4OnOtcuu9Fs1m7t5pQVlWysr8kkBNSu/NIisZpDTtIddo4S/ofiK6
8N00mp3buWk9hwwEtXCXlZlQJ1DomtqmaOe5W/AsvxNTKiCoEpHPRoFDzePenykTfX
sKD9BpdPq4efU7ex+BulAalSDWvxi776HiH0Du4JiXz8GvVr+JQd9NhNElDL/j+zdF
GCzdc4WdWlbhzb/nlCi+6s2u4g6wIDAQABAoIBACUl3Wuo4tRWG1jhqv+yGVQZDn4j
njPH5PdFaKd3Rg5DZUQeZZ9rrNNDaS6pa/OWngPairtjF+rRRwIJ1ZhKMpP//71RVt
Ar9Eu0jUBvYkWoFVFTlAu1aJP8iDTiX7DQ1N/iQRdnNrjfld0IEXY6NMU30GRQ5nLJ
H/Xfb2NP+SwpWD5pzK1rnHtYUMhtKs8SzMhUax7UI5UUGIcuRjEbjR3F0gA87YtZee
/zVdIRhuklGcWghc01AFLgENnLNEngykmdQjAn4lAX5eM+/nGPHxUfbWIihLNW+uTV
31g4mFCxCkTsipyxC22xTZTWFlq806jkn/s3xSlYzJ1XGY+gBkECgYEA+FlPDTzKQz
OdWv11PiCYXdtnDLyW3dfAsyvSj4SOlmgqqfVbrkjtwvelwBJQFP2xcD681rstf8Wp
gM9+sCIXkr/r70LB+5kGCSDVpwVm610nrMav3nkQpzeutJICFgOBbN/0cDL94/9ff/
sGDSNSPERJMJYd9jlOQaKF65x3wu8CgYEA5CR1sCGeHKqBf26L67u0Kt7EuEd+DV3a
l0D/7EGD+c+p7m/o8RGVEwZRWzv6IdZfA3/9P/oDcO+qjWMuQrhxHmx035pQU1K+tX
+G
-----END RSA PRIVATE KEY-----

I am using this template to create the object

CK_ATTRIBUTE privateKeyTemplate[] =
        {
            { CKA_CLASS,            &classPrivateKey,     sizeof(classPrivateKey)     },
            { CKA_LABEL,            labelPrivate,         strlen((char*)labelPrivate) },
            { CKA_KEY_TYPE,         &keyType,             sizeof(keyType)             },
            { CKA_TOKEN,            &bTrue,               sizeof(bTrue)               },
            { CKA_ID,               enrollmentId,         sizeof(enrollmentId)        },
            { CKA_PRIVATE,          &bTrue,               sizeof(bTrue)               },
            { CKA_VALUE,            byteArray,            sizeof(byteArray)           },
            { CKA_VALUE_LEN,        &l,                   sizeof(l)                   },
            { CKA_SUBJECT,          enrollmentId,         sizeof(enrollmentId)        },
            { CKA_MODULUS,          modulusArray,         modulusArrayLength          },
            { CKA_PRIVATE_EXPONENT, privateExponentArray, privateExponentArrayLength},
            { CKA_PUBLIC_EXPONENT,  exponentArray,        exponentArrayLength         },
            { CKA_EXPONENT_1,       exp1Array,            exp1ArrayLength             },
            { CKA_EXPONENT_2,       exp2Array,            exp2ArrayLength             },
            { CKA_PRIME_1,          pArray,               pArrayLength                },
            { CKA_PRIME_2,          qArray,               qArrayLength                },
            { CKA_COEFFICIENT,      qInvArray,            qInvArrayLength             },
            { CKA_DERIVE,           &bFalse,              sizeof(bFalse)              },
            { CKA_SENSITIVE,        &bTrue,               sizeof(bTrue)               },
            { CKA_DECRYPT,          &bTrue,               sizeof(bTrue)               },
            { CKA_SIGN,             &bTrue,               sizeof(bTrue)               },
            { CKA_SIGN_RECOVER,     &bFalse,              sizeof(bFalse)              },
            { CKA_EXTRACTABLE,      &bFalse,              sizeof(bFalse)              },
            { CKA_MODIFIABLE,       &bFalse,              sizeof(bFalse)              },
            { CKA_WRAP,             &bTrue,               sizeof(bTrue)               }
        };

Here is my full function:

void Dongle::createPrivateKey(char *data, char* enrollmentId, CK_SESSION_HANDLE hSession) {
    CK_RV rv = CKR_OK;
    
    CK_BBOOL    bFalse  = CK_FALSE;
    CK_BBOOL    bTrue   = CK_TRUE;
    CK_KEY_TYPE keyType = CKK_RSA;
    
    CK_OBJECT_HANDLE hObject;
    
    std::string labelPriv = std::string("private") + enrollmentId;
    CK_UTF8CHAR * labelPrivate = convertToCK_UTF8CHAR(labelPriv); //Label of private key.

    
    
    RSA* rsa_key = NULL;
    d::decode_rsa_private_key(data, &rsa_key);
    
    std::string s = std::string(data);
    d::removeSubstrs(s, "\n");
    d::removeSubstrs(s, "-----BEGIN RSA PRIVATE KEY-----");
    d::removeSubstrs(s, "-----END RSA PRIVATE KEY-----");
    
    
    int l;
    CK_BYTE * byteArray = d::base64_decode(s.c_str(), &l);
    
    for (int i=0; i<l; i++) {
        printf("%x ", byteArray[i]);
    }

    if (rsa_key != NULL) {
        // Access modulus and exponent
        const BIGNUM* modulus = RSA_get0_n(rsa_key);
        unsigned char* modulusArray = NULL;
        size_t modulusArrayLength;
        d::bignum_to_bytearray(modulus, &modulusArray, &modulusArrayLength);
        
        const BIGNUM* exponent = RSA_get0_e(rsa_key);
        unsigned char* exponentArray = NULL;
        size_t exponentArrayLength;
        d::bignum_to_bytearray(exponent, &exponentArray, &exponentArrayLength);
        
        const BIGNUM* privateExponent = RSA_get0_d(rsa_key);
        unsigned char* privateExponentArray = NULL;
        size_t privateExponentArrayLength;
        d::bignum_to_bytearray(privateExponent, &privateExponentArray, &privateExponentArrayLength);
        
        const BIGNUM* p = RSA_get0_p(rsa_key);
        unsigned char* pArray = NULL;
        size_t pArrayLength;
        d::bignum_to_bytearray(p, &pArray, &pArrayLength);
        
        const BIGNUM* q = RSA_get0_q(rsa_key);
        unsigned char* qArray = NULL;
        size_t qArrayLength;
        d::bignum_to_bytearray(q, &qArray, &qArrayLength);
        
        const BIGNUM* exp1 = RSA_get0_dmp1(rsa_key);
        unsigned char* exp1Array = NULL;
        size_t exp1ArrayLength;
        d::bignum_to_bytearray(exp1, &exp1Array, &exp1ArrayLength);
        
        const BIGNUM* exp2 = RSA_get0_dmq1(rsa_key);
        unsigned char* exp2Array = NULL;
        size_t exp2ArrayLength;
        d::bignum_to_bytearray(exp2, &exp2Array, &exp2ArrayLength);
        
        const BIGNUM* qInv = RSA_get0_iqmp(rsa_key);
        unsigned char* qInvArray = NULL;
        size_t qInvArrayLength;
        d::bignum_to_bytearray(qInv, &qInvArray, &qInvArrayLength);
        


        
        CK_OBJECT_CLASS  classPrivateKey = CKO_PRIVATE_KEY;
        CK_ATTRIBUTE privateKeyTemplate[] =
        {
            { CKA_CLASS,            &classPrivateKey,     sizeof(classPrivateKey)     },
            { CKA_LABEL,            labelPrivate,         strlen((char*)labelPrivate) },
            { CKA_KEY_TYPE,         &keyType,             sizeof(keyType)             },
            { CKA_TOKEN,            &bTrue,               sizeof(bTrue)               },
            { CKA_ID,               enrollmentId,         sizeof(enrollmentId)        },
            { CKA_PRIVATE,          &bTrue,               sizeof(bTrue)               },
            { CKA_VALUE,            byteArray,            sizeof(byteArray)           },
            { CKA_VALUE_LEN,        &l,                   sizeof(l)                   },
            { CKA_SUBJECT,          enrollmentId,         sizeof(enrollmentId)        },
            { CKA_MODULUS,          modulusArray,         modulusArrayLength          },
            { CKA_PRIVATE_EXPONENT, privateExponentArray, privateExponentArrayLength},
            { CKA_PUBLIC_EXPONENT,  exponentArray,        exponentArrayLength         },
            { CKA_EXPONENT_1,       exp1Array,            exp1ArrayLength             },
            { CKA_EXPONENT_2,       exp2Array,            exp2ArrayLength             },
            { CKA_PRIME_1,          pArray,               pArrayLength                },
            { CKA_PRIME_2,          qArray,               qArrayLength                },
            { CKA_COEFFICIENT,      qInvArray,            qInvArrayLength             },
            { CKA_DERIVE,           &bFalse,              sizeof(bFalse)              },
            { CKA_SENSITIVE,        &bTrue,               sizeof(bTrue)               },
            { CKA_DECRYPT,          &bTrue,               sizeof(bTrue)               },
            { CKA_SIGN,             &bTrue,               sizeof(bTrue)               },
            { CKA_SIGN_RECOVER,     &bFalse,              sizeof(bFalse)              },
            { CKA_EXTRACTABLE,      &bFalse,              sizeof(bFalse)              },
            { CKA_MODIFIABLE,       &bFalse,              sizeof(bFalse)              },
            { CKA_WRAP,             &bTrue,               sizeof(bTrue)               }
        };
        
        // Clean up
        delete[] byteArray;
        
        rv = C_CreateObject( hSession,
                             privateKeyTemplate,
                             1,
                             &hObject );
        
        if (rv == CKR_OK) {
            std::cout<< "Created object handle"<< hObject<< std::endl;
        }

        // Clean up
        RSA_free(rsa_key);
    }       
}

I am getting CKR_TEMPLATE_INCOMPLETE when trying to create the object.


Solution

  • The third argument to C_CreateObject should be the number of attributes in the template -- for your current code 25, not 1. But better coding practice is to compute it, so you don't forget to update it when you change something: sizeof(privateKeyTemplate)/sizeof(privateKeyTemplate[0]) or sizeof(privateKeyTemplate)/sizeof(CK_ATTRIBUTE) (whichever you prefer).

    Also, you are using only the first 4 or 8 characters pointed to by enrollmentId for CKA_ID, and trying to do the same for CKA_SUBJECT which must be a DER encoding not a character string. Similarly you are pointing to only part of byteArray for CKA_VALUE, or would be if you hadn't deleted it prematurely which means there may not be anything there and it may even crash (although that's rare for something this small). Plus I don't recall seeing any device use CKA_VALUE for a privatekey object at all, but my experience doesn't include SafeNet.