Пример #1
0
/*
	Implementation specific date parser.
	Does not actually verify the date
*/
int32 getValidity(psPool_t *pool, unsigned char **pp, int32 len,
					   char **notBefore, char **notAfter)
{
	unsigned char	*p = *pp, *end;
	int32			seqLen, timeLen;

	end = p + len;
	if (len < 1 || *(p++) != (ASN_SEQUENCE | ASN_CONSTRUCTED) || 
			asnParseLength(&p, len - 1, &seqLen) < 0 || (end - p) < seqLen) {
		return -1;
	}
/*
	Have notBefore and notAfter times in UTCTime or GeneralizedTime formats
*/
	if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME))) {
		return -1;
	}
	p++;
/*
	Allocate them as null terminated strings
*/
	if (asnParseLength(&p, seqLen, &timeLen) < 0 || (end - p) < timeLen) {
		return -1;
	}
	*notBefore = psMalloc(pool, timeLen + 1);
	if (*notBefore == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memcpy(*notBefore, p, timeLen);
	(*notBefore)[timeLen] = '\0';
	p = p + timeLen;
	if ((end - p) < 1 || ((*p != ASN_UTCTIME) && (*p != ASN_GENERALIZEDTIME))) {
		return -1;
	}
	p++;
	if (asnParseLength(&p, seqLen - timeLen, &timeLen) < 0 || 
			(end - p) < timeLen) {
		return -1;
	}
	*notAfter = psMalloc(pool, timeLen + 1);
	if (*notAfter == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memcpy(*notAfter, p, timeLen);
	(*notAfter)[timeLen] = '\0';
	p = p + timeLen;

	*pp = p;
	return 0;
}
Пример #2
0
/*
	Get the BIT STRING key and plug into RSA structure.  Not included in
	asn1.c because it deals directly with the sslRsaKey_t struct.
*/
int32 getPubKey(psPool_t *pool, unsigned char **pp, int32 len, 
					 sslRsaKey_t *pubKey)
{
	unsigned char	*p = *pp;
	int32			pubKeyLen, ignore_bits, seqLen;

	if (len < 1 || (*(p++) != ASN_BIT_STRING) ||
			asnParseLength(&p, len - 1, &pubKeyLen) < 0 || 
			(len - 1) < pubKeyLen) {
		return -1;
	}
	
	ignore_bits = *p++;
/*
	We assume this is always zero
*/
	sslAssert(ignore_bits == 0);

	if (getSequence(&p, pubKeyLen, &seqLen) < 0 ||
			getBig(pool, &p, seqLen, &pubKey->N) < 0 ||
			getBig(pool, &p, seqLen, &pubKey->e) < 0) {
		return -1;
	}
	pubKey->size = mp_unsigned_bin_size(&pubKey->N);

	*pp = p;
	return 0;
}
Пример #3
0
/*
	Could be optional.  If the tag doesn't contain the value from the left
	of the IMPLICIT keyword we don't have a match and we don't incr the pointer.
*/
int32 getImplicitBitString(psPool_t *pool, unsigned char **pp, int32 len, 
						int32 impVal, unsigned char **bitString, int32 *bitLen)
{
	unsigned char	*p = *pp;
	int32			ignore_bits;

	if (len < 1) {
		return -1;
	}
/*
	We don't treat this case as an error, because of the optional nature.
*/	
	if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | impVal)) {
		return 0;
	}

	p++;
	if (asnParseLength(&p, len, bitLen) < 0) {
		return -1;
	}
	ignore_bits = *p++;
	sslAssert(ignore_bits == 0);

	*bitString = psMalloc(pool, *bitLen);
	if (*bitString == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memcpy(*bitString, p, *bitLen);
	*pp = p + *bitLen;
	return 0;
}
Пример #4
0
/*
	Currently just returning the raw BIT STRING and size in bytes
*/
int32 getSignature(psPool_t *pool, unsigned char **pp, int32 len,
						unsigned char **sig, int32 *sigLen)
{
	unsigned char	*p = *pp, *end;
	int32			ignore_bits, llen;
	
	end = p + len;
	if (len < 1 || (*(p++) != ASN_BIT_STRING) ||
			asnParseLength(&p, len - 1, &llen) < 0 || (end - p) < llen) {
		return -1;
	}
	ignore_bits = *p++;
/*
	We assume this is always 0.
*/
	sslAssert(ignore_bits == 0);
/*
	Length included the ignore_bits byte
*/
	*sigLen = llen - 1;
	*sig = psMalloc(pool, *sigLen);
	if (*sig == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memcpy(*sig, p, *sigLen);
	*pp = p + *sigLen;
	return 0;
}
Пример #5
0
/*
	Explicit value encoding has an additional tag layer
*/
int32 getExplicitVersion(unsigned char **pp, int32 len, int32 expVal, int32 *val)
{
	unsigned char	*p = *pp;
	int32			exLen;

	if (len < 1) {
		return -1;
	}
/*
	This is an optional value, so don't error if not present.  The default
	value is version 1
*/	
	if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | expVal)) {
		*val = 0;
		return 0;
	}
	p++;
	if (asnParseLength(&p, len - 1, &exLen) < 0 || (len - 1) < exLen) {
		return -1;
	}
	if (getInteger(&p, exLen, val) < 0) {
		return -1;
	}
	*pp = p;
	return 0;
}
Пример #6
0
/*
	Although a certificate serial number is encoded as an integer type, that
	doesn't prevent it from being abused as containing a variable length
	binary value.  Get it here.
*/	
int32 getSerialNum(psPool_t *pool, unsigned char **pp, int32 len, 
						unsigned char **sn, int32 *snLen)
{
	unsigned char	*p = *pp;
	int32			vlen;

	if ((*p != (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) &&
			(*p != ASN_INTEGER)) {
		matrixStrDebugMsg("ASN getSerialNumber failed\n", NULL);
		return -1;
	}
	p++;

	if (len < 1 || asnParseLength(&p, len - 1, &vlen) < 0) {
		matrixStrDebugMsg("ASN getSerialNumber failed\n", NULL);
		return -1;
	}
	*snLen = vlen;
	*sn = psMalloc(pool, vlen);
	if (*sn == NULL) {
		return -8; /* SSL_MEM_ERROR */
	}
	memcpy(*sn, p, vlen);
	p += vlen;
	*pp = p;
	return 0;
}
Пример #7
0
/*
	Implementation specific OID parser for suppported RSA algorithms
*/
int32 getAlgorithmIdentifier(unsigned char **pp, int32 len, int32 *oi,
								  int32 isPubKey)
{
	unsigned char	*p = *pp, *end;
	int32			arcLen, llen;

	end = p + len;
	if (len < 1 || getSequence(&p, len, &llen) < 0) {
		return -1;
	}
	if (end - p < 1) {
		return -1;
	}
	if (*(p++) != ASN_OID || asnParseLength(&p, (int32)(end - p), &arcLen) < 0 ||
			llen < arcLen) {
		return -1;
	}
/*
	List of expected (currently supported) OIDs
	algorithm				  summed	length		hex
	sha1						 88		05		2b0e03021a
	md2							646		08		2a864886f70d0202
	md5							649		08		2a864886f70d0205
	rsaEncryption				645		09		2a864886f70d010101
	md2WithRSAEncryption:		646		09		2a864886f70d010102
	md5WithRSAEncryption		648		09		2a864886f70d010104
	sha-1WithRSAEncryption		649		09		2a864886f70d010105

	Yes, the summing isn't ideal (as can be seen with the duplicate 649),
	but the specific implementation makes this ok.
*/
	if (end - p < 2) {
		return -1;
	}
	if (isPubKey && (*p != 0x2a) && (*(p + 1) != 0x86)) {
/*
		Expecting DSA here if not RSA, but OID doesn't always match
*/
		matrixStrDebugMsg("Unsupported algorithm identifier\n", NULL);
		return -1;
	}
	*oi = 0;
	while (arcLen-- > 0) {
		*oi += (int32)*p++;
	}
/*
	Each of these cases might have a trailing NULL parameter.  Skip it
*/
	if (*p != ASN_NULL) {
		*pp = p;
		return 0;
	}
	if (end - p < 2) {
		return -1;
	}
	*pp = p + 2;
	return 0;
}
Пример #8
0
/*
	Extract a set length from the DER stream
*/
int32 getSet(unsigned char **pp, int32 len, int32 *setlen)
{
	unsigned char	*p = *pp;

	if (len < 1 || *(p++) != (ASN_SET | ASN_CONSTRUCTED) || 
			asnParseLength(&p, len - 1, setlen) < 0 || len < *setlen) {
		return -1;
	}
	*pp = p;
	return 0;
}
Пример #9
0
/*
	Do the signature validation for a subject certificate against a
	known CA certificate
*/
int32 psAsnConfirmSignature(unsigned char *sigHash, unsigned char *sigOut,
							int32 sigLen)
{
	unsigned char	*end, *p = sigOut;
	unsigned char	hash[SSL_SHA1_HASH_SIZE];
	int32			len, oi;

	end = p + sigLen;
/*
	DigestInfo ::= SEQUENCE {
		digestAlgorithm DigestAlgorithmIdentifier,
		digest Digest }

	DigestAlgorithmIdentifier ::= AlgorithmIdentifier

	Digest ::= OCTET STRING
*/
	if (getSequence(&p, (int32)(end - p), &len) < 0) {
		return -1;
	}

/*
	Could be MD5 or SHA1
 */
	if (getAlgorithmIdentifier(&p, (int32)(end - p), &oi, 0) < 0) {
		return -1;
	}
	if ((*p++ != ASN_OCTET_STRING) ||
			asnParseLength(&p, (int32)(end - p), &len) < 0 || (end - p) <  len) {
		return -1;
	}
	memcpy(hash, p, len);
	if (oi == OID_MD5 || oi == OID_MD2) {
		if (len != SSL_MD5_HASH_SIZE) {
			return -1;
		}
	} else if (oi == OID_SHA1) {
		if (len != SSL_SHA1_HASH_SIZE) {
			return -1;
		}
	} else {
		return -1;
	}
/*
	hash should match sigHash
*/
	if (memcmp(hash, sigHash, len) != 0) {
		return -1;
	}
	return 0;
}
Пример #10
0
/*
	Get an integer
*/
int32 getInteger(unsigned char **pp, int32 len, int32 *val)
{
	unsigned char	*p = *pp, *end;
	uint32			ui;
	int32			vlen;

	end = p + len;
	if (len < 1 || *(p++) != ASN_INTEGER ||
			asnParseLength(&p, len - 1, &vlen) < 0) {
		matrixStrDebugMsg("ASN getInteger failed\n", NULL);
		return -1;
	}
/*
	This check prevents us from having a big positive integer where the 
	high bit is set because it will be encoded as 5 bytes (with leading 
	blank byte).  If that is required, a getUnsigned routine should be used
*/
	if (vlen > sizeof(int32) || end - p < vlen) {
		matrixStrDebugMsg("ASN getInteger failed\n", NULL);
		return -1;
	}
	ui = 0;
/*
	If high bit is set, it's a negative integer, so perform the two's compliment
	Otherwise do a standard big endian read (most likely case for RSA)
*/
	if (*p & 0x80) {
		while (vlen-- > 0) {
			ui = (ui << 8) | (*p ^ 0xFF);
			p++;
		}
		vlen = (int32)ui;
		vlen++;
		vlen = -vlen;
		*val = vlen;
	} else {
		while (vlen-- > 0) {
			ui = (ui << 8) | *p;
			p++;
		}
		*val = (int32)ui;
	}
	*pp = p;
	return 0;
}
Пример #11
0
/*
	Callback to extract a big int32 (stream of bytes) from the DER stream
*/
int32 getBig(psPool_t *pool, unsigned char **pp, int32 len, mp_int *big)
{
	unsigned char	*p = *pp;
	int32			vlen;

	if (len < 1 || *(p++) != ASN_INTEGER ||
			asnParseLength(&p, len - 1, &vlen) < 0) {
		matrixStrDebugMsg("ASN getBig failed\n", NULL);
		return -1;
	}
	mp_init(pool, big);
	if (mp_read_unsigned_bin(big, p, vlen) != 0) {
		mp_clear(big);
		matrixStrDebugMsg("ASN getBig failed\n", NULL);
		return -1;
	}
	p += vlen;
	*pp = p;
	return 0;
}
Пример #12
0
/*
	X509v3 extensions
*/
static int32 getExplicitExtensions(psPool_t *pool, unsigned char **pp, 
								 int32 inlen, int32 expVal,
								 v3extensions_t *extensions)
{
	unsigned char		*p = *pp, *end;
	unsigned char		*extEnd, *extStart;
	int32				len, noid, tmpLen, critical, fullExtLen;
	unsigned char		oid[SSL_MD5_HASH_SIZE];
	sslMd5Context_t		md5ctx;

	end = p + inlen;
	if (inlen < 1) {
		return -1;
	}
/*
	Not treating this as an error because it is optional.
*/
	if (*p != (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | expVal)) {
		return 0;
	}
	p++;
	if (asnParseLength(&p, (int32)(end - p), &len) < 0 || (end - p) < len) {
		return -1;
	}
/*
	Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension

	Extension  ::=  SEQUENCE {
		extnID		OBJECT IDENTIFIER,
		extnValue	OCTET STRING	}
*/
	if (getSequence(&p, (int32)(end - p), &len) < 0) {
		return -1;
	}
	extEnd = p + len;
	while ((p != extEnd) && *p == (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
		if (getSequence(&p, (int32)(extEnd - p), &fullExtLen) < 0) {
			return -1;
		}
		extStart = p;
/*
		Conforming CAs MUST support key identifiers, basic constraints,
		key usage, and certificate policies extensions
	
		id-ce-authorityKeyIdentifier	OBJECT IDENTIFIER ::=	{ id-ce 35 }
		id-ce-basicConstraints			OBJECT IDENTIFIER ::=	{ id-ce 19 } 133
		id-ce-keyUsage					OBJECT IDENTIFIER ::=	{ id-ce 15 }
		id-ce-certificatePolicies		OBJECT IDENTIFIER ::=	{ id-ce 32 }
		id-ce-subjectAltName			OBJECT IDENTIFIER ::=	{ id-ce 17 }  131
*/
		if (extEnd - p < 1 || *p++ != ASN_OID) {
			return -1;
		}
		
		if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || 
				(extEnd - p) < len) {
			return -1;
		}
/*
		Send the OID through a digest to get the unique id
*/
		matrixMd5Init(&md5ctx);
		while (len-- > 0) {
			matrixMd5Update(&md5ctx, p, sizeof(char));
			p++;
		}
		matrixMd5Final(&md5ctx, oid);
		noid = lookupExt(oid);

/*
		Possible boolean value here for 'critical' id.  It's a failure if a
		critical extension is found that is not supported
*/
		critical = 0;
		if (*p == ASN_BOOLEAN) {
			p++;
			if (*p++ != 1) {
				matrixStrDebugMsg("Error parsing cert extension\n", NULL);
				return -1;
			}
			if (*p++ > 0) {
				critical = 1;
			}
		}
		if (extEnd - p < 1 || (*p++ != ASN_OCTET_STRING) ||
				asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || 
				extEnd - p < len) {
			matrixStrDebugMsg("Expecting OCTET STRING in ext parse\n", NULL);
			return -1;
		}

		switch (noid) {
/*
			 BasicConstraints ::= SEQUENCE {
				cA						BOOLEAN DEFAULT FALSE,
				pathLenConstraint		INTEGER (0..MAX) OPTIONAL }
*/
			case EXT_BASIC_CONSTRAINTS:
				if (getSequence(&p, (int32)(extEnd - p), &len) < 0) {
					return -1;
				}
/*
				"This goes against PKIX guidelines but some CAs do it and some
				software requires this to avoid interpreting an end user
				certificate as a CA."
					- OpenSSL certificate configuration doc

				basicConstraints=CA:FALSE
*/
				if (len == 0) {
					break;
				}
				if (extEnd - p < 3) {
					return -1;
				}
				if (*p++ != ASN_BOOLEAN) {
					return -1;
				}
				if (*p++ != 1) {
					return -1;
				}
				extensions->bc.ca = *p++;
/*
				Now need to check if there is a path constraint. Only makes
				sense if cA is true.  If it's missing, there is no limit to
				the cert path
*/
				if (*p == ASN_INTEGER) {
					if (getInteger(&p, (int32)(extEnd - p),
							&(extensions->bc.pathLenConstraint)) < 0) {
						return -1;
					}
				} else {
					extensions->bc.pathLenConstraint = -1;
				}
				break;
			case EXT_ALT_SUBJECT_NAME:
				if (getSequence(&p, (int32)(extEnd - p), &len) < 0) {
					return -1;
				}
/*
				Looking only for DNS, URI, and email here to support
				FQDN for Web clients

				FUTURE:  Support all subject alt name members
				GeneralName ::= CHOICE {
					otherName						[0]		OtherName,
					rfc822Name						[1]		IA5String,
					dNSName							[2]		IA5String,
					x400Address						[3]		ORAddress,
					directoryName					[4]		Name,
					ediPartyName					[5]		EDIPartyName,
					uniformResourceIdentifier		[6]		IA5String,
					iPAddress						[7]		OCTET STRING,
					registeredID					[8]		OBJECT IDENTIFIER }
*/
				while (len > 0) {
					if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) {
						p++;
						tmpLen = *p++;
						if (extEnd - p < tmpLen) {
							return -1;
						}
						extensions->san.dns = psMalloc(pool, tmpLen + 1);
						if (extensions->san.dns == NULL) {
							return -8; /* SSL_MEM_ERROR */
						}
						memset(extensions->san.dns, 0x0, tmpLen + 1);
						memcpy(extensions->san.dns, p, tmpLen);
					} else if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 6)) {
						p++;
						tmpLen = *p++;
						if (extEnd - p < tmpLen) {
							return -1;
						}
						extensions->san.uri = psMalloc(pool, tmpLen + 1);
						if (extensions->san.uri == NULL) {
							return -8; /* SSL_MEM_ERROR */
						}
						memset(extensions->san.uri, 0x0, tmpLen + 1);
						memcpy(extensions->san.uri, p, tmpLen);
					} else if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 1)) {
						p++;
						tmpLen = *p++;
						if (extEnd - p < tmpLen) {
							return -1;
						}
						extensions->san.email = psMalloc(pool, tmpLen + 1);
						if (extensions->san.email == NULL) {
							return -8; /* SSL_MEM_ERROR */
						}
						memset(extensions->san.email, 0x0, tmpLen + 1);
						memcpy(extensions->san.email, p, tmpLen);
					} else {
						matrixStrDebugMsg("Unsupported subjectAltName type.n",
							NULL);
						p++;
						tmpLen = *p++;
						if (extEnd - p < tmpLen) {
							return -1;
						}
					}
					p = p + tmpLen;
					len -= tmpLen + 2; /* the magic 2 is the type and length */
				}
				break;
