//MS: populate DATE_TIME_INFO struct with year,month, day,hour,minute,second,etc
static int ssl_get_ASN1_UTCTIME(const ASN1_UTCTIME *tm, DATE_TIME_INFO *dti)
{
    const char *v;
    int gmt=0;
    int i;
    int y=0,M=0,d=0,h=0,m=0,s=0;

    memset(dti, 0, sizeof(*dti));

    i=tm->length;
    v=(const char *)tm->data;

    if (i < 10) { goto err; }
    if (v[i-1] == 'Z') gmt=1;
    for (i=0; i<10; i++)
        if ((v[i] > '9') || (v[i] < '0')) { goto err; }
    y= (v[0]-'0')*10+(v[1]-'0');
    if (y < 50) y+=100;
    M= (v[2]-'0')*10+(v[3]-'0');
    if ((M > 12) || (M < 1)) { goto err; }
    d= (v[4]-'0')*10+(v[5]-'0');
    h= (v[6]-'0')*10+(v[7]-'0');
    m=  (v[8]-'0')*10+(v[9]-'0');
    if (tm->length >=12 &&
        (v[10] >= '0') && (v[10] <= '9') &&
        (v[11] >= '0') && (v[11] <= '9'))
        s=  (v[10]-'0')*10+(v[11]-'0');

    dti->year = SwapEndianIfBEc32(y+1900);
    dti->month = SwapEndianIfBEc32(M);
    dti->day = SwapEndianIfBEc32(d);
    dti->hour = SwapEndianIfBEc32(h);
    dti->minute = SwapEndianIfBEc32(m);
    dti->second = SwapEndianIfBEc32(s);
    dti->dlsTime = 0; //TODO:HOW to find
    dti->tzOffset = SwapEndianIfBEc32(gmt); //TODO:How to find

    return(1);

    
err:
    TINYCLR_SSL_PRINTF("Bad time value\r\n");
    return(0);
}
CK_RV PKCS11_Objects_OpenSSL::FindObjectsInit(Cryptoki_Session_Context* pSessionCtx, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
{
    FIND_OBJECT_DATA *pData;
    INT32 i = 0, len;

    if(pSessionCtx->FindObjectsCtx != NULL)
    {
        return CKR_FUNCTION_NOT_PARALLEL;
    }

    pData = (FIND_OBJECT_DATA*)TINYCLR_SSL_MALLOC(sizeof(FIND_OBJECT_DATA));

    if(pData == NULL) return CKR_DEVICE_MEMORY;

    pSessionCtx->FindObjectsCtx = pData;

    pData->FileName[0] = 0;
    pData->GroupName[0] = 0;

    while(i < ulCount)
    {
        switch(pTemplate[i].type)
        {
            case CKA_CLASS:
                switch(SwapEndianIfBEc32(*(INT32*)pTemplate[i].pValue))
                {
                    case CKO_CERTIFICATE:
                        pData->ObjectType = CertificateType;
                        break;

                    case CKO_PUBLIC_KEY:
                    case CKO_SECRET_KEY:
                    case CKO_PRIVATE_KEY:
                        pData->ObjectType = KeyType;
                        break;

                    default:
                        pData->ObjectType = DataType;
                        break;
                }
                break;

            case CKA_LABEL:
                len = pTemplate[i].ulValueLen;

                if(len >= ARRAYSIZE(pData->GroupName))
                {
                    len = ARRAYSIZE(pData->GroupName) - 1;
                }
                
                TINYCLR_SSL_MEMCPY( pData->GroupName, pTemplate[i].pValue, len );

                pData->GroupName[len] = 0;
                break;

            case CKA_OBJECT_ID:
                len = pTemplate[i].ulValueLen;

                if(len >= ARRAYSIZE(pData->FileName))
                {
                    len = ARRAYSIZE(pData->FileName) - 1;
                }

                TINYCLR_SSL_MEMCPY( pData->FileName, pTemplate[i].pValue, len );

                pData->FileName[len] = 0;
                break;

            default:
                return CKR_ATTRIBUTE_TYPE_INVALID;
        }
        i++;
    }   
    
    return CKR_OK;
}
CK_RV PKCS11_Objects_OpenSSL::SetAttributeValue(Cryptoki_Session_Context* pSessionCtx, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) 
{
    OBJECT_DATA* pObj = PKCS11_Objects_OpenSSL::GetObjectFromHandle(pSessionCtx, hObject);

    if(pObj == NULL) return CKR_OBJECT_HANDLE_INVALID;

    if(pObj->Type == CertificateType)
    {
        CERT_DATA* pCertData = (CERT_DATA*)pObj->Data;
        X509* pCert = pCertData->cert;
        CHAR group[20] = {0};
        CHAR fileName[20] = {0};
        INT32 len = 0;

        BOOL fSave = FALSE;
        BOOL fDelete = FALSE;
    
        for(int i=0; i<(int)ulCount; i++)
        {
            switch(pTemplate[i].type)
            {
                case CKA_PERSIST:
                    fSave = SwapEndianIfBEc32(*(INT32*)pTemplate[i].pValue) != 0;
                    fDelete = !fSave;
                    break;

                case CKA_LABEL:
                    len = pTemplate[i].ulValueLen;

                    if(len >= ARRAYSIZE(group))
                    {
                        len = ARRAYSIZE(group) - 1;
                    }
                    
                    TINYCLR_SSL_MEMCPY(group, pTemplate[i].pValue, len);
                    
                    group[len] = 0;
                    
                    break;

                case CKA_OBJECT_ID:
                    len = pTemplate[i].ulValueLen;

                    if(len >= ARRAYSIZE(fileName))
                    {
                        len = ARRAYSIZE(fileName) - 1;
                    }
                    
                    TINYCLR_SSL_MEMCPY(fileName, pTemplate[i].pValue, len);
                    
                    fileName[len] = 0;
                    
                    break;

                default:
                    return CKR_ATTRIBUTE_TYPE_INVALID;
            }
        }

        if(fDelete)
        {
            hal_strcpy_s(fileName, ARRAYSIZE(pObj->FileName), pObj->FileName);

            pObj->GroupName[0] = 0;
                
            if(g_OpenSSL_Token.Storage != NULL && g_OpenSSL_Token.Storage->Delete != NULL)
            {
                if(!g_OpenSSL_Token.Storage->Delete(fileName, group)) return CKR_FUNCTION_FAILED;
            }
            else
            {
                return CKR_FUNCTION_NOT_SUPPORTED;
            }
        }
        else if(fSave)
        {
            hal_strcpy_s(pObj->GroupName, ARRAYSIZE(pObj->GroupName), group   );
            hal_strcpy_s(pObj->FileName , ARRAYSIZE(pObj->FileName ), fileName);
            
            if(g_OpenSSL_Token.Storage != NULL && g_OpenSSL_Token.Storage->Create != NULL)
            {
                BOOL res;
                UINT8* pData, *pTmp;
                INT32 len = i2d_X509( pCert, NULL );

                if(len <= 0) return CKR_FUNCTION_FAILED;

                pData = (UINT8*)TINYCLR_SSL_MALLOC(len);

                if(pData == NULL) return CKR_DEVICE_MEMORY;

                pTmp = pData;

                i2d_X509(pCert, &pTmp);

                // TODO: Save private key as well
                
                res = g_OpenSSL_Token.Storage->Create( fileName, group, CertificateType, pData, len );

                TINYCLR_SSL_FREE(pData);

                if(!res) return CKR_FUNCTION_FAILED;
            }
            else
            {
                return CKR_FUNCTION_NOT_SUPPORTED;
            }
        }
        else
        {
            return CKR_ATTRIBUTE_TYPE_INVALID;
        }
    }

    return CKR_OK;
}
CK_RV PKCS11_Objects_OpenSSL::GetAttributeValue(Cryptoki_Session_Context* pSessionCtx, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount)
{
    OBJECT_DATA* pObj = PKCS11_Objects_OpenSSL::GetObjectFromHandle(pSessionCtx, hObject);

    if(pObj == NULL) return CKR_OBJECT_HANDLE_INVALID;

    if(pObj->Type == CertificateType)
    {
        CERT_DATA* pCertData = (CERT_DATA*)pObj->Data;
        X509* pCert = pCertData->cert;
        INT32 valLen = 0;
    
        for(int i=0; i<(int)ulCount; i++)
        {
            switch(pTemplate[i].type)
            {
                case CKA_CLASS:
                    *(INT32*)pTemplate[i].pValue = SwapEndianIfBEc32(CKO_CERTIFICATE);
                    break;
                case CKA_PRIVATE:
                    *(INT32*)pTemplate[i].pValue = SwapEndianIfBEc32(pCertData->privKeyData.key == NULL ? 0 : 1);
                    valLen = sizeof(INT32);
                    break;

                case CKA_VALUE_BITS:
                    {
                        *(INT32*)pTemplate[i].pValue = SwapEndianIfBEc32(pCertData->pubKeyData.size);
                        valLen = sizeof(INT32);
                    }
                    break;
                    
                case CKA_KEY_TYPE:
                    {
                        *(UINT32*)pTemplate[i].pValue = SwapEndianIfBEc32(pCertData->pubKeyData.type);
                        valLen = sizeof(UINT32);
                    }
                    break;

                case CKA_ISSUER:
                    {
                        char* name=X509_NAME_oneline(X509_get_issuer_name(pCert),NULL,0);
                        valLen = TINYCLR_SSL_STRLEN(name) + 1;

                        if(valLen > pTemplate[i].ulValueLen) valLen = pTemplate[i].ulValueLen;
                        
                        hal_strcpy_s((char*)pTemplate[i].pValue, valLen, name);
                        OPENSSL_free(name);
                    }
                    break;

                case CKA_SUBJECT:
                    {
                        char* subject=X509_NAME_oneline(X509_get_subject_name(pCert),NULL,0);
                        valLen = TINYCLR_SSL_STRLEN(subject) + 1;

                        if(valLen > pTemplate[i].ulValueLen) valLen = pTemplate[i].ulValueLen;
                        
                        hal_strcpy_s((char*)pTemplate[i].pValue, valLen, subject);
                        OPENSSL_free(subject);
                    }
                    break;

                case CKA_SERIAL_NUMBER:
                    {
                        ASN1_INTEGER* asn = X509_get_serialNumber(pCert);

                        valLen = asn->length;

                        if(valLen > pTemplate[i].ulValueLen) valLen = pTemplate[i].ulValueLen;

                        TINYCLR_SSL_MEMCPY(pTemplate[i].pValue, asn->data, valLen);
                    }
                    break;

                case CKA_MECHANISM_TYPE:
                    if(pCert->sig_alg != NULL)
                    {
                        int signature_nid;
                        CK_MECHANISM_TYPE type = CKM_VENDOR_DEFINED;
                        
                        signature_nid = OBJ_obj2nid(pCert->sig_alg->algorithm);

                        switch(signature_nid)
                        {
                            case NID_sha1WithRSA:
                            case NID_sha1WithRSAEncryption:
                                //szNid = "1.2.840.113549.1.1.5";
                                type = CKM_SHA1_RSA_PKCS;
                                break;

                            case NID_md5WithRSA:
                            case NID_md5WithRSAEncryption:
                                //szNid = "1.2.840.113549.1.1.4";
                                type = CKM_MD5_RSA_PKCS;
                                break;

                            case NID_sha256WithRSAEncryption:
                                //szNid = "1.2.840.113549.1.1.11";
                                type = CKM_SHA256_RSA_PKCS;
                                break;

                            case NID_sha384WithRSAEncryption:
                                //szNid = "1.2.840.113549.1.1.12";
                                type = CKM_SHA384_RSA_PKCS;
                                break;

                            case NID_sha512WithRSAEncryption:
                                //szNid = "1.2.840.113549.1.1.13";
                                type = CKM_SHA512_RSA_PKCS;
                                break;
                        }

                        valLen = sizeof(CK_MECHANISM_TYPE);
                        *(CK_MECHANISM_TYPE*)pTemplate[i].pValue = SwapEndianIfBEc32(type);
                    }
                    break;

                case CKA_START_DATE:
                    {
                        DATE_TIME_INFO dti;
                        
                        ssl_get_ASN1_UTCTIME(X509_get_notBefore(pCert), &dti);

                        valLen = (INT32)pTemplate[i].ulValueLen;

                        if(valLen > sizeof(dti)) valLen = sizeof(dti);

                        TINYCLR_SSL_MEMCPY(pTemplate[i].pValue, &dti, valLen);
                    }
                    break;

                case CKA_END_DATE:
                    {
                        DATE_TIME_INFO dti;
                        
                        ssl_get_ASN1_UTCTIME(X509_get_notAfter(pCert), &dti);

                        valLen = pTemplate[i].ulValueLen;

                        if(valLen > sizeof(dti)) valLen = sizeof(dti);

                        TINYCLR_SSL_MEMCPY(pTemplate[i].pValue, &dti, valLen);
                    }
                    break;

                case CKA_VALUE:
                    {
                        UINT8* pData = (UINT8*)pTemplate[i].pValue;
                        UINT8* pTmp = pData;

                        valLen = i2d_X509(pCert, NULL);

                        if(valLen > pTemplate[i].ulValueLen) return CKR_DEVICE_MEMORY;
                        
                        valLen = i2d_X509(pCert, &pTmp);

                        if(valLen < 0) return CKR_FUNCTION_FAILED;
                    }
                    break;

                case CKA_VALUE_LEN:
                    *(UINT32*)pTemplate[i].pValue = SwapEndianIfBEc32(valLen);
                    break;

                default:
                    return CKR_ATTRIBUTE_TYPE_INVALID;
            }
        }
    }
    else if(pObj->Type == KeyType)
    {
        KEY_DATA* pKey = (KEY_DATA*)pObj->Data;
        int valLen = 0;
        bool isPrivate = false;

        for(int i=0; i<(int)ulCount; i++)
        {
            switch(pTemplate[i].type)
            {
                case CKA_CLASS:
                    *(INT32*)pTemplate[i].pValue = SwapEndianIfBEc32((0 != (pKey->attrib & Private) ? CKO_PRIVATE_KEY : 0 != (pKey->attrib & Public) ? CKO_PUBLIC_KEY : CKO_SECRET_KEY));
                    break;
                    
                case CKA_MODULUS:
                    if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->n, (UINT8*)pTemplate[i].pValue);
                    }    
                    break;

                case CKA_EXPONENT_1:
                    if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->dmp1, (UINT8*)pTemplate[i].pValue);
                    }    
                    break;

                case CKA_EXPONENT_2:
                    if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->dmq1, (UINT8*)pTemplate[i].pValue);
                    }    
                    break;

                case CKA_COEFFICIENT:
                    if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->iqmp, (UINT8*)pTemplate[i].pValue);
                    }    
                    break;
                    
                case CKA_PRIME_1:
                    if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->p, (UINT8*)pTemplate[i].pValue);
                    }    
                    break;

                case CKA_PRIME_2:
                    if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->q, (UINT8*)pTemplate[i].pValue);
                    }    
                    break;

                
                case CKA_PRIVATE_EXPONENT:
                    if(pKey->type == CKK_DSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.dsa->priv_key, (UINT8*)pTemplate[i].pValue);
                    }
                    else if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->d, (UINT8*)pTemplate[i].pValue);
                    }
                    break;
                case CKA_PUBLIC_EXPONENT:
                    if(pKey->type == CKK_DSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;
                
                        valLen = BN_bn2bin(pRealKey->pkey.dsa->pub_key, (UINT8*)pTemplate[i].pValue);
                    }
                    else if(pKey->type == CKK_EC)
                    {
                        UINT8 pTmp[66*2+1];
                    
                        EC_KEY* pEC = ((EVP_PKEY*)pKey->key)->pkey.ec;
                        
                        const EC_POINT* point = EC_KEY_get0_public_key(pEC);
                        valLen = EC_POINT_point2oct(EC_KEY_get0_group(pEC), point, POINT_CONVERSION_UNCOMPRESSED, (UINT8*)pTmp, ARRAYSIZE(pTmp), NULL);
                    
                        if(valLen == 0) return CKR_FUNCTION_FAILED;
                            
                        memmove(pTemplate[i].pValue, &pTmp[1], valLen-1); // remove POINT_CONVERSION_UNCOMPRESSED header byte
                    }
                    else if(pKey->type == CKK_RSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.rsa->e, (UINT8*)pTemplate[i].pValue);
                    }                    
                    break;

                case CKA_PRIME:
                    if(pKey->type == CKK_DSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.dsa->p, (UINT8*)pTemplate[i].pValue);
                    }
                    break;

                case CKA_SUBPRIME:
                    if(pKey->type == CKK_DSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;

                        valLen = BN_bn2bin(pRealKey->pkey.dsa->q, (UINT8*)pTemplate[i].pValue);
                    }
                    break;

                case CKA_BASE:
                    if(pKey->type == CKK_DSA)
                    {
                        EVP_PKEY* pRealKey = (EVP_PKEY*)pKey->key;
                        
                        valLen = BN_bn2bin(pRealKey->pkey.dsa->g, (UINT8*)pTemplate[i].pValue);
                    }
                    break;

                case CKA_PRIVATE:
                    isPrivate = 0 != *(INT32*)pTemplate[i].pValue;
                    break;
                

                case CKA_KEY_TYPE:
                    *(INT32*)pTemplate[i].pValue = SwapEndianIfBEc32(pKey->type);
                    break; 

                case CKA_VALUE_BITS:
                    *(UINT32*)pTemplate[i].pValue = SwapEndianIfBEc32(pKey->size);
                    break;

                case CKA_VALUE:
                    switch(pKey->type)
                    {
                        case CKK_AES:
                        case CKK_GENERIC_SECRET:
                            {
                                // TODO: Add permissions to export key
                                int len = (pKey->size + 7) / 8;
                                
                                if(len > (INT32)pTemplate[i].ulValueLen) len = (int)pTemplate[i].ulValueLen;
                                
                                TINYCLR_SSL_MEMCPY(pTemplate[i].pValue, pKey->key, len);
                                valLen = len;
                            }
                            break;

                        default:
                            return CKR_ATTRIBUTE_TYPE_INVALID;                                
                    }
                    break;

                case CKA_VALUE_LEN:
                    switch(pKey->type)
                    {
                        case CKK_EC:
                            *(UINT32*)pTemplate[i].pValue = SwapEndianIfBEc32(valLen);
                            break;

                        default:
                            return CKR_ATTRIBUTE_TYPE_INVALID;
                    }
                    break;

                default:
                    return CKR_ATTRIBUTE_TYPE_INVALID;
            }
        }
    }

    return CKR_OK;    
}
CK_RV PKCS11_Objects_OpenSSL::CreateObject(Cryptoki_Session_Context* pSessionCtx, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject)
{
    UINT32 attribIndex = 0;
    
    if(pTemplate[attribIndex].type == CKA_CLASS && pTemplate[attribIndex].ulValueLen == sizeof(CK_OBJECT_CLASS))
    {
        CK_OBJECT_CLASS cls = SwapEndianIfBEc32(*(CK_OBJECT_CLASS*)pTemplate[attribIndex].pValue);
        CHAR pwd[64];
        int len;

        switch(cls)
        {
            case CKO_CERTIFICATE:
                for(++attribIndex; attribIndex < ulCount; attribIndex++)
                {
                    switch(pTemplate[attribIndex].type)
                    {
                        case CKA_PASSWORD:
                            len = pTemplate[attribIndex].ulValueLen;

                            if(len >= ARRAYSIZE(pwd))
                            {
                                len = ARRAYSIZE(pwd) - 1;
                            }
                        
                            TINYCLR_SSL_MEMCPY(pwd, pTemplate[attribIndex].pValue, len);

                            pwd[len] = 0;

                            break;

                        case CKA_VALUE:
                        {
                            OBJECT_DATA* pObject = NULL;
                            EVP_PKEY* privateKey = NULL;
                            X509 *x =  ssl_parse_certificate(pTemplate[attribIndex].pValue, pTemplate[attribIndex].ulValueLen, pwd, &privateKey);

                            if (x == NULL)
                            {
                                TINYCLR_SSL_PRINTF("Unable to load certificate\n");
                                return CKR_FUNCTION_FAILED;
                            }
                            else
                            {
                                CK_RV retVal = LoadX509Cert(pSessionCtx, x, &pObject, privateKey, phObject);

                                if(retVal != CKR_OK) X509_free(x);

                                return retVal;
                            }
                            
                        }
                    }
                }
                break;
                
        }
    }

    return CKR_FUNCTION_NOT_SUPPORTED;
}
CK_RV PKCS11_Digest_OpenSSL::DigestInit(Cryptoki_Session_Context* pSessionCtx, CK_MECHANISM_PTR pMechanism)
{
    OPENSSL_HEADER();
    
    OpenSSLDigestData* pDigData;
    const EVP_MD*      pDigest;
    CK_OBJECT_HANDLE   hKey   = CK_OBJECT_HANDLE_INVALID;
    bool               isHMAC = false;

    if(pSessionCtx            == NULL) return CKR_SESSION_CLOSED;
    if(pSessionCtx->DigestCtx != NULL) return CKR_SESSION_PARALLEL_NOT_SUPPORTED; // another digest is in progress
    
    pDigData = (OpenSSLDigestData*)TINYCLR_SSL_MALLOC(sizeof(*pDigData));

    if(pDigData == NULL) return CKR_DEVICE_MEMORY;

    TINYCLR_SSL_MEMSET(pDigData, 0, sizeof(*pDigData));
    
    EVP_MD_CTX_init(&pDigData->CurrentCtx);
    
    switch(pMechanism->mechanism)
    {
        case CKM_SHA_1:
            pDigest = EVP_sha1();
            break;
        case CKM_SHA224:
            pDigest = EVP_sha224();
            break;
        case CKM_SHA256:
            pDigest = EVP_sha256();
            break;
        case CKM_SHA384:
            pDigest = EVP_sha384();
            break;
        case CKM_SHA512:
            pDigest = EVP_sha512();
            break;

        case CKM_MD5:
            pDigest = EVP_md5();
            break;

        case CKM_RIPEMD160:
            pDigest = EVP_ripemd160();
            break;

        case CKM_MD5_HMAC:
            pDigest = EVP_md5();
            isHMAC = true;
            break;

        case CKM_SHA_1_HMAC:
            pDigest = EVP_sha1();
            isHMAC = true;
            break;

        case CKM_SHA256_HMAC:
            pDigest = EVP_sha256();
            isHMAC = true;
            break;

        case CKM_SHA384_HMAC:
            pDigest = EVP_sha384();
            isHMAC = true;
            break;

        case CKM_SHA512_HMAC:
            pDigest = EVP_sha512();
            isHMAC = true;
            break;

        case CKM_RIPEMD160_HMAC:
            pDigest = EVP_ripemd160();
            isHMAC = true;
            break;
            

        default:
            OPENSSL_SET_AND_LEAVE(CKR_MECHANISM_INVALID);
    }


    if(isHMAC)
    {
        if(pMechanism->pParameter != NULL && pMechanism->ulParameterLen == sizeof(CK_OBJECT_HANDLE))
        {
            hKey = SwapEndianIfBEc32(*(CK_OBJECT_HANDLE*)pMechanism->pParameter);
        }
        else 
        {
            OPENSSL_SET_AND_LEAVE(CKR_MECHANISM_PARAM_INVALID);
        }

        pDigData->HmacKey = PKCS11_Keys_OpenSSL::GetKeyFromHandle(pSessionCtx, hKey, TRUE);

        if(pDigData->HmacKey==NULL) OPENSSL_SET_AND_LEAVE(CKR_MECHANISM_PARAM_INVALID);

        pDigData->HmacCtx.md = pDigest;

        OPENSSL_CHECKRESULT(HMAC_Init(&pDigData->HmacCtx, pDigData->HmacKey->key, pDigData->HmacKey->size/8, pDigData->HmacCtx.md));
    }
    else
    {
        OPENSSL_CHECKRESULT(EVP_DigestInit_ex(&pDigData->CurrentCtx, pDigest, NULL));
    }
    
    pSessionCtx->DigestCtx = pDigData;
    
    OPENSSL_CLEANUP();
    if(retVal != CKR_OK && pDigData != NULL)
    {
        TINYCLR_SSL_FREE(pDigData);
    }
    OPENSSL_RETURN();
}
int ssl_connect_internal(int sd, const char* szTargetHost, int sslContextHandle)
{
    int err = SOCK_SOCKET_ERROR;
    SSL *ssl = NULL;
    int nonblock = 0;

    // Retrieve SSL struct from g_SSL_Driver    
    if((sslContextHandle >= ARRAYSIZE(g_SSL_Driver.m_sslContextArray)) || (sslContextHandle < 0))
    {
        goto error;
    }
    
    // sd should already have been created
    // Now do the SSL negotiation   
    ssl = (SSL*)g_SSL_Driver.m_sslContextArray[sslContextHandle].SslContext;
    if (ssl == NULL) goto error;

    if (!SSL_set_fd(ssl, sd))
    {
        goto error;
    }

    if(ssl->verify_mode != SSL_VERIFY_NONE)
    {
        SSL_CTX* pCtx = SSL_get_SSL_CTX(ssl);

        if(pCtx != NULL)
        {
            X509_STORE *pStore = SSL_CTX_get_cert_store(pCtx);

            if(sk_num(&pStore->objs->stack) == 0)
            {
                CryptokiSession* pSession;
                CK_SLOT_ID  slotID;
                OBJECT_DATA* pObj;
                CK_ATTRIBUTE attribs[2];
                CK_OBJECT_CLASS cls = SwapEndianIfBEc32(CKO_CERTIFICATE);
                LPSTR label = "CA";
                CK_SESSION_HANDLE hSess;

                if(CKR_OK == C_OpenSession(0, CKF_SERIAL_SESSION, NULL, NULL, &hSess) && 
                   CKR_OK == Cryptoki_GetSlotIDFromSession(hSess, &slotID, &pSession))
                {
                    attribs[0].type = CKA_CLASS;
                    attribs[0].pValue = &cls;
                    attribs[0].ulValueLen = sizeof(cls);

                    attribs[1].type = CKA_LABEL;
                    attribs[1].pValue = label;
                    attribs[1].ulValueLen = 2;

                    if(CKR_OK == C_FindObjectsInit(hSess, attribs, ARRAYSIZE(attribs)))
                    {
                        CK_OBJECT_HANDLE hObjs[20];
                        CK_ULONG cnt = 0;

                        if(CKR_OK == C_FindObjects(hSess, hObjs, ARRAYSIZE(hObjs), &cnt) && cnt > 0)
                        {
                            for(int i=0; i<cnt; i++)
                            {
                                pObj = PKCS11_Objects_OpenSSL::GetObjectFromHandle(&pSession->Context, hObjs[i]);

                                if(pObj != NULL && pObj->Type == 3 /*CertificateType*/)
                                {
                                    CERT_DATA* pCert = (CERT_DATA*)pObj->Data;

                                    X509_STORE_add_cert(pStore, pCert->cert);
                                }
                            }
                        }

                        C_FindObjectsFinal(hSess);
                    }
                }

                if(pStore->objs == NULL || 0 == sk_num(&pStore->objs->stack))
                {
                    ssl->verify_mode = SSL_VERIFY_NONE;
                }

                C_CloseSession(hSess);
            }
        }
    }

    if(szTargetHost != NULL && szTargetHost[0] != 0)
    {
        SSL_set_tlsext_host_name(ssl, szTargetHost);
    }

    SOCK_ioctl(sd, SOCK_FIONBIO, &nonblock);

    err = SSL_connect (ssl);    

    nonblock = 1;
    SOCK_ioctl(sd, SOCK_FIONBIO, &nonblock);

    err = SSL_get_error(ssl,err);
      
    if(err == SSL_ERROR_WANT_READ)
    {
        err = SOCK_EWOULDBLOCK;
#if !defined(TCPIP_LWIP) && !defined(TCPIP_LWIP_OS)
        SOCKET_DRIVER.ClearStatusBitsForSocket( sd, FALSE );        
#endif
    }
    else if(err == SSL_ERROR_WANT_WRITE)
    {
        err = SOCK_TRY_AGAIN;
#if !defined(TCPIP_LWIP) && !defined(TCPIP_LWIP_OS)
        SOCKET_DRIVER.ClearStatusBitsForSocket( sd, TRUE );        
#endif
    }

    SOCKET_DRIVER.SetSocketSslData(sd, (void*)ssl);

error:
    return err;
}
HRESULT Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_FindObjectEnum::FindObjects___SZARRAY_MicrosoftSPOTCryptokiCryptokiObject__I4( CLR_RT_StackFrame& stack )
{
    TINYCLR_HEADER();
    CLR_RT_HeapBlock* pThis      = stack.This();
    CLR_RT_HeapBlock* pSession   = pThis[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_FindObjectEnum::FIELD__m_session].Dereference();
    CLR_RT_HeapBlock  ref, *pRef;
    CK_SESSION_HANDLE hSession;
    CK_ULONG          cntObj     = (CK_ULONG)stack.Arg1().NumericByRef().u4;
    CK_OBJECT_HANDLE  objs[128];
    CK_OBJECT_CLASS   objType = CKO_DATA;
    CLR_INT32         i;
    CLR_RT_TypeDef_Index objIndex = g_CLR_RT_WellKnownTypes.m_CryptokiObject;
    BOOL isKey = FALSE;
    CK_ATTRIBUTE      attribs[] =
    {
        { CKA_CLASS, &objType, sizeof(objType) },
    };

    FAULT_ON_NULL(pSession);

    if(cntObj > ARRAYSIZE(objs)) TINYCLR_SET_AND_LEAVE(CLR_E_OUT_OF_RANGE);

    hSession = pSession[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_Session::FIELD__m_handle].NumericByRef().u4;

    CRYPTOKI_CHECK_RESULT(stack, C_FindObjects(hSession, objs, cntObj, &cntObj ));

    CRYPTOKI_CHECK_RESULT(stack, C_GetAttributeValue(hSession, objs[0], attribs, ARRAYSIZE(attribs)));

    SwapEndianAndAssignIfBEc32(objType, objType);
    
    switch(objType)
    {
        case CKO_CERTIFICATE:
            objIndex = g_CLR_RT_WellKnownTypes.m_CryptokiCertificate;
            break;
    
        case CKO_PRIVATE_KEY:
        case CKO_PUBLIC_KEY:
        case CKO_SECRET_KEY:
        case CKO_OTP_KEY:
            objIndex = g_CLR_RT_WellKnownTypes.m_CryptoKey;
            isKey = TRUE;
            break;
    }

    TINYCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance(ref, (CLR_UINT32)cntObj, objIndex));

    if(cntObj == 0)
    {
        stack.SetResult_Object(ref.DereferenceArray());
        TINYCLR_SET_AND_LEAVE(S_OK);
    }

    pRef = (CLR_RT_HeapBlock*)ref.DereferenceArray()->GetFirstElement();

    for(i=0; i<(INT32)cntObj; i++)
    {
        CLR_RT_HeapBlock *pObject;        

        TINYCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex( *pRef, objIndex ));

        pObject = pRef->Dereference();
        pObject[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_CryptokiObject::FIELD__m_handle            ].SetInteger((CLR_INT32)objs[i]);
        pObject[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_SessionContainer::FIELD__m_session         ].SetObjectReference(pSession);
        pObject[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_SessionContainer::FIELD__m_ownsSession     ].SetBoolean(false);
        pObject[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_SessionContainer::FIELD__m_isDisposed      ].SetBoolean(false);
        pObject[Library_security_pkcs11_native_Microsoft_SPOT_Cryptoki_SessionContainer::FIELD__m_isSessionClosing].SetBoolean(false);

        if(isKey)
        {
            CK_ULONG keySize = (CK_ULONG)-1;
            CK_ULONG keyType = (CK_ULONG)-1;

            CK_ATTRIBUTE attribs[] =
            {
                { CKA_VALUE_BITS, &keySize, sizeof(keySize) },
                { CKA_KEY_TYPE  , &keyType, sizeof(keyType) },
            };

            pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_keyType].NumericByRef().s4 = SwapEndianIfBEc32(keyType);

            C_GetAttributeValue(hSession, objs[i], attribs, ARRAYSIZE(attribs));
            
            pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_length].NumericByRef().u4 = SwapEndianIfBEc32(keySize);

            switch(objType)
            {
                case CKO_PRIVATE_KEY:
                    pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_privateKeyHandle].NumericByRef().u4 = objs[i];
                    break;

                case CKO_PUBLIC_KEY:
                case CKO_SECRET_KEY:
                default:
                    pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_privateKeyHandle].NumericByRef().u4 = CK_OBJECT_HANDLE_INVALID;
                    break;
            }

        }
        else if(objType == CKO_CERTIFICATE)
        {
            CK_ULONG keySize   = (CK_ULONG)-1;
            CK_ULONG keyType   = (CK_ULONG)-1;
            BOOL     isPrivate = FALSE;
            
            CK_ATTRIBUTE attribs[] = 
            {
                { CKA_VALUE_BITS, &keySize, sizeof(keySize)},
                { CKA_KEY_TYPE  , &keyType, sizeof(keyType)},
                { CKA_PRIVATE   , &isPrivate, sizeof(isPrivate)},
            };

            C_GetAttributeValue(hSession, objs[i], attribs, ARRAYSIZE(attribs));            

            pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_keyType].NumericByRef().s4 = SwapEndianIfBEc32(keyType);

            pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_length].NumericByRef().u4 = SwapEndianIfBEc32(keySize);

            if(isPrivate == TRUE)
            {
                pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_privateKeyHandle].NumericByRef().u4 = objs[i];
            }
            else
            {
                pObject[Library_security_pkcs11_native_System_Security_Cryptography_CryptoKey::FIELD__m_privateKeyHandle].NumericByRef().u4 = CK_OBJECT_HANDLE_INVALID;
            }
        }

        pRef++;
    }

    stack.SetResult_Object(ref.DereferenceArray());

    TINYCLR_NOCLEANUP();
}
示例#9
0
/* C_CreateObject creates a new object. */
CK_DEFINE_FUNCTION(CK_RV, C_CreateObject)
(
  CK_SESSION_HANDLE hSession,    /* the session's handle */
  CK_ATTRIBUTE_PTR  pTemplate,   /* the object's template */
  CK_ULONG          ulCount,     /* attributes in template */
  CK_OBJECT_HANDLE_PTR phObject  /* gets new object's handle. */
)
{
    CK_RV ret;
    CK_SLOT_ID slotID;
    CryptokiSession* pSession;
    CK_ULONG i = 0;

    ret = Cryptoki_GetSlotIDFromSession(hSession, &slotID, &pSession);

    if(ret       != CKR_OK) return ret;
    if(pTemplate == NULL  ) return CKR_ARGUMENTS_BAD;
    if(phObject  == NULL  ) return CKR_ARGUMENTS_BAD;

    *phObject = (CK_OBJECT_HANDLE)-1;
    
    if(pTemplate[i].type == CKA_CLASS && pTemplate[i].ulValueLen == sizeof(CK_OBJECT_CLASS))
    {
        CK_OBJECT_CLASS cls = SwapEndianIfBEc32(*(CK_OBJECT_CLASS*)pTemplate[i].pValue);

        i++; if(i > ulCount) return CKR_ARGUMENTS_BAD;

        switch(cls)
        {
            case CKO_SECRET_KEY:
                if(pSession->Token->KeyMgmt != NULL && pSession->Token->KeyMgmt->LoadSecretKey != NULL )
                {
                    if(pTemplate[i].type == CKA_KEY_TYPE)
                    {
                        CK_KEY_TYPE type = SwapEndianIfBEc32(*(CK_KEY_TYPE*)pTemplate[i].pValue);

                        i++; if(i > ulCount) return CKR_ARGUMENTS_BAD;
                        
                        if(pTemplate[i].type == CKA_VALUE)
                        {
                            ret = pSession->Token->KeyMgmt->LoadSecretKey(&pSession->Context, type, (const UINT8*)pTemplate[i].pValue, pTemplate[i].ulValueLen, phObject);
                            
#ifdef _DEBUG
                            if(ret == CKR_OK)
                            {
                                pSession->AddObjectHandle(*phObject);
                            }
#endif
                            
                            return ret;
                        }
                    }
                }
                break;
            case CKO_PRIVATE_KEY:
            case CKO_PUBLIC_KEY:
                if(pSession->Token->KeyMgmt != NULL)
                {
                    if(pTemplate[i].type == CKA_KEY_TYPE)
                    {
                        CK_KEY_TYPE type = SwapEndianIfBEc32(*(CK_KEY_TYPE*)pTemplate[i].pValue);

                        bool bPrivate = (cls == CKO_PRIVATE_KEY);
                        
                        if(type == CKK_DSA && pSession->Token->KeyMgmt->LoadDsaKey != NULL)
                        {
                            DsaKeyData dsaKeyData;

                            memset(&dsaKeyData, 0, sizeof(dsaKeyData));
                           
                            i++;

                            for(;i<ulCount; i++)
                            {
                                switch(pTemplate[i].type)
                                {
                                    case CKA_PRIME:
                                        dsaKeyData.Prime_p        = (PBYTE)pTemplate[i].pValue;
                                        dsaKeyData.Prime_p_len    = pTemplate[i].ulValueLen;
                                        break;
 
                                    case CKA_SUBPRIME:
                                        dsaKeyData.Subprime_q     = (PBYTE)pTemplate[i].pValue;
                                        dsaKeyData.Subprime_q_len = pTemplate[i].ulValueLen;
                                        break;
                                        
                                    case CKA_BASE:
                                        dsaKeyData.Base_g         = (PBYTE)pTemplate[i].pValue;
                                        dsaKeyData.Base_g_len     = pTemplate[i].ulValueLen;
                                        break;
 
                                     case CKA_PRIVATE_EXPONENT:
                                         dsaKeyData.Private_x     = (PBYTE)pTemplate[i].pValue;
                                         dsaKeyData.Private_x_len = pTemplate[i].ulValueLen;
                                         break;
                                         
                                    case CKA_VALUE:
                                        if(bPrivate)
                                        {
                                            dsaKeyData.Private_x     = (PBYTE)pTemplate[i].pValue;
                                            dsaKeyData.Private_x_len = pTemplate[i].ulValueLen;
                                        }
                                        else
                                        {
                                            dsaKeyData.Public_y      = (PBYTE)pTemplate[i].pValue;
                                            dsaKeyData.Public_y_len  = pTemplate[i].ulValueLen;
                                        }
                                        break;

                                    // public and private in same key
                                    case CKA_PUBLIC_EXPONENT:
                                        if(bPrivate)
                                        {
                                            dsaKeyData.Public_y      = (PBYTE)pTemplate[i].pValue;
                                            dsaKeyData.Public_y_len  = pTemplate[i].ulValueLen;
                                        }
                                        break;
                                }
                            }

                            dsaKeyData.Seed_len = dsaKeyData.Base_g_len;

                            ret = pSession->Token->KeyMgmt->LoadDsaKey(&pSession->Context, dsaKeyData, bPrivate, phObject);
                            
#ifdef _DEBUG
                            if(ret == CKR_OK)
                            {
                                pSession->AddObjectHandle(*phObject);
                            }
#endif

                            return ret;
                        }
                        else if(type == CKK_RSA && pSession->Token->KeyMgmt->LoadRsaKey != NULL)
                        {
                            PBYTE    pRawData = NULL;
                            CK_ULONG rawDataLen = 0;
                            RsaKeyData pParams;

                            memset(&pParams, 0, sizeof(pParams));
                            
                            i++;

                            for(;i<ulCount; i++)
                            {
                                switch(pTemplate[i].type)
                                {
                                    case CKA_MODULUS:
                                        pParams.Modulus             = (PBYTE)pTemplate[i].pValue;
                                        pParams.Modulus_len         = pTemplate[i].ulValueLen;
                                        break;

                                    case CKA_PUBLIC_EXPONENT:
                                        pParams.PublicExponent      = (PBYTE)pTemplate[i].pValue;
                                        pParams.PublicExponent_len  = pTemplate[i].ulValueLen;
                                        break;
                                        
                                    case CKA_PRIVATE_EXPONENT:
                                        pParams.PrivateExponent     = (PBYTE)pTemplate[i].pValue;
                                        pParams.PrivateExponent_len = pTemplate[i].ulValueLen;
                                        break;

                                    case CKA_PRIME_1:
                                        pParams.Prime1          = (PBYTE)pTemplate[i].pValue;
                                        pParams.Prime1_len      = pTemplate[i].ulValueLen;
                                        break;
                                    case CKA_PRIME_2:
                                        pParams.Prime2          = (PBYTE)pTemplate[i].pValue;
                                        pParams.Prime2_len      = pTemplate[i].ulValueLen;
                                        break;
                                    case CKA_EXPONENT_1:
                                        pParams.Exponent1       = (PBYTE)pTemplate[i].pValue;
                                        pParams.Exponent1_len   = pTemplate[i].ulValueLen;
                                        break;
                                    case CKA_EXPONENT_2:
                                        pParams.Exponent2       = (PBYTE)pTemplate[i].pValue;
                                        pParams.Exponent2_len   = pTemplate[i].ulValueLen;
                                        break;
                                    case CKA_COEFFICIENT:
                                        pParams.Coefficient     = (PBYTE)pTemplate[i].pValue;
                                        pParams.Coefficient_len = pTemplate[i].ulValueLen;
                                        break;                                        

                                    case CKA_VALUE:
                                        pRawData                = (PBYTE)pTemplate[i].pValue;
                                        rawDataLen              = pTemplate[i].ulValueLen;
                                        break;
                                }
                            }

                            if(pRawData != NULL && rawDataLen > 0)
                            {
                                ret = pSession->Token->KeyMgmt->LoadKeyBlob(&pSession->Context, pRawData, rawDataLen, CKK_RSA, Public, phObject);
                            }
                            else
                            {
                                ret = pSession->Token->KeyMgmt->LoadRsaKey(&pSession->Context, pParams, bPrivate, phObject);
                            }
                            
#ifdef _DEBUG
                            if(ret == CKR_OK)
                            {
                                pSession->AddObjectHandle(*phObject);
                            }
#endif
                            
                            return ret;
                        }
                    }
                }
                break;
        }
    }

    // give the drivers object management a chance to handle this
    if(pSession->Token->ObjectMgmt != NULL && pSession->Token->ObjectMgmt->CreateObject != NULL)
    {
        ret = pSession->Token->ObjectMgmt->CreateObject(&pSession->Context, pTemplate, ulCount, phObject);
        
#ifdef _DEBUG
        if(ret == CKR_OK)
        {
            pSession->AddObjectHandle(*phObject);
        }
#endif
        
        return ret;
    }
    
    return CKR_FUNCTION_NOT_SUPPORTED;
}