/* ==================================================================== * Copyright (c) 1998-2008 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ #include #include #include #include #include #include #include #ifdef USE_HSM #include "cr_hsm_code.h" #include "cr_hsm_bignum.h" // for develop #include #include #include #else // openssl #include #include #include #include "cr_NCT2_priv_dev.c" #include "cr_NCT2_priv_prod.c" #endif // USE_HSM #include "cr_NCT2_pub_dev.c" #include "cr_NCT2_pub_prod.c" #include "cr_generate_id.h" #include "cr_generate_id_private.h" #define CR_CERT_EXPIRE_SECS ( 60*60*24*365* 20 ) // デバイス証明書期限 20年 ※うるう年は無視 u8 tempSign[ 70 ]; // TWL device cert base typedef struct CR_DeviceCert { u8 sigType [ 4 ]; // 0x000 - 0x003 : 0x00010005, signature type is ECDSA + SHA256 u8 eccSignature[ 60 ]; // 0x004 - 0x03F : ECDSA using SHA-1 and CA key u8 padding0 [ 64 ]; // 0x040 - 0x07F : zero-filled u8 issuerName [ 64 ]; // 0x080 - 0x0BF : issuer name, "Root-CA00000002-MS00000008" u8 keyType [ 4 ]; // 0x0C0 - 0x0C3 : 0x00000002, cert public key type is ECC233 u8 subject [ 64 ]; // 0x0C4 - 0x103 : subject field, "CTxxxxxxxx-yy" u32 expiryDate; // 0x104 - 0x107 : second from Epoch (Jan 1, 1970 00:00) u8 eccPubKey [ 60 ]; // 0x108 - 0x143 : cert public key (openssl sect233r1) u8 padding1 [ 60 ]; // 0x144 - 0x17F : zero-filled } CR_DeviceCert; const u8 issuerName[] = { 0x14, 0x33, 0x34, 0x2E, 0x3F, 0x34, 0x3E, 0x35, 0x19, 0x1B, 0x7A, 0x77, 0x7A, 0x1D, 0x68, 0x05, 0x14, 0x33, 0x34, 0x2E, 0x3F, 0x34, 0x3E, 0x35, 0x19, 0x0E, 0x08, 0x68 }; static void BN2BinWithPadding( BIGNUM *pBn, u8 *pDst, int dstLen ); // create CTR Device cert int GenerateCTRDeviceCert( EC_KEY *pECkey, u32 device_id, u8 bonding_option, u8 *pDevCertSign, u32 *pExpiryDate ) { int ret_code = CR_GENID_SUCCESS; CR_DeviceCert deviceCert; EC_KEY *NCT2 = NULL; int i; #ifdef DEBUG_PRINT if ( sizeof( CR_DeviceCert ) > 384 ) { printf( "CR_DeviceCert size error. %d\n", sizeof(CR_DeviceCert) ); } #endif memset( &deviceCert, 0, sizeof(deviceCert) ); // sigType 0x00010005 ECDSA+SHA256 deviceCert.sigType[0] = 0x00; deviceCert.sigType[1] = 0x01; deviceCert.sigType[2] = 0x00; deviceCert.sigType[3] = 0x05; // issuerName for( i = 0; i < sizeof(issuerName); i++ ) { deviceCert.issuerName[ i ] = issuerName[ i ] ^ 0x5a; } sprintf( &deviceCert.issuerName[ sizeof(issuerName) ], "%s", bonding_option ? "dev" : "prod" ); // keyType 0x00000002 ECC233 deviceCert.keyType[0] = 0x00; deviceCert.keyType[1] = 0x00; deviceCert.keyType[2] = 0x00; deviceCert.keyType[3] = 0x02; // subject : CT + device_id + bonding_option sprintf( deviceCert.subject, "CT%08X-%02X", (unsigned int)device_id, bonding_option ); // expiryDate +20years *pExpiryDate += CR_CERT_EXPIRE_SECS; // ID_BUFにも証明書期限をセットする。 deviceCert.expiryDate = *pExpiryDate; // eccPubKey BN2BinWithPadding( &pECkey->pub_key->X, &deviceCert.eccPubKey[ 0 ], 30 ); BN2BinWithPadding( &pECkey->pub_key->Y, &deviceCert.eccPubKey[ 30 ], 30 ); #if 0 DEBUG_PRINT_ARRAY( "eccPubKey:", (const char *)deviceCert.eccPubKey, 60 ); DEBUG_PRINT_ARRAY( "eccPubKey.X:", (const char *)pECkey->pub_key->X.d, pECkey->pub_key->X.dmax * 4 ); DEBUG_PRINT_ARRAY( "eccPubKey.Y:", (const char *)pECkey->pub_key->Y.d, pECkey->pub_key->Y.dmax * 4 ); #endif // eccSignature #ifdef USE_HSM // TODO: HSM使用時の処理を実装 // ECDSA署名付加 u8 sha256Buf[ SHA256_DIGEST_LENGTH ]; // CR_DeviceCertのSHA256計算 SHA256( deviceCert.issuerName, (int)&deviceCert + sizeof(CR_DeviceCert) - (int)deviceCert.issuerName, sha256Buf ); DEBUG_PRINT_ARRAY( "sha256(HSM)", (const char *)sha256Buf, 32 ); //u8 sha1Buf[ 20 ]; //SHA1( deviceCert.issuerName, (int)&deviceCert + sizeof(CR_DeviceCert) - (int)deviceCert.issuerName, sha1Buf ); //DEBUG_PRINT_ARRAY( "sha1(HSM)", (const char *)sha1buf, 20 ); ret_code = hsm_ecdsa_sign( deviceCert.eccSignature, sha256Buf, bonding_option ); if ( ret_code != CR_GENID_SUCCESS ) { SetErrorInfo( __FUNCTION__, __LINE__ ); return ret_code; } #else // !USE_HSM // DERフォーマットのECC鍵を読み込み { // bonding_option によって、鍵を差し替え const unsigned char *der_priv = bonding_option ? cr_NCT2_priv_dev : cr_NCT2_priv_prod; int priv_len = der_priv[ 8 ] | der_priv[ 9 ] << 8; // KEY長を取り出し der_priv += 0x10; // ヘッダ部分を除外してKEY実体を指定 // ECCは、秘密鍵のみで公開鍵成分もセットされるようなので、公開鍵は読み込まない。 NCT2 = d2i_ECPrivateKey( NULL, &der_priv, priv_len ); if( NCT2 == NULL ) { ret_code = CR_GENID_ERROR_ECC_READ_PRIVATE_KEY; goto end; } #if 0 DEBUG_PRINT_ARRAY( "EC priv:", (const char *)NCT2->priv_key->d, NCT2->priv_key->dmax * 4); DEBUG_PRINT_ARRAY( "EC pub.X:", (const char *)NCT2->pub_key->X.d, NCT2->pub_key->X.dmax * 4 ); DEBUG_PRINT_ARRAY( "EC pub.Y:", (const char *)NCT2->pub_key->Y.d, NCT2->pub_key->Y.dmax * 4 ); #endif } // ECDSA署名付加 { u8 sha256buf[ SHA256_DIGEST_LENGTH ]; u8 ecdsasig[ 0x80 ]; const u8 *pECDSAsig = ecdsasig; ECDSA_SIG *sig = NULL; int signLen = 0; int test_ret = 0; // CR_DeviceCertのSHA256計算 SHA256( deviceCert.issuerName, (int)&deviceCert + sizeof(CR_DeviceCert) - (int)deviceCert.issuerName, sha256buf ); // 上位232bit分で署名 memset( ecdsasig, 0, sizeof(ecdsasig) ); test_ret = ECDSA_sign( 0, sha256buf, 233/8, ecdsasig, &signLen, NCT2 ); if (test_ret == 0) { ret_code = CR_GENID_ERROR_ECDSA_SIGN; SetErrorInfo( __FUNCTION__, __LINE__ ); goto end; } DEBUG_PRINT_ARRAY( "ECDSA:", (const char *)ecdsasig, signLen ); #if 0 // 署名ベリファイ ret_code = ECDSA_verify( 0, sha1buf, 20, tempSign, 66, NCT2 ); if( ret_code != 1) { ret_code = CR_GENID_ERROR_ECDSA_VERIFY; SetErrorInfo( __FUNCTION__, __LINE__ ); goto end; } #endif // DERデコードして、r と s を eccSignature にセット sig = d2i_ECDSA_SIG( NULL, &pECDSAsig, signLen ); if( sig == NULL ) { ret_code = CR_GENID_ERROR_ECDSA_DEC; SetErrorInfo( __FUNCTION__, __LINE__ ); goto end; } #if 0 DEBUG_PRINT_ARRAY( "ECDSA.r:", (const char *)sig->r->d, sig->r->dmax * 4); DEBUG_PRINT_ARRAY( "ECDSA.s:", (const char *)sig->s->d, sig->s->dmax * 4 ); #endif BN2BinWithPadding( sig->r, &deviceCert.eccSignature[ 0 ], 30 ); BN2BinWithPadding( sig->s, &deviceCert.eccSignature[ 30 ], 30 ); memcpy( pDevCertSign, &deviceCert.eccSignature, 60 ); if( sig ) ECDSA_SIG_free( sig ); if( NCT2 ) EC_KEY_free( NCT2 ); NCT2 = NULL; #ifdef DEBUG_DEVICE_CERT_OUTPUT_FILE DebugFileOutput( device_id, "dgst", sha256buf, 233/8 ); DebugFileOutput( device_id, "sign", ecdsasig, signLen ); #endif // DEBUG_DEVICE_CERT_OUTPUT_FILE } #endif // USE_HSM // ECDSA署名検証 { // bonding_option によって、鍵を差し替え const unsigned char *der_pub = bonding_option ? cr_NCT2_pub_dev : cr_NCT2_pub_prod; int pub_len = der_pub[ 8 ] | der_pub[ 9 ] << 8; // KEY長を取り出し der_pub += 0x10; // ヘッダ部分を除外してKEY実体を指定 // BIT STRING の実データ部分のみを指定するよう調整 pub_len = der_pub[0x15] - 1; der_pub += 0x17; // ECC公開鍵の読み込み NCT2 = EC_KEY_new_by_curve_name( NID_sect233r1 ); if( NCT2 == NULL ) { SetErrorInfo( __FUNCTION__, __LINE__ ); ret_code = CR_GENID_ERROR_ECC_KEY_NEW; goto end; } if( o2i_ECPublicKey( &NCT2, &der_pub, pub_len ) == NULL ) { SetErrorInfo( __FUNCTION__, __LINE__ ); ret_code = CR_GENID_ERROR_ECC_READ_PUBLIC_KEY; goto end; } #if 0 // TODO: ハッシュ処理 int i; u8 verifyHash[30]; memset( verifyHash, 0, sizeof( verifyHash ) ); verifyHash[0] = sha256Buf[0] >> 7; for ( i = 1; i < 30; i++ ) { verifyHash[i] = (sha256Buf[i-1] << 1) | (sha256Buf[i] >> 7); } DEBUG_PRINT_ARRAY( (char*)"verifyHash(HSM)", (const char *)verifyHash, 30 ); // TODO: ECDSA署名(DER)を再構築 u8 signBuf[70]; int signLen = 66; memset( signBuf, 0, sizeof( signBuf ) ); signBuf[0] = 0x30; signBuf[1] = 0x40; signBuf[2] = 0x02; signBuf[3] = 0x1E; memcpy( &signBuf[4], &deviceCert.eccSignature[0], 0x1E ); signBuf[0x22] = 0x02; signBuf[0x23] = 0x1E; memcpy( &signBuf[0x24], &deviceCert.eccSignature[30], 0x1E ); DEBUG_PRINT_ARRAY( (char*)"sign(HSM)", (const char *)signBuf, signLen ); // 署名ベリファイ ret_code = ECDSA_verify( 0, verifyHash, 30, signBuf, signLen, NCT2 ); if( ret_code != 1) { ret_code = CR_GENID_ERROR_ECDSA_VERIFY; SetErrorInfo( __FUNCTION__, __LINE__ ); goto end; } #endif } ret_code = CR_GENID_SUCCESS; #if 0 if ( cr_print_flag ) { int i; printf( "deviceCert:\n" ); printf( "sigType : 0x%08X\n", *(unsigned int*)deviceCert.sigType ); DEBUG_PRINT_ARRAY( "eccSignature:", (const char *)deviceCert.eccSignature, sizeof(deviceCert.eccSignature) ); DEBUG_PRINT_ARRAY( "padding0:", (const char *)deviceCert.padding0, sizeof(deviceCert.padding0) ); printf( "issuerName : " ); for ( i = 0; i < sizeof(deviceCert.issuerName); i++ ) printf( "%c", deviceCert.issuerName[i] ); printf( "\n" ); printf( "keyType : 0x%08X\n", *(unsigned int*)deviceCert.keyType ); printf( "subject : " ); for ( i = 0; i < sizeof(deviceCert.subject); i++ ) printf( "%c", deviceCert.subject[i] ); printf( "\n" ); printf( "expiryDate : 0x%08X\n", (unsigned int)deviceCert.expiryDate ); { struct tm *tmt; tmt = gmtime( &deviceCert.expiryDate ); printf( " GMT:%d-%02d-%02d %02d:%02d:%02d\n", tmt->tm_year+1900, tmt->tm_mon+1, tmt->tm_mday, tmt->tm_hour, tmt->tm_min, tmt->tm_sec ); } DEBUG_PRINT_ARRAY( "eccPubKey :", (const char *)deviceCert.eccPubKey, sizeof(deviceCert.eccPubKey) ); DEBUG_PRINT_ARRAY( "padding1:", (const char *)deviceCert.padding1, sizeof(deviceCert.padding1) ); #ifdef DEBUG_DEVICE_CERT_OUTPUT_FILE DebugFileOutput( device_id, "crt", (const u8 *)&deviceCert, sizeof(CR_DeviceCert) ); #endif // DEBUG_DEVICE_CERT_OUTPUT_FILE } #endif // dump deviceCert end: if( NCT2 ) EC_KEY_free( NCT2 ); return ret_code; } // generate_CTRCustom_deviceCert // 指定BIGNUMをバイナリ変換して指定バッファに右詰めでセット static void BN2BinWithPadding( BIGNUM *pBN, u8 *pDst, int dstLen ) { int i; int bnBitLen, bnByteLen; u8 buffer[ 32 ]; memset( buffer, 0, sizeof(buffer) ); bnBitLen = BN_num_bits( pBN ); bnByteLen = ( bnBitLen / 8 ) + ( ( bnBitLen % 8 ) ? 1 : 0 ); BN_bn2bin( pBN, (u8*)buffer ); for( i = 0; i < bnByteLen; i++ ) { pDst[ dstLen - 1 - i ] = buffer[ bnByteLen - 1 - i ]; } }