Add check for RSA key pair modulus & public exponent
authorjob <job@openbsd.org>
Mon, 6 Mar 2023 16:04:52 +0000 (16:04 +0000)
committerjob <job@openbsd.org>
Mon, 6 Mar 2023 16:04:52 +0000 (16:04 +0000)
Both the SPKI inside a CA's .cer TBS section and Signers wrapped in CMS
must be RSA, with mod 2048 & (e) 0x10001

OK tb@

usr.sbin/rpki-client/cert.c
usr.sbin/rpki-client/cms.c
usr.sbin/rpki-client/extern.h
usr.sbin/rpki-client/rpki-client.8
usr.sbin/rpki-client/validate.c

index 1a74911..7185fab 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cert.c,v 1.102 2023/02/21 10:18:47 tb Exp $ */
+/*     $OpenBSD: cert.c,v 1.103 2023/03/06 16:04:52 job Exp $ */
 /*
  * Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
  * Copyright (c) 2021 Job Snijders <job@openbsd.org>
@@ -648,6 +648,7 @@ cert_parse_pre(const char *fn, const unsigned char *der, size_t len)
        X509                    *x = NULL;
        X509_EXTENSION          *ext = NULL;
        ASN1_OBJECT             *obj;
+       EVP_PKEY                *pkey;
        struct parse             p;
 
        /* just fail for empty buffers, the warning was printed elsewhere */
@@ -747,6 +748,13 @@ cert_parse_pre(const char *fn, const unsigned char *der, size_t len)
 
        switch (p.res->purpose) {
        case CERT_PURPOSE_CA:
+               if ((pkey = X509_get0_pubkey(x)) == NULL) {
+                       warnx("%s: X509_get0_pubkey failed", p.fn);
+                       goto out;
+               }
+               if (!valid_ca_pkey(p.fn, pkey))
+                       goto out;
+
                if (X509_get_key_usage(x) != (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) {
                        warnx("%s: RFC 6487 section 4.8.4: key usage violation",
                            p.fn);
index 7e80109..752c7d1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cms.c,v 1.28 2023/03/06 09:14:29 job Exp $ */
+/*     $OpenBSD: cms.c,v 1.29 2023/03/06 16:04:52 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -76,6 +76,7 @@ cms_parse_validate_internal(X509 **xp, const char *fn, const unsigned char *der,
        STACK_OF(X509_CRL)              *crls;
        STACK_OF(CMS_SignerInfo)        *sinfos;
        CMS_SignerInfo                  *si;
+       EVP_PKEY                        *pkey;
        X509_ALGOR                      *pdig, *psig;
        int                              i, nattrs, nid;
        int                              has_ct = 0, has_md = 0, has_st = 0,
@@ -183,8 +184,11 @@ cms_parse_validate_internal(X509 **xp, const char *fn, const unsigned char *der,
                goto out;
        }
 
-       /* Check digest and signature algorithms */
-       CMS_SignerInfo_get0_algs(si, NULL, NULL, &pdig, &psig);
+       /* Check digest and signature algorithms (RFC 7935) */
+       CMS_SignerInfo_get0_algs(si, &pkey, NULL, &pdig, &psig);
+       if (!valid_ca_pkey(fn, pkey))
+               goto out;
+
        X509_ALGOR_get0(&obj, NULL, NULL, pdig);
        nid = OBJ_obj2nid(obj);
        if (nid != NID_sha256) {
index 9470d77..f331e5b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.167 2023/01/13 08:58:36 claudio Exp $ */
+/*     $OpenBSD: extern.h,v 1.168 2023/03/06 16:04:52 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -660,6 +660,7 @@ int          valid_econtent_version(const char *, const ASN1_INTEGER *);
 int             valid_aspa(const char *, struct cert *, struct aspa *);
 int             valid_geofeed(const char *, struct cert *, struct geofeed *);
 int             valid_uuid(const char *);
+int             valid_ca_pkey(const char *, EVP_PKEY *);
 
 /* Working with CMS. */
 unsigned char  *cms_parse_validate(X509 **, const char *,
index 76224b0..45d5bc4 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: rpki-client.8,v 1.90 2023/03/06 15:50:33 job Exp $
+.\"    $OpenBSD: rpki-client.8,v 1.91 2023/03/06 16:04:52 job Exp $
 .\"
 .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
 .\"
@@ -395,6 +395,16 @@ agreement regarding ARIN service restrictions.
 .Re
 .Pp
 .Rs
+.%T The Profile for Algorithms and Key Sizes for Use in the Resource Public Key Infrastructure
+.%R RFC 7935
+.%A Geoff Huston
+.%A George Michaelson
+.%U https://www.rfc-editor.org/rfc/rfc7935
+.%D Aug, 2016
+.%I IETF
+.Re
+.Pp
+.Rs
 .%T The RPKI Repository Delta Protocol (RRDP)
 .%R RFC 8182
 .%A Tim Bruijnzeels
index 223b9c5..d7ac327 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: validate.c,v 1.54 2023/01/18 18:12:20 job Exp $ */
+/*     $OpenBSD: validate.c,v 1.55 2023/03/06 16:04:52 job Exp $ */
 /*
  * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
  *
@@ -588,3 +588,44 @@ valid_uuid(const char *s)
        }
 }
 
+int
+valid_ca_pkey(const char *fn, EVP_PKEY *pkey)
+{
+       RSA             *rsa;
+       const BIGNUM    *rsa_e;
+       int              key_bits;
+
+       if (pkey == NULL) {
+               warnx("%s: failure, pkey is NULL", fn);
+               return 0;
+       }
+
+       if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
+               warnx("%s: Expected EVP_PKEY_RSA, got %d", fn,
+                   EVP_PKEY_base_id(pkey));
+               return 0;
+       }
+
+       if ((key_bits = EVP_PKEY_bits(pkey)) != 2048) {
+               warnx("%s: RFC 7935: expected 2048-bit modulus, got %d bits",
+                   fn, key_bits);
+               return 0;
+       }
+
+       if ((rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
+               warnx("%s: failed to extract RSA public key", fn);
+               return 0;
+       }
+
+       if ((rsa_e = RSA_get0_e(rsa)) == NULL) {
+               warnx("%s: failed to get RSA exponent", fn);
+               return 0;
+       }
+
+       if (!BN_is_word(rsa_e, 65537)) {
+               warnx("%s: incorrect exponent (e) in RSA public key", fn);
+               return 0;
+       }
+
+       return 1;
+}