Пример #1
0
/**
 * Finalise HMAC
 *
 * @v digest		Digest algorithm to use
 * @v digest_ctx	Digest context
 * @v key		Key
 * @v key_len		Length of key
 * @v hmac		HMAC digest to fill in
 *
 * The length of the key should be less than the block size of the
 * digest algorithm being used.  (If the key length is greater, it
 * will be replaced with its own digest, and key_len will be updated
 * accordingly).
 */
void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
		  void *key, size_t *key_len, void *hmac ) {
	unsigned char k_opad[digest->blocksize];
	unsigned int i;

	/* Reduce key if necessary */
	if ( *key_len > sizeof ( k_opad ) )
		hmac_reduce_key ( digest, key, key_len );

	/* Construct output pad */
	memset ( k_opad, 0, sizeof ( k_opad ) );
	memcpy ( k_opad, key, *key_len );
	for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
		k_opad[i] ^= 0x5c;
	}
	
	/* Finish inner hash */
	digest_final ( digest, digest_ctx, hmac );

	/* Perform outer hash */
	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
	digest_update ( digest, digest_ctx, hmac, digest->digestsize );
	digest_final ( digest, digest_ctx, hmac );
}
Пример #2
0
/**
 * Build OCSP request
 *
 * @v ocsp		OCSP check
 * @ret rc		Return status code
 */
static int ocsp_request ( struct ocsp_check *ocsp ) {
	struct digest_algorithm *digest = &ocsp_digest_algorithm;
	struct asn1_builder *builder = &ocsp->request.builder;
	struct asn1_cursor *cert_id_tail = &ocsp->request.cert_id_tail;
	uint8_t digest_ctx[digest->ctxsize];
	uint8_t name_digest[digest->digestsize];
	uint8_t pubkey_digest[digest->digestsize];
	int rc;

	/* Generate digests */
	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data,
			ocsp->cert->issuer.raw.len );
	digest_final ( digest, digest_ctx, name_digest );
	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx,
			ocsp->issuer->subject.public_key.raw_bits.data,
			ocsp->issuer->subject.public_key.raw_bits.len );
	digest_final ( digest, digest_ctx, pubkey_digest );

	/* Construct request */
	if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data,
					 ocsp->cert->serial.raw.len ),
		      asn1_prepend ( builder, ASN1_OCTET_STRING,
				     pubkey_digest, sizeof ( pubkey_digest ) ),
		      asn1_prepend ( builder, ASN1_OCTET_STRING,
				     name_digest, sizeof ( name_digest ) ),
		      asn1_prepend ( builder, ASN1_SEQUENCE,
				     ocsp_algorithm_id,
				     sizeof ( ocsp_algorithm_id ) ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ),
		      asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) {
		DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n",
		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
		return rc;
	}
	DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n",
		ocsp, x509_name ( ocsp->cert ) );
	DBGC2_HDA ( ocsp, 0, builder->data, builder->len );

	/* Parse certificate ID for comparison with response */
	cert_id_tail->data = builder->data;
	cert_id_tail->len = builder->len;
	if ( ( rc = ( asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_enter ( cert_id_tail, ASN1_SEQUENCE ),
		      asn1_skip ( cert_id_tail, ASN1_SEQUENCE ) ) ) != 0 ) {
		DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
		       ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
		return rc;
	}

	return 0;
}
Пример #3
0
/**
 * Compare responder's certificate public key hash
 *
 * @v ocsp		OCSP check
 * @v cert		Certificate
 * @ret difference	Difference as returned by memcmp()
 */