#ifdef USE_FULL_CERT_PARSE
			case EXT_AUTH_KEY_ID:
/*
				AuthorityKeyIdentifier ::= SEQUENCE {
				keyIdentifier				[0] KeyIdentifier			OPTIONAL,
				authorityCertIssuer			[1] GeneralNames			OPTIONAL,
				authorityCertSerialNumber	[2] CertificateSerialNumber	OPTIONAL }

				KeyIdentifier ::= OCTET STRING
*/
				if (getSequence(&p, (int32)(extEnd - p), &len) < 0) {
					return -1;
				}
/*
				Have seen a cert that has a zero length ext here.  Let it pass.
*/
				if (len == 0) {
					break;
				}
/*
				All memebers are optional
*/
				if (*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 0)) {
					p++;
					if (asnParseLength(&p, (int32)(extEnd - p), 
							&extensions->ak.keyLen) < 0 ||
							extEnd - p < extensions->ak.keyLen) {
						return -1;
					}
					extensions->ak.keyId = psMalloc(pool, extensions->ak.keyLen);
					if (extensions->ak.keyId == NULL) {
						return -8; /* SSL_MEM_ERROR */
					}
					memcpy(extensions->ak.keyId, p, extensions->ak.keyLen);
					p = p + extensions->ak.keyLen;
				}
				if (*p == (ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED | 1)) {
					p++;
					if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 ||
							len < 1 || extEnd - p < len) {
						return -1;
					}
					if ((*p ^ ASN_CONTEXT_SPECIFIC ^ ASN_CONSTRUCTED) != 4) {
/*
						FUTURE: support other name types
						We are just dealing with DN formats here
*/
						matrixIntDebugMsg("Error auth key-id name type: %d\n",
							*p ^ ASN_CONTEXT_SPECIFIC ^ ASN_CONSTRUCTED);
						return -1;
					}
					p++;
					if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || 
							extEnd - p < len) {
						return -1;
					}
					if (getDNAttributes(pool, &p, (int32)(extEnd - p),
							&(extensions->ak.attribs)) < 0) {
						return -1;
					}
				}
				if ((*p == (ASN_CONTEXT_SPECIFIC | ASN_PRIMITIVE | 2)) ||
						(*p == ASN_INTEGER)){
/*
					Treat as a serial number (not a native INTEGER)
*/
					if (getSerialNum(pool, &p, (int32)(extEnd - p),
							&(extensions->ak.serialNum), &len) < 0) {
						return -1;
					}
					extensions->ak.serialNumLen = len;
				}
				break;

			case EXT_KEY_USAGE:
/*
				KeyUsage ::= BIT STRING {
					digitalSignature		(0),
					nonRepudiation			(1),
					keyEncipherment			(2),
					dataEncipherment		(3),
					keyAgreement			(4),
					keyCertSign				(5),

					cRLSign					(6),
					encipherOnly			(7),
					decipherOnly			(8) }
*/
				if (*p++ != ASN_BIT_STRING) {
					return -1;
				}
				if (asnParseLength(&p, (int32)(extEnd - p), &len) < 0 || 
						extEnd - p < len) {
					return -1;
				}
				if (len != 2) {
					return -1;
				}
/*
				Assure all unused bits are 0 and store away
*/
				extensions->keyUsage = (*(p + 1)) & ~((1 << *p) -1);
				p = p + len;
				break;
			case EXT_SUBJ_KEY_ID:
/*
				The value of the subject key identifier MUST be the value
				placed in the key identifier field of the Auth Key Identifier
				extension of certificates issued by the subject of
				this certificate.
*/
				if (*p++ != ASN_OCTET_STRING || asnParseLength(&p,
						(int32)(extEnd - p), &(extensions->sk.len)) < 0 ||
						extEnd - p < extensions->sk.len) {
					return -1;
				}
				extensions->sk.id = psMalloc(pool, extensions->sk.len);
				if (extensions->sk.id == NULL) {
					return -8; /* SSL_MEM_ERROR */
				}
				memcpy(extensions->sk.id, p, extensions->sk.len);
				p = p + extensions->sk.len;
				break;
