mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-14 03:30:17 +01:00
cherry-picked mozilla NSS upstream changes (to rev 46bd290c):
bug1061701, bug1210361, bug1210364, bug1210380, bug1210389, bug1009429, bug1211444, bug1180096, bug1210484, bug1211915, bug1211725, bug1213931, bug1214806, bug1214762, bug1214777, bug1214841, bug1214834, bug1213948, bug1213980, bug1192028, bug1202868, bug1214829, bug1026688, bug1214825, bug1216318
This commit is contained in:
parent
5c0160b5fb
commit
0310c45fa3
@ -26,7 +26,9 @@ include $(CORE_DEPTH)/coreconf/config.mk
|
||||
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
|
||||
#######################################################################
|
||||
|
||||
|
||||
ifdef NSS_DISABLE_GTESTS
|
||||
DIRS := $(filter-out external_tests,$(DIRS))
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
# (5) Execute "global" rules. (OPTIONAL) #
|
||||
@ -56,7 +58,11 @@ NSPR_CONFIGURE = $(CORE_DEPTH)/../nspr/configure
|
||||
#
|
||||
|
||||
ifeq ($(OS_TARGET),Android)
|
||||
NSPR_CONFIGURE_OPTS += --with-android-ndk=$(ANDROID_NDK) --target=arm-linux-androideabi --with-android-version=$(OS_TARGET_RELEASE)
|
||||
NSPR_CONFIGURE_OPTS += --with-android-ndk=$(ANDROID_NDK) \
|
||||
--target=$(ANDROID_PREFIX) \
|
||||
--with-android-version=$(OS_TARGET_RELEASE) \
|
||||
--with-android-toolchain=$(ANDROID_TOOLCHAIN) \
|
||||
--with-android-platform=$(ANDROID_SYSROOT)
|
||||
endif
|
||||
ifdef BUILD_OPT
|
||||
NSPR_CONFIGURE_OPTS += --disable-debug --enable-optimize
|
||||
|
@ -970,6 +970,7 @@ AddNameConstraints(void *extHandle)
|
||||
|
||||
if (!arena || ! constraints) {
|
||||
SECU_PrintError(progName, "out of memory");
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
|
@ -471,6 +471,9 @@ loser:
|
||||
PR_Free(_this->arch);
|
||||
_this->arch = NULL;
|
||||
}
|
||||
if(copy) {
|
||||
PR_Free(copy);
|
||||
}
|
||||
|
||||
return errStr;
|
||||
}
|
||||
|
@ -833,7 +833,10 @@ rm_dash_r (char *path)
|
||||
/* Recursively delete all entries in the directory */
|
||||
while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
|
||||
sprintf(filename, "%s/%s", path, entry->name);
|
||||
if(rm_dash_r(filename)) return -1;
|
||||
if(rm_dash_r(filename)) {
|
||||
PR_CloseDir(dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(PR_CloseDir(dir) != PR_SUCCESS) {
|
||||
|
@ -522,7 +522,7 @@ CK_RVtoStr(CK_RV errNum) {
|
||||
|
||||
/* Do binary search of table. */
|
||||
while (low + 1 < high) {
|
||||
i = (low + high) / 2;
|
||||
i = low + (high - low) / 2;
|
||||
num = errStrings[i].errNum;
|
||||
if (errNum == num)
|
||||
return errStrings[i].errString;
|
||||
|
@ -25,9 +25,12 @@ DEFAULT_COMPILER = gcc
|
||||
ifeq ($(OS_TARGET),Android)
|
||||
ifndef ANDROID_NDK
|
||||
$(error Must set ANDROID_NDK to the path to the android NDK first)
|
||||
endif
|
||||
ifndef ANDROID_TOOLCHAIN_VERSION
|
||||
$(error Must set ANDROID_TOOLCHAIN_VERSION to the requested version number)
|
||||
endif
|
||||
ANDROID_PREFIX=$(OS_TEST)-linux-androideabi
|
||||
ANDROID_TARGET=$(ANDROID_PREFIX)-4.4.3
|
||||
ANDROID_TARGET=$(ANDROID_PREFIX)-$(ANDROID_TOOLCHAIN_VERSION)
|
||||
# should autodetect which linux we are on, currently android only
|
||||
# supports linux-x86 prebuilts
|
||||
ANDROID_TOOLCHAIN=$(ANDROID_NDK)/toolchains/$(ANDROID_TARGET)/prebuilt/linux-x86
|
||||
|
@ -197,7 +197,8 @@ ifneq ($(_MSC_VER),$(_MSC_VER_6))
|
||||
# Disable C4267: conversion from 'size_t' to 'type', possible loss of data
|
||||
# Disable C4244: conversion from 'type1' to 'type2', possible loss of data
|
||||
# Disable C4018: 'expression' : signed/unsigned mismatch
|
||||
OS_CFLAGS += -w44267 -w44244 -w44018
|
||||
# Disable C4312: 'type cast': conversion from 'type1' to 'type2' of greater size
|
||||
OS_CFLAGS += -w44267 -w44244 -w44018 -w44312
|
||||
ifeq ($(_MSC_VER_GE_12),1)
|
||||
OS_CFLAGS += -FS
|
||||
endif
|
||||
|
@ -280,7 +280,12 @@ endif
|
||||
# IMPL_STRATEGY may be defined too.
|
||||
#
|
||||
|
||||
ifdef CROSS_COMPILE
|
||||
OBJDIR_NAME = $(OS_TARGET)$(OS_RELEASE)$(CPU_TAG)$(LIBC_TAG)$(IMPL_STRATEGY)$(OBJDIR_TAG).OBJ
|
||||
else
|
||||
OBJDIR_NAME = $(OS_TARGET)$(OS_RELEASE)$(CPU_TAG)$(COMPILER_TAG)$(LIBC_TAG)$(IMPL_STRATEGY)$(OBJDIR_TAG).OBJ
|
||||
endif
|
||||
|
||||
|
||||
ifeq (,$(filter-out WIN%,$(OS_TARGET)))
|
||||
ifndef BUILD_OPT
|
||||
@ -289,7 +294,11 @@ ifndef BUILD_OPT
|
||||
# (RTL) in the debug build
|
||||
#
|
||||
ifdef USE_DEBUG_RTL
|
||||
ifdef CROSS_COMPILE
|
||||
OBJDIR_NAME = $(OS_TARGET)$(OS_RELEASE)$(CPU_TAG)$(IMPL_STRATEGY)$(OBJDIR_TAG).OBJD
|
||||
else
|
||||
OBJDIR_NAME = $(OS_TARGET)$(OS_RELEASE)$(CPU_TAG)$(COMPILER_TAG)$(IMPL_STRATEGY)$(OBJDIR_TAG).OBJD
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -350,7 +350,7 @@ define2(char *name, char *val, struct inclist *file)
|
||||
/* Fast inline binary search */
|
||||
register char *s1;
|
||||
register char *s2;
|
||||
register int middle = (first + last) / 2;
|
||||
register int middle = first + (last - first) / 2;
|
||||
|
||||
/* Fast inline strchr() */
|
||||
s1 = name;
|
||||
@ -436,7 +436,7 @@ slookup(char *symbol, struct inclist *file)
|
||||
/* Fast inline binary search */
|
||||
register char *s1;
|
||||
register char *s2;
|
||||
register int middle = (first + last) / 2;
|
||||
register int middle = first + (last - first) / 2;
|
||||
|
||||
/* Fast inline strchr() */
|
||||
s1 = symbol;
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "secport.h"
|
||||
#include "seccomon.h"
|
||||
#include "secoid.h"
|
||||
#include "sslerr.h"
|
||||
#include "genname.h"
|
||||
#include "keyhi.h"
|
||||
#include "cert.h"
|
||||
@ -23,6 +22,7 @@
|
||||
#include "pkim.h"
|
||||
#include "pki3hack.h"
|
||||
#include "base.h"
|
||||
#include "keyhi.h"
|
||||
|
||||
/*
|
||||
* Check the validity times of a certificate
|
||||
@ -34,6 +34,94 @@ CERT_CertTimesValid(CERTCertificate *c)
|
||||
return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
|
||||
}
|
||||
|
||||
SECStatus checkKeyParams(const SECAlgorithmID *sigAlgorithm, const SECKEYPublicKey *key)
|
||||
{
|
||||
SECStatus rv;
|
||||
SECOidTag sigAlg;
|
||||
SECOidTag curve;
|
||||
PRUint32 policyFlags = 0;
|
||||
PRInt32 minLen, len;
|
||||
|
||||
sigAlg = SECOID_GetAlgorithmTag(sigAlgorithm);
|
||||
|
||||
switch(sigAlg) {
|
||||
case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
|
||||
case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
|
||||
case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
|
||||
case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
|
||||
case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
|
||||
if (key->keyType != ecKey) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
curve = SECKEY_GetECCOid(&key->u.ec.DEREncodedParams);
|
||||
if (curve != 0) {
|
||||
if (NSS_GetAlgorithmPolicy(curve, &policyFlags) == SECFailure ||
|
||||
!(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
|
||||
PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
return SECFailure;
|
||||
} else {
|
||||
return SECSuccess;
|
||||
}
|
||||
} else {
|
||||
PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
return SECFailure;
|
||||
}
|
||||
return SECSuccess;
|
||||
case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
|
||||
case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
|
||||
case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
|
||||
case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
|
||||
case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
|
||||
case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
|
||||
case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
|
||||
case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
|
||||
if (key->keyType != rsaKey && key->keyType != rsaPssKey) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
len = 8 * key->u.rsa.modulus.len;
|
||||
|
||||
rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minLen);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (len < minLen) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
case SEC_OID_ANSIX9_DSA_SIGNATURE:
|
||||
case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
|
||||
case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
|
||||
case SEC_OID_SDN702_DSA_SIGNATURE:
|
||||
case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
|
||||
case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
|
||||
if (key->keyType != dsaKey) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
len = 8 * key->u.dsa.params.prime.len;
|
||||
|
||||
rv = NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minLen);
|
||||
if (rv != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
if (len < minLen) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
return SECSuccess;
|
||||
default:
|
||||
return SECSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* verify the signature of a signed data object with the given DER publickey
|
||||
*/
|
||||
@ -50,7 +138,6 @@ CERT_VerifySignedDataWithPublicKey(const CERTSignedData *sd,
|
||||
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
/* check the signature */
|
||||
sig = sd->signature;
|
||||
/* convert sig->len from bit counts to byte count. */
|
||||
@ -61,11 +148,17 @@ CERT_VerifySignedDataWithPublicKey(const CERTSignedData *sd,
|
||||
if (rv == SECSuccess) {
|
||||
/* Are we honoring signatures for this algorithm? */
|
||||
PRUint32 policyFlags = 0;
|
||||
rv = checkKeyParams(&sd->signatureAlgorithm, pubKey);
|
||||
if (rv != SECSuccess) {
|
||||
PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
rv = NSS_GetAlgorithmPolicy(hashAlg, &policyFlags);
|
||||
if (rv == SECSuccess &&
|
||||
!(policyFlags & NSS_USE_ALG_IN_CERT_SIGNATURE)) {
|
||||
PORT_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
|
||||
rv = SECFailure;
|
||||
return SECFailure;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
|
@ -260,6 +260,14 @@ extern int SECKEY_ECParamsToKeySize(const SECItem *params);
|
||||
*/
|
||||
extern int SECKEY_ECParamsToBasePointOrderLen(const SECItem *params);
|
||||
|
||||
/*
|
||||
* Returns the object identifier of the curve, of the provided
|
||||
* elliptic curve parameters structures.
|
||||
*
|
||||
* Return 0 on failure (unknown EC domain parameters).
|
||||
*/
|
||||
SECOidTag SECKEY_GetECCOid(const SECKEYECParams * params);
|
||||
|
||||
SEC_END_PROTOS
|
||||
|
||||
#endif /* _KEYHI_H_ */
|
||||
|
@ -1904,3 +1904,22 @@ SECKEY_CacheStaticFlags(SECKEYPrivateKey* key)
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECOidTag
|
||||
SECKEY_GetECCOid(const SECKEYECParams * params)
|
||||
{
|
||||
SECItem oid = { siBuffer, NULL, 0};
|
||||
SECOidData *oidData = NULL;
|
||||
|
||||
/*
|
||||
* params->data needs to contain the ASN encoding of an object ID (OID)
|
||||
* representing a named curve. Here, we strip away everything
|
||||
* before the actual OID and use the OID to look up a named curve.
|
||||
*/
|
||||
if (params->data[0] != SEC_ASN1_OBJECT_ID) return 0;
|
||||
oid.len = params->len - 2;
|
||||
oid.data = params->data + 2;
|
||||
if ((oidData = SECOID_FindOID(&oid)) == NULL) return 0;
|
||||
|
||||
return oidData->offset;
|
||||
}
|
||||
|
@ -579,6 +579,7 @@ get_token_objects_for_cache (
|
||||
&numObjects,
|
||||
&status);
|
||||
if (status != PR_SUCCESS) {
|
||||
nss_ZFreeIf(objects);
|
||||
return status;
|
||||
}
|
||||
for (i=0; i<numObjects; i++) {
|
||||
|
@ -13,6 +13,13 @@
|
||||
#include <stddef.h> /* for ptrdiff_t */
|
||||
/* #define USE_INDEXING 1 */
|
||||
|
||||
/* Some processors automatically fix up unaligned memory access, so they can
|
||||
* read or write a HALF (4 bytes) at a time whether the address is 4-byte
|
||||
* aligned or not. */
|
||||
#if defined(NSS_X86_OR_X64)
|
||||
#define HAVE_UNALIGNED_ACCESS 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The tables below are the 8 sbox functions, with the 6-bit input permutation
|
||||
* and the 32-bit output permutation pre-computed.
|
||||
@ -421,11 +428,13 @@ DES_MakeSchedule( HALF * ks, const BYTE * key, DESDirection direction)
|
||||
int delta;
|
||||
unsigned int ls;
|
||||
|
||||
#if defined(NSS_X86_OR_X64)
|
||||
#if defined(HAVE_UNALIGNED_ACCESS)
|
||||
left = HALFPTR(key)[0];
|
||||
right = HALFPTR(key)[1];
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#endif
|
||||
#else
|
||||
if (((ptrdiff_t)key & 0x03) == 0) {
|
||||
left = HALFPTR(key)[0];
|
||||
@ -572,11 +581,13 @@ DES_Do1Block(HALF * ks, const BYTE * inbuf, BYTE * outbuf)
|
||||
register HALF left, right;
|
||||
register HALF temp;
|
||||
|
||||
#if defined(NSS_X86_OR_X64)
|
||||
#if defined(HAVE_UNALIGNED_ACCESS)
|
||||
left = HALFPTR(inbuf)[0];
|
||||
right = HALFPTR(inbuf)[1];
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#endif
|
||||
#else
|
||||
if (((ptrdiff_t)inbuf & 0x03) == 0) {
|
||||
left = HALFPTR(inbuf)[0];
|
||||
@ -643,9 +654,11 @@ DES_Do1Block(HALF * ks, const BYTE * inbuf, BYTE * outbuf)
|
||||
|
||||
FP(left, right, temp);
|
||||
|
||||
#if defined(NSS_X86_OR_X64)
|
||||
#if defined(HAVE_UNALIGNED_ACCESS)
|
||||
#if defined(IS_LITTLE_ENDIAN)
|
||||
BYTESWAP(left, temp);
|
||||
BYTESWAP(right, temp);
|
||||
#endif
|
||||
HALFPTR(outbuf)[0] = left;
|
||||
HALFPTR(outbuf)[1] = right;
|
||||
#else
|
||||
|
@ -49,8 +49,15 @@ JAR_calculate_digest(void *data, long length)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
md5 = PK11_CreateDigestContext(SEC_OID_MD5);
|
||||
md5 = PK11_CreateDigestContext(SEC_OID_MD5);
|
||||
if (md5 == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
sha1 = PK11_CreateDigestContext(SEC_OID_SHA1);
|
||||
if (sha1 == NULL) {
|
||||
PK11_DestroyContext(md5, PR_TRUE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (length >= 0) {
|
||||
PK11_DigestBegin (md5);
|
||||
@ -107,6 +114,12 @@ JAR_digest_file (char *filename, JAR_Digest *dig)
|
||||
sha1 = PK11_CreateDigestContext (SEC_OID_SHA1);
|
||||
|
||||
if (md5 == NULL || sha1 == NULL) {
|
||||
if (md5) {
|
||||
PK11_DestroyContext(md5, PR_TRUE);
|
||||
}
|
||||
if (sha1) {
|
||||
PK11_DestroyContext(sha1, PR_TRUE);
|
||||
}
|
||||
/* can't generate digest contexts */
|
||||
PORT_Free (buf);
|
||||
JAR_FCLOSE (fp);
|
||||
|
@ -26,7 +26,7 @@ DIRS = \
|
||||
libpkix \
|
||||
certdb certhigh pk11wrap cryptohi nss \
|
||||
$(ZLIB_SRCDIR) ssl \
|
||||
pkcs12 pkcs7 smime \
|
||||
pkcs7 pkcs12 smime \
|
||||
crmf jar \
|
||||
ckfw $(SYSINIT_SRCDIR) \
|
||||
$(NULL)
|
||||
|
@ -6,6 +6,7 @@ CORE_DEPTH = ../..
|
||||
|
||||
PRIVATE_EXPORTS = \
|
||||
nssrenam.h \
|
||||
nssoptions.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS = \
|
||||
@ -16,6 +17,7 @@ MODULE = nss
|
||||
|
||||
CSRCS = \
|
||||
nssinit.c \
|
||||
nssoptions.c \
|
||||
nssver.c \
|
||||
utilwrap.c \
|
||||
$(NULL)
|
||||
|
@ -1082,3 +1082,11 @@ SECKEY_BigIntegerBitLength;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
;+NSS_3.21 { # NSS 3.21 release
|
||||
;+ global:
|
||||
NSS_OptionGet;
|
||||
NSS_OptionSet;
|
||||
SECMOD_CreateModuleEx;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
|
@ -294,6 +294,19 @@ SECStatus NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData);
|
||||
*/
|
||||
SECStatus NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData);
|
||||
|
||||
/* Available options for NSS_OptionSet() and NSS_OptionGet().
|
||||
*/
|
||||
#define NSS_RSA_MIN_KEY_SIZE (1<<0)
|
||||
#define NSS_DH_MIN_KEY_SIZE (1<<1)
|
||||
#define NSS_DSA_MIN_KEY_SIZE (1<<2)
|
||||
|
||||
/*
|
||||
* Set and get global options for the NSS library.
|
||||
*/
|
||||
SECStatus NSS_OptionSet(PRInt32 which, PRInt32 value);
|
||||
SECStatus NSS_OptionGet(PRInt32 which, PRInt32 *value);
|
||||
|
||||
|
||||
/*
|
||||
* Close the Cert, Key databases.
|
||||
*/
|
||||
|
73
security/nss/lib/nss/nssoptions.c
Normal file
73
security/nss/lib/nss/nssoptions.c
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* NSS utility functions
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "seccomon.h"
|
||||
#include "secoidt.h"
|
||||
#include "secoid.h"
|
||||
#include "nss.h"
|
||||
#include "nssoptions.h"
|
||||
|
||||
struct nssOps {
|
||||
PRInt32 rsaMinKeySize;
|
||||
PRInt32 dhMinKeySize;
|
||||
PRInt32 dsaMinKeySize;
|
||||
};
|
||||
|
||||
static struct nssOps nss_ops = {
|
||||
SSL_RSA_MIN_MODULUS_BITS,
|
||||
SSL_DH_MIN_P_BITS,
|
||||
SSL_DSA_MIN_P_BITS
|
||||
};
|
||||
|
||||
SECStatus
|
||||
NSS_OptionSet(PRInt32 which, PRInt32 value)
|
||||
{
|
||||
SECStatus rv = SECSuccess;
|
||||
|
||||
switch (which) {
|
||||
case NSS_RSA_MIN_KEY_SIZE:
|
||||
nss_ops.rsaMinKeySize = value;
|
||||
break;
|
||||
case NSS_DH_MIN_KEY_SIZE:
|
||||
nss_ops.dhMinKeySize = value;
|
||||
break;
|
||||
case NSS_DSA_MIN_KEY_SIZE:
|
||||
nss_ops.dsaMinKeySize = value;
|
||||
break;
|
||||
default:
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECStatus
|
||||
NSS_OptionGet(PRInt32 which, PRInt32 *value)
|
||||
{
|
||||
SECStatus rv = SECSuccess;
|
||||
|
||||
switch (which) {
|
||||
case NSS_RSA_MIN_KEY_SIZE:
|
||||
*value = nss_ops.rsaMinKeySize;
|
||||
break;
|
||||
case NSS_DH_MIN_KEY_SIZE:
|
||||
*value = nss_ops.dhMinKeySize;
|
||||
break;
|
||||
case NSS_DSA_MIN_KEY_SIZE:
|
||||
*value = nss_ops.dsaMinKeySize;
|
||||
break;
|
||||
default:
|
||||
rv = SECFailure;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
21
security/nss/lib/nss/nssoptions.h
Normal file
21
security/nss/lib/nss/nssoptions.h
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* NSS utility functions
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/*
|
||||
* Include the default limits here
|
||||
*/
|
||||
/* SSL default limits are here so we don't have to import a private SSL header
|
||||
* file into NSS proper */
|
||||
|
||||
/* The minimum server key sizes accepted by the clients.
|
||||
* Not 1024 to be conservative. */
|
||||
#define SSL_RSA_MIN_MODULUS_BITS 1023
|
||||
/* 1023 to avoid cases where p = 2q+1 for a 512-bit q turns out to be
|
||||
* only 1023 bits and similar. We don't have good data on whether this
|
||||
* happens because NSS used to count bit lengths incorrectly. */
|
||||
#define SSL_DH_MIN_P_BITS 1023
|
||||
#define SSL_DSA_MIN_P_BITS 1023
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "secasn1.h"
|
||||
#include "secoid.h"
|
||||
#include "secerr.h"
|
||||
#include "sslerr.h"
|
||||
#include "sechash.h"
|
||||
|
||||
#include "secpkcs5.h"
|
||||
@ -74,7 +73,7 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey,
|
||||
SECItem *ckaId = NULL;
|
||||
SECItem *pubValue = NULL;
|
||||
int signedcount = 0;
|
||||
int templateCount = 0;
|
||||
unsigned int templateCount = 0;
|
||||
SECStatus rv;
|
||||
|
||||
/* if we already have an object in the desired slot, use it */
|
||||
@ -403,7 +402,7 @@ pk11_get_Decoded_ECPoint(PLArenaPool *arena, const SECItem *ecParams,
|
||||
/* If the point is uncompressed and the lengths match, it
|
||||
* must be an unencoded point */
|
||||
if ((*((char *)ecPoint->pValue) == EC_POINT_FORM_UNCOMPRESSED)
|
||||
&& (ecPoint->ulValueLen == keyLen)) {
|
||||
&& (ecPoint->ulValueLen == (unsigned int)keyLen)) {
|
||||
return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue);
|
||||
}
|
||||
|
||||
@ -417,7 +416,7 @@ pk11_get_Decoded_ECPoint(PLArenaPool *arena, const SECItem *ecParams,
|
||||
|
||||
/* it coded correctly & we know the key length (and they match)
|
||||
* then we are done, return the results. */
|
||||
if (keyLen && rv == SECSuccess && publicKeyValue->len == keyLen) {
|
||||
if (keyLen && rv == SECSuccess && publicKeyValue->len == (unsigned int)keyLen) {
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
@ -549,7 +548,7 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id)
|
||||
PLArenaPool *arena;
|
||||
PLArenaPool *tmp_arena;
|
||||
SECKEYPublicKey *pubKey;
|
||||
int templateCount = 0;
|
||||
unsigned int templateCount = 0;
|
||||
CK_KEY_TYPE pk11KeyType;
|
||||
CK_RV crv;
|
||||
CK_ATTRIBUTE template[8];
|
||||
@ -2308,7 +2307,7 @@ PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname)
|
||||
CK_ATTRIBUTE *attrs;
|
||||
CK_BBOOL ckTrue = CK_TRUE;
|
||||
CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY;
|
||||
int tsize = 0;
|
||||
unsigned int tsize = 0;
|
||||
int objCount = 0;
|
||||
CK_OBJECT_HANDLE *key_ids;
|
||||
SECKEYPublicKeyList *keys;
|
||||
@ -2354,7 +2353,7 @@ PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx)
|
||||
CK_ATTRIBUTE *attrs;
|
||||
CK_BBOOL ckTrue = CK_TRUE;
|
||||
CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY;
|
||||
int tsize = 0;
|
||||
unsigned int tsize = 0;
|
||||
int objCount = 0;
|
||||
CK_OBJECT_HANDLE *key_ids;
|
||||
SECKEYPrivateKeyList *keys;
|
||||
|
@ -1441,6 +1441,7 @@ pk11_FindCertObjectByRecipientNew(PK11SlotInfo *slot, NSSCMSRecipient **recipien
|
||||
sizeof(CK_SLOT_ID) + sizeof(SECMODModuleID));
|
||||
if (!slotid) {
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
PK11_FreeSlotList(sl);
|
||||
return NULL;
|
||||
}
|
||||
for (le = sl->head; le; le = le->next) {
|
||||
|
@ -21,7 +21,6 @@
|
||||
|
||||
#include "certdb.h"
|
||||
#include "secerr.h"
|
||||
#include "sslerr.h"
|
||||
|
||||
#include "pki3hack.h"
|
||||
#include "dev3hack.h"
|
||||
|
@ -133,6 +133,17 @@ secmod_NewModule(void)
|
||||
SECMODModule *
|
||||
SECMOD_CreateModule(const char *library, const char *moduleName,
|
||||
const char *parameters, const char *nss)
|
||||
{
|
||||
return SECMOD_CreateModuleEx(library, moduleName, parameters, nss, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* for 3.4 we continue to use the old SECMODModule structure
|
||||
*/
|
||||
SECMODModule *
|
||||
SECMOD_CreateModuleEx(const char *library, const char *moduleName,
|
||||
const char *parameters, const char *nss,
|
||||
const char *config)
|
||||
{
|
||||
SECMODModule *mod = secmod_NewModule();
|
||||
char *slotParams,*ciphers;
|
||||
@ -148,6 +159,9 @@ SECMOD_CreateModule(const char *library, const char *moduleName,
|
||||
if (parameters) {
|
||||
mod->libraryParams = PORT_ArenaStrdup(mod->arena,parameters);
|
||||
}
|
||||
if (config) {
|
||||
/* XXX: Apply configuration */
|
||||
}
|
||||
mod->internal = NSSUTIL_ArgHasFlag("flags","internal",nssc);
|
||||
mod->isFIPS = NSSUTIL_ArgHasFlag("flags","FIPS",nssc);
|
||||
mod->isCritical = NSSUTIL_ArgHasFlag("flags","critical",nssc);
|
||||
@ -977,6 +991,7 @@ SECMODModule *
|
||||
SECMOD_LoadModule(char *modulespec,SECMODModule *parent, PRBool recurse)
|
||||
{
|
||||
char *library = NULL, *moduleName = NULL, *parameters = NULL, *nss= NULL;
|
||||
char *config = NULL;
|
||||
SECStatus status;
|
||||
SECMODModule *module = NULL;
|
||||
SECMODModule *oldModule = NULL;
|
||||
@ -985,17 +1000,19 @@ SECMOD_LoadModule(char *modulespec,SECMODModule *parent, PRBool recurse)
|
||||
/* initialize the underlying module structures */
|
||||
SECMOD_Init();
|
||||
|
||||
status = NSSUTIL_ArgParseModuleSpec(modulespec, &library, &moduleName,
|
||||
¶meters, &nss);
|
||||
status = NSSUTIL_ArgParseModuleSpecEx(modulespec, &library, &moduleName,
|
||||
¶meters, &nss,
|
||||
&config);
|
||||
if (status != SECSuccess) {
|
||||
goto loser;
|
||||
}
|
||||
|
||||
module = SECMOD_CreateModule(library, moduleName, parameters, nss);
|
||||
module = SECMOD_CreateModuleEx(library, moduleName, parameters, nss, config);
|
||||
if (library) PORT_Free(library);
|
||||
if (moduleName) PORT_Free(moduleName);
|
||||
if (parameters) PORT_Free(parameters);
|
||||
if (nss) PORT_Free(nss);
|
||||
if (config) PORT_Free(config);
|
||||
if (!module) {
|
||||
goto loser;
|
||||
}
|
||||
|
@ -64,6 +64,9 @@ SECStatus SECMOD_UnloadUserModule(SECMODModule *mod);
|
||||
|
||||
SECMODModule * SECMOD_CreateModule(const char *lib, const char *name,
|
||||
const char *param, const char *nss);
|
||||
SECMODModule * SECMOD_CreateModuleEx(const char *lib, const char *name,
|
||||
const char *param, const char *nss,
|
||||
const char *config);
|
||||
/*
|
||||
* After a fork(), PKCS #11 says we need to call C_Initialize again in
|
||||
* the child before we can use the module. This function causes this
|
||||
|
@ -1487,6 +1487,8 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
|
||||
SECStatus rv;
|
||||
SECItem ignore = {0};
|
||||
void *mark;
|
||||
SECItem *salt = NULL;
|
||||
SECItem *params = NULL;
|
||||
|
||||
if(!p12exp || !p12exp->safeInfos) {
|
||||
return NULL;
|
||||
@ -1552,11 +1554,10 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
|
||||
/* init password pased integrity mode */
|
||||
if(p12exp->integrityEnabled) {
|
||||
SECItem pwd = {siBuffer,NULL, 0};
|
||||
SECItem *salt = sec_pkcs12_generate_salt();
|
||||
PK11SymKey *symKey;
|
||||
SECItem *params;
|
||||
CK_MECHANISM_TYPE integrityMechType;
|
||||
CK_MECHANISM_TYPE hmacMechType;
|
||||
salt = sec_pkcs12_generate_salt();
|
||||
|
||||
/* zero out macData and set values */
|
||||
PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
|
||||
@ -1567,13 +1568,11 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
|
||||
}
|
||||
if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt)
|
||||
!= SECSuccess) {
|
||||
/* XXX salt is leaked */
|
||||
PORT_SetError(SEC_ERROR_NO_MEMORY);
|
||||
goto loser;
|
||||
}
|
||||
if (!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->mac.iter),
|
||||
NSS_PBE_DEFAULT_ITERATION_COUNT)) {
|
||||
/* XXX salt is leaked */
|
||||
goto loser;
|
||||
}
|
||||
|
||||
@ -1581,7 +1580,6 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
|
||||
if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd,
|
||||
p12exp->integrityInfo.pwdInfo.password, PR_TRUE,
|
||||
PR_TRUE, PR_TRUE)) {
|
||||
/* XXX salt is leaked */
|
||||
goto loser;
|
||||
}
|
||||
/*
|
||||
@ -1603,7 +1601,6 @@ sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
|
||||
case SEC_OID_MD2:
|
||||
integrityMechType = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
|
||||
default:
|
||||
/* XXX params is leaked */
|
||||
goto loser;
|
||||
}
|
||||
|
||||
@ -1645,6 +1642,12 @@ loser:
|
||||
sec_pkcs12_encoder_destroy_context(p12enc);
|
||||
if (p12exp->arena != NULL)
|
||||
PORT_ArenaRelease(p12exp->arena, mark);
|
||||
if (salt) {
|
||||
SECITEM_ZfreeItem(salt, PR_TRUE);
|
||||
}
|
||||
if (params) {
|
||||
PK11_DestroyPBEParams(params);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
@ -408,7 +408,6 @@ SEC_PKCS7EncryptContents(PLArenaPool *poolp,
|
||||
void *wincx)
|
||||
{
|
||||
SECAlgorithmID *algid = NULL;
|
||||
SECItem * result = NULL;
|
||||
SECItem * src;
|
||||
SECItem * dest;
|
||||
SECItem * blocked_data = NULL;
|
||||
@ -524,9 +523,6 @@ loser:
|
||||
if(blocked_data != NULL)
|
||||
SECITEM_ZfreeItem(blocked_data, PR_TRUE);
|
||||
|
||||
if(result != NULL)
|
||||
SECITEM_ZfreeItem(result, PR_TRUE);
|
||||
|
||||
if(rv == SECFailure)
|
||||
PORT_ArenaRelease(poolp, mark);
|
||||
else
|
||||
|
@ -203,7 +203,8 @@ sec_PKCS7CreateEncryptObject (PLArenaPool *poolp, PK11SymKey *key,
|
||||
rv = PK11_ParamToAlgid(algtag,param,poolp,algid);
|
||||
if(rv != SECSuccess) {
|
||||
PORT_Free (result);
|
||||
SECITEM_FreeItem(param,PR_TRUE);
|
||||
SECITEM_FreeItem(param,PR_TRUE);
|
||||
PK11_DestroyContext(ciphercx, PR_TRUE);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -239,6 +239,7 @@ STAN_GetCertIdentifierFromDER(NSSArena *arenaOpt, NSSDER *der)
|
||||
}
|
||||
secrv = CERT_KeyFromDERCert(arena, &secDER, &secKey);
|
||||
if (secrv != SECSuccess) {
|
||||
PORT_FreeArena(arena, PR_FALSE);
|
||||
return NULL;
|
||||
}
|
||||
rvKey = nssItem_Create(arenaOpt, NULL, secKey.len, (void *)secKey.data);
|
||||
|
@ -1058,6 +1058,9 @@ nssCertificateCollection_Create (
|
||||
{
|
||||
nssPKIObjectCollection *collection;
|
||||
collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
|
||||
if (!collection) {
|
||||
return NULL;
|
||||
}
|
||||
collection->objectType = pkiObjectType_Certificate;
|
||||
collection->destroyObject = cert_destroyObject;
|
||||
collection->getUIDFromObject = cert_getUIDFromObject;
|
||||
@ -1164,6 +1167,9 @@ nssCRLCollection_Create (
|
||||
{
|
||||
nssPKIObjectCollection *collection;
|
||||
collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
|
||||
if (!collection) {
|
||||
return NULL;
|
||||
}
|
||||
collection->objectType = pkiObjectType_CRL;
|
||||
collection->destroyObject = crl_destroyObject;
|
||||
collection->getUIDFromObject = crl_getUIDFromObject;
|
||||
|
@ -120,7 +120,7 @@ NSSCMSCipherContext *
|
||||
NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgorithmID *algid)
|
||||
{
|
||||
NSSCMSCipherContext *cc;
|
||||
void *ciphercx;
|
||||
void *ciphercx = NULL;
|
||||
SECStatus rv;
|
||||
CK_MECHANISM_TYPE cryptoMechType;
|
||||
PK11SlotInfo *slot;
|
||||
@ -186,6 +186,7 @@ NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgori
|
||||
}
|
||||
|
||||
cc->cx = ciphercx;
|
||||
ciphercx = NULL;
|
||||
cc->doit = (nss_cms_cipher_function)PK11_CipherOp;
|
||||
cc->destroy = (nss_cms_cipher_destroy)PK11_DestroyContext;
|
||||
cc->encrypt = PR_TRUE;
|
||||
@ -193,6 +194,9 @@ NSS_CMSCipherContext_StartEncrypt(PLArenaPool *poolp, PK11SymKey *key, SECAlgori
|
||||
|
||||
loser:
|
||||
SECITEM_FreeItem(param, PR_TRUE);
|
||||
if (ciphercx) {
|
||||
PK11_DestroyContext(ciphercx, PR_TRUE);
|
||||
}
|
||||
|
||||
return cc;
|
||||
}
|
||||
|
@ -2762,7 +2762,7 @@ NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
|
||||
case SECMOD_MODULE_DB_FUNCTION_FIND:
|
||||
if (secmod == NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return NULL;
|
||||
goto loser;
|
||||
}
|
||||
if (rw && (dbType != NSS_DB_TYPE_LEGACY) &&
|
||||
(dbType != NSS_DB_TYPE_MULTIACCESS)) {
|
||||
@ -2805,7 +2805,7 @@ NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
|
||||
case SECMOD_MODULE_DB_FUNCTION_ADD:
|
||||
if (secmod == NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return NULL;
|
||||
goto loser;
|
||||
}
|
||||
rvstr = (sftkdbCall_AddSecmodDB(appName,filename,secmod,
|
||||
(char *)args,rw) == SECSuccess) ? &success: NULL;
|
||||
@ -2813,7 +2813,7 @@ NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
|
||||
case SECMOD_MODULE_DB_FUNCTION_DEL:
|
||||
if (secmod == NULL) {
|
||||
PORT_SetError(SEC_ERROR_INVALID_ARGS);
|
||||
return NULL;
|
||||
goto loser;
|
||||
}
|
||||
rvstr = (sftkdbCall_DeleteSecmodDB(appName,filename,secmod,
|
||||
(char *)args,rw) == SECSuccess) ? &success: NULL;
|
||||
@ -2823,6 +2823,8 @@ NSC_ModuleDBFunc(unsigned long function,char *parameters, void *args)
|
||||
(char **)args,rw) == SECSuccess) ? &success: NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
loser:
|
||||
if (secmod) PR_smprintf_free(secmod);
|
||||
if (appName) PORT_Free(appName);
|
||||
if (filename) PORT_Free(filename);
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "prerror.h"
|
||||
#include "pratom.h"
|
||||
#include "prthread.h"
|
||||
#include "nss.h"
|
||||
#include "nssoptions.h"
|
||||
|
||||
#include "pk11func.h"
|
||||
#include "secmod.h"
|
||||
@ -4518,6 +4520,7 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes,
|
||||
PORT_Assert(bytes <= 3);
|
||||
i->len = 0;
|
||||
i->data = NULL;
|
||||
i->type = siBuffer;
|
||||
count = ssl3_ConsumeHandshakeNumber(ss, bytes, b, length);
|
||||
if (count < 0) { /* Can't test for SECSuccess here. */
|
||||
return SECFailure;
|
||||
@ -6985,13 +6988,19 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
|
||||
unsigned dh_p_bits;
|
||||
unsigned dh_g_bits;
|
||||
unsigned dh_Ys_bits;
|
||||
PRInt32 minDH;
|
||||
|
||||
rv = ssl3_ConsumeHandshakeVariable(ss, &dh_p, 2, &b, &length);
|
||||
if (rv != SECSuccess) {
|
||||
goto loser; /* malformed. */
|
||||
}
|
||||
|
||||
rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minDH);
|
||||
if (rv != SECSuccess) {
|
||||
minDH = SSL_DH_MIN_P_BITS;
|
||||
}
|
||||
dh_p_bits = SECKEY_BigIntegerBitLength(&dh_p);
|
||||
if (dh_p_bits < SSL_DH_MIN_P_BITS) {
|
||||
if (dh_p_bits < minDH) {
|
||||
errCode = SSL_ERROR_WEAK_SERVER_EPHEMERAL_DH_KEY;
|
||||
goto alert_loser;
|
||||
}
|
||||
@ -10710,19 +10719,40 @@ ssl3_AuthCertificate(sslSocket *ss)
|
||||
ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
|
||||
if (pubKey) {
|
||||
KeyType pubKeyType;
|
||||
PRInt32 minKey;
|
||||
ss->sec.keaKeyBits = ss->sec.authKeyBits =
|
||||
SECKEY_PublicKeyStrengthInBits(pubKey);
|
||||
pubKeyType = SECKEY_GetPublicKeyType(pubKey);
|
||||
minKey = ss->sec.authKeyBits;
|
||||
switch (pubKeyType) {
|
||||
case rsaKey:
|
||||
case rsaPssKey:
|
||||
case rsaOaepKey:
|
||||
rv = NSS_OptionGet(NSS_RSA_MIN_KEY_SIZE, &minKey);
|
||||
if (rv != SECSuccess) {
|
||||
minKey = SSL_RSA_MIN_MODULUS_BITS;
|
||||
}
|
||||
break;
|
||||
case dsaKey:
|
||||
rv = NSS_OptionGet(NSS_DSA_MIN_KEY_SIZE, &minKey);
|
||||
if (rv != SECSuccess) {
|
||||
minKey = SSL_DSA_MIN_P_BITS;
|
||||
}
|
||||
break;
|
||||
case dhKey:
|
||||
rv = NSS_OptionGet(NSS_DH_MIN_KEY_SIZE, &minKey);
|
||||
if (rv != SECSuccess) {
|
||||
minKey = SSL_DH_MIN_P_BITS;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Too small: not good enough. Send a fatal alert. */
|
||||
/* We aren't checking EC here on the understanding that we only
|
||||
* support curves we like, a decision that might need revisiting. */
|
||||
if (((pubKeyType == rsaKey || pubKeyType == rsaPssKey ||
|
||||
pubKeyType == rsaOaepKey) &&
|
||||
ss->sec.authKeyBits < SSL_RSA_MIN_MODULUS_BITS) ||
|
||||
(pubKeyType == dsaKey &&
|
||||
ss->sec.authKeyBits < SSL_DSA_MIN_P_BITS) ||
|
||||
(pubKeyType == dhKey &&
|
||||
ss->sec.authKeyBits < SSL_DH_MIN_P_BITS)) {
|
||||
if ( ss->sec.authKeyBits < minKey) {
|
||||
PORT_SetError(SSL_ERROR_WEAK_SERVER_CERT_KEY);
|
||||
(void)SSL3_SendAlert(ss, alert_fatal,
|
||||
ss->version >= SSL_LIBRARY_VERSION_TLS_1_0
|
||||
|
@ -422,12 +422,12 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
|
||||
}
|
||||
/* length of server_name_list */
|
||||
listLenBytes = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len);
|
||||
if (listLenBytes < 0 || listLenBytes != data->len) {
|
||||
(void)ssl3_DecodeError(ss);
|
||||
if (listLenBytes < 0) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (listLenBytes == 0) {
|
||||
return SECSuccess; /* ignore an empty extension */
|
||||
if (listLenBytes == 0 || listLenBytes != data->len) {
|
||||
(void)ssl3_DecodeError(ss);
|
||||
return SECFailure;
|
||||
}
|
||||
ldata = *data;
|
||||
/* Calculate the size of the array.*/
|
||||
@ -452,9 +452,6 @@ ssl3_HandleServerNameXtn(sslSocket * ss, PRUint16 ex_type, SECItem *data)
|
||||
}
|
||||
listCount += 1;
|
||||
}
|
||||
if (!listCount) {
|
||||
return SECFailure; /* nothing we can act on */
|
||||
}
|
||||
names = PORT_ZNewArray(SECItem, listCount);
|
||||
if (!names) {
|
||||
return SECFailure;
|
||||
@ -1099,7 +1096,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
|
||||
CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC;
|
||||
PK11Context *aes_ctx_pkcs11;
|
||||
CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC;
|
||||
PK11Context *hmac_ctx_pkcs11;
|
||||
PK11Context *hmac_ctx_pkcs11 = NULL;
|
||||
unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH];
|
||||
unsigned int computed_mac_length;
|
||||
unsigned char iv[AES_BLOCK_SIZE];
|
||||
@ -1364,14 +1361,18 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
|
||||
goto loser;
|
||||
|
||||
rv = PK11_DigestBegin(hmac_ctx_pkcs11);
|
||||
if (rv != SECSuccess) goto loser;
|
||||
rv = PK11_DigestOp(hmac_ctx_pkcs11, key_name,
|
||||
SESS_TICKET_KEY_NAME_LEN);
|
||||
if (rv != SECSuccess) goto loser;
|
||||
rv = PK11_DigestOp(hmac_ctx_pkcs11, iv, sizeof(iv));
|
||||
if (rv != SECSuccess) goto loser;
|
||||
rv = PK11_DigestOp(hmac_ctx_pkcs11, (unsigned char *)length_buf, 2);
|
||||
if (rv != SECSuccess) goto loser;
|
||||
rv = PK11_DigestOp(hmac_ctx_pkcs11, ciphertext.data, ciphertext.len);
|
||||
if (rv != SECSuccess) goto loser;
|
||||
rv = PK11_DigestFinal(hmac_ctx_pkcs11, computed_mac,
|
||||
&computed_mac_length, sizeof(computed_mac));
|
||||
PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE);
|
||||
if (rv != SECSuccess) goto loser;
|
||||
}
|
||||
|
||||
@ -1400,6 +1401,8 @@ ssl3_SendNewSessionTicket(sslSocket *ss)
|
||||
if (rv != SECSuccess) goto loser;
|
||||
|
||||
loser:
|
||||
if (hmac_ctx_pkcs11)
|
||||
PK11_DestroyContext(hmac_ctx_pkcs11, PR_TRUE);
|
||||
if (plaintext_item.data)
|
||||
SECITEM_FreeItem(&plaintext_item, PR_FALSE);
|
||||
if (ciphertext.data)
|
||||
|
@ -155,15 +155,6 @@ typedef enum { SSLAppOpRead = 0,
|
||||
|
||||
#define EXPORT_RSA_KEY_LENGTH 64 /* bytes */
|
||||
|
||||
/* The minimum server key sizes accepted by the clients.
|
||||
* Not 1024 to be conservative. */
|
||||
#define SSL_RSA_MIN_MODULUS_BITS 1023
|
||||
/* 1023 to avoid cases where p = 2q+1 for a 512-bit q turns out to be
|
||||
* only 1023 bits and similar. We don't have good data on whether this
|
||||
* happens because NSS used to count bit lengths incorrectly. */
|
||||
#define SSL_DH_MIN_P_BITS 1023
|
||||
#define SSL_DSA_MIN_P_BITS 1023
|
||||
|
||||
#define INITIAL_DTLS_TIMEOUT_MS 1000 /* Default value from RFC 4347 = 1s*/
|
||||
#define MAX_DTLS_TIMEOUT_MS 60000 /* 1 minute */
|
||||
#define DTLS_FINISHED_TIMER_MS 120000 /* Time to wait in FINISHED state */
|
||||
|
@ -277,3 +277,9 @@ _SGN_VerifyPKCS1DigestInfo;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
;+NSSUTIL_3.21 { # NSS Utilities 3.21 release
|
||||
;+ global:
|
||||
NSSUTIL_ArgParseModuleSpecEx;
|
||||
;+ local:
|
||||
;+ *;
|
||||
;+};
|
||||
|
@ -951,6 +951,33 @@ sec_asn1d_parse_more_length (sec_asn1d_state *state,
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for sec_asn1d_prepare_for_contents.
|
||||
* Checks that a value representing a number of bytes consumed can be
|
||||
* subtracted from a remaining length. If so, returns PR_TRUE.
|
||||
* Otherwise, sets the error SEC_ERROR_BAD_DER, indicates that there was a
|
||||
* decoding error in the given SEC_ASN1DecoderContext, and returns PR_FALSE.
|
||||
*/
|
||||
static PRBool
|
||||
sec_asn1d_check_and_subtract_length (unsigned long *remaining,
|
||||
unsigned long consumed,
|
||||
SEC_ASN1DecoderContext *cx)
|
||||
{
|
||||
PORT_Assert(remaining);
|
||||
PORT_Assert(cx);
|
||||
if (!remaining || !cx) {
|
||||
PORT_SetError (SEC_ERROR_INVALID_ARGS);
|
||||
cx->status = decodeError;
|
||||
return PR_FALSE;
|
||||
}
|
||||
if (*remaining < consumed) {
|
||||
PORT_SetError (SEC_ERROR_BAD_DER);
|
||||
cx->status = decodeError;
|
||||
return PR_FALSE;
|
||||
}
|
||||
*remaining -= consumed;
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
|
||||
@ -958,6 +985,7 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
|
||||
SECItem *item;
|
||||
PLArenaPool *poolp;
|
||||
unsigned long alloc_len;
|
||||
sec_asn1d_state *parent;
|
||||
|
||||
#ifdef DEBUG_ASN1D_STATES
|
||||
{
|
||||
@ -966,6 +994,63 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The maximum length for a child element should be constrained to the
|
||||
* length remaining in the first definite length element in the ancestor
|
||||
* stack. If there is no definite length element in the ancestor stack,
|
||||
* there's nothing to constrain the length of the child, so there's no
|
||||
* further processing necessary.
|
||||
*
|
||||
* It's necessary to walk the ancestor stack, because it's possible to have
|
||||
* definite length children that are part of an indefinite length element,
|
||||
* which is itself part of an indefinite length element, and which is
|
||||
* ultimately part of a definite length element. A simple example of this
|
||||
* would be the handling of constructed OCTET STRINGs in BER encoding.
|
||||
*
|
||||
* This algorithm finds the first definite length element in the ancestor
|
||||
* stack, if any, and if so, ensures that the length of the child element
|
||||
* is consistent with the number of bytes remaining in the constraining
|
||||
* ancestor element (that is, after accounting for any other sibling
|
||||
* elements that may have been read).
|
||||
*
|
||||
* It's slightly complicated by the need to account both for integer
|
||||
* underflow and overflow, as well as ensure that for indefinite length
|
||||
* encodings, there's also enough space for the End-of-Contents (EOC)
|
||||
* octets (Tag = 0x00, Length = 0x00, or two bytes).
|
||||
*/
|
||||
|
||||
/* Determine the maximum length available for this element by finding the
|
||||
* first definite length ancestor, if any. */
|
||||
parent = sec_asn1d_get_enclosing_construct(state);
|
||||
while (parent && parent->indefinite) {
|
||||
parent = sec_asn1d_get_enclosing_construct(parent);
|
||||
}
|
||||
/* If parent is null, state is either the outermost state / at the top of
|
||||
* the stack, or the outermost state uses indefinite length encoding. In
|
||||
* these cases, there's nothing external to constrain this element, so
|
||||
* there's nothing to check. */
|
||||
if (parent) {
|
||||
unsigned long remaining = parent->pending;
|
||||
parent = state;
|
||||
do {
|
||||
if (!sec_asn1d_check_and_subtract_length(
|
||||
&remaining, parent->consumed, state->top) ||
|
||||
/* If parent->indefinite is true, parent->contents_length is
|
||||
* zero and this is a no-op. */
|
||||
!sec_asn1d_check_and_subtract_length(
|
||||
&remaining, parent->contents_length, state->top) ||
|
||||
/* If parent->indefinite is true, then ensure there is enough
|
||||
* space for an EOC tag of 2 bytes. */
|
||||
(parent->indefinite && !sec_asn1d_check_and_subtract_length(
|
||||
&remaining, 2, state->top))) {
|
||||
/* This element is larger than its enclosing element, which is
|
||||
* invalid. */
|
||||
return;
|
||||
}
|
||||
} while ((parent = sec_asn1d_get_enclosing_construct(parent)) &&
|
||||
parent->indefinite);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX I cannot decide if this allocation should exclude the case
|
||||
* where state->endofcontents is true -- figure it out!
|
||||
@ -1007,21 +1092,6 @@ sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
|
||||
*/
|
||||
state->pending = state->contents_length;
|
||||
|
||||
/* If this item has definite length encoding, and
|
||||
** is enclosed by a definite length constructed type,
|
||||
** make sure it isn't longer than the remaining space in that
|
||||
** constructed type.
|
||||
*/
|
||||
if (state->contents_length > 0) {
|
||||
sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
|
||||
if (parent && !parent->indefinite &&
|
||||
state->consumed + state->contents_length > parent->pending) {
|
||||
PORT_SetError (SEC_ERROR_BAD_DER);
|
||||
state->top->status = decodeError;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* An EXPLICIT is nothing but an outer header, which we have
|
||||
* already parsed and accepted. Now we need to do the inner
|
||||
@ -1720,10 +1790,107 @@ sec_asn1d_next_substring (sec_asn1d_state *state)
|
||||
if (state->pending == 0)
|
||||
done = PR_TRUE;
|
||||
} else {
|
||||
PRBool preallocatedString;
|
||||
sec_asn1d_state *temp_state;
|
||||
PORT_Assert (state->indefinite);
|
||||
|
||||
item = (SECItem *)(child->dest);
|
||||
if (item != NULL && item->data != NULL) {
|
||||
|
||||
/**
|
||||
* At this point, there's three states at play:
|
||||
* child: The element that was just parsed
|
||||
* state: The currently processed element
|
||||
* 'parent' (aka state->parent): The enclosing construct
|
||||
* of state, or NULL if this is the top-most element.
|
||||
*
|
||||
* This state handles both substrings of a constructed string AND
|
||||
* child elements of items whose template type was that of
|
||||
* SEC_ASN1_ANY, SEC_ASN1_SAVE, SEC_ASN1_ANY_CONTENTS, SEC_ASN1_SKIP
|
||||
* template, as described in sec_asn1d_prepare_for_contents. For
|
||||
* brevity, these will be referred to as 'string' and 'any' types.
|
||||
*
|
||||
* This leads to the following possibilities:
|
||||
* 1: This element is an indefinite length string, part of a
|
||||
* definite length string.
|
||||
* 2: This element is an indefinite length string, part of an
|
||||
* indefinite length string.
|
||||
* 3: This element is an indefinite length any, part of a
|
||||
* definite length any.
|
||||
* 4: This element is an indefinite length any, part of an
|
||||
* indefinite length any.
|
||||
* 5: This element is an indefinite length any and does not
|
||||
* meet any of the above criteria. Note that this would include
|
||||
* an indefinite length string type matching an indefinite
|
||||
* length any template.
|
||||
*
|
||||
* In Cases #1 and #3, the definite length 'parent' element will
|
||||
* have allocated state->dest based on the parent elements definite
|
||||
* size. During the processing of 'child', sec_asn1d_parse_leaf will
|
||||
* have copied the (string, any) data directly into the offset of
|
||||
* dest, as appropriate, so there's no need for this class to still
|
||||
* store the child - it's already been processed.
|
||||
*
|
||||
* In Cases #2 and #4, dest will be set to the parent element's dest,
|
||||
* but dest->data will not have been allocated yet, due to the
|
||||
* indefinite length encoding. In this situation, it's necessary to
|
||||
* hold onto child (and all other children) until the EOC, at which
|
||||
* point, it becomes possible to compute 'state's overall length. Once
|
||||
* 'state' has a computed length, this can then be fed to 'parent' (via
|
||||
* this state), and then 'parent' can similarly compute the length of
|
||||
* all of its children up to the EOC, which will ultimately transit to
|
||||
* sec_asn1d_concat_substrings, determine the overall size needed,
|
||||
* allocate, and copy the contents (of all of parent's children, which
|
||||
* would include 'state', just as 'state' will have copied all of its
|
||||
* children via sec_asn1d_concat_substrings)
|
||||
*
|
||||
* The final case, Case #5, will manifest in that item->data and
|
||||
* item->len will be NULL/0, respectively, since this element was
|
||||
* indefinite-length encoded. In that case, both the tag and length will
|
||||
* already exist in state's subitems, via sec_asn1d_record_any_header,
|
||||
* and so the contents (aka 'child') should be added to that list of
|
||||
* items to concatenate in sec_asn1d_concat_substrings once the EOC
|
||||
* is encountered.
|
||||
*
|
||||
* To distinguish #2/#4 from #1/#3, it's sufficient to walk the ancestor
|
||||
* tree. If the current type is a string type, then the enclosing
|
||||
* construct will be that same type (#1/#2). If the current type is an
|
||||
* any type, then the enclosing construct is either an any type (#3/#4)
|
||||
* or some other type (#5). Since this is BER, this nesting relationship
|
||||
* between 'state' and 'parent' may go through several levels of
|
||||
* constructed encoding, so continue walking the ancestor chain until a
|
||||
* clear determination can be made.
|
||||
*
|
||||
* The variable preallocatedString is used to indicate Case #1/#3,
|
||||
* indicating an in-place copy has already occurred, and Cases #2, #4,
|
||||
* and #5 all have the same behaviour of adding a new substring.
|
||||
*/
|
||||
preallocatedString = PR_FALSE;
|
||||
temp_state = state;
|
||||
while (temp_state && item == temp_state->dest && temp_state->indefinite) {
|
||||
sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(temp_state);
|
||||
if (!parent || parent->underlying_kind != temp_state->underlying_kind) {
|
||||
/* Case #5 - Either this is a top-level construct or it is part
|
||||
* of some other element (e.g. a SEQUENCE), in which case, a
|
||||
* new item should be allocated. */
|
||||
break;
|
||||
}
|
||||
if (!parent->indefinite) {
|
||||
/* Cases #1 / #3 - A definite length ancestor exists, for which
|
||||
* this is a substring that has already copied into dest. */
|
||||
preallocatedString = PR_TRUE;
|
||||
break;
|
||||
}
|
||||
if (!parent->substring) {
|
||||
/* Cases #2 / #4 - If the parent is not a substring, but is
|
||||
* indefinite, then there's nothing further up that may have
|
||||
* preallocated dest, thus child will not have already
|
||||
* been copied in place, therefore it's necessary to save child
|
||||
* as a subitem. */
|
||||
break;
|
||||
}
|
||||
temp_state = parent;
|
||||
}
|
||||
if (item != NULL && item->data != NULL && !preallocatedString) {
|
||||
/*
|
||||
* Save the string away for later concatenation.
|
||||
*/
|
||||
|
@ -762,6 +762,31 @@ NSSUTIL_MkSlotString(unsigned long slotID, unsigned long defaultFlags,
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* Parse Full module specs into: library, commonName, module parameters,
|
||||
* and NSS specifi parameters.
|
||||
*/
|
||||
SECStatus
|
||||
NSSUTIL_ArgParseModuleSpecEx(char *modulespec, char **lib, char **mod,
|
||||
char **parameters, char **nss,
|
||||
char **config)
|
||||
{
|
||||
int next;
|
||||
modulespec = NSSUTIL_ArgStrip(modulespec);
|
||||
|
||||
*lib = *mod = *parameters = *nss = *config = 0;
|
||||
|
||||
while (*modulespec) {
|
||||
NSSUTIL_HANDLE_STRING_ARG(modulespec,*lib,"library=",;)
|
||||
NSSUTIL_HANDLE_STRING_ARG(modulespec,*mod,"name=",;)
|
||||
NSSUTIL_HANDLE_STRING_ARG(modulespec,*parameters,"parameters=",;)
|
||||
NSSUTIL_HANDLE_STRING_ARG(modulespec,*nss,"nss=",;)
|
||||
NSSUTIL_HANDLE_STRING_ARG(modulespec,*config,"config=",;)
|
||||
NSSUTIL_HANDLE_FINAL_ARG(modulespec)
|
||||
}
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Parse Full module specs into: library, commonName, module parameters,
|
||||
* and NSS specifi parameters.
|
||||
@ -788,11 +813,12 @@ NSSUTIL_ArgParseModuleSpec(char *modulespec, char **lib, char **mod,
|
||||
/************************************************************************
|
||||
* make a new module spec from it's components */
|
||||
char *
|
||||
NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
|
||||
char *NSS)
|
||||
NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName, char *parameters,
|
||||
char *NSS,
|
||||
char *config)
|
||||
{
|
||||
char *moduleSpec;
|
||||
char *lib,*name,*param,*nss;
|
||||
char *lib,*name,*param,*nss,*conf;
|
||||
|
||||
/*
|
||||
* now the final spec
|
||||
@ -801,7 +827,13 @@ NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
|
||||
name = nssutil_formatPair("name",commonName,'\"');
|
||||
param = nssutil_formatPair("parameters",parameters,'\"');
|
||||
nss = nssutil_formatPair("NSS",NSS,'\"');
|
||||
moduleSpec = PR_smprintf("%s %s %s %s", lib,name,param,nss);
|
||||
if (config) {
|
||||
conf = nssutil_formatPair("config",config,'\"');
|
||||
moduleSpec = PR_smprintf("%s %s %s %s %s", lib,name,param,nss,conf);
|
||||
nssutil_freePair(conf);
|
||||
} else {
|
||||
moduleSpec = PR_smprintf("%s %s %s %s", lib,name,param,nss);
|
||||
}
|
||||
nssutil_freePair(lib);
|
||||
nssutil_freePair(name);
|
||||
nssutil_freePair(param);
|
||||
@ -809,6 +841,15 @@ NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
|
||||
return (moduleSpec);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* make a new module spec from it's components */
|
||||
char *
|
||||
NSSUTIL_MkModuleSpec(char *dllName, char *commonName, char *parameters,
|
||||
char *NSS)
|
||||
{
|
||||
return NSSUTIL_MkModuleSpecEx(dllName, commonName, parameters, NSS, NULL);
|
||||
}
|
||||
|
||||
|
||||
#define NSSUTIL_ARG_FORTEZZA_FLAG "FORTEZZA"
|
||||
/******************************************************************************
|
||||
|
@ -39,8 +39,12 @@ char * NSSUTIL_MkSlotString(unsigned long slotID, unsigned long defaultFlags,
|
||||
PRBool hasRootCerts, PRBool hasRootTrust);
|
||||
SECStatus NSSUTIL_ArgParseModuleSpec(char *modulespec, char **lib, char **mod,
|
||||
char **parameters, char **nss);
|
||||
SECStatus NSSUTIL_ArgParseModuleSpecEx(char *modulespec, char **lib, char **mod,
|
||||
char **parameters, char **nss, char **config);
|
||||
char *NSSUTIL_MkModuleSpec(char *dllName, char *commonName,
|
||||
char *parameters, char *NSS);
|
||||
char *NSSUTIL_MkModuleSpecEx(char *dllName, char *commonName,
|
||||
char *parameters, char *NSS, char *config);
|
||||
void NSSUTIL_ArgParseCipherFlags(unsigned long *newCiphers,char *cipherList);
|
||||
char * NSSUTIL_MkNSSString(char **slotStrings, int slotCount, PRBool internal,
|
||||
PRBool isFIPS, PRBool isModuleDB, PRBool isModuleDBOnly,
|
||||
|
@ -79,7 +79,7 @@ dbupgrade_main()
|
||||
|
||||
if [ -d fips ]; then
|
||||
echo "upgrading db fips"
|
||||
${BINDIR}/certutil -S -g 512 -n tmprsa -t "u,u,u" -s "CN=tmprsa, C=US" -x -d sql:fips -f ${FIPSPWFILE} -z ${NOISE_FILE} 2>&1
|
||||
${BINDIR}/certutil -S -g 1024 -n tmprsa -t "u,u,u" -s "CN=tmprsa, C=US" -x -d sql:fips -f ${FIPSPWFILE} -z ${NOISE_FILE} 2>&1
|
||||
html_msg $? 0 "Upgrading fips"
|
||||
# remove our temp certificate we created in the fist token
|
||||
${BINDIR}/certutil -F -n tmprsa -d sql:fips -f ${FIPSPWFILE} 2>&1
|
||||
|
@ -1316,7 +1316,7 @@ GetMechInfo(CK_MECHANISM_TYPE type)
|
||||
l = 0; r = numMechs-1;
|
||||
|
||||
while(l <= r) {
|
||||
mid = (l+r)/2;
|
||||
mid = l+(r-l)/2;
|
||||
if(mechInfo[mid].type == type) {
|
||||
return &(mechInfo[mid]);
|
||||
} else if(mechInfo[mid].type < type) {
|
||||
|
Loading…
Reference in New Issue
Block a user