static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp,
					     struct x509_certificate *cert ) {
	struct ocsp_responder *responder = &ocsp->response.responder;
	struct asn1_cursor key_hash;
	uint8_t ctx[SHA1_CTX_SIZE];
	uint8_t digest[SHA1_DIGEST_SIZE];
	int difference;

	/* Enter responder key hash */
	memcpy ( &key_hash, &responder->id, sizeof ( key_hash ) );
	asn1_enter ( &key_hash, ASN1_OCTET_STRING );

	/* Sanity check */
	difference = ( sizeof ( digest ) - key_hash.len );
	if ( difference )
		return difference;

	/* Generate SHA1 hash of certificate's public key */
	digest_init ( &sha1_algorithm, ctx );
	digest_update ( &sha1_algorithm, ctx,
			cert->subject.public_key.raw_bits.data,
			cert->subject.public_key.raw_bits.len );
	digest_final ( &sha1_algorithm, ctx, digest );

	/* Compare responder key hash with hash of certificate's public key */
	return memcmp ( digest, key_hash.data, sizeof ( digest ) );
}
Пример #4
0
/**
 * Calculate digest algorithm cost
 *
 * @v digest		Digest algorithm
 * @ret cost		Cost (in cycles per byte)
 */
unsigned long digest_cost ( struct digest_algorithm *digest ) {
	static uint8_t random[8192]; /* Too large for stack */
	uint8_t ctx[digest->ctxsize];
	uint8_t out[digest->digestsize];
	struct profiler profiler;
	unsigned long cost;
	unsigned int i;

	/* Fill buffer with pseudo-random data */
	srand ( 0x1234568 );
	for ( i = 0 ; i < sizeof ( random ) ; i++ )
		random[i] = rand();

	/* Profile digest calculation */
	memset ( &profiler, 0, sizeof ( profiler ) );
	for ( i = 0 ; i < PROFILE_COUNT ; i++ ) {
		profile_start ( &profiler );
		digest_init ( digest, ctx );
		digest_update ( digest, ctx, random, sizeof ( random ) );
		digest_final ( digest, ctx, out );
		profile_stop ( &profiler );
	}

	/* Round to nearest whole number of cycles per byte */
	cost = ( ( profile_mean ( &profiler ) + ( sizeof ( random ) / 2 ) ) /
		 sizeof ( random ) );

	return cost;
}
Пример #5
0
/**
 * Test digest algorithm
 *
 * @v digest		Digest algorithm
 * @v fragments		Digest test fragment list, or NULL
 * @v data		Test data
 * @v len		Length of test data
 * @v expected		Expected digest value
 * @ret ok		Digest value is as expected
 */
int digest_test ( struct digest_algorithm *digest,
		  struct digest_test_fragments *fragments,
		  void *data, size_t len, void *expected ) {
	uint8_t ctx[digest->ctxsize];
	uint8_t out[digest->digestsize];
	size_t frag_len = 0;
	unsigned int i;

	/* Initialise digest */
	digest_init ( digest, ctx );

	/* Update digest fragment-by-fragment */
	for ( i = 0 ; len && ( i < ( sizeof ( fragments->len ) /
				     sizeof ( fragments->len[0] ) ) ) ; i++ ) {
		if ( fragments )
			frag_len = fragments->len[i];
		if ( ( frag_len == 0 ) || ( frag_len < len ) )
			frag_len = len;
		digest_update ( digest, ctx, data, frag_len );
		data += frag_len;
		len -= frag_len;
	}

	/* Finalise digest */
	digest_final ( digest, ctx, out );

	/* Compare against expected output */
	return ( memcmp ( expected, out, sizeof ( out ) ) == 0 );
}
Пример #6
0
/**
 * Report server passphrase test result
 *
 * @v test		Content information segment test
 * @v info		Content information
 * @v pass		Server passphrase
 * @v pass_len		Length of server passphrase
 * @v file		Test code file
 * @v line		Test code line
 */
