Index: cmd/certutil/certutil.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/cmd/certutil/certutil.c,v retrieving revision 1.97.2.7 diff -u -r1.97.2.7 certutil.c --- cmd/certutil/certutil.c 9 Jun 2006 18:10:02 -0000 1.97.2.7 +++ cmd/certutil/certutil.c 27 Dec 2006 23:56:19 -0000 @@ -1846,6 +1846,101 @@ return (rv); } + +static SECItem * +SignCertEx(CERTCertDBHandle *handle, CERTCertificate *cert, + PRBool selfsign, SECOidTag hashAlgTag, + SECKEYPrivateKey *privKey, + char *issuerNickName, void *pwarg, + SECItem* randParams) +{ + SECItem der; + SECItem *result = NULL; + SECKEYPrivateKey *caPrivateKey = NULL; + SECStatus rv; + PRArenaPool *arena; + SECOidTag algID; + void *dummy; + + if (!selfsign) { + CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg); + if( (CERTCertificate *)NULL == issuer ) { + SECU_PrintError(progName, "unable to find issuer with nickname %s", + issuerNickName); + return (SECItem *)NULL; + } + + privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg); + CERT_DestroyCertificate(issuer); + if (caPrivateKey == NULL) { + SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName); + return NULL; + } + } + arena = cert->arena; + + + /* only supports RSA MD5 and SHA1 rand*/ + if (privKey->keyType == rsaKey && hashAlgTag == SEC_OID_MD5) { + algID = SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION; + } else if (privKey->keyType == rsaKey && hashAlgTag == SEC_OID_SHA1) { + algID = SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION; + } else { + algID = SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION; + /* no supported */ + printf("NO SUPPORT for %d, changed to RAND_MD5_WITH_RSA\n", hashAlgTag); + } + + SECItem* p = (SECItem*) PORT_Alloc(sizeof(SECItem)); + p->type = siSaltValue; + p->data = (unsigned char*) PORT_Alloc(randParams->len + 2); + p->data[0] = 0x04; + p->data[1] = randParams->len; + p->len = randParams->len + 2; + memcpy(&p->data[2], randParams->data, randParams->len); + rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, p); + PORT_Free(p->data); PORT_Free(p); + + if (rv != SECSuccess) { + fprintf(stderr, "Could not set signature algorithm id."); + goto done; + } + + /* we only deal with cert v3 here */ + *(cert->version.data) = 2; + cert->version.len = 1; + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem (arena, &der, cert, + SEC_ASN1_GET(CERT_CertificateTemplate)); + if (!dummy) { + fprintf (stderr, "Could not encode certificate.\n"); + goto done; + } + + result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem)); + if (result == NULL) { + fprintf (stderr, "Could not allocate item for certificate data.\n"); + goto done; + } + rv = SEC_DerSignDataEx(arena, result, der.data, der.len, privKey, algID, + randParams); + + if (rv != SECSuccess) { + fprintf (stderr, "Could not sign encoded certificate data.\n"); + PORT_Free(result); + result = NULL; + goto done; + } + cert->derCert = *result; +done: + if (caPrivateKey) { + SECKEY_DestroyPrivateKey(caPrivateKey); + } + return result; +} + static SECItem * SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, SECOidTag hashAlgTag, @@ -2185,6 +2280,16 @@ return rv; } + + +/* Note, + * The correct way of doing this is to add additional command line options + * to enable the randomized hash. + * + * Here, we take the short cut. The changes here are: + * 1) for self signed certifiates, still use the old way of signing. + * 2) if not self-signed, this always use the new randomized hash. + */ static SECStatus CreateCert( CERTCertDBHandle *handle, @@ -2264,8 +2369,27 @@ CERT_FinishExtensions(extHandle); - certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag, - selfsignprivkey, issuerNickName,pwarg); + if (selfsign) { + /* Use the existing alg. non-randomized */ + certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag, + selfsignprivkey, issuerNickName,pwarg); + } else { + /* Change this to use randomized hash */ + SECItem* rand_params = (SECItem*) PORT_Alloc(sizeof (SECItem)); + rand_params->type = siSaltValue; + rand_params->data= (unsigned char*) malloc(16 * sizeof (unsigned char)); + + /* hard code the salt value for the prototype. This is for easier + * verification of output, etc. */ + /* TODO(wshao) Use PRNG for salt data */ + memcpy (rand_params->data, "Gce;lf04EqFgzBV-?@", 16); + rand_params->len = 16; + + certDER = SignCertEx(handle, subjectCert, selfsign, hashAlgTag, + selfsignprivkey, issuerNickName,pwarg, rand_params); + PORT_Free(rand_params->data); + PORT_Free(rand_params); + } if (certDER) { if (ascii) { Index: lib/cryptohi/cryptoht.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/cryptohi/cryptoht.h,v retrieving revision 1.3 diff -u -r1.3 cryptoht.h --- lib/cryptohi/cryptoht.h 27 Apr 2004 23:04:35 -0000 1.3 +++ lib/cryptohi/cryptoht.h 27 Dec 2006 23:56:20 -0000 @@ -44,5 +44,10 @@ typedef struct SGNContextStr SGNContext; typedef struct VFYContextStr VFYContext; +/* Put it here for demonstration purpose. + * The idea is that we will phase out SGNContext eventually. + * So replace it with the new structure without visible API changes. + */ +typedef struct SGNContextExStr SGNContextEx; #endif /* _CRYPTOHT_H_ */ Index: lib/cryptohi/hasht.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/cryptohi/hasht.h,v retrieving revision 1.7 diff -u -r1.7 hasht.h --- lib/cryptohi/hasht.h 7 Nov 2005 18:44:20 -0000 1.7 +++ lib/cryptohi/hasht.h 27 Dec 2006 23:56:20 -0000 @@ -41,6 +41,8 @@ /* Opaque objects */ typedef struct SECHashObjectStr SECHashObject; typedef struct HASHContextStr HASHContext; +/* parameters for randomized hash */ +typedef struct RANDHashParamsStr RANDHashParams; /* * The hash functions the security library supports @@ -81,11 +83,30 @@ void (*end)(void *, unsigned char *, unsigned int *, unsigned int); unsigned int blocklength; /* hash input block size (in bytes) */ HASH_HashType type; + /* size of length encoding in the last-block padding */ + unsigned int length_encoding_size; }; struct HASHContextStr { const struct SECHashObjectStr *hashobj; void *hash_context; + + /* Added for randomized hash */ + RANDHashParams *rand_params; + /*unsigned int message_length;*/ +}; + +/* We require that the salt len be at least 16 bytes in length. Padding will + * be added upto the block size of the hash function. If it is longer than + * the block size, it will be truncated. it is less than the block size. + */ +struct RANDHashParamsStr { + int salt_length; /* in bytes */ + unsigned char* salt; + + /* The following are for internal use */ + /* 2 byte is enough. so far, the max block length is 128 */ + unsigned short next_index_; }; /* This symbol is NOT exported from the NSS DLL. Code that needs a Index: lib/cryptohi/sechash.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/cryptohi/sechash.c,v retrieving revision 1.6 diff -u -r1.6 sechash.c --- lib/cryptohi/sechash.c 7 Nov 2005 18:44:20 -0000 1.6 +++ lib/cryptohi/sechash.c 27 Dec 2006 23:56:20 -0000 @@ -39,6 +39,13 @@ #include "blapi.h" #include "pk11func.h" /* for the PK11_ calls below. */ +#define MD2_LEN_ENCODING_SIZE 8 +#define MD5_LEN_ENCODING_SIZE 8 +#define SHA1_LEN_ENCODING_SIZE 8 +#define SHA256_LEN_ENCODING_SIZE 8 +#define SHA384_LEN_ENCODING_SIZE 8 +#define SHA512_LEN_ENCODING_SIZE 16 + static void * null_hash_new_context(void) { @@ -116,7 +123,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) null_hash_end, 0, - HASH_AlgNULL + HASH_AlgNULL, + 0 }, { MD2_LENGTH, (void * (*)(void)) md2_NewContext, @@ -127,7 +135,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) PK11_DigestFinal, MD2_BLOCK_LENGTH, - HASH_AlgMD2 + HASH_AlgMD2, + MD2_LEN_ENCODING_SIZE }, { MD5_LENGTH, (void * (*)(void)) md5_NewContext, @@ -138,7 +147,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) PK11_DigestFinal, MD5_BLOCK_LENGTH, - HASH_AlgMD5 + HASH_AlgMD5, + MD5_LEN_ENCODING_SIZE }, { SHA1_LENGTH, (void * (*)(void)) sha1_NewContext, @@ -149,7 +159,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) PK11_DigestFinal, SHA1_BLOCK_LENGTH, - HASH_AlgSHA1 + HASH_AlgSHA1, + SHA1_LEN_ENCODING_SIZE }, { SHA256_LENGTH, (void * (*)(void)) sha256_NewContext, @@ -160,7 +171,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) PK11_DigestFinal, SHA256_BLOCK_LENGTH, - HASH_AlgSHA256 + HASH_AlgSHA256, + SHA256_LEN_ENCODING_SIZE }, { SHA384_LENGTH, (void * (*)(void)) sha384_NewContext, @@ -171,7 +183,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) PK11_DigestFinal, SHA384_BLOCK_LENGTH, - HASH_AlgSHA384 + HASH_AlgSHA384, + SHA384_LEN_ENCODING_SIZE }, { SHA512_LENGTH, (void * (*)(void)) sha512_NewContext, @@ -182,7 +195,8 @@ (void (*)(void *, unsigned char *, unsigned int *, unsigned int)) PK11_DigestFinal, SHA512_BLOCK_LENGTH, - HASH_AlgSHA512 + HASH_AlgSHA512, + SHA512_LEN_ENCODING_SIZE }, }; @@ -298,7 +312,7 @@ ret->hash_context = hash_context; ret->hashobj = &SECHashObjects[type]; - + ret->rand_params = NULL; return(ret); loser: @@ -328,7 +342,22 @@ ret->hash_context = hash_context; ret->hashobj = context->hashobj; - + if (context->rand_params != NULL) { + RANDHashParams *params = + (RANDHashParams*)PORT_Alloc(sizeof(RANDHashParams)); + if (params == NULL) { + PORT_Free(ret); + goto loser; + } + memcpy(params, context->rand_params, sizeof(RANDHashParams)); + + /* wshao: this only makes a shadow copy of the salt value in + * randomized hash. TODO: redo salt copy + */ + ret->hash_context = hash_context; + ret->hashobj = context->hashobj; + ret->rand_params = params; + } return(ret); loser: @@ -344,6 +373,13 @@ HASH_Destroy(HASHContext *context) { (* context->hashobj->destroy)(context->hash_context, PR_TRUE); + if (context->rand_params != NULL) { + /* wshao: there may be a problem for cloned context. + * It was a shadow copy + */ + PORT_Free(context->rand_params->salt); + PORT_Free(context->rand_params); + } PORT_Free(context); return; } @@ -376,6 +412,163 @@ max_result_len); return; } +#define MIN_SALT_LENGTH 16 +/* Set randomized parameter for HASHContext. This must be called before + * HASH_Begin is called. + * If salt_len > block size, truncate it. + * If salt_len < 16. reject it. + * Please note that, the params will have data of the block length by + * repeating the input salt. + */ +PRBool +HASH_SetRandomize(HASHContext* context, + unsigned char* salt, + int salt_len) +{ + RANDHashParams *params; + int len; + int total_written; + int to_write; + if (salt_len < MIN_SALT_LENGTH) { + return PR_FALSE; + } + params = (RANDHashParams*)PORT_Alloc(sizeof(RANDHashParams)); + if (params == NULL) { + return PR_FALSE; + } + len = context->hashobj->blocklength; + if (salt_len > len) { + /* ignore the rest */ + salt_len = len; + } + params->salt_length = salt_len; + params->next_index_ = 0; + /* TODO: check null. */ + params->salt = (unsigned char*) PORT_Alloc(len); + total_written = 0; + to_write = len - total_written; + to_write = to_write > salt_len ? salt_len : to_write; + while (to_write > 0) { + memcpy(params->salt + total_written, salt, to_write); + total_written += to_write; + to_write = len - total_written; + to_write = to_write > salt_len ? salt_len : to_write; + } + + context->rand_params = params; + return PR_TRUE; +} + +HASHContext* HASH_CreateEx(HASH_HashType type, + SECItem* params) +{ + /* TODO: deprecate HASH_Create */ + HASHContext* ctx = HASH_Create(type); + if (ctx && params->type == siSaltValue) { + HASH_SetRandomize(ctx, params->data, params->len); + } + return ctx; +} + +void HASH_BeginEx(HASHContext *context) +{ + unsigned char r_0[HASH_BLOCK_LENGTH_MAX]; + int len; + HASH_Begin(context); /* TODO: deprecate HASH_Begin later */ + + if (context->rand_params) { + if (context->hashobj == NULL) { + /* something seriously wrong. e.g, incorrect call sequence */ + return; + } + len = (context->hashobj->blocklength); + /* get r_0 */ + + memset(r_0, 0, HASH_BLOCK_LENGTH_MAX); + memcpy(r_0, context->rand_params->salt, context->rand_params->salt_length); + (* context->hashobj->update)(context->hash_context, r_0, len); + } +} + +void HASH_UpdateEx(HASHContext *context, + const unsigned char *src, + unsigned int len) +{ + int i = 0; + if (context->rand_params) { + unsigned short next_index = context->rand_params->next_index_; + + unsigned char* new_src = (unsigned char*) PORT_Alloc(len); + + for (i=0; irand_params->salt[next_index++] ^ src[i]; + if (next_index == context->hashobj->blocklength) { + next_index = 0; + } + } + /*context->msg_len += len;*/ + context->rand_params->next_index_ = next_index; + (* context->hashobj->update)(context->hash_context, new_src, len); + PORT_Free(new_src); + } else { + (* context->hashobj->update)(context->hash_context, src, len); + } +} +void HASH_EndEx(HASHContext *context, + unsigned char *result, + unsigned int *result_len, + unsigned int max_result_len) +{ + /* TODO: figure out r_2 */ + unsigned int b = context->hashobj->blocklength; + unsigned int c = context->hashobj->length_encoding_size; + unsigned char* padding = NULL; + unsigned short next_index = context->rand_params->next_index_; + + unsigned short bit_length = next_index << 3; + int i; + PORT_Assert((b-c-3) > 0); + + if (context->rand_params != NULL) { + if (next_index <=(b-c-3) && next_index != 0) { + unsigned short length = b - c - 1 - next_index; + padding = (unsigned char*)PORT_Alloc(length); + memset(padding, 0, length); + memcpy(padding + (length-sizeof(unsigned short)), &bit_length, + sizeof(unsigned short)); + + for (i=0; irand_params->salt[next_index++] ^ padding[i]; + } + (*context->hashobj->update)(context->hash_context, padding, b-c-next_index); + PORT_Free(padding); + } else { + /* TODO: need to use htons */ + if (next_index != 0) { + padding = (unsigned char*)PORT_Alloc(b-next_index); + memset(padding, 0, b-next_index); + for (i=0; irand_params->salt[next_index + i] ^ padding[i]; + } + (*context->hashobj->update)(context->hash_context, padding, b-next_index); + PORT_Free(padding); + } + padding = (unsigned char*)PORT_Alloc(b-c-1); + memset(padding, 0, b-c-1); + memcpy(padding + (b-c-1-sizeof(unsigned short)),&bit_length, + sizeof(unsigned short)); + + for (i=0; irand_params->salt[i]; + } + (*context->hashobj->update)(context->hash_context, padding, b-c-1); + PORT_Free(padding); + } + } + (* context->hashobj->end)(context->hash_context, result, result_len, + max_result_len); +} Index: lib/cryptohi/sechash.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/cryptohi/sechash.h,v retrieving revision 1.5 diff -u -r1.5 sechash.h --- lib/cryptohi/sechash.h 27 Apr 2004 23:04:35 -0000 1.5 +++ lib/cryptohi/sechash.h 27 Dec 2006 23:56:20 -0000 @@ -81,6 +81,29 @@ extern HASH_HashType HASH_GetHashTypeByOidTag(SECOidTag hashOid); +/* The following functions are added for randomized hash. + * Ideally, the changes should be made to the original HASH_ functions + * instead of in newly added functions. But we choose to add new functions + * in order to minimize changes to the existing code. + */ +extern HASHContext* HASH_CreateEx(HASH_HashType type, + SECItem* params); + +extern void HASH_BeginEx(HASHContext *context); + +extern void HASH_UpdateEx(HASHContext *context, + const unsigned char *src, + unsigned int len); + +extern void HASH_EndEx(HASHContext *context, + unsigned char *result, + unsigned int *result_len, + unsigned int max_result_len); + +extern PRBool HASH_SetRandomize(HASHContext* context, + unsigned char* salt, + int salt_len); + SEC_END_PROTOS #endif /* _HASH_H_ */ Index: lib/cryptohi/secsign.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/cryptohi/secsign.c,v retrieving revision 1.14.2.3 diff -u -r1.14.2.3 secsign.c --- lib/cryptohi/secsign.c 28 Apr 2006 03:35:29 -0000 1.14.2.3 +++ lib/cryptohi/secsign.c 27 Dec 2006 23:56:20 -0000 @@ -55,6 +55,18 @@ void *hashcx; const SECHashObject *hashobj; SECKEYPrivateKey *key; + /* wshao: Add for randomized hash */ + RANDHashParams *rand_params; +}; + +/* SGNContext with Randomized hash support. + * This new structure uses the HASH_ APIs instead of the low level hash objects. + */ +struct SGNContextExStr { + SECOidTag signalg; + + HASHContext* hash_ctx_; + SECKEYPrivateKey *key; }; SGNContext * @@ -173,6 +185,138 @@ return cx; } +/* + * For new structure. Copy&paste the above method with minor modifications. + * Use HASHContext instead of direct use of low-level hash objects. + * TODO: need to add support for algs other than RAND_MD5 and RAND_SHA1 + */ +SGNContextEx* +SGN_NewContextEx(SECOidTag alg, SECKEYPrivateKey *key, + SECItem *params) +{ + SGNContextEx *cx; + SECOidTag signalg; + KeyType keyType; + + HASHContext* hash_ctx; + HASH_HashType hash_type = HASH_AlgNULL; + + /* OK, map a PKCS #7 hash and encrypt algorithm into + * a standard hashing algorithm. Why did we pass in the whole + * PKCS #7 algTag if we were just going to change here you might + * ask. Well the answer is for some cards we may have to do the + * hashing on card. It may not support CKM_RSA_PKCS sign algorithm, + * it may just support CKM_RSA_PKCS_WITH_SHA1 and/or CKM_RSA_PKCS_WITH_MD5. + */ + switch (alg) { + /* We probably shouldn't be generating MD2 signatures either */ + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + hash_type = HASH_AlgMD2; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION: + hash_type = HASH_AlgMD5; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: + hash_type = HASH_AlgSHA1; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + hash_type = HASH_AlgSHA256; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + hash_type = HASH_AlgSHA384; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + hash_type = HASH_AlgSHA512; + signalg = SEC_OID_PKCS1_RSA_ENCRYPTION; + keyType = rsaKey; + break; + + /* what about normal DSA? */ + case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: + case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: + hash_type = HASH_AlgSHA1; + signalg = SEC_OID_ANSIX9_DSA_SIGNATURE; + keyType = dsaKey; + break; + case SEC_OID_MISSI_DSS: + case SEC_OID_MISSI_KEA_DSS: + case SEC_OID_MISSI_KEA_DSS_OLD: + case SEC_OID_MISSI_DSS_OLD: + hash_type = HASH_AlgSHA1; + signalg = SEC_OID_MISSI_DSS; /* XXX Is there a better algid? */ + keyType = fortezzaKey; + break; + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: + hash_type = HASH_AlgSHA1; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: + hash_type = HASH_AlgSHA256; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: + hash_type = HASH_AlgSHA384; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: + hash_type = HASH_AlgSHA512; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; + /* we don't implement MD4 hashes. + * we *CERTAINLY* don't want to sign one! */ + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: + default: + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return 0; + } + + /* verify our key type */ + if (key->keyType != keyType && + !((key->keyType == dsaKey) && (keyType == fortezzaKey)) && + !((key->keyType == fortezzaKey) && (keyType == dsaKey)) ) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return 0; + } + +#ifndef NSS_ECC_MORE_THAN_SUITE_B + if (key->keyType == ecKey) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return 0; + } +#endif + + hash_ctx = HASH_CreateEx(hash_type, params); + if (hash_ctx == NULL) { + return NULL; + } + cx = (SGNContextEx*) PORT_ZAlloc(sizeof(SGNContextEx)); + if (cx) { + cx->signalg = signalg; + cx->hash_ctx_ = hash_ctx; + cx->key = key; + } else { + HASH_Destroy(hash_ctx); + } + return cx; +} + void SGN_DestroyContext(SGNContext *cx, PRBool freeit) { @@ -311,6 +455,144 @@ return rv; } +SECStatus +SGN_BeginEx(SGNContextEx *cx) { + HASH_BeginEx(cx->hash_ctx_); + return SECSuccess; +} + +SECStatus +SGN_UpdateEx(SGNContextEx *cx, unsigned char *input, unsigned inputLen) +{ + if (cx->hash_ctx_ == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + HASH_UpdateEx(cx->hash_ctx_, input, inputLen); + return SECSuccess; +} + +SECStatus +SGN_EndEx(SGNContextEx *cx, SECItem *result) +{ + unsigned char digest[HASH_LENGTH_MAX]; + unsigned part1; + int signatureLen; + SECStatus rv; + SECOidTag hashalg; + SECItem digder, sigitem; + PRArenaPool *arena = 0; + SECKEYPrivateKey *privKey = cx->key; + SGNDigestInfo *di = 0; + + result->data = 0; + digder.data = 0; + + /* Finish up digest function */ + if (cx->hash_ctx_ == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + HASH_EndEx(cx->hash_ctx_, digest, &part1, sizeof(digest)); + + if (privKey->keyType == rsaKey) { + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + rv = SECFailure; + goto loser; + } + + switch (cx->hash_ctx_->hashobj->type) { + case HASH_AlgMD2: + hashalg = SEC_OID_MD2; + break; + case HASH_AlgMD5: + hashalg = SEC_OID_MD5; + break; + case HASH_AlgSHA1: + hashalg = SEC_OID_SHA1; + break; + case HASH_AlgSHA256: + hashalg = SEC_OID_SHA256; + break; + case HASH_AlgSHA384: + hashalg = SEC_OID_SHA384; + break; + case HASH_AlgSHA512: + hashalg = SEC_OID_SHA512; + break; + default: + hashalg = SEC_OID_UNKNOWN; + } + + /* Construct digest info */ + di = SGN_CreateDigestInfo(hashalg, digest, part1); + if (!di) { + rv = SECFailure; + goto loser; + } + + /* Der encode the digest as a DigestInfo */ + rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, di); + if (rv != SECSuccess) { + goto loser; + } + } else { + digder.data = digest; + digder.len = part1; + } + + /* + ** Encrypt signature after constructing appropriate PKCS#1 signature + ** block + */ + signatureLen = PK11_SignatureLen(privKey); + if (signatureLen <= 0) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + rv = SECFailure; + goto loser; + } + sigitem.len = signatureLen; + sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); + + if (sigitem.data == NULL) { + rv = SECFailure; + goto loser; + } + + rv = PK11_Sign(privKey, &sigitem, &digder); + if (rv != SECSuccess) { + PORT_Free(sigitem.data); + sigitem.data = NULL; + goto loser; + } + + if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || + (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { + /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ + rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); + PORT_Free(sigitem.data); + if (rv != SECSuccess) + goto loser; + } else { + result->len = sigitem.len; + result->data = sigitem.data; + } + + loser: + SGN_DestroyDigestInfo(di); + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + return rv; +} + + + + + + /************************************************************************/ /* @@ -345,6 +627,45 @@ return rv; } + +/* + * This only supports randomized PKCS#1 MD5 and SHA1 with RSA + * Encryption + */ +SECStatus +SEC_SignDataEx(SECItem *res, unsigned char *buf, int len, + SECKEYPrivateKey *pk, SECOidTag algid, + SECItem *randParams) +{ + if (randParams != NULL && randParams->type == siSaltValue && + (algid == SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION || + algid == SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION)) { + + SECStatus rv; + SGNContextEx *sgn; + sgn = SGN_NewContextEx(algid, pk, randParams); + + if (sgn == NULL) + return SECFailure; + + rv = SGN_BeginEx(sgn); + if (rv != SECSuccess) + goto loser; + + rv = SGN_UpdateEx(sgn, buf, len); + if (rv != SECSuccess) + goto loser; + + rv = SGN_EndEx(sgn, res); + + loser: + return rv; + + } else { + return SEC_SignData(res, buf, len, pk, algid); + } +} + /************************************************************************/ DERTemplate CERTSignedDataTemplate[] = @@ -432,6 +753,83 @@ } SECStatus +SEC_DerSignDataEx(PRArenaPool *arena, SECItem *result, + unsigned char *buf, int len, SECKEYPrivateKey *pk, + SECOidTag algID, SECItem *randParams) +{ + SECItem it, *params; + CERTSignedData sd; + SECStatus rv; + + it.data = 0; + + /* XXX We should probably have some asserts here to make sure the key type + * and algID match + */ + + if (algID == SEC_OID_UNKNOWN) { + switch(pk->keyType) { + case rsaKey: + algID = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + break; + case dsaKey: + algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + break; + case ecKey: + algID = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; + break; + default: + PORT_SetError(SEC_ERROR_INVALID_KEY); + return SECFailure; + } + /* In this case, we ignore randParams */ + /* Sign input buffer */ + randParams = NULL; + rv = SEC_SignData(&it, buf, len, pk, algID); + } else { + rv = SEC_SignDataEx(&it, buf, len, pk, algID, randParams); + } + + if (rv) goto loser; + + /* Fill out SignedData object */ + PORT_Memset(&sd, 0, sizeof(sd)); + sd.data.data = buf; + sd.data.len = len; + sd.signature.data = it.data; + sd.signature.len = it.len << 3; /* convert to bit string */ + + /* randParams should only be passed when algID is a randomized algorithm */ + if (randParams != NULL && randParams->type == siSaltValue) { + /* Need to rewrite params */ + printf("OKAY ==== set alg params \n"); + params = (SECItem*) PORT_Alloc(sizeof(SECItem)); + params->type = siSaltValue; + params->data = (unsigned char*) PORT_Alloc(randParams->len + 2); + params->data[0] = 0x04; + params->data[1] = randParams->len; + params->len = randParams->len + 2; + memcpy(¶ms->data[2], randParams->data, randParams->len); + rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, params); + PORT_Free(params->data); + PORT_Free(params); + } else { + rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, 0); + printf("Oh well, we are not setting alg params \n"); + } + + if (rv) goto loser; + + /* DER encode the signed data object */ + rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); + /* FALL THROUGH */ + + loser: + PORT_Free(it.data); + return rv; +} + +SECStatus SGN_Digest(SECKEYPrivateKey *privKey, SECOidTag algtag, SECItem *result, SECItem *digest) { Index: lib/cryptohi/secvfy.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/cryptohi/secvfy.c,v retrieving revision 1.16.2.5 diff -u -r1.16.2.5 secvfy.c --- lib/cryptohi/secvfy.c 9 Sep 2006 22:14:56 -0000 1.16.2.5 +++ lib/cryptohi/secvfy.c 27 Dec 2006 23:56:20 -0000 @@ -92,7 +92,8 @@ goto sigloser; } /* make sure the "parameters" are not too bogus. */ - if (di->digestAlgorithm.parameters.len > 2) { + if (di->digestAlgorithm.parameters.len > 2 && + di->digestAlgorithm.parameters.type != siSaltValue) { goto sigloser; } if (di->digest.len > maxdigestlen) { @@ -151,6 +152,8 @@ * VFY_CreateContext call. If false, the * signature must be provided with a * VFY_EndWithSignature call. */ + /* TODO(wshao): may phase out hashobj above */ + HASHContext* hash_ctx_; }; /* @@ -235,9 +238,11 @@ *hashalg = SEC_OID_MD2; break; case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION: *hashalg = SEC_OID_MD5; break; case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION: case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: *hashalg = SEC_OID_SHA1; break; @@ -326,7 +331,9 @@ VFYContext *cx; SECStatus rv; unsigned int sigLen; - + HASH_HashType type; + SECItem *p; + size_t rand_length; cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); if (cx) { cx->wincx = wincx; @@ -392,6 +399,32 @@ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); goto loser; } + + /*TODO(wshao): set ctx for all other hash type */ + cx->hash_ctx_ = NULL; + if (algid == SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION || + algid == SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION) { + + type = HASH_AlgMD5; + if (algid == SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION) { + type = HASH_AlgSHA1; + } + printf("RAND MD5/SHA1 create context rand_data length %d\n", params->len); + printf("RAND MD5/SHA1 %x %x %x %x\n", params->data[0], params->data[1], + params->data[2], params->data[3]); + + /* need to ignore the first 2 bytes. */ + PORT_Assert(params->data[0] == 0x04); + p = (SECItem*) PORT_Alloc(sizeof(SECItem)); + p->type = siSaltValue; + rand_length = (size_t) params->data[1]; + p->data = (unsigned char*) PORT_Alloc(rand_length); + memcpy(p->data, ¶ms->data[2], rand_length); + p->len = rand_length; + cx->hash_ctx_ = HASH_CreateEx(type, p); + PORT_Free(p->data); + PORT_Free(p); + } } return cx; @@ -427,6 +460,14 @@ SECStatus VFY_Begin(VFYContext *cx) { + if (cx->hash_ctx_ != NULL) { + /* TODO(wshao): the problem is that HASH_Begin returns void. + * consider changing API later. + */ + HASH_BeginEx(cx->hash_ctx_); + return SECSuccess; + } + if (cx->hashcx != NULL) { (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); cx->hashcx = NULL; @@ -447,6 +488,14 @@ SECStatus VFY_Update(VFYContext *cx, unsigned char *input, unsigned inputLen) { + /* TODO(wshao): return type of HASH_UpdateEx. + * TODO(wshao): check/test for all other alg types + */ + if (cx->hash_ctx_ != NULL) { + HASH_UpdateEx(cx->hash_ctx_, input, inputLen); + return SECSuccess; + } + if (cx->hashcx == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -468,11 +517,15 @@ return SECFailure; } - if (cx->hashcx == NULL) { + if (cx->hash_ctx_ != NULL) { + HASH_EndEx(cx->hash_ctx_, final, &part, sizeof(final)); + } else { + if (cx->hashcx == NULL) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; + } + (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); } - (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); switch (cx->type) { case VFY_DSA: case VFY_ECDSA: @@ -633,8 +686,9 @@ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - return vfy_VerifyDataPrivate(buf, len, key, sig, + + /* TODO(wshao): preprocessing of data here */ + return vfy_VerifyDataPrivate(buf, len, key, sig, SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), &sigAlgorithm->parameters, wincx); } - Index: lib/nss/nss.def =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/nss/nss.def,v retrieving revision 1.158.2.5 diff -u -r1.158.2.5 nss.def --- lib/nss/nss.def 8 Jun 2006 05:42:36 -0000 1.158.2.5 +++ lib/nss/nss.def 27 Dec 2006 23:56:20 -0000 @@ -173,6 +173,7 @@ SEC_DeletePermCertificate; SEC_DeletePermCRL; SEC_DerSignData; +SEC_DerSignDataEx; SEC_DestroyCrl; SEC_FindCrlByDERCert; SEC_FindCrlByName; @@ -265,6 +266,10 @@ SGN_End; SGN_NewContext; SGN_Update; +SGN_BeginEx; +SGN_EndEx; +SGN_NewContextEx; +SGN_UpdateEx; VFY_Begin; VFY_CreateContext; VFY_DestroyContext; @@ -605,6 +610,10 @@ HASH_End; HASH_ResultLen; HASH_Update; +HASH_BeginEx; +HASH_CreateEx; +HASH_EndEx; +HASH_UpdateEx; NSSBase64_DecodeBuffer; # from Stan NSSBase64_EncodeItem; # from Stan PK11_GetKeyGen; Index: lib/ssl/ssl3ecc.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/ssl/ssl3ecc.c,v retrieving revision 1.3.2.9 diff -u -r1.3.2.9 ssl3ecc.c --- lib/ssl/ssl3ecc.c 5 Aug 2006 01:54:03 -0000 1.3.2.9 +++ lib/ssl/ssl3ecc.c 27 Dec 2006 23:56:20 -0000 @@ -1254,6 +1254,31 @@ return SECSuccess; } +PRInt32 +ssl3_SendCertificateTypeIndicationExtension( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + PRUint32 len, span; + + if (!ss) + return 0; + if (append && maxBytes >= 6) { + SECStatus rv; + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, 18, 2); + if (rv != SECSuccess) return 0; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, 2, 2); + if (rv != SECSuccess) return 0; + /* value */ + rv = ssl3_AppendHandshakeNumber(ss, 0xFF, 2); + if (rv != SECSuccess) return 0; + } + return 6; +} + /* Table of handlers for received TLS hello extensions, one per extension. * In the second generation, this table will be dynamic, and functions * will be registered here. @@ -1275,6 +1300,7 @@ static const ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSION_SENDERS] = { { 0, &ssl3_SendServerNameIndicationExtension }, + { 18, &ssl3_SendCertificateTypeIndicationExtension }, #ifdef NSS_ENABLE_ECC { 10, &ssl3_SendSupportedEllipticCurvesExtension }, { 11, &ssl3_SendSupportedPointFormatsExtension }, @@ -1375,4 +1401,3 @@ } return total_exten_len; } - Index: lib/ssl/sslimpl.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/ssl/sslimpl.h,v retrieving revision 1.42.2.8 diff -u -r1.42.2.8 sslimpl.h --- lib/ssl/sslimpl.h 19 Jul 2006 01:42:58 -0000 1.42.2.8 +++ lib/ssl/sslimpl.h 27 Dec 2006 23:56:20 -0000 @@ -175,7 +175,7 @@ /* This makes the cert cache entry exactly 4k. */ #define SSL_MAX_CACHED_CERT_LEN 4060 -#define MAX_EXTENSION_SENDERS 3 +#define MAX_EXTENSION_SENDERS 4 #define NUM_MIXERS 9 Index: lib/util/secalgid.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/util/secalgid.c,v retrieving revision 1.4 diff -u -r1.4 secalgid.c --- lib/util/secalgid.c 25 Apr 2004 15:03:18 -0000 1.4 +++ lib/util/secalgid.c 27 Dec 2006 23:56:20 -0000 @@ -110,6 +110,23 @@ } if (params) { + if (which == SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION || + which == SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION) { + if (SECITEM_CopyItem(arena, &id->parameters, params)) { + return SECFailure; + } + } else if (params->len >= 16 && + (which == SEC_OID_SHA1 || + which == SEC_OID_MD5)) { + /* sorry, break the logic on add_null_params above. + * TODO(wshao): revisit this + */ + if (SECITEM_CopyItem(arena, &id->parameters, params)) { + return SECFailure; + } + + } else { + /* * I am specifically *not* enforcing the following assertion * (by following it up with an error and a return of failure) @@ -124,6 +141,7 @@ if (SECITEM_CopyItem(arena, &id->parameters, params)) { return SECFailure; } + } } else { /* * Again, this is not considered an error. But if we assume @@ -179,4 +197,3 @@ /* This functions simply returns the address of the above-declared template. */ SEC_ASN1_CHOOSER_IMPLEMENT(SECOID_AlgorithmIDTemplate) - Index: lib/util/seccomon.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/util/seccomon.h,v retrieving revision 1.5 diff -u -r1.5 seccomon.h --- lib/util/seccomon.h 25 Apr 2004 15:03:18 -0000 1.5 +++ lib/util/seccomon.h 27 Dec 2006 23:56:20 -0000 @@ -73,7 +73,8 @@ siDEROID = 9, siUnsignedInteger = 10, siUTCTime = 11, - siGeneralizedTime = 12 + siGeneralizedTime = 12, + siSaltValue = 13 /* for randomized hash and potential use in PSS */ } SECItemType; typedef struct SECItemStr SECItem; Index: lib/util/secoid.c =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/util/secoid.c,v retrieving revision 1.31.28.1 diff -u -r1.31.28.1 secoid.c --- lib/util/secoid.c 21 Jan 2006 19:01:35 -0000 1.31.28.1 +++ lib/util/secoid.c 27 Dec 2006 23:56:20 -0000 @@ -200,6 +200,13 @@ CONST_OID pkcs1SHA384WithRSAEncryption[] = { PKCS1, 12 }; CONST_OID pkcs1SHA512WithRSAEncryption[] = { PKCS1, 13 }; +/* Add for randomized hash in signature. 99 and 100 are arbitrary. + * Should consider a proposal for stanardard number for the randomized + * version of algorithms. + */ +CONST_OID pkcs1RandMD5WithRSAEncryption[] = { PKCS1, 99 }; +CONST_OID pkcs1RandSHA1WithRSAEncryption[] = { PKCS1, 100 }; + CONST_OID pkcs5PbeWithMD2AndDEScbc[] = { PKCS5, 0x01 }; CONST_OID pkcs5PbeWithMD5AndDEScbc[] = { PKCS5, 0x03 }; CONST_OID pkcs5PbeWithSha1AndDEScbc[] = { PKCS5, 0x0a }; @@ -1469,6 +1476,14 @@ SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE, "X9.62 ECDSA signature with SHA512", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), + + OD( pkcs1RandMD5WithRSAEncryption, SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION, + "PKCS #1 Randomized MD5 With RSA Encryption", CKM_MD5_RSA_PKCS, + INVALID_CERT_EXTENSION ), + OD( pkcs1RandSHA1WithRSAEncryption, SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION, + "PKCS #1 Randomized SHA-1 With RSA Encryption", CKM_SHA1_RSA_PKCS, + INVALID_CERT_EXTENSION ), + }; /* Index: lib/util/secoidt.h =================================================================== RCS file: /cvsroot/mozilla/security/nss/lib/util/secoidt.h,v retrieving revision 1.19.28.1 diff -u -r1.19.28.1 secoidt.h --- lib/util/secoidt.h 21 Jan 2006 19:01:35 -0000 1.19.28.1 +++ lib/util/secoidt.h 27 Dec 2006 23:56:21 -0000 @@ -413,6 +413,11 @@ SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE = 278, SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE = 279, SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE = 280, + + /* RANDOMIZED HASH in PKCS#1 MD5/SHA1 */ + SEC_OID_PKCS1_RAND_MD5_WITH_RSA_ENCRYPTION = 281, + SEC_OID_PKCS1_RAND_SHA1_WITH_RSA_ENCRYPTION = 282, + SEC_OID_TOTAL } SECOidTag;