📄 x509.c
字号:
*keys = lkeys = psMalloc(pool, sizeof(sslKeys_t));
if (lkeys == NULL) {
return -8; /* SSL_MEM_ERROR */
}
memset(lkeys, 0x0, sizeof(sslKeys_t));
/*
The buffers are just the ASN.1 streams so the intermediate parse
that used to be here is gone. Doing a straight memcpy for this
and passing that along to X509ParseCert
*/
lkeys->cert.certBin = psMalloc(pool, certLen);
memcpy(lkeys->cert.certBin, certBuf, certLen);
lkeys->cert.certLen = certLen;
if (matrixRsaParsePrivKey(pool, privBuf, privLen, &lkeys->cert.privKey) < 0) {
matrixStrDebugMsg("Error reading private key mem\n", NULL);
matrixRsaFreeKeys(lkeys);
return -1;
}
#ifdef USE_CLIENT_SIDE_SSL
if (trustedCABuf != NULL && trustedCALen > 0) {
if (matrixX509ParseCert(pool, trustedCABuf, trustedCALen,
&lkeys->caCerts) < 0) {
matrixStrDebugMsg("Error parsing CA cert\n", NULL);
matrixRsaFreeKeys(lkeys);
return -1;
}
}
#endif /* USE_CLIENT_SIDE_SSL */
return 0;
}
/******************************************************************************/
/*
In-memory version of matrixX509ReadPubKey.
This function was written strictly for clarity in the PeerSec crypto API
subset. It extracts only the public key from a certificate file for use
in the lower level encrypt/decrypt RSA routines.
*/
int32 matrixX509ParsePubKey(psPool_t *pool, char *certBuf, int32 certLen,
sslRsaKey_t **key)
{
sslRsaKey_t *lkey;
sslRsaCert_t *certStruct;
int32 err;
if (matrixX509ParseCert(pool, certBuf, certLen, &certStruct) < 0) {
matrixX509FreeCert(certStruct);
return -1;
}
lkey = *key = psMalloc(pool, sizeof(sslRsaKey_t));
memset(lkey, 0x0, sizeof(sslRsaKey_t));
if ((err = _mp_init_multi(pool, &lkey->e, &lkey->N, NULL,
NULL, NULL, NULL, NULL, NULL)) != MP_OKAY) {
matrixX509FreeCert(certStruct);
psFree(lkey);
return err;
}
mp_copy(&certStruct->publicKey.e, &lkey->e);
mp_copy(&certStruct->publicKey.N, &lkey->N);
mp_shrink(&lkey->e);
mp_shrink(&lkey->N);
lkey->size = certStruct->publicKey.size;
matrixX509FreeCert(certStruct);
return 0;
}
/******************************************************************************/
/*
Parse an X509 ASN.1 certificate stream
http://www.faqs.org/rfcs/rfc2459.html section 4.1
*/
int32 matrixX509ParseCert(psPool_t *pool, unsigned char *pp, int32 size,
sslRsaCert_t **outcert)
{
sslRsaCert_t *cert;
sslMd5Context_t md5Ctx;
sslSha1Context_t sha1Ctx;
unsigned char *p, *end, *certStart, *certEnd;
int32 certLen, len, parsing;
#ifdef USE_MD2
sslMd2Context_t md2Ctx;
#endif /* USE_MD2 */
/*
Allocate the cert structure right away. User MUST always call
matrixX509FreeCert regardless of whether this function succeeds.
memset is important because the test for NULL is what is used
to determine what to free
*/
*outcert = cert = psMalloc(pool, sizeof(sslRsaCert_t));
if (cert == NULL) {
return -8; /* SSL_MEM_ERROR */
}
memset(cert, '\0', sizeof(sslRsaCert_t));
p = pp;
end = p + size;
/*
Certificate ::= SEQUENCE {
tbsCertificate TBSCertificate,
signatureAlgorithm AlgorithmIdentifier,
signatureValue BIT STRING }
*/
parsing = 1;
while (parsing) {
if (getSequence(&p, (int32)(end - p), &len) < 0) {
matrixStrDebugMsg("Initial cert parse error\n", NULL);
return -1;
}
certStart = p;
/*
TBSCertificate ::= SEQUENCE {
version [0] EXPLICIT Version DEFAULT v1,
serialNumber CertificateSerialNumber,
signature AlgorithmIdentifier,
issuer Name,
validity Validity,
subject Name,
subjectPublicKeyInfo SubjectPublicKeyInfo,
issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version shall be v2 or v3
subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
-- If present, version shall be v2 or v3
extensions [3] EXPLICIT Extensions OPTIONAL
-- If present, version shall be v3 }
*/
if (getSequence(&p, (int32)(end - p), &len) < 0) {
matrixStrDebugMsg("ASN sequence parse error\n", NULL);
return -1;
}
certEnd = p + len;
certLen = (int32)(certEnd - certStart);
/*
Version ::= INTEGER { v1(0), v2(1), v3(2) }
*/
if (getExplicitVersion(&p, (int32)(end - p), 0, &cert->version) < 0) {
matrixStrDebugMsg("ASN version parse error\n", NULL);
return -1;
}
if (cert->version != 2) {
matrixIntDebugMsg("Warning: non-v3 certificate version: %d\n",
cert->version);
}
/*
CertificateSerialNumber ::= INTEGER
*/
if (getSerialNum(pool, &p, (int32)(end - p), &cert->serialNumber,
&cert->serialNumberLen) < 0) {
matrixStrDebugMsg("ASN serial number parse error\n", NULL);
return -1;
}
/*
AlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER,
parameters ANY DEFINED BY algorithm OPTIONAL }
*/
if (getAlgorithmIdentifier(&p, (int32)(end - p),
&cert->certAlgorithm, 0) < 0) {
return -1;
}
/*
Name ::= CHOICE {
RDNSequence }
RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
AttributeTypeAndValue ::= SEQUENCE {
type AttributeType,
value AttributeValue }
AttributeType ::= OBJECT IDENTIFIER
AttributeValue ::= ANY DEFINED BY AttributeType
*/
if (getDNAttributes(pool, &p, (int32)(end - p), &cert->issuer) < 0) {
return -1;
}
/*
Validity ::= SEQUENCE {
notBefore Time,
notAfter Time }
*/
if (getValidity(pool, &p, (int32)(end - p), &cert->notBefore,
&cert->notAfter) < 0) {
return -1;
}
/*
Subject DN
*/
if (getDNAttributes(pool, &p, (int32)(end - p), &cert->subject) < 0) {
return -1;
}
/*
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
*/
if (getSequence(&p, (int32)(end - p), &len) < 0) {
return -1;
}
if (getAlgorithmIdentifier(&p, (int32)(end - p),
&cert->pubKeyAlgorithm, 1) < 0) {
return -1;
}
if (getPubKey(pool, &p, (int32)(end - p), &cert->publicKey) < 0) {
return -1;
}
/*
As the next three values are optional, we can do a specific test here
*/
if (*p != (ASN_SEQUENCE | ASN_CONSTRUCTED)) {
if (getImplicitBitString(pool, &p, (int32)(end - p), IMPLICIT_ISSUER_ID,
&cert->uniqueUserId, &cert->uniqueUserIdLen) < 0 ||
getImplicitBitString(pool, &p, (int32)(end - p), IMPLICIT_SUBJECT_ID,
&cert->uniqueSubjectId, &cert->uniqueSubjectIdLen) < 0 ||
getExplicitExtensions(pool, &p, (int32)(end - p), EXPLICIT_EXTENSION,
&cert->extensions) < 0) {
return -1;
}
}
/*
This is the end of the cert. Do a check here to be certain
*/
if (certEnd != p) {
return -1;
}
/*
Certificate signature info
*/
if (getAlgorithmIdentifier(&p, (int32)(end - p),
&cert->sigAlgorithm, 0) < 0) {
return -1;
}
/*
Signature algorithm must match that specified in TBS cert
*/
if (cert->certAlgorithm != cert->sigAlgorithm) {
matrixStrDebugMsg("Parse error: mismatched signature type\n", NULL);
return -1;
}
/*
Compute the hash of the cert here for CA validation
*/
if (cert->certAlgorithm == OID_RSA_MD5) {
matrixMd5Init(&md5Ctx);
matrixMd5Update(&md5Ctx, certStart, certLen);
matrixMd5Final(&md5Ctx, cert->sigHash);
} else if (cert->certAlgorithm == OID_RSA_SHA1) {
matrixSha1Init(&sha1Ctx);
matrixSha1Update(&sha1Ctx, certStart, certLen);
matrixSha1Final(&sha1Ctx, cert->sigHash);
}
#ifdef USE_MD2
else if (cert->certAlgorithm == OID_RSA_MD2) {
matrixMd2Init(&md2Ctx);
matrixMd2Update(&md2Ctx, certStart, certLen);
matrixMd2Final(&md2Ctx, cert->sigHash);
}
#endif /* USE_MD2 */
if (getSignature(pool, &p, (int32)(end - p), &cert->signature,
&cert->signatureLen) < 0) {
return -1;
}
/*
The ability to parse additional chained certs is a PKI product
feature addition. Chaining in MatrixSSL is handled internally.
*/
if (p != end) {
cert->next = psMalloc(pool, sizeof(sslRsaCert_t));
cert = cert->next;
memset(cert, '\0', sizeof(sslRsaCert_t));
} else {
parsing = 0;
}
}
return (int32)(p - pp);
}
/******************************************************************************/
/*
User must call after all calls to matrixX509ParseCert
(we violate the coding standard a bit here for clarity)
*/
void matrixX509FreeCert(sslRsaCert_t *cert)
{
sslRsaCert_t *curr, *next;
curr = cert;
while (curr) {
psFreeDNStruct(&curr->issuer);
psFreeDNStruct(&curr->subject);
if (curr->serialNumber) psFree(curr->serialNumber);
if (curr->notBefore) psFree(curr->notBefore);
if (curr->notAfter) psFree(curr->notAfter);
if (curr->publicKey.N.dp) mp_clear(&(curr->publicKey.N));
if (curr->publicKey.e.dp) mp_clear(&(curr->publicKey.e));
if (curr->signature) psFree(curr->signature);
if (curr->uniqueUserId) psFree(curr->uniqueUserId);
if (curr->uniqueSubjectId) psFree(curr->uniqueSubjectId);
if (curr->extensions.san.dns) psFree(curr->extensions.san.dns);
if (curr->extensions.san.uri) psFree(curr->extensions.san.uri);
if (curr->extensions.san.email) psFree(curr->extensions.san.email);
#ifdef USE_FULL_CERT_PARSE
if (curr->extensions.sk.id) psFree(curr->extensions.sk.id);
if (curr->extensions.ak.keyId) psFree(curr->extensions.ak.keyId);
if (curr->extensions.ak.serialNum) psFree(curr->extensions.ak.serialNum);
if (curr->extensions.ak.attribs.commonName)
psFree(curr->extensions.ak.attribs.commonName);
if (curr->extensions.ak.attribs.country)
psFree(curr->extensions.ak.attribs.country);
if (curr->extensions.ak.attribs.state)
psFree(curr->extensions.ak.attribs.state);
if (curr->extensions.ak.attribs.locality)
psFree(curr->extensions.ak.attribs.locality);
if (curr->extensions.ak.attribs.organization)
psFree(curr->extensions.ak.attribs.organization);
if (curr->extensions.ak.attribs.orgUnit)
psFree(curr->extensions.ak.attribs.orgUnit);
#endif /* SSL_FULL_CERT_PARSE */
next = curr->next;
psFree(curr);
curr = next;
}
}
/******************************************************************************/
/*
Do the signature validation for a subject certificate against a
known CA certificate
*/
int32 psAsnConfirmSignature(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;
}
/******************************************************************************/
/*
Extension lookup
*/
static int32 lookupExt(char md5hash[SSL_MD5_HASH_SIZE])
{
int32 i, j;
const char *tmp;
for (i = 0; ;i++) {
if (extTable[i].id == -1) {
return -1;
}
tmp = extTable[i].hash;
for (j = 0; j < SSL_MD5_HASH_SIZE; j++) {
if (md5hash[j] != tmp[j]) {
break;
}
if (j == SSL_MD5_HASH_SIZE - 1) {
return extTable[i].id;
}
}
}
return -1;
}
/******************************************************************************/
/*
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;
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++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -