aboutsummaryrefslogtreecommitdiffstats
path: root/src/pluto/x509.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pluto/x509.c')
-rw-r--r--src/pluto/x509.c350
1 files changed, 126 insertions, 224 deletions
diff --git a/src/pluto/x509.c b/src/pluto/x509.c
index 9a5714bc9..ca926a9b8 100644
--- a/src/pluto/x509.c
+++ b/src/pluto/x509.c
@@ -35,7 +35,6 @@
#include "mp_defs.h"
#include "log.h"
#include "id.h"
-#include "pkcs1.h"
#include "x509.h"
#include "crl.h"
#include "ca.h"
@@ -198,36 +197,33 @@ static const asn1Object_t pubkeyObjects[] = {
* ASN.1 definition of an X.509v3 x509_cert
*/
static const asn1Object_t certObjects[] = {
- { 0, "certificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
- { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
- { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
- { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
- { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
- { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
- { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
- { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
- { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
- { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
- { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
- { 2, "subjectPublicKeyInfo", ASN1_SEQUENCE, ASN1_NONE }, /* 11 */
- { 3, "algorithm", ASN1_EOC, ASN1_RAW }, /* 12 */
- { 3, "subjectPublicKey", ASN1_BIT_STRING, ASN1_BODY }, /* 13 */
- { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 14 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
- { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 16 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 17 */
- { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 18 */
- { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 19 */
- { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 20 */
- { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 21 */
- { 5, "critical", ASN1_BOOLEAN, ASN1_DEF |
- ASN1_BODY }, /* 22 */
- { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 23 */
- { 3, "end loop", ASN1_EOC, ASN1_END }, /* 24 */
- { 2, "end opt", ASN1_EOC, ASN1_END }, /* 25 */
- { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 26 */
- { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 27 */
- { 0, "exit", ASN1_EOC, ASN1_EXIT }
+ { 0, "x509", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
+ { 1, "tbsCertificate", ASN1_SEQUENCE, ASN1_OBJ }, /* 1 */
+ { 2, "DEFAULT v1", ASN1_CONTEXT_C_0, ASN1_DEF }, /* 2 */
+ { 3, "version", ASN1_INTEGER, ASN1_BODY }, /* 3 */
+ { 2, "serialNumber", ASN1_INTEGER, ASN1_BODY }, /* 4 */
+ { 2, "signature", ASN1_EOC, ASN1_RAW }, /* 5 */
+ { 2, "issuer", ASN1_SEQUENCE, ASN1_OBJ }, /* 6 */
+ { 2, "validity", ASN1_SEQUENCE, ASN1_NONE }, /* 7 */
+ { 3, "notBefore", ASN1_EOC, ASN1_RAW }, /* 8 */
+ { 3, "notAfter", ASN1_EOC, ASN1_RAW }, /* 9 */
+ { 2, "subject", ASN1_SEQUENCE, ASN1_OBJ }, /* 10 */
+ { 2, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_RAW }, /* 11 */
+ { 2, "issuerUniqueID", ASN1_CONTEXT_C_1, ASN1_OPT }, /* 12 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 13 */
+ { 2, "subjectUniqueID", ASN1_CONTEXT_C_2, ASN1_OPT }, /* 14 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 15 */
+ { 2, "optional extensions", ASN1_CONTEXT_C_3, ASN1_OPT }, /* 16 */
+ { 3, "extensions", ASN1_SEQUENCE, ASN1_LOOP }, /* 17 */
+ { 4, "extension", ASN1_SEQUENCE, ASN1_NONE }, /* 18 */
+ { 5, "extnID", ASN1_OID, ASN1_BODY }, /* 19 */
+ { 5, "critical", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 20 */
+ { 5, "extnValue", ASN1_OCTET_STRING, ASN1_BODY }, /* 21 */
+ { 3, "end loop", ASN1_EOC, ASN1_END }, /* 22 */
+ { 2, "end opt", ASN1_EOC, ASN1_END }, /* 23 */
+ { 1, "signatureAlgorithm", ASN1_EOC, ASN1_RAW }, /* 24 */
+ { 1, "signatureValue", ASN1_BIT_STRING, ASN1_BODY }, /* 25 */
+ { 0, "exit", ASN1_EOC, ASN1_EXIT }
};
#define X509_OBJ_CERTIFICATE 0
#define X509_OBJ_TBS_CERTIFICATE 1
@@ -238,13 +234,12 @@ static const asn1Object_t certObjects[] = {
#define X509_OBJ_NOT_BEFORE 8
#define X509_OBJ_NOT_AFTER 9
#define X509_OBJ_SUBJECT 10
-#define X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM 12
-#define X509_OBJ_SUBJECT_PUBLIC_KEY 13
-#define X509_OBJ_EXTN_ID 21
-#define X509_OBJ_CRITICAL 22
-#define X509_OBJ_EXTN_VALUE 23
-#define X509_OBJ_ALGORITHM 26
-#define X509_OBJ_SIGNATURE 27
+#define X509_OBJ_SUBJECT_PUBLIC_KEY_INFO 11
+#define X509_OBJ_EXTN_ID 19
+#define X509_OBJ_CRITICAL 20
+#define X509_OBJ_EXTN_VALUE 21
+#define X509_OBJ_ALGORITHM 24
+#define X509_OBJ_SIGNATURE 25
const x509cert_t empty_x509cert = {
NULL , /* *next */
@@ -262,11 +257,7 @@ const x509cert_t empty_x509cert = {
0 , /* notBefore */
0 , /* notAfter */
{ NULL, 0 } , /* subject */
- /* subjectPublicKeyInfo */
- OID_UNKNOWN , /* subjectPublicKeyAlgorithm */
- { NULL, 0 } , /* subjectPublicKey */
- { NULL, 0 } , /* modulus */
- { NULL, 0 } , /* publicExponent */
+ NULL , /* public_key */
/* issuerUniqueID */
/* subjectUniqueID */
/* extensions */
@@ -1140,13 +1131,19 @@ chunk_t build_subjectAltNames(generalName_t *subjectAltNames)
/**
* Build a to-be-signed X.509 certificate body
*/
-static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
+static chunk_t build_tbs_x509cert(x509cert_t *cert, public_key_t *rsa)
{
/* version is always X.509v3 */
chunk_t version = asn1_simple_object(ASN1_CONTEXT_C_0, ASN1_INTEGER_2);
chunk_t extensions = chunk_empty;
+ chunk_t key = rsa->get_encoding(rsa);
+
+ chunk_t keyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
+ asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
+ asn1_bitstring("m", key));
+
if (cert->subjectAltName != NULL)
{
extensions = asn1_wrap(ASN1_CONTEXT_C_3, "m"
@@ -1156,7 +1153,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
return asn1_wrap(ASN1_SEQUENCE, "mmccmcmm"
, version
- , asn1_simple_object(ASN1_INTEGER, cert->serialNumber)
+ , asn1_integer("c", cert->serialNumber)
, asn1_algorithmIdentifier(cert->sigAlg)
, cert->issuer
, asn1_wrap(ASN1_SEQUENCE, "mm"
@@ -1164,7 +1161,7 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
, asn1_from_time(&cert->notAfter, ASN1_UTCTIME)
)
, cert->subject
- , pkcs1_build_publicKeyInfo(rsa)
+ , keyInfo
, extensions
);
}
@@ -1172,13 +1169,13 @@ static chunk_t build_tbs_x509cert(x509cert_t *cert, const RSA_public_key_t *rsa)
/**
* Build a DER-encoded X.509 certificate
*/
-void build_x509cert(x509cert_t *cert, const RSA_public_key_t *cert_key,
- const RSA_private_key_t *signer_key)
+void build_x509cert(x509cert_t *cert, public_key_t *cert_key,
+ private_key_t *signer_key)
{
chunk_t tbs_cert = build_tbs_x509cert(cert, cert_key);
- chunk_t signature = pkcs1_build_signature(tbs_cert, cert->sigAlg
- , signer_key, TRUE);
+ chunk_t signature = x509_build_signature(tbs_cert, cert->sigAlg
+ , signer_key, TRUE);
cert->certificate = asn1_wrap(ASN1_SEQUENCE, "mcm"
, tbs_cert
@@ -1210,6 +1207,7 @@ void free_x509cert(x509cert_t *cert)
{
if (cert != NULL)
{
+ DESTROY_IF(cert->public_key);
free_generalNames(cert->subjectAltName, FALSE);
free_generalNames(cert->crlDistributionPoints, FALSE);
free(cert->certificate.ptr);
@@ -1318,111 +1316,75 @@ void store_x509certs(x509cert_t **firstcert, bool strict)
}
/**
- * Decrypts an RSA signature using the issuer's certificate
+ * Check if a signature over binary blob is genuine
*/
-static bool decrypt_sig(chunk_t sig, int alg, const x509cert_t *issuer_cert,
- chunk_t *digest)
+bool x509_check_signature(chunk_t tbs, chunk_t sig, int algorithm,
+ const x509cert_t *issuer_cert)
{
- switch (alg)
- {
- chunk_t decrypted;
+ public_key_t *key = issuer_cert->public_key;
+ signature_scheme_t scheme = SIGN_DEFAULT;
- case OID_RSA_ENCRYPTION:
- case OID_MD2_WITH_RSA:
+ switch (algorithm)
+ {
case OID_MD5_WITH_RSA:
+ scheme = SIGN_RSA_EMSA_PKCS1_MD5;
+ break;
case OID_SHA1_WITH_RSA:
- case OID_SHA1_WITH_RSA_OIW:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ break;
case OID_SHA256_WITH_RSA:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
+ break;
case OID_SHA384_WITH_RSA:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
+ break;
case OID_SHA512_WITH_RSA:
- {
- mpz_t s;
- RSA_public_key_t rsa;
-
- init_RSA_public_key(&rsa, issuer_cert->publicExponent
- , issuer_cert->modulus);
-
- /* decrypt the signature s = s^e mod n */
- n_to_mpz(s, sig.ptr, sig.len);
- mpz_powm(s, s, &rsa.e, &rsa.n);
-
- /* convert back to bytes */
- decrypted = mpz_to_n(s, rsa.k);
- DBG(DBG_PARSING,
- DBG_dump_chunk(" decrypted signature: ", decrypted)
- )
-
- /* copy the least significant bits of decrypted signature
- * into the digest string
- */
- memcpy(digest->ptr, decrypted.ptr + decrypted.len - digest->len,
- digest->len);
-
- /* free memory */
- free_RSA_public_content(&rsa);
- free(decrypted.ptr);
- mpz_clear(s);
- return TRUE;
- }
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
+ break;
+ case OID_ECDSA_WITH_SHA1:
+ scheme = SIGN_ECDSA_WITH_SHA1;
+ break;
default:
- digest->len = 0;
return FALSE;
}
+ return key->verify(key, scheme, tbs, sig);
}
/**
- * Check if a signature over binary blob is genuine
+ * Build an ASN.1 encoded PKCS#1 signature over a binary blob
*/
-bool check_signature(chunk_t tbs, chunk_t sig, int digest_alg, int enc_alg,
- const x509cert_t *issuer_cert)
+chunk_t x509_build_signature(chunk_t tbs, int hash_alg, private_key_t *key,
+ bool bit_string)
{
- u_char digest_buf[MAX_DIGEST_LEN];
- u_char decrypted_buf[MAX_DIGEST_LEN];
- chunk_t digest = {digest_buf, MAX_DIGEST_LEN};
- chunk_t decrypted = {decrypted_buf, MAX_DIGEST_LEN};
-
- DBG(DBG_PARSING,
- if (digest_alg != OID_UNKNOWN)
- {
- DBG_log("signature digest algorithm: '%s'",oid_names[digest_alg].name);
- }
- else
- {
- DBG_log("unknown signature digest algorithm");
- }
- )
+ signature_scheme_t scheme = SIGN_DEFAULT;
+ chunk_t signature;
- if (!compute_digest(tbs, digest_alg, &digest))
+ switch (hash_alg)
{
- plog(" digest algorithm not supported");
- return FALSE;
+ case OID_MD5:
+ scheme = SIGN_RSA_EMSA_PKCS1_MD5;
+ break;
+ case OID_SHA1:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA1;
+ break;
+ case OID_SHA256:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA256;
+ break;
+ case OID_SHA384:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA384;
+ break;
+ case OID_SHA512:
+ scheme = SIGN_RSA_EMSA_PKCS1_SHA512;
+ break;
+ default:
+ return chunk_empty;
}
-
- DBG(DBG_PARSING,
- DBG_dump_chunk(" digest:", digest)
- )
-
- decrypted.len = digest.len; /* we want the same digest length */
-
- DBG(DBG_PARSING,
- if (enc_alg != OID_UNKNOWN)
- {
- DBG_log("signature encryption algorithm: '%s'",oid_names[enc_alg].name);
- }
- else
- {
- DBG_log("unknown signature encryption algorithm");
- }
- )
-
- if (!decrypt_sig(sig, enc_alg, issuer_cert, &decrypted))
+ if (!key->sign(key, scheme, tbs, &signature))
{
- plog(" decryption algorithm not supported");
- return FALSE;
- }
-
- /* check if digests are equal */
- return memeq(decrypted.ptr, digest.ptr, digest.len);
+ return chunk_empty;
+ }
+ return (bit_string) ? asn1_bitstring("m", signature)
+ : asn1_wrap(ASN1_OCTET_STRING, "m", signature);
}
/**
@@ -1489,15 +1451,17 @@ void gntoid(struct id *id, const generalName_t *gn)
*/
bool compute_subjectKeyID(x509cert_t *cert, chunk_t subjectKeyID)
{
- hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
+ identification_t *keyid;
+ chunk_t encoding;
- if (hasher == NULL)
+ keyid = cert->public_key->get_id(cert->public_key, ID_PUBKEY_SHA1);
+ if (keyid == NULL)
{
- plog(" no SHA-1 hasher available to compute subjectKeyID");
+ plog(" unable to compute subjectKeyID");
return FALSE;
}
- hasher->get_hash(hasher, cert->subjectPublicKey, subjectKeyID.ptr);
- hasher->destroy(hasher);
+ encoding = keyid->get_encoding(keyid);
+ memcpy(subjectKeyID.ptr, encoding.ptr, subjectKeyID.len);
return TRUE;
}
@@ -1825,50 +1789,6 @@ static generalName_t* parse_crlDistributionPoints(chunk_t blob, int level0)
}
/**
- * Parses an RSA public key
- */
-bool parse_RSA_public_key(chunk_t blob, u_int level0, x509cert_t *cert)
-{
- asn1_parser_t *parser;
- chunk_t object;
- int objectID;
- bool success = FALSE;
-
- parser = asn1_parser_create(pubkeyObjects, blob);
- parser->set_top_level(parser, level0);
-
- while (parser->iterate(parser, &objectID, &object))
- {
- switch (objectID) {
- case PUB_KEY_RSA_PUBLIC_KEY:
- cert->subjectPublicKey = object;
- break;
- case PUB_KEY_MODULUS:
- if (object.len < RSA_MIN_OCTETS + 1)
- {
- plog(" " RSA_MIN_OCTETS_UGH);
- goto end;
- }
- if (object.len > RSA_MAX_OCTETS + (size_t)(*object.ptr == 0x00))
- {
- plog(" " RSA_MAX_OCTETS_UGH);
- goto end;
- }
- cert->modulus = object;
- break;
- case PUB_KEY_EXPONENT:
- cert->publicExponent = object;
- break;
- }
- }
- success = parser->success(parser);
-
-end:
- parser->destroy(parser);
- return success;
-}
-
-/**
* Parses an X.509v3 certificate
*/
bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
@@ -1927,30 +1847,11 @@ bool parse_x509cert(chunk_t blob, u_int level0, x509cert_t *cert)
DBG_log(" '%s'",buf)
)
break;
- case X509_OBJ_SUBJECT_PUBLIC_KEY_ALGORITHM:
- if (asn1_parse_algorithmIdentifier(object, level, NULL) == OID_RSA_ENCRYPTION)
- {
- cert->subjectPublicKeyAlgorithm = PUBKEY_ALG_RSA;
- }
- else
- {
- plog(" unsupported public key algorithm");
- goto end;
- }
- break;
- case X509_OBJ_SUBJECT_PUBLIC_KEY:
- if (object.len > 0 && *object.ptr == 0x00)
- {
- /* skip initial bit string octet defining 0 unused bits */
- object = chunk_skip(object, 1);
- if (!parse_RSA_public_key(object, level, cert))
- {
- goto end;
- }
- }
- else
+ case X509_OBJ_SUBJECT_PUBLIC_KEY_INFO:
+ cert->public_key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY,
+ KEY_ANY, BUILD_BLOB_ASN1_DER, object, BUILD_END);
+ if (cert->public_key == NULL)
{
- plog(" invalid RSA public key format");
goto end;
}
break;
@@ -2116,8 +2017,8 @@ bool verify_x509cert(const x509cert_t *cert, bool strict, time_t *until)
DBG_log("issuer cacert found")
)
- if (!check_signature(cert->tbsCertificate, cert->signature
- , cert->algorithm, cert->algorithm, issuer_cert))
+ if (!x509_check_signature(cert->tbsCertificate, cert->signature,
+ cert->algorithm, issuer_cert))
{
plog("certificate signature is invalid");
unlock_authcert_list("verify_x509cert");
@@ -2220,9 +2121,8 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
{
if (auth_flags == AUTH_NONE || (auth_flags & cert->authority_flags))
{
- unsigned keysize;
- char keyid[KEYID_BUF];
u_char buf[BUF_LEN];
+ public_key_t *key = cert->public_key;
cert_t c;
c.type = CERT_X509_SIGNATURE;
@@ -2242,36 +2142,38 @@ void list_x509cert_chain(const char *caption, x509cert_t* cert,
whack_log(RC_COMMENT, " subject: '%s'", buf);
dntoa(buf, BUF_LEN, cert->issuer);
whack_log(RC_COMMENT, " issuer: '%s'", buf);
- datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':'
- , buf, BUF_LEN);
+ datatot(cert->serialNumber.ptr, cert->serialNumber.len, ':',
+ buf, BUF_LEN);
whack_log(RC_COMMENT, " serial: %s", buf);
- form_keyid(cert->publicExponent, cert->modulus, keyid, &keysize);
- whack_log(RC_COMMENT, " pubkey: %4d RSA Key %s%s"
- , 8*keysize, keyid
- , cert->smartcard ? ", on smartcard" :
- (has_private_key(c)? ", has private key" : ""));
whack_log(RC_COMMENT, " validity: not before %T %s",
&cert->notBefore, utc,
(cert->notBefore < now)?"ok":"fatal (not valid yet)");
whack_log(RC_COMMENT, " not after %T %s",
&cert->notAfter, utc,
check_expiry(cert->notAfter, CA_CERT_WARNING_INTERVAL, TRUE));
+ whack_log(RC_COMMENT, " pubkey: %N %4d bits%s",
+ key_type_names, key->get_type(key),
+ key->get_keysize(key) * BITS_PER_BYTE,
+ cert->smartcard ? ", on smartcard" :
+ (has_private_key(c)? ", has private key" : ""));
+ whack_log(RC_COMMENT, " keyid: %Y",
+ key->get_id(key, ID_PUBKEY_INFO_SHA1));
if (cert->subjectKeyID.ptr != NULL)
{
- datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':'
- , buf, BUF_LEN);
+ datatot(cert->subjectKeyID.ptr, cert->subjectKeyID.len, ':',
+ buf, BUF_LEN);
whack_log(RC_COMMENT, " subjkey: %s", buf);
}
if (cert->authKeyID.ptr != NULL)
{
- datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':'
- , buf, BUF_LEN);
+ datatot(cert->authKeyID.ptr, cert->authKeyID.len, ':',
+ buf, BUF_LEN);
whack_log(RC_COMMENT, " authkey: %s", buf);
}
if (cert->authKeySerialNumber.ptr != NULL)
{
- datatot(cert->authKeySerialNumber.ptr, cert->authKeySerialNumber.len
- , ':', buf, BUF_LEN);
+ datatot(cert->authKeySerialNumber.ptr,
+ cert->authKeySerialNumber.len, ':', buf, BUF_LEN);
whack_log(RC_COMMENT, " aserial: %s", buf);
}
}