static int readAVA( INOUT STREAM *stream, OUT_INT_Z int *type, OUT_LENGTH_SHORT_Z int *length, OUT_TAG_ENCODED_Z int *stringTag ) { const DN_COMPONENT_INFO *dnComponentInfo; BYTE oid[ MAX_OID_SIZE + 8 ]; int oidLength, tag, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( type, sizeof( int ) ) ); assert( isWritePtr( length, sizeof( int ) ) ); assert( isWritePtr( stringTag, sizeof( int ) ) ); /* Clear return values */ *type = 0; *length = 0; *stringTag = 0; /* Read the start of the AVA and determine the type from the AttributeType field. If we find something that we don't recognise we indicate it as a non-component type that can be read or written but not directly accessed by the user (although it can still be accessed using the cursor functions) */ readSequence( stream, NULL ); status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, BER_OBJECT_IDENTIFIER ); if( cryptStatusError( status ) ) return( status ); dnComponentInfo = findDNInfoByOID( oid, oidLength ); if( dnComponentInfo == NULL ) { /* If we don't recognise the component type at all, skip it */ status = readUniversal( stream ); return( cryptStatusError( status ) ? status : OK_SPECIAL ); } *type = dnComponentInfo->type; /* We've reached the data value, make sure that it's in order. When we read the wrapper around the string type with readGenericHole() we have to allow a minimum length of zero instead of one because of broken AVAs with zero-length strings */ tag = peekTag( stream ); if( cryptStatusError( tag ) ) return( tag ); if( tag == BER_BITSTRING ) return( readAVABitstring( stream, length, stringTag ) ); *stringTag = tag; return( readGenericHole( stream, length, 0, tag ) ); }
long integer; int oidLength, innerLength, value, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( offset, sizeof( int ) ) ); /* Clear return values */ *objectType = CRYPT_CERTTYPE_NONE; *offset = 0; /* Read the contentType OID, determine the content type based on it, and read the content encapsulation and header. It can be either a PKCS #7 certificate chain, a Netscape certificate sequence, or an X.509 userCertificate (which is just an oddball certificate wrapper) */ status = readEncodedOID( stream, oid, MAX_OID_SIZE, &oidLength, BER_OBJECT_IDENTIFIER ); if( cryptStatusError( status ) ) return( status ); if( oidLength != sizeofOID( OID_CMS_SIGNEDDATA ) || \ memcmp( oid, OID_CMS_SIGNEDDATA, oidLength ) ) return( CRYPT_ERROR_BADDATA ); readConstructedI( stream, NULL, 0 ); status = readSequenceI( stream, NULL ); if( cryptStatusError( status ) ) return( status ); /* Read the version number (1 = PKCS #7 v1.5, 2 = PKCS #7 v1.6, 3 = S/MIME with attribute certificate(s)) and SET OF DigestAlgorithmIdentifier (this is empty for a pure certificate chain, nonempty for signed data) */ status = readShortInteger( stream, &integer );
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 ); }
static int readGeneralInfoAttribute( INOUT STREAM *stream, INOUT CMP_PROTOCOL_INFO *protocolInfo ) { BYTE oid[ MAX_OID_SIZE + 8 ]; int length, status; assert( isWritePtr( stream, sizeof( STREAM ) ) ); assert( isWritePtr( protocolInfo, sizeof( CMP_PROTOCOL_INFO ) ) ); /* Read the attribute. Since there are only two attribute types that we 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, &length, BER_OBJECT_IDENTIFIER ); if( cryptStatusError( status ) ) return( status ); /* Process the cryptlib presence-check value */ if( length == sizeofOID( OID_CRYPTLIB_PRESENCECHECK ) && \ !memcmp( oid, OID_CRYPTLIB_PRESENCECHECK, length ) ) { /* The other side is running cryptlib, we can make some common-sense assumptions about its behaviour */ protocolInfo->isCryptlib = TRUE; return( readUniversal( stream ) ); /* Attribute */ } /* Check for the ESSCertID, which fixes CMP's broken certificate identification mechanism */ if( length == sizeofOID( OID_ESS_CERTID ) && \ !memcmp( oid, OID_ESS_CERTID, length ) ) { BYTE certID[ CRYPT_MAX_HASHSIZE + 8 ]; int certIDsize, endPos; /* Extract the certificate hash from the ESSCertID */ readSet( stream, NULL ); /* Attribute */ readSequence( stream, NULL ); /* SigningCerts */ readSequence( stream, NULL ); /* Certs */ status = readSequence( stream, &length ); /* ESSCertID */ if( cryptStatusError( status ) ) return( status ); endPos = stell( stream ) + length; status = readOctetString( stream, certID, &certIDsize, KEYID_SIZE, KEYID_SIZE ); if( cryptStatusError( status ) ) return( status ); if( protocolInfo->certIDsize != KEYID_SIZE || \ memcmp( certID, protocolInfo->certID, KEYID_SIZE ) ) { /* The certificate used for authentication purposes has changed, remember the new certID */ memcpy( protocolInfo->certID, certID, KEYID_SIZE ); protocolInfo->certIDsize = KEYID_SIZE; protocolInfo->certIDchanged = TRUE; } if( stell( stream ) < endPos ) { /* Skip the issuerSerial if there's one present. We can't really do much with it in this form without rewriting it into the standard issuerAndSerialNumber, but in any case we don't need it because we've already got the certificate ID */ status = readUniversal( stream ); } return( status ); } /* It's something that we don't recognise, skip it */ return( readUniversal( stream ) ); }