static int readKeyDerivationInfo( INOUT STREAM *stream, OUT QUERY_INFO *queryInfo ) { long endPos, value; int length, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( queryInfo, sizeof( QUERY_INFO ) ) ); /* Clear return value */ memset( queryInfo, 0, sizeof( QUERY_INFO ) ); /* Read the outer wrapper and key derivation algorithm OID */ readConstructed( stream, NULL, CTAG_KK_DA ); status = readFixedOID( stream, OID_PBKDF2, sizeofOID( OID_PBKDF2 ) ); if( cryptStatusError( status ) ) return( status ); /* Read the PBKDF2 parameters, limiting the salt and iteration count to sane values */ status = readSequence( stream, &length ); if( cryptStatusError( status ) ) return( status ); endPos = stell( stream ) + length; readOctetString( stream, queryInfo->salt, &queryInfo->saltLength, 2, CRYPT_MAX_HASHSIZE ); status = readShortInteger( stream, &value ); if( cryptStatusError( status ) ) return( status ); if( value < 1 || value > MAX_KEYSETUP_ITERATIONS ) return( CRYPT_ERROR_BADDATA ); queryInfo->keySetupIterations = ( int ) value; queryInfo->keySetupAlgo = CRYPT_ALGO_HMAC_SHA1; if( stell( stream ) < endPos && \ sPeek( stream ) == BER_INTEGER ) { /* There's an optional key length that may override the default key size present, read it. Note that we compare the upper bound to MAX_WORKING_KEYSIZE rather than CRYPT_MAX_KEYSIZE, since this is a key used directly with an encryption algorithm rather than a generic keying value that may be hashed down to size */ status = readShortInteger( stream, &value ); if( cryptStatusError( status ) ) return( status ); if( value < MIN_KEYSIZE || value > MAX_WORKING_KEYSIZE ) return( CRYPT_ERROR_BADDATA ); queryInfo->keySize = ( int ) value; } if( stell( stream ) < endPos ) { CRYPT_ALGO_TYPE prfAlgo; /* There's a non-default hash algorithm ID present, read it */ status = readAlgoID( stream, &prfAlgo, ALGOID_CLASS_HASH ); if( cryptStatusError( status ) ) return( status ); queryInfo->keySetupAlgo = prfAlgo; } return( CRYPT_OK ); }
static int readRsaPrivateKeyOld( INOUT STREAM *stream, INOUT CONTEXT_INFO *contextInfoPtr ) { CRYPT_ALGO_TYPE cryptAlgo; PKC_INFO *rsaKey = contextInfoPtr->ctxPKC; const int startPos = stell( stream ); int length, endPos, iterationCount, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( contextInfoPtr, sizeof( CONTEXT_INFO ) ) ); REQUIRES( contextInfoPtr->type == CONTEXT_PKC && \ contextInfoPtr->capabilityInfo->cryptAlgo == CRYPT_ALGO_RSA ); /* Skip the PKCS #8 wrapper. When we read the OCTET STRING encapsulation we use MIN_PKCSIZE_THRESHOLD rather than MIN_PKCSIZE so that a too-short key will get to readBignumChecked(), which returns an appropriate error code */ readSequence( stream, &length ); /* Outer wrapper */ readShortInteger( stream, NULL ); /* Version */ status = readAlgoID( stream, &cryptAlgo, ALGOID_CLASS_PKC ); if( cryptStatusError( status ) || cryptAlgo != CRYPT_ALGO_RSA ) return( CRYPT_ERROR_BADDATA ); status = readOctetStringHole( stream, NULL, ( 2 * MIN_PKCSIZE_THRESHOLD ) + \ ( 5 * ( MIN_PKCSIZE_THRESHOLD / 2 ) ), DEFAULT_TAG ); if( cryptStatusError( status ) ) /* OCTET STRING encapsulation */ return( status ); /* Read the header */ readSequence( stream, NULL ); status = readShortInteger( stream, NULL ); if( cryptStatusError( status ) ) return( status ); /* Read the RSA key components, skipping n and e if we've already got them via the associated public key/certificate */ if( BN_is_zero( &rsaKey->rsaParam_n ) ) { status = readBignumChecked( stream, &rsaKey->rsaParam_n, RSAPARAM_MIN_N, RSAPARAM_MAX_N, NULL ); if( cryptStatusOK( status ) ) status = readBignum( stream, &rsaKey->rsaParam_e, RSAPARAM_MIN_E, RSAPARAM_MAX_E, &rsaKey->rsaParam_n ); } else { readUniversal( stream ); status = readUniversal( stream ); } if( cryptStatusOK( status ) ) { /* d isn't used so we skip it */ status = readUniversal( stream ); } if( cryptStatusOK( status ) ) status = readBignum( stream, &rsaKey->rsaParam_p, RSAPARAM_MIN_P, RSAPARAM_MAX_P, &rsaKey->rsaParam_n ); if( cryptStatusOK( status ) ) status = readBignum( stream, &rsaKey->rsaParam_q, RSAPARAM_MIN_Q, RSAPARAM_MAX_Q, &rsaKey->rsaParam_n ); if( cryptStatusOK( status ) ) status = readBignum( stream, &rsaKey->rsaParam_exponent1, RSAPARAM_MIN_EXP1, RSAPARAM_MAX_EXP1, &rsaKey->rsaParam_n ); if( cryptStatusOK( status ) ) status = readBignum( stream, &rsaKey->rsaParam_exponent2, RSAPARAM_MIN_EXP2, RSAPARAM_MAX_EXP2, &rsaKey->rsaParam_n ); if( cryptStatusOK( status ) ) status = readBignum( stream, &rsaKey->rsaParam_u, RSAPARAM_MIN_U, RSAPARAM_MAX_U, &rsaKey->rsaParam_n ); if( cryptStatusError( status ) ) return( status ); /* Check whether there are any attributes present */ if( stell( stream ) >= startPos + length ) return( CRYPT_OK ); /* Read the attribute wrapper */ status = readConstructed( stream, &length, 0 ); if( cryptStatusError( status ) ) return( status ); endPos = stell( stream ) + length; /* Read the collection of attributes. Unlike any other key-storage format, PKCS #8 stores the key usage information as an X.509 attribute alongside the encrypted private key data so we have to process whatever attributes may be present in order to find the keyUsage (if there is any) in order to set the object action permissions */ for( iterationCount = 0; stell( stream ) < endPos && \ iterationCount < FAILSAFE_ITERATIONS_MED; iterationCount++ ) { BYTE oid[ MAX_OID_SIZE + 8 ]; int oidLength, actionFlags, value; /* Read the attribute. Since there's only one attribute type that we can use, we hardcode the read in here rather than performing a general-purpose attribute read */ readSequence( stream, NULL ); status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, BER_OBJECT_IDENTIFIER ); if( cryptStatusError( status ) ) return( status ); /* If it's not a key-usage attribute, we can't do much with it */ if( oidLength != sizeofOID( OID_X509_KEYUSAGE ) || \ memcmp( oid, OID_X509_KEYUSAGE, oidLength ) ) { status = readUniversal( stream ); if( cryptStatusError( status ) ) return( status ); continue; } /* Read the keyUsage attribute and convert it into cryptlib action permissions */ readSet( stream, NULL ); status = readBitString( stream, &value ); if( cryptStatusError( status ) ) return( status ); actionFlags = ACTION_PERM_NONE; if( value & ( KEYUSAGE_SIGN | KEYUSAGE_CA ) ) { actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_SIGN, \ ACTION_PERM_ALL ) | \ MK_ACTION_PERM( MESSAGE_CTX_SIGCHECK, \ ACTION_PERM_ALL ); } if( value & KEYUSAGE_CRYPT ) { actionFlags |= MK_ACTION_PERM( MESSAGE_CTX_ENCRYPT, \ ACTION_PERM_ALL ) | \ MK_ACTION_PERM( MESSAGE_CTX_DECRYPT, \ ACTION_PERM_ALL ); } #if 0 /* 11/6/13 Windows sets these flags to what are effectively gibberish values (dataEncipherment for a signing key, digitalSignature for an encryption key) so in order to be able to use the key we have to ignore the keyUsage settings, in the same way that every other application seems to */ if( actionFlags == ACTION_PERM_NONE ) return( CRYPT_ERROR_NOTAVAIL ); status = krnlSendMessage( contextInfoPtr->objectHandle, IMESSAGE_SETATTRIBUTE, &actionFlags, CRYPT_IATTRIBUTE_ACTIONPERMS ); if( cryptStatusError( status ) ) return( status ); #else assert( actionFlags != ACTION_PERM_NONE ); /* Warn in debug mode */ #endif /* 0 */ } ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED ); return( CRYPT_OK ); }