#endif /* USE_FULL_CERT_PARSE */
/*
			Unsupported or skipping because USE_FULL_CERT_PARSE is undefined
*/
			default:
				if (critical) {
/*
					SPEC DIFFERENCE:  Ignoring an unrecognized critical
					extension.  The specification dictates an error should
					occur, but real-world experience has shown this is not
					a realistic or desirable action.  Also, no other SSL
					implementations have been found to error in this case.
					It is NOT a security risk in an RSA authenticaion sense.
*/
					matrixStrDebugMsg("Unknown critical ext encountered\n",
						NULL);
				}
				p++;
/*
				Skip over based on the length reported from the ASN_SEQUENCE
				surrounding the entire extension.  It is not a guarantee that
				the value of the extension itself will contain it's own length.
*/
				p = p + (fullExtLen - (p - extStart));
				break;
		}
	}
	*pp = p;
	return 0;
}
Пример #13
0
/*
	Implementations of this specification MUST be prepared to receive
	the following standard attribute types in issuer names:
	country, organization, organizational-unit, distinguished name qualifier,
	state or province name, and common name 
*/
int32 getDNAttributes(psPool_t *pool, unsigned char **pp, int32 len, 
						   DNattributes_t *attribs)
{
	sslSha1Context_t	hash;
	unsigned char		*p = *pp;
	unsigned char		*dnEnd, *dnStart;
	int32				llen, setlen, arcLen, id, stringType;
	char				*stringOut;

	dnStart = p;
	if (getSequence(&p, len, &llen) < 0) {
		return -1;
	}
	dnEnd = p + llen;

	matrixSha1Init(&hash);
	while (p < dnEnd) {
		if (getSet(&p, (int32)(dnEnd - p), &setlen) < 0) {
			return -1;
		}
		if (getSequence(&p, (int32)(dnEnd - p), &llen) < 0) {
			return -1;
		}
		if (dnEnd <= p || (*(p++) != ASN_OID) ||
				asnParseLength(&p, (int32)(dnEnd - p), &arcLen) < 0 || 
				(dnEnd - p) < arcLen) {
			return -1;
		}
/*
		id-at   OBJECT IDENTIFIER       ::=     {joint-iso-ccitt(2) ds(5) 4}
		id-at-commonName		OBJECT IDENTIFIER		::=		{id-at 3}
		id-at-countryName		OBJECT IDENTIFIER		::=		{id-at 6}
		id-at-localityName		OBJECT IDENTIFIER		::=		{id-at 7}
		id-at-stateOrProvinceName		OBJECT IDENTIFIER	::=	{id-at 8}
		id-at-organizationName			OBJECT IDENTIFIER	::=	{id-at 10}
		id-at-organizationalUnitName	OBJECT IDENTIFIER	::=	{id-at 11}
*/
		*pp = p;
/*
		FUTURE: Currently skipping OIDs not of type {joint-iso-ccitt(2) ds(5) 4}
		However, we could be dealing with an OID we MUST support per RFC.
		domainComponent is one such example.
*/
		if (dnEnd - p < 2) {
			return -1;
		}
		if ((*p++ != 85) || (*p++ != 4) ) {
			p = *pp;
/*
			Move past the OID and string type, get data size, and skip it.
			NOTE: Have had problems parsing older certs in this area.
*/
			if (dnEnd - p < arcLen + 1) {
				return -1;
			}
			p += arcLen + 1;
			if (asnParseLength(&p, (int32)(dnEnd - p), &llen) < 0 || 
					dnEnd - p < llen) {
				return -1;
			}
			p = p + llen;
			continue;
		}
/*
		Next are the id of the attribute type and the ASN string type
*/
		if (arcLen != 3 || dnEnd - p < 2) {
			return -1;
		}
		id = (int32)*p++;
/*
		Done with OID parsing
*/
		stringType = (int32)*p++;

		asnParseLength(&p, (int32)(dnEnd - p), &llen);
		if (dnEnd - p < llen) {
			return -1;
		}
		switch (stringType) {
			case ASN_PRINTABLESTRING:
			case ASN_UTF8STRING:
			case ASN_IA5STRING:
			case ASN_T61STRING:
			case ASN_BMPSTRING:
				stringOut = psMalloc(pool, llen + 1);
				if (stringOut == NULL) {
					return -8; /* SSL_MEM_ERROR */
				}
				memcpy(stringOut, p, llen);
				stringOut[llen] = '\0';
				p = p + llen;
				break;
			default:
				matrixStrDebugMsg("Parsing untested DN attrib type\n", NULL);
				return -1;
		}

		switch (id) {
			case ATTRIB_COUNTRY_NAME:
				if (attribs->country) {
					psFree(attribs->country);
				}
				attribs->country = stringOut;
				break;
			case ATTRIB_STATE_PROVINCE:
				if (attribs->state) {
					psFree(attribs->state);
				}
				attribs->state = stringOut;
				break;
			case ATTRIB_LOCALITY:
				if (attribs->locality) {
					psFree(attribs->locality);
				}
				attribs->locality = stringOut;
				break;
			case ATTRIB_ORGANIZATION:
				if (attribs->organization) {
					psFree(attribs->organization);
				}
				attribs->organization = stringOut;
				break;
			case ATTRIB_ORG_UNIT:
				if (attribs->orgUnit) {
					psFree(attribs->orgUnit);
				}
				attribs->orgUnit = stringOut;
				break;
			case ATTRIB_COMMON_NAME:
				if (attribs->commonName) {
					psFree(attribs->commonName);
				}
				attribs->commonName = stringOut;
				break;
/*
			Not a MUST support
*/
			default:
				psFree(stringOut);
				stringOut = NULL;
				break;
		}
/*
		Hash up the DN.  Nice for validation later
*/
		if (stringOut != NULL) {
			matrixSha1Update(&hash, (unsigned char*)stringOut, llen);
		}
	}
	matrixSha1Final(&hash, (unsigned char*)attribs->hash);
	*pp = p;
	return 0;
}