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

Diff for /src/usr.bin/ssh/kex.c between version 1.185 and 1.186

version 1.185, 2024/01/08 00:34:33 version 1.186, 2024/05/17 00:30:23
Line 76 
Line 76 
         "languages stoc",          "languages stoc",
 };  };
   
 struct kexalg {  
         char *name;  
         u_int type;  
         int ec_nid;  
         int hash_alg;  
 };  
 static const struct kexalg kexalgs[] = {  
 #ifdef WITH_OPENSSL  
         { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 },  
         { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 },  
         { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 },  
         { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 },  
         { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 },  
         { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 },  
         { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },  
         { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2,  
             NID_X9_62_prime256v1, SSH_DIGEST_SHA256 },  
         { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1,  
             SSH_DIGEST_SHA384 },  
         { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,  
             SSH_DIGEST_SHA512 },  
 #endif  
         { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },  
         { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },  
         { KEX_SNTRUP761X25519_SHA512, KEX_KEM_SNTRUP761X25519_SHA512, 0,  
             SSH_DIGEST_SHA512 },  
         { NULL, 0, -1, -1},  
 };  
   
 char *  
 kex_alg_list(char sep)  
 {  
         char *ret = NULL, *tmp;  
         size_t nlen, rlen = 0;  
         const struct kexalg *k;  
   
         for (k = kexalgs; k->name != NULL; k++) {  
                 if (ret != NULL)  
                         ret[rlen++] = sep;  
                 nlen = strlen(k->name);  
                 if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) {  
                         free(ret);  
                         return NULL;  
                 }  
                 ret = tmp;  
                 memcpy(ret + rlen, k->name, nlen + 1);  
                 rlen += nlen;  
         }  
         return ret;  
 }  
   
 static const struct kexalg *  
 kex_alg_by_name(const char *name)  
 {  
         const struct kexalg *k;  
   
         for (k = kexalgs; k->name != NULL; k++) {  
                 if (strcmp(k->name, name) == 0)  
                         return k;  
         }  
         return NULL;  
 }  
   
 /* Validate KEX method name list */  
 int  
 kex_names_valid(const char *names)  
 {  
         char *s, *cp, *p;  
   
         if (names == NULL || strcmp(names, "") == 0)  
                 return 0;  
         if ((s = cp = strdup(names)) == NULL)  
                 return 0;  
         for ((p = strsep(&cp, ",")); p && *p != '\0';  
             (p = strsep(&cp, ","))) {  
                 if (kex_alg_by_name(p) == NULL) {  
                         error("Unsupported KEX algorithm \"%.100s\"", p);  
                         free(s);  
                         return 0;  
                 }  
         }  
         debug3("kex names ok: [%s]", names);  
         free(s);  
         return 1;  
 }  
   
 /* returns non-zero if proposal contains any algorithm from algs */  
 static int  
 has_any_alg(const char *proposal, const char *algs)  
 {  
         char *cp;  
   
         if ((cp = match_list(proposal, algs, NULL)) == NULL)  
                 return 0;  
         free(cp);  
         return 1;  
 }  
   
 /*  /*
  * Concatenate algorithm names, avoiding duplicates in the process.  
  * Caller must free returned string.  
  */  
 char *  
 kex_names_cat(const char *a, const char *b)  
 {  
         char *ret = NULL, *tmp = NULL, *cp, *p;  
         size_t len;  
   
         if (a == NULL || *a == '\0')  
                 return strdup(b);  
         if (b == NULL || *b == '\0')  
                 return strdup(a);  
         if (strlen(b) > 1024*1024)  
                 return NULL;  
         len = strlen(a) + strlen(b) + 2;  
         if ((tmp = cp = strdup(b)) == NULL ||  
             (ret = calloc(1, len)) == NULL) {  
                 free(tmp);  
                 return NULL;  
         }  
         strlcpy(ret, a, len);  
         for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {  
                 if (has_any_alg(ret, p))  
                         continue; /* Algorithm already present */  
                 if (strlcat(ret, ",", len) >= len ||  
                     strlcat(ret, p, len) >= len) {  
                         free(tmp);  
                         free(ret);  
                         return NULL; /* Shouldn't happen */  
                 }  
         }  
         free(tmp);  
         return ret;  
 }  
   
 /*  
  * Assemble a list of algorithms from a default list and a string from a  
  * configuration file. The user-provided string may begin with '+' to  
  * indicate that it should be appended to the default, '-' that the  
  * specified names should be removed, or '^' that they should be placed  
  * at the head.  
  */  
 int  
 kex_assemble_names(char **listp, const char *def, const char *all)  
 {  
         char *cp, *tmp, *patterns;  
         char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL;  
         int r = SSH_ERR_INTERNAL_ERROR;  
   
         if (listp == NULL || def == NULL || all == NULL)  
                 return SSH_ERR_INVALID_ARGUMENT;  
   
         if (*listp == NULL || **listp == '\0') {  
                 if ((*listp = strdup(def)) == NULL)  
                         return SSH_ERR_ALLOC_FAIL;  
                 return 0;  
         }  
   
         list = *listp;  
         *listp = NULL;  
         if (*list == '+') {  
                 /* Append names to default list */  
                 if ((tmp = kex_names_cat(def, list + 1)) == NULL) {  
                         r = SSH_ERR_ALLOC_FAIL;  
                         goto fail;  
                 }  
                 free(list);  
                 list = tmp;  
         } else if (*list == '-') {  
                 /* Remove names from default list */  
                 if ((*listp = match_filter_denylist(def, list + 1)) == NULL) {  
                         r = SSH_ERR_ALLOC_FAIL;  
                         goto fail;  
                 }  
                 free(list);  
                 /* filtering has already been done */  
                 return 0;  
         } else if (*list == '^') {  
                 /* Place names at head of default list */  
                 if ((tmp = kex_names_cat(list + 1, def)) == NULL) {  
                         r = SSH_ERR_ALLOC_FAIL;  
                         goto fail;  
                 }  
                 free(list);  
                 list = tmp;  
         } else {  
                 /* Explicit list, overrides default - just use "list" as is */  
         }  
   
         /*  
          * The supplied names may be a pattern-list. For the -list case,  
          * the patterns are applied above. For the +list and explicit list  
          * cases we need to do it now.  
          */  
         ret = NULL;  
         if ((patterns = opatterns = strdup(list)) == NULL) {  
                 r = SSH_ERR_ALLOC_FAIL;  
                 goto fail;  
         }  
         /* Apply positive (i.e. non-negated) patterns from the list */  
         while ((cp = strsep(&patterns, ",")) != NULL) {  
                 if (*cp == '!') {  
                         /* negated matches are not supported here */  
                         r = SSH_ERR_INVALID_ARGUMENT;  
                         goto fail;  
                 }  
                 free(matching);  
                 if ((matching = match_filter_allowlist(all, cp)) == NULL) {  
                         r = SSH_ERR_ALLOC_FAIL;  
                         goto fail;  
                 }  
                 if ((tmp = kex_names_cat(ret, matching)) == NULL) {  
                         r = SSH_ERR_ALLOC_FAIL;  
                         goto fail;  
                 }  
                 free(ret);  
                 ret = tmp;  
         }  
         if (ret == NULL || *ret == '\0') {  
                 /* An empty name-list is an error */  
                 /* XXX better error code? */  
                 r = SSH_ERR_INVALID_ARGUMENT;  
                 goto fail;  
         }  
   
         /* success */  
         *listp = ret;  
         ret = NULL;  
         r = 0;  
   
  fail:  
         free(matching);  
         free(opatterns);  
         free(list);  
         free(ret);  
         return r;  
 }  
   
 /*  
  * Fill out a proposal array with dynamically allocated values, which may   * Fill out a proposal array with dynamically allocated values, which may
  * be modified as required for compatibility reasons.   * be modified as required for compatibility reasons.
  * Any of the options may be NULL, in which case the default is used.   * Any of the options may be NULL, in which case the default is used.
Line 512 
Line 274 
             (alg = strsep(&algs, ","))) {              (alg = strsep(&algs, ","))) {
                 if ((sigalg = sshkey_sigalg_by_name(alg)) == NULL)                  if ((sigalg = sshkey_sigalg_by_name(alg)) == NULL)
                         continue;                          continue;
                 if (!has_any_alg(sigalg, sigalgs))                  if (!kex_has_any_alg(sigalg, sigalgs))
                         continue;                          continue;
                 /* Don't add an algorithm twice. */                  /* Don't add an algorithm twice. */
                 if (ssh->kex->server_sig_algs != NULL &&                  if (ssh->kex->server_sig_algs != NULL &&
                     has_any_alg(sigalg, ssh->kex->server_sig_algs))                      kex_has_any_alg(sigalg, ssh->kex->server_sig_algs))
                         continue;                          continue;
                 xextendf(&ssh->kex->server_sig_algs, ",", "%s", sigalg);                  xextendf(&ssh->kex->server_sig_algs, ",", "%s", sigalg);
         }          }