static void
peerdist_info_passphrase_okx ( struct peerdist_info_segment_test *test,
			       const struct peerdist_info *info,
			       uint8_t *pass, size_t pass_len,
			       const char *file, unsigned int line ) {
	struct digest_algorithm *digest = info->digest;
	uint8_t ctx[digest->ctxsize];
	uint8_t secret[digest->digestsize];
	uint8_t expected[digest->digestsize];
	size_t digestsize = info->digestsize;
	size_t secretsize = digestsize;

	/* Calculate server secret */
	digest_init ( digest, ctx );
	digest_update ( digest, ctx, pass, pass_len );
	digest_final ( digest, ctx, secret );

	/* Calculate expected segment secret */
	hmac_init ( digest, ctx, secret, &secretsize );
	assert ( secretsize == digestsize );
	hmac_update ( digest, ctx, test->expected_hash, digestsize );
	hmac_final ( digest, ctx, secret, &secretsize, expected );
	assert ( secretsize == digestsize );

	/* Verify segment secret */
	okx ( memcmp ( test->expected_secret, expected, digestsize ) == 0,
	      file, line );
}
Пример #7
0
/**
 * Finalise HTTP Digest
 *
 * @v ctx		Digest context
 * @v out		Buffer for digest output
 * @v len		Buffer length
 */
static void http_digest_final ( struct md5_context *ctx, char *out,
				size_t len ) {
	uint8_t digest[MD5_DIGEST_SIZE];

	/* Finalise and base16-encode MD5 digest */
	digest_final ( &md5_algorithm, ctx, digest );
	base16_encode ( digest, sizeof ( digest ), out, len );
}
Пример #8
0
/**
 * Reduce HMAC key length
 *
 * @v digest		Digest algorithm to use
 * @v digest_ctx	Digest context
 * @v key		Key
 * @v key_len		Length of key
 */
static void hmac_reduce_key ( struct digest_algorithm *digest,
			      void *key, size_t *key_len ) {
	uint8_t digest_ctx[digest->ctxsize];

	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx, key, *key_len );
	digest_final ( digest, digest_ctx, key );
	*key_len = digest->digestsize;
}
Пример #9
0
/**
 * The "digest" command
 *
 * @v argc		Argument count
 * @v argv		Argument list
 * @v digest		Digest algorithm
 * @ret rc		Exit code
 */
static int digest_exec ( int argc, char **argv,
			 struct digest_algorithm *digest ) {
	const char *image_name;
	struct image *image;
	uint8_t digest_ctx[digest->ctxsize];
	uint8_t digest_out[digest->digestsize];
	uint8_t buf[128];
	size_t offset;
	size_t len;
	size_t frag_len;
	int i;
	unsigned j;

	if ( argc < 2 ||
	     !strcmp ( argv[1], "--help" ) ||
	     !strcmp ( argv[1], "-h" ) ) {
		digest_syntax ( argv );
		return 1;
	}

	for ( i = 1 ; i < argc ; i++ ) {
		image_name = argv[i];

		/* find image */
		image = find_image ( image_name );
		if ( ! image ) {
			printf ( "No such image: %s\n", image_name );
			continue;
		}
		offset = 0;
		len = image->len;

		/* calculate digest */
		digest_init ( digest, digest_ctx );
		while ( len ) {
			frag_len = len;
			if ( frag_len > sizeof ( buf ) )
				frag_len = sizeof ( buf );
			copy_from_user ( buf, image->data, offset, frag_len );
			digest_update ( digest, digest_ctx, buf, frag_len );
			len -= frag_len;
			offset += frag_len;
		}
		digest_final ( digest, digest_ctx, digest_out );

		for ( j = 0 ; j < sizeof ( digest_out ) ; j++ )
			printf ( "%02x", digest_out[j] );

		printf ( "  %s\n", image->name );
	}

	return 0;
}
Пример #10
0
/**
 * Check OCSP response signature
 *
 * @v ocsp		OCSP check
 * @v signer		Signing certificate
 * @ret rc		Return status code
 */
static int ocsp_check_signature ( struct ocsp_check *ocsp,
				  struct x509_certificate *signer ) {
	struct ocsp_response *response = &ocsp->response;
	struct digest_algorithm *digest = response->algorithm->digest;
	struct pubkey_algorithm *pubkey = response->algorithm->pubkey;
	struct x509_public_key *public_key = &signer->subject.public_key;
	uint8_t digest_ctx[ digest->ctxsize ];
	uint8_t digest_out[ digest->digestsize ];
	uint8_t pubkey_ctx[ pubkey->ctxsize ];
	int rc;

	/* Generate digest */
	digest_init ( digest, digest_ctx );
	digest_update ( digest, digest_ctx, response->tbs.data,
			response->tbs.len );
	digest_final ( digest, digest_ctx, digest_out );

	/* Initialise public-key algorithm */
	if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
				  public_key->raw.len ) ) != 0 ) {
		DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: "
		       "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
		goto err_init;
	}

	/* Verify digest */
	if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
				    response->signature.data,
				    response->signature.len ) ) != 0 ) {
		DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: "
		       "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
		goto err_verify;
	}

	DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n",
		ocsp, x509_name ( ocsp->cert ) );

 err_verify:
	pubkey_final ( pubkey, pubkey_ctx );
 err_init:
	return rc;
}
Пример #11
0
/**
 * Distribute entropy throughout a buffer
 *
 * @v hash		Underlying hash algorithm
 * @v input		Input data
 * @v input_len		Length of input data, in bytes
 * @v output		Output buffer
 * @v output_len	Length of output buffer, in bytes
 *
 * This is the Hash_df function defined in ANS X9.82 Part 3-2007
 * Section 10.5.2 (NIST SP 800-90 Section 10.4.1).
 *
 * The number of bits requested is implicit in the length of the
 * output buffer.  Requests must be for an integral number of bytes.
 *
 * The output buffer is filled incrementally with each iteration of
 * the central loop, rather than constructing an overall "temp" and
 * then taking the leftmost(no_of_bits_to_return) bits.
 *
 * There is no way for the Hash_df function to fail.  The returned
 * status SUCCESS is implicit.
 */
void hash_df ( struct digest_algorithm *hash, const void *input,
	       size_t input_len, void *output, size_t output_len ) {
	uint8_t context[hash->ctxsize];
	uint8_t digest[hash->digestsize];
	size_t frag_len;
	struct {
		uint8_t pad[3];
		uint8_t counter;
		uint32_t no_of_bits_to_return;
	} __attribute__ (( packed )) prefix;
	void *temp;
	size_t remaining;

	DBGC ( &hash_df, "HASH_DF input:\n" );
	DBGC_HDA ( &hash_df, 0, input, input_len );

	/* Sanity checks */
	assert ( input != NULL );
	assert ( output != NULL );

	/* 1.  temp = the Null string
	 * 2.  len = ceil ( no_of_bits_to_return / outlen )
	 *
	 * (Nothing to do.  We fill the output buffer incrementally,
	 * rather than constructing the complete "temp" in-memory.
	 * "len" is implicit in the number of iterations required to
	 * fill the output buffer, and so is not calculated
	 * explicitly.)
	 */

	/* 3.  counter = an 8-bit binary value representing the integer "1" */
	prefix.counter = 1;

	/* 4.  For i = 1 to len do */
	for ( temp = output, remaining = output_len ; remaining > 0 ; ) {

		/* Comment: in step 5.1 (sic), no_of_bits_to_return is
		 * used as a 32-bit string.
		 *
		 * 4.1  temp = temp || Hash ( counter || no_of_bits_to_return
		 *                            || input_string )
		 */
		prefix.no_of_bits_to_return = htonl ( output_len * 8 );
		digest_init ( hash, context );
		digest_update ( hash, context, &prefix.counter,
				( sizeof ( prefix ) -
				  offsetof ( typeof ( prefix ), counter ) ) );
		digest_update ( hash, context, input, input_len );
		digest_final ( hash, context, digest );

		/* 4.2  counter = counter + 1 */
		prefix.counter++;

		/* 5.    requested_bits = Leftmost ( no_of_bits_to_return )
		 *       of temp
		 *
		 * (We fill the output buffer incrementally.)
		 */
		frag_len = sizeof ( digest );
		if ( frag_len > remaining )
			frag_len = remaining;
		memcpy ( temp, digest, frag_len );
		temp += frag_len;
		remaining -= frag_len;
	}

	/* 6.  Return SUCCESS and requested_bits */
	DBGC ( &hash_df, "HASH_DF output:\n" );
	DBGC_HDA ( &hash_df, 0, output, output_len );
	return;
}