[BACK]Return to ssh-ecdsa-sk.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/ssh-ecdsa-sk.c between version 1.6 and 1.7

version 1.6, 2020/06/22 05:56:23 version 1.7, 2020/06/22 05:58:35
Line 43 
Line 43 
 #define SSHKEY_INTERNAL  #define SSHKEY_INTERNAL
 #include "sshkey.h"  #include "sshkey.h"
   
   /*
    * Check FIDO/W3C webauthn signatures clientData field against the expected
    * format and prepare a hash of it for use in signature verification.
    *
    * webauthn signatures do not sign the hash of the message directly, but
    * instead sign a JSON-like "clientData" wrapper structure that contains the
    * message hash along with a other information.
    *
    * Fortunately this structure has a fixed format so it is possible to verify
    * that the hash of the signed message is present within the clientData
    * structure without needing to implement any JSON parsing.
    */
   static int
   webauthn_check_prepare_hash(const u_char *data, size_t datalen,
       const char *origin, const struct sshbuf *wrapper,
       uint8_t flags, const struct sshbuf *extensions,
       u_char *msghash, size_t msghashlen)
   {
           int r = SSH_ERR_INTERNAL_ERROR;
           struct sshbuf *chall = NULL, *m = NULL;
   
           if ((m = sshbuf_new()) == NULL ||
               (chall = sshbuf_from(data, datalen)) == NULL) {
                   r = SSH_ERR_ALLOC_FAIL;
                   goto out;
           }
           /*
            * Ensure origin contains no quote character and that the flags are
            * consistent with what we received
            */
           if (strchr(origin, '\"') != NULL ||
               (flags & 0x40) != 0 /* AD */ ||
               ((flags & 0x80) == 0 /* ED */) != (sshbuf_len(extensions) == 0)) {
                   r = SSH_ERR_INVALID_FORMAT;
                   goto out;
           }
   #define WEBAUTHN_0      "{\"type\":\"webauthn.get\",\"challenge\":\""
   #define WEBAUTHN_1      "\",\"origin\":\""
   #define WEBAUTHN_2      "\""
           if ((r = sshbuf_put(m, WEBAUTHN_0, sizeof(WEBAUTHN_0) - 1)) != 0 ||
               (r = sshbuf_dtourlb64(chall, m, 0)) != 0 ||
               (r = sshbuf_put(m, WEBAUTHN_1, sizeof(WEBAUTHN_1) - 1)) != 0 ||
               (r = sshbuf_put(m, origin, strlen(origin))) != 0 ||
               (r = sshbuf_put(m, WEBAUTHN_2, sizeof(WEBAUTHN_2) - 1)) != 0)
                   goto out;
   #ifdef DEBUG_SK
           fprintf(stderr, "%s: received origin: %s\n", __func__, origin);
           fprintf(stderr, "%s: received clientData:\n", __func__);
           sshbuf_dump(wrapper, stderr);
           fprintf(stderr, "%s: expected clientData premable:\n", __func__);
           sshbuf_dump(m, stderr);
   #endif
           /* Check that the supplied clientData matches what we expect */
           if ((r = sshbuf_cmp(wrapper, 0, sshbuf_ptr(m), sshbuf_len(m))) != 0)
                   goto out;
   
           /* Prepare hash of clientData */
           if ((r = ssh_digest_buffer(SSH_DIGEST_SHA256, wrapper,
               msghash, msghashlen)) != 0)
                   goto out;
   
           /* success */
           r = 0;
    out:
           sshbuf_free(chall);
           sshbuf_free(m);
           return r;
   }
   
 /* ARGSUSED */  /* ARGSUSED */
 int  int
 ssh_ecdsa_sk_verify(const struct sshkey *key,  ssh_ecdsa_sk_verify(const struct sshkey *key,
Line 55 
Line 124 
         u_char sig_flags;          u_char sig_flags;
         u_char msghash[32], apphash[32], sighash[32];          u_char msghash[32], apphash[32], sighash[32];
         u_int sig_counter;          u_int sig_counter;
         int ret = SSH_ERR_INTERNAL_ERROR;          int is_webauthn = 0, ret = SSH_ERR_INTERNAL_ERROR;
         struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL;          struct sshbuf *b = NULL, *sigbuf = NULL, *original_signed = NULL;
         char *ktype = NULL;          struct sshbuf *webauthn_wrapper = NULL, *webauthn_exts = NULL;
           char *ktype = NULL, *webauthn_origin = NULL;
         struct sshkey_sig_details *details = NULL;          struct sshkey_sig_details *details = NULL;
 #ifdef DEBUG_SK  #ifdef DEBUG_SK
         char *tmp = NULL;          char *tmp = NULL;
Line 84 
Line 154 
                 ret = SSH_ERR_INVALID_FORMAT;                  ret = SSH_ERR_INVALID_FORMAT;
                 goto out;                  goto out;
         }          }
         if (strcmp(ktype, "sk-ecdsa-sha2-nistp256@openssh.com") != 0) {          if (strcmp(ktype, "webauthn-sk-ecdsa-sha2-nistp256@openssh.com") == 0)
                   is_webauthn = 1;
           else if (strcmp(ktype, "sk-ecdsa-sha2-nistp256@openssh.com") != 0) {
                 ret = SSH_ERR_INVALID_FORMAT;                  ret = SSH_ERR_INVALID_FORMAT;
                 goto out;                  goto out;
         }          }
Line 94 
Line 166 
                 ret = SSH_ERR_INVALID_FORMAT;                  ret = SSH_ERR_INVALID_FORMAT;
                 goto out;                  goto out;
         }          }
           if (is_webauthn) {
                   if (sshbuf_get_cstring(b, &webauthn_origin, NULL) != 0 ||
                       sshbuf_froms(b, &webauthn_wrapper) != 0 ||
                       sshbuf_froms(b, &webauthn_exts) != 0) {
                           ret = SSH_ERR_INVALID_FORMAT;
                           goto out;
                   }
           }
         if (sshbuf_len(b) != 0) {          if (sshbuf_len(b) != 0) {
                 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;                  ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
                 goto out;                  goto out;
Line 109 
Line 189 
                 ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;                  ret = SSH_ERR_UNEXPECTED_TRAILING_DATA;
                 goto out;                  goto out;
         }          }
   
 #ifdef DEBUG_SK  #ifdef DEBUG_SK
         fprintf(stderr, "%s: data: (len %zu)\n", __func__, datalen);          fprintf(stderr, "%s: data: (len %zu)\n", __func__, datalen);
         /* sshbuf_dump_data(data, datalen, stderr); */          /* sshbuf_dump_data(data, datalen, stderr); */
Line 118 
Line 199 
         free(tmp);          free(tmp);
         fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",          fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
             __func__, sig_flags, sig_counter);              __func__, sig_flags, sig_counter);
           if (is_webauthn) {
                   fprintf(stderr, "%s: webauthn origin: %s\n", __func__,
                       webauthn_origin);
                   fprintf(stderr, "%s: webauthn_wrapper:\n", __func__);
                   sshbuf_dump(webauthn_wrapper, stderr);
           }
 #endif  #endif
         if ((sig = ECDSA_SIG_new()) == NULL) {          if ((sig = ECDSA_SIG_new()) == NULL) {
                 ret = SSH_ERR_ALLOC_FAIL;                  ret = SSH_ERR_ALLOC_FAIL;
Line 134 
Line 221 
                 ret = SSH_ERR_ALLOC_FAIL;                  ret = SSH_ERR_ALLOC_FAIL;
                 goto out;                  goto out;
         }          }
         if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,          if (is_webauthn) {
                   if ((ret = webauthn_check_prepare_hash(data, datalen,
                       webauthn_origin, webauthn_wrapper, sig_flags, webauthn_exts,
                       msghash, sizeof(msghash))) != 0)
                           goto out;
           } else if ((ret = ssh_digest_memory(SSH_DIGEST_SHA256, data, datalen,
             msghash, sizeof(msghash))) != 0)              msghash, sizeof(msghash))) != 0)
                 goto out;                  goto out;
         /* Application value is hashed before signature */          /* Application value is hashed before signature */
Line 151 
Line 243 
             apphash, sizeof(apphash))) != 0 ||              apphash, sizeof(apphash))) != 0 ||
             (ret = sshbuf_put_u8(original_signed, sig_flags)) != 0 ||              (ret = sshbuf_put_u8(original_signed, sig_flags)) != 0 ||
             (ret = sshbuf_put_u32(original_signed, sig_counter)) != 0 ||              (ret = sshbuf_put_u32(original_signed, sig_counter)) != 0 ||
               (ret = sshbuf_putb(original_signed, webauthn_exts)) != 0 ||
             (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0)              (ret = sshbuf_put(original_signed, msghash, sizeof(msghash))) != 0)
                 goto out;                  goto out;
         /* Signature is over H(original_signed) */          /* Signature is over H(original_signed) */
Line 190 
Line 283 
         explicit_bzero(sighash, sizeof(msghash));          explicit_bzero(sighash, sizeof(msghash));
         explicit_bzero(apphash, sizeof(apphash));          explicit_bzero(apphash, sizeof(apphash));
         sshkey_sig_details_free(details);          sshkey_sig_details_free(details);
           sshbuf_free(webauthn_wrapper);
           sshbuf_free(webauthn_exts);
           free(webauthn_origin);
         sshbuf_free(original_signed);          sshbuf_free(original_signed);
         sshbuf_free(sigbuf);          sshbuf_free(sigbuf);
         sshbuf_free(b);          sshbuf_free(b);

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7