Line 1091 
Line 853 
 static int  static int
 choose_kex(struct kex *k, char *client, char *server)  choose_kex(struct kex *k, char *client, char *server)
 {  {
         const struct kexalg *kexalg;  
   
         k->name = match_list(client, server, NULL);          k->name = match_list(client, server, NULL);
   
         debug("kex: algorithm: %s", k->name ? k->name : "(no match)");          debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
         if (k->name == NULL)          if (k->name == NULL)
                 return SSH_ERR_NO_KEX_ALG_MATCH;                  return SSH_ERR_NO_KEX_ALG_MATCH;
         if ((kexalg = kex_alg_by_name(k->name)) == NULL) {          if (!kex_name_valid(k->name)) {
                 error_f("unsupported KEX method %s", k->name);                  error_f("unsupported KEX method %s", k->name);
                 return SSH_ERR_INTERNAL_ERROR;                  return SSH_ERR_INTERNAL_ERROR;
         }          }
         k->kex_type = kexalg->type;          k->kex_type = kex_type_from_name(k->name);
         k->hash_alg = kexalg->hash_alg;          k->hash_alg = kex_hash_from_name(k->name);
         k->ec_nid = kexalg->ec_nid;          k->ec_nid = kex_nid_from_name(k->name);
         return 0;          return 0;
 }  }
   
Line 1154 
Line 914 
 static int  static int
 kexalgs_contains(char **peer, const char *ext)  kexalgs_contains(char **peer, const char *ext)
 {  {
         return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);          return kex_has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
 }  }
   
 static int  static int
Line 1205 
Line 965 
   
         /* Check whether client supports rsa-sha2 algorithms */          /* Check whether client supports rsa-sha2 algorithms */
         if (kex->server && (kex->flags & KEX_INITIAL)) {          if (kex->server && (kex->flags & KEX_INITIAL)) {
                 if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],                  if (kex_has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],
                     "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com"))                      "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com"))
                         kex->flags |= KEX_RSA_SHA2_256_SUPPORTED;                          kex->flags |= KEX_RSA_SHA2_256_SUPPORTED;
                 if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],                  if (kex_has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS],
                     "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com"))                      "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com"))
                         kex->flags |= KEX_RSA_SHA2_512_SUPPORTED;                          kex->flags |= KEX_RSA_SHA2_512_SUPPORTED;
         }          }

Legend:
Removed from v.1.185  
changed lines
  Added in v.1.186