The diff below has three independent parts which I intend to commit
separately. It does not change anything.

In op_thumbprint() use EVP_Digest() for simplicity. The conversion
is straightforward and it's an obvious win.

The second part converts EVP_Sign*() usage to EVP_DigestSign(). This is
a bit more ergonomic, in particular it allows us to allocate the exact
amount needed, rather than some mysterious estimate from EVP_PKEY_size().

The third part (the last hunk) is the most interesting bit. We can
simplify this using API that wasn't available at the time this was
written.

1. bn_len can be determined with EVP_PKEY_bits(). This uses the
   group order internally, which is more correct for signatures
   than the degree, even if it works out to the same number 48.
   Move this a bit down to when it's needed.

2. Use the saner API ECDSA_SIG_get0_{r,s}() which is less error
   prone than ECDSA_SIG_get0().

3. Zero padding can be done with BN_bn2binpad() which is less
   fiddly than doing this by hand. Also, error check.

Index: acctproc.c
===================================================================
RCS file: /cvs/src/usr.sbin/acme-client/acctproc.c,v
retrieving revision 1.24
diff -u -p -r1.24 acctproc.c
--- acctproc.c  14 Dec 2022 15:02:43 -0000      1.24
+++ acctproc.c  15 Dec 2022 06:13:36 -0000
@@ -133,8 +133,7 @@ static int
 op_thumbprint(int fd, EVP_PKEY *pkey)
 {
        char            *thumb = NULL, *dig64 = NULL;
-       EVP_MD_CTX      *ctx = NULL;
-       unsigned char   *dig = NULL;
+       unsigned char    dig[EVP_MAX_MD_SIZE];
        unsigned int     digsz;
        int              rc = 0;
 
@@ -161,32 +160,21 @@ op_thumbprint(int fd, EVP_PKEY *pkey)
         * it up in the read loop).
         */
 
-       if ((dig = malloc(EVP_MAX_MD_SIZE)) == NULL) {
-               warn("malloc");
-               goto out;
-       } else if ((ctx = EVP_MD_CTX_new()) == NULL) {
-               warnx("EVP_MD_CTX_new");
-               goto out;
-       } else if (!EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) {
-               warnx("EVP_SignInit_ex");
+       if (!EVP_Digest(thumb, strlen(thumb), dig, &digsz, EVP_sha256(),
+           NULL)) {
+               warnx("EVP_Digest");
                goto out;
-       } else if (!EVP_DigestUpdate(ctx, thumb, strlen(thumb))) {
-               warnx("EVP_SignUpdate");
-               goto out;
-       } else if (!EVP_DigestFinal_ex(ctx, dig, &digsz)) {
-               warnx("EVP_SignFinal");
-               goto out;
-       } else if ((dig64 = base64buf_url((char *)dig, digsz)) == NULL) {
+       }
+       if ((dig64 = base64buf_url((char *)dig, digsz)) == NULL) {
                warnx("base64buf_url");
                goto out;
-       } else if (writestr(fd, COMM_THUMB, dig64) < 0)
+       }
+       if (writestr(fd, COMM_THUMB, dig64) < 0)
                goto out;
 
        rc = 1;
 out:
-       EVP_MD_CTX_free(ctx);
        free(thumb);
-       free(dig);
        free(dig64);
        return rc;
 }
@@ -265,17 +253,16 @@ op_sign(int fd, EVP_PKEY *pkey, enum acc
 {
        EVP_MD_CTX              *ctx = NULL;
        const EVP_MD            *evp_md = NULL;
-       EC_KEY                  *ec;
        ECDSA_SIG               *ec_sig = NULL;
        const BIGNUM            *ec_sig_r = NULL, *ec_sig_s = NULL;
-       int                      cc, rc = 0;
-       unsigned int             digsz, bufsz, degree, bn_len, r_len, s_len;
+       int                      bn_len, cc, rc = 0;
        char                    *nonce = NULL, *pay = NULL, *pay64 = NULL;
        char                    *prot = NULL, *prot64 = NULL;
        char                    *sign = NULL, *dig64 = NULL, *fin = NULL;
        char                    *url = NULL, *kid = NULL, *alg = NULL;
-       unsigned char           *dig = NULL, *buf = NULL;
        const unsigned char     *digp;
+       unsigned char           *dig = NULL, *buf = NULL;
+       size_t                   digsz;
 
        /* Read our payload and nonce from the requestor. */
 
@@ -349,27 +336,28 @@ op_sign(int fd, EVP_PKEY *pkey, enum acc
                goto out;
        }
 
-       if ((dig = malloc(EVP_PKEY_size(pkey))) == NULL) {
-               warn("malloc");
-               goto out;
-       }
-
        /*
-        * Here we go: using our RSA key as merged into the envelope,
-        * sign a SHA256 digest of our message.
+        * Using the key as merged into the envelope, sign the message.
         */
 
        if ((ctx = EVP_MD_CTX_new()) == NULL) {
                warnx("EVP_MD_CTX_new");
                goto out;
-       } else if (!EVP_SignInit_ex(ctx, evp_md, NULL)) {
-               warnx("EVP_SignInit_ex");
+       }
+       if (!EVP_DigestSignInit(ctx, NULL, evp_md, NULL, pkey)) {
+               warnx("EVP_DigestSignInit");
+               goto out;
+       }
+       if (!EVP_DigestSign(ctx, NULL, &digsz, sign, cc)) {
+               warnx("EVP_DigestSign");
                goto out;
-       } else if (!EVP_SignUpdate(ctx, sign, strlen(sign))) {
-               warnx("EVP_SignUpdate");
+       }
+       if ((dig = malloc(digsz)) == NULL) {
+               warn("malloc");
                goto out;
-       } else if (!EVP_SignFinal(ctx, dig, &digsz, pkey)) {
-               warnx("EVP_SignFinal");
+       }
+       if (!EVP_DigestSign(ctx, dig, &digsz, sign, cc)) {
+               warnx("EVP_DigestSign");
                goto out;
        }
 
@@ -381,40 +369,35 @@ op_sign(int fd, EVP_PKEY *pkey, enum acc
                }
                break;
        case EVP_PKEY_EC:
-               if ((ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
-                       warnx("EVP_PKEY_get0_EC_KEY");
-                       goto out;
-               }
-               degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec));
-               bn_len = (degree + 7) / 8;
-
-               digp = dig; /* d2i_ECDSA_SIG advances digp */
+               digp = dig;
                if ((ec_sig = d2i_ECDSA_SIG(NULL, &digp, digsz)) == NULL) {
                        warnx("d2i_ECDSA_SIG");
                        goto out;
                }
 
-               ECDSA_SIG_get0(ec_sig, &ec_sig_r, &ec_sig_s);
-
-               r_len = BN_num_bytes(ec_sig_r);
-               s_len = BN_num_bytes(ec_sig_s);
-
-               if((r_len > bn_len) || (s_len > bn_len)) {
+               if ((ec_sig_r = ECDSA_SIG_get0_r(ec_sig)) == NULL ||
+                   (ec_sig_s = ECDSA_SIG_get0_s(ec_sig)) == NULL) {
                        warnx("ECDSA_SIG_get0");
                        goto out;
                }
 
-               bufsz = 2 * bn_len;
-               if ((buf = calloc(1, bufsz)) == NULL) {
+               if ((bn_len = (EVP_PKEY_bits(pkey) + 7) / 8) <= 0) {
+                       warnx("EVP_PKEY_bits");
+                       goto out;
+               }
+
+               if ((buf = calloc(2, bn_len)) == NULL) {
                        warnx("calloc");
                        goto out;
                }
 
-               /* put r and s in with leading zeros if any */
-               BN_bn2bin(ec_sig_r, buf + bn_len - r_len);
-               BN_bn2bin(ec_sig_s, buf + bufsz - s_len);
+               if (BN_bn2binpad(ec_sig_r, buf, bn_len) != bn_len ||
+                   BN_bn2binpad(ec_sig_s, buf + bn_len, bn_len) != bn_len) {
+                       warnx("BN_bn2binpad");
+                       goto out;
+               }
 
-               if ((dig64 = base64buf_url((char *)buf, bufsz)) == NULL) {
+               if ((dig64 = base64buf_url((char *)buf, 2 * bn_len)) == NULL) {
                        warnx("base64buf_url");
                        goto out;
                }

Reply via email to