/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2006 * */ #include #include #include // for little-big endian conversion #include // for message digest #include #include "bi.h" #include "daa_parameter.h" #include "list.h" #include "daa_structs.h" #include "issuer.h" //standard bit length extension to obtain a uniformly distributed number [0,element] static const int SAFETY_PARAM = 80; static bi_array_ptr get_generators( const TSS_DAA_PK_internal *pk) { bi_array_ptr result = ALLOC_BI_ARRAY(); int i; bi_new_array( result, 3 + pk->capitalY->length ); for(i = 0; ilength; i++) { result->array[i] = pk->capitalS; } return result; } static bi_array_ptr get_verifiable_numbers( const TSS_DAA_PK_internal *pk) { bi_array_ptr result = ALLOC_BI_ARRAY(); int i; bi_new_array( result, 3 + pk->capitalY->length); result->array[0] = pk->capitalZ; result->array[1] = pk->capitalR0; result->array[2] = pk->capitalR1; // CAPITAL Y ( capitalRReceiver + capitalRIssuer) for( i=0; icapitalY ->length; i++) result->array[ 3+i] = pk->capitalY->array[i]; return result; } /* computes an array of random numbers in the range of [1,element] */ void compute_random_numbers( bi_array_ptr result, int quantity, const bi_ptr element) { int i=0; for( i=0; iarray[i], element); bi_inc( result->array[i]); // array[i]++ } } int test_bit( int pos, BYTE* array, int length) { return (((int)array[ length - (pos / 8) - 1]) & (1 << (pos % 8))) != 0; } void toByteArray( BYTE *result, int length, bi_ptr bi, char *logMsg) { LogDebug("-> toByteArray <%d> %s",(int)bi, logMsg); LogDebug("lenghts <%d|%d>",length, (int)bi_nbin_size(bi)); bi_2_byte_array( result, length, bi); LogDebug("<- toByteArray result=%s [<%d|%d>] ", dump_byte_array( length, result), length, (int)bi_nbin_size(bi)); } /* Compute the message digest used in the proof. (from DAA_Param, the digest algorithm is RSA, but this is not available in openssl, the successor of RSA is SHA1 */ TSS_RESULT generateMessageDigest(BYTE *md_value, int *md_len, const TSS_DAA_PK_internal *pk, bi_array_ptr *commitments, const int commitments_size ) { EVP_MD_CTX mdctx; const EVP_MD *md; int i, j; int length = DAA_PARAM_SIZE_RSA_MODULUS / 8; BYTE *array; // 10000 to be sure, and this memory will be released quite quickly array = (BYTE *)malloc( 10000); if (array == NULL) { LogError("malloc of %d bytes failed", 10000); return TSPERR(TSS_E_OUTOFMEMORY); } OpenSSL_add_all_digests(); md = EVP_get_digestbyname( DAA_PARAM_MESSAGE_DIGEST_ALGORITHM); EVP_MD_CTX_init(&mdctx); EVP_DigestInit_ex(&mdctx, md, NULL); #ifdef DAA_DEBUG fprintf(stderr, "modulus=%s\n", bi_2_hex_char( pk->modulus)); #endif toByteArray( array, length, pk->modulus, "!! [generateMessageDigest modulus] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); toByteArray( array, length, pk->capitalS, "!! [generateMessageDigest capitalS] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); // add capitalZ, capitalR0, capitalR1, capitalY LogDebug("capitalZ capitalR0 capitalY"); toByteArray( array, length, pk->capitalZ, "!! [generateMessageDigest capitalZ] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); toByteArray( array, length, pk->capitalR0, "!! [generateMessageDigest capitalR0] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); toByteArray( array, length, pk->capitalR1, "!! [generateMessageDigest capitalR1] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); // CAPITAL Y ( capitalRReceiver ) LogDebug("capitalRReceiver"); for( i=0; icapitalRReceiver->length; i++) { toByteArray( array, length, pk->capitalRReceiver->array[i], "!![generateMessageDigest capitalRReceiver] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); } LogDebug("capitalRIssuer"); // CAPITAL Y ( capitalRIssuer) for( i=0; icapitalRIssuer->length; i++) { toByteArray( array, length, pk->capitalRIssuer->array[i], "!![generateMessageDigest capitalRReceiver] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); } LogDebug("commitments"); for( i=0; ilength; j++) { toByteArray( array, length, commitments[i]->array[j], "!! [generateMessageDigest commitments] current_size=%d length=%d\n"); EVP_DigestUpdate(&mdctx, array , length); } } EVP_DigestFinal_ex(&mdctx, md_value, md_len); EVP_MD_CTX_cleanup(&mdctx); free( array); return TSS_SUCCESS; } int is_range_correct( bi_ptr b, bi_ptr range) { return bi_cmp( b, range) < 0 && bi_cmp( b, bi_0) >= 0; } /* Verifies if the parameters Z,R0,R1,RReceiver and RIssuer of the public key were correctly computed. pk: the public key, which one wants to verfy. */ TSS_RESULT is_pk_correct( TSS_DAA_PK_internal *public_key, TSS_DAA_PK_PROOF_internal *proof, int *isCorrect ) { int bit_size_message_digest = DAA_PARAM_SIZE_MESSAGE_DIGEST; bi_ptr n = public_key->modulus; int num_of_variables; int i,j; TSS_RESULT result = TSS_SUCCESS; BYTE verifiable_challenge[EVP_MAX_MD_SIZE]; int length_challenge; bi_array_ptr verifiable_numbers; bi_array_ptr *verification_commitments = NULL; bi_array_ptr generators = NULL; bi_t tmp; bi_t tmp1; #ifdef DAA_DEBUG FILE *f; bi_array_ptr *commitments; #endif bi_new( tmp); bi_new( tmp1); *isCorrect = 0; #ifdef DAA_DEBUG f=fopen("/tmp/commits", "r"); commitments = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * num_of_variables); if (commitments == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_array_ptr) * num_of_variables); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i=0; icapitalGamma)) { LogError( "pk->capitalGamma not prime\ncapitalGamma=\n%s", bi_2_hex_char( public_key->capitalGamma)); result = TSS_E_BAD_PARAMETER; goto close; } if( !bi_is_probable_prime( public_key->rho)) { LogError( "pk->rho not prime\nrho=\n%s", bi_2_hex_char( public_key->rho)); result = TSS_E_BAD_PARAMETER; goto close; } // (capitalGamma - 1) % rho should be equal to 0 if( !bi_equals( bi_mod( tmp1, bi_sub( tmp1, public_key->capitalGamma, bi_1), public_key->rho), bi_0)) { LogError( "(capitalGamma - 1) %% rho != 0\nActual value:\n%s", bi_2_hex_char( tmp1)); result = TSS_E_BAD_PARAMETER; } // (gamma ^ rho) % capitalGamma should be equals to 1 if ( !bi_equals( bi_mod_exp( tmp1, public_key->gamma, public_key->rho, public_key->capitalGamma), bi_1) ) { LogError( "(gamma ^ rho) %% capitalGamma != 1\nActual value:\n%s", bi_2_hex_char( tmp1)); result = TSS_E_BAD_PARAMETER; goto close; } // (gamma ^ rho) % capitalGamma should be equal to 1 if ( !bi_equals( bi_mod_exp( tmp1, public_key->gamma, public_key->rho, public_key->capitalGamma), bi_1) ) { LogError( "(gamma ^ rho) %% capitalGamma != 1\nActual value:\n%s", bi_2_hex_char( tmp1)); result = TSS_E_BAD_PARAMETER; goto close; } LogDebug("STEP 2 check whether all public key parameters have the required length"); if( bi_nbin_size( n) != DAA_PARAM_SIZE_RSA_MODULUS / 8) { LogError( "size( n)[%ld] != DAA_PARAM_SIZE_RSA_MODULUS[%d]", bi_nbin_size( n), DAA_PARAM_SIZE_RSA_MODULUS / 8); result = TSS_E_BAD_PARAMETER; goto close; } if( bi_cmp( n, bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_RSA_MODULUS)) >= 0) { LogError( "n[%ld] != DAA_PARAM_SIZE_RSA_MODULUS[%d]", bi_nbin_size( n), DAA_PARAM_SIZE_RSA_MODULUS); result = TSS_E_BAD_PARAMETER; goto close; } if( bi_cmp( n, bi_shift_left( tmp1, bi_1, DAA_PARAM_SIZE_RSA_MODULUS - 1 )) <= 0) { LogError( "n[%ld] != DAA_PARAM_SIZE_RSA_MODULUS[%d]", bi_nbin_size( n), DAA_PARAM_SIZE_RSA_MODULUS); result = TSS_E_BAD_PARAMETER; goto close; } // rho if( bi_nbin_size( public_key->rho) * 8 != DAA_PARAM_SIZE_RHO) { LogError( "size( rho)[%ld] != DAA_PARAM_SIZE_RHO[%d]", bi_nbin_size( public_key->rho) * 8, DAA_PARAM_SIZE_RHO); result = TSS_E_BAD_PARAMETER; goto close; } // Gamma if( bi_nbin_size( public_key->capitalGamma) * 8 != DAA_PARAM_SIZE_MODULUS_GAMMA) { LogError( "size( rho)[%ld] != DAA_PARAM_SIZE_MODULUS_GAMMA[%d]", bi_nbin_size( public_key->capitalGamma) * 8, DAA_PARAM_SIZE_MODULUS_GAMMA); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalS, n) == 0) { LogError( "range not correct( pk->capitalS)\ncapitalS=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalS), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalZ, n) == 0) { LogError( "range not correct( pk->capitalZ)\ncapitalZ=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalZ), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalR0, n) == 0) { LogError( "range not correct( pk->capitalR0)\ncapitalR0=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalR0), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } if( is_range_correct( public_key->capitalR1, n) == 0) { LogError( "range not correct( pk->capitalR1)\ncapitalR1=\n%s\nn=\n%s", bi_2_hex_char( public_key->capitalR1), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } for( i=0; icapitalY->length; i++) { if( is_range_correct( public_key->capitalY->array[i], n) == 0) { LogError( "range not correct(pk->capitalY[%d])\ncapitalY[%d]=\n%s\nn=\n%s", i, i, bi_2_hex_char( public_key->capitalY->array[i]), bi_2_hex_char( n)); result = TSS_E_BAD_PARAMETER; goto close; } } LogDebug("STEP 3 - compute verification commitments"); // only the array is allocated, but all refs are pointing to public_key numbers generators = get_generators( public_key); verifiable_numbers = get_verifiable_numbers( public_key); num_of_variables = verifiable_numbers->length; verification_commitments = (bi_array_ptr *)malloc( sizeof(bi_array_ptr)*num_of_variables); if (verification_commitments == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_array_ptr)*num_of_variables); result = TSPERR(TSS_E_OUTOFMEMORY); goto close; } for( i = 0; ichallenge, proof->length_challenge)); #endif bi_mod_exp( verification_commitments[i]->array[j], generators->array[i], proof->response[i]->array[j], n); if( test_bit( j, proof->challenge, proof->length_challenge)) { bi_mul( verification_commitments[i]->array[j], verification_commitments[i]->array[j], verifiable_numbers->array[i]); #ifdef DAA_DEBUG DUMP_BI( verification_commitments[i]->array[j]); #endif bi_mod( verification_commitments[i]->array[j], verification_commitments[i]->array[j], n); } #ifdef DAA_DEBUG if( commitments != NULL && bi_equals( verification_commitments[i]->array[j], commitments[i]->array[j]) ==0) { LogError( "!! ERROR i=%d j=%d\n", i, j); DUMP_BI( commitments[i]->array[j]); DUMP_BI( verification_commitments[i]->array[j]); DUMP_BI( generators->array[i]); DUMP_BI( proof->response[i]->array[j]); DUMP_BI( verifiable_numbers->array[i]); } printf( "o"); fflush( stdout); #endif } } // STEP 3 - d generateMessageDigest( verifiable_challenge, &length_challenge, public_key, verification_commitments, num_of_variables); LogDebug("verifiable challenge=%s", dump_byte_array( length_challenge, verifiable_challenge)); LogDebug(" challenge=%s", dump_byte_array( proof->length_challenge, proof->challenge)); if( length_challenge != proof->length_challenge) { result = TSS_E_BAD_PARAMETER; goto close; } for( i=0; ichallenge[i]) { result = TSS_E_BAD_PARAMETER; goto close; } } *isCorrect = ( memcmp( verifiable_challenge, proof->challenge, length_challenge) == 0); close: if( verification_commitments != NULL) { for( i = 0; imodulus; int num_of_variables; int bit_size_message_digest = DAA_PARAM_SIZE_MESSAGE_DIGEST; bi_array_ptr *xTildes = NULL; BYTE *challenge_param; bi_array_ptr exponents = ALLOC_BI_ARRAY(); bi_new_array2( exponents, 3 + x->length); exponents->array[0] = xz; exponents->array[1] = x0; exponents->array[2] = x1; bi_copy_array( x, 0, exponents, 3, x->length); num_of_variables = exponents->length; LogDebug("Step a - choose random numbers"); LogDebug("\nchoose random numbers\n"); xTildes = (bi_array_ptr *)malloc( sizeof(bi_array_ptr) * num_of_variables); if (xTildes == NULL) { LogError("malloc of %d bytes failed", sizeof(bi_array_ptr) * num_of_variables); return NULL; } for( i=0; iarray[j], generators->array[i], xTildes[i]->array[j], n); } } #ifdef DAA_DEBUG FILE *f=fopen("/tmp/commits", "w"); for( i=0; iarray[j], xTildes[i]->array[j], exponents->array[i]); } else { bi_set( response[i]->array[j], xTildes[i]->array[j]); } bi_mod( response[i]->array[j], response[i]->array[j], product_PQ_prime); #ifdef DAA_DEBUG printf("#"); fflush(stdout); #endif } } challenge_param = (BYTE *)malloc( length_challenge); if (challenge_param == NULL) { LogError("malloc of %d bytes failed", length_challenge); return NULL; } memcpy( challenge_param, challenge, length_challenge); return create_DAA_PK_PROOF( challenge_param, length_challenge, response, num_of_variables); }