/* * ssl_version_supported - Check that the specified `version` is supported by * `SSL *` instance * * @s: The SSL handle for the candidate method * @version: Protocol version to test against * * Returns 1 when supported, otherwise 0 */ int ssl_version_supported(const SSL *s, int version) { const version_info *vent; const version_info *table; switch (s->method->version) { default: /* Version should match method version for non-ANY method */ return version_cmp(s, version, s->version) == 0; case TLS_ANY_VERSION: table = tls_version_table; break; case DTLS_ANY_VERSION: table = dtls_version_table; break; } for (vent = table; vent->version != 0 && version_cmp(s, version, vent->version) <= 0; ++vent) { if (vent->cmeth != NULL && version_cmp(s, version, vent->version) == 0 && ssl_method_error(s, vent->cmeth()) == 0) { return 1; } } return 0; }
/** * Free version string. */ void G_COLD version_close(void) { if (version_cmp(&our_version, &last_rel_version) < 0) g_warning("upgrade recommended: most recent released version seen: %s", version_str(&last_rel_version)); else if (version_cmp(&our_version, &last_dev_version) < 0) g_warning("upgrade possible: most recent development version seen: %s", version_str(&last_dev_version)); }
/* * ssl_choose_server_version - Choose server (D)TLS version. Called when the * client HELLO is received to select the final server protocol version and * the version specific method. * * @s: server SSL handle. * * Returns 0 on success or an SSL error reason number on failure. */ int ssl_choose_server_version(SSL *s) { /*- * With version-flexible methods we have an initial state with: * * s->method->version == (D)TLS_ANY_VERSION, * s->version == (D)TLS_MAX_VERSION. * * So we detect version-flexible methods via the method version, not the * handle version. */ int server_version = s->method->version; int client_version = s->client_version; const version_info *vent; const version_info *table; int disabled = 0; switch (server_version) { default: if (version_cmp(s, client_version, s->version) < 0) return SSL_R_WRONG_SSL_VERSION; /* * If this SSL handle is not from a version flexible method we don't * (and never did) check min/max FIPS or Suite B constraints. Hope * that's OK. It is up to the caller to not choose fixed protocol * versions they don't want. If not, then easy to fix, just return * ssl_method_error(s, s->method) */ return 0; case TLS_ANY_VERSION: table = tls_version_table; break; case DTLS_ANY_VERSION: table = dtls_version_table; break; } for (vent = table; vent->version != 0; ++vent) { const SSL_METHOD *method; if (vent->smeth == NULL || version_cmp(s, client_version, vent->version) < 0) continue; method = vent->smeth(); if (ssl_method_error(s, method) == 0) { s->version = vent->version; s->method = method; return 0; } disabled = 1; } return disabled ? SSL_R_UNSUPPORTED_PROTOCOL : SSL_R_VERSION_TOO_LOW; }
/** * Based on the timestamp and their advertised version, find out the * token key they used. * * @return NULL if we cannot locate any suitable keys. */ static const struct tokkey * find_tokkey_version(const version_t *ver, time_t now) { uint i; /* * All versions before r16370 used the first key set when they expired. * If we're more recent, we probably have a stripped list of past key * sets, and therefore cannot validate their token. * * All versions after we switched to git can be checked provided we still * have a copy of the keys that they had at the time they were released. */ if ( ver->timestamp < GIT_SWITCH && /* Before we switched to git */ ver->build != 0 && ver->build < 16370 ) return find_tokkey(now); if (GNET_PROPERTY(version_debug) > 4) { g_debug("%s: looking for proper keyset (theirs is %u.%u.%u)", G_STRFUNC, ver->major, ver->minor, ver->patchlevel); } /* * Expired servents will always use their last key set. Even if we're * more recent, we can try to validate by mimicing the behaviour of * these servents. * * We determine the index of the last key set that they must know about * and we look for the token up to that index only. */ for (i = 0; i < G_N_ELEMENTS(token_keys); i++) { const struct tokkey *tk = &token_keys[i]; if (version_cmp(ver, &tk->ver) <= 0) { if (GNET_PROPERTY(version_debug) > 4) { g_debug("%s: matched at %u.%u.%u, index=%u", G_STRFUNC, tk->ver.major, tk->ver.minor, tk->ver.patchlevel, i); } break; } } if (GNET_PROPERTY(version_debug) > 4) { g_debug("%s: fallback max=%u (/%zu)", G_STRFUNC, i, G_N_ELEMENTS(token_keys)); } i++; /* We need a count, not an index */ i = MIN(i, G_N_ELEMENTS(token_keys)); /* In case loop did not match */ return find_tokkey_upto_fallback(now, i); }
int main() { version v1, v2, v3; char c[64]; version_init(&v1, 1, 2, 6); version_parse(&v2, "2.1.6"); version_init(&v3, 1, 2, 5); int count = version_to_string(&c[0], &v1); printf("version: %s\n", c); printf("count: %i\n", count); int b; b = version_cmp(&v1, &v2); printf("b1: %i\n", b); b = version_cmp(&v1, &v3); printf("b2: %i\n", b); b = version_cmp(&v2, &v3); printf("b3: %i\n", b); }
/* * ssl_method_error - Check whether an SSL_METHOD is enabled. * * @s: The SSL handle for the candidate method * @method: the intended method. * * Returns 0 on success, or an SSL error reason on failure. */ static int ssl_method_error(const SSL *s, const SSL_METHOD *method) { int version = method->version; if ((s->min_proto_version != 0 && version_cmp(s, version, s->min_proto_version) < 0) || ssl_security(s, SSL_SECOP_VERSION, 0, version, NULL) == 0) return SSL_R_VERSION_TOO_LOW; if (s->max_proto_version != 0 && version_cmp(s, version, s->max_proto_version) > 0) return SSL_R_VERSION_TOO_HIGH; if ((s->options & method->mask) != 0) return SSL_R_UNSUPPORTED_PROTOCOL; if ((method->flags & SSL_METHOD_NO_SUITEB) != 0 && tls1_suiteb(s)) return SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE; else if ((method->flags & SSL_METHOD_NO_FIPS) != 0 && FIPS_mode()) return SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE; return 0; }
void version_require(const char* package, const version* package_version, const char* dependency, const version* dependency_version, const version* required_version) { int c = version_cmp(dependency_version, required_version); if (c < 0) { char pvs[64]; char rvs[64]; char dvs[64]; version_to_string(pvs, package_version); version_to_string(rvs, required_version); version_to_string(dvs, dependency_version); printf("package %s %s requires %s %s but found version: %s\n", package, pvs, dependency, rvs, dvs); exit(1); } }
void http_request_h(struct http_conn *conn, const struct http_msg *msg, void *arg) { int err; enum app_cmd cmd; const struct http_hdr * expect_hdr; struct mbuf *mb = msg->mb; uint8_t *ret_buf; size_t ret_len; if(pl_strcmp(&msg->met, "POST")) { http_creply(conn, 405, "Method not allowed", "text/plain", "EMET"); return; } expect_hdr = http_msg_hdr(msg, HTTP_HDR_EXPECT); if(expect_hdr != NULL && version_cmp(version, &expect_hdr->val) < 0) { http_creply(conn, 417, "Expectation Failed", "text/plain", "%s", version); return; } cmd = (enum app_cmd)(hash_joaat_ci(msg->path.p, msg->path.l) & 0xfff); err = app_handle(cmd, mbuf_buf(mb), mbuf_get_left(mb), &ret_buf, &ret_len); if(err < 0) { http_creply(conn, 500, "Internal Server Error", "text/plain", "EINT"); return; } if(err > 200) { http_creply(conn, err, "Error", "text/plain", "NO", 2); return; } if(err == 0) { http_creply(conn, 200, "OK", "text/plain; charset=utf-8", "%b", ret_buf, ret_len); } else { http_creply(conn, 403, "Forbidden", "text/plain", "%b", ret_buf, ret_len); } free(ret_buf); }
static int compare_ref_name(const void *a_, const void *b_) { const char * const*a = a_, * const*b = b_; return version_cmp(*a, *b); }
int main(int argc, char **argv) { int ch, cmp = 0; if (argc == 4 && !strcmp(argv[1], "-t")) { cmp = version_cmp(argv[2], argv[3]); printf(cmp > 0 ? ">\n" : (cmp < 0 ? "<\n" : "=\n")); exit(0); } else if (argc == 4 && !strcmp(argv[1], "-T")) { cmp = version_match(argv[3], argv[2]); exit(cmp == 1 ? 0 : 1); } else while ((ch = getopt_long(argc, argv, opts, longopts, NULL)) != -1) { switch(ch) { case 'v': Verbose++; break; case 'I': UseINDEXOnly = TRUE; break; case 'l': LimitChars = optarg; break; case 'L': PreventChars = optarg; break; case 'q': Quiet = TRUE; break; case 's': MatchName = optarg; break; case 'O': LookUpOrigin = optarg; break; case 'o': ShowOrigin = TRUE; break; case 't': errx(2, "Invalid -t usage."); break; case 'T': errx(2, "Invalid -T usage."); break; case 'X': RegexExtended = TRUE; break; case 'h': default: usage(); break; } } argc -= optind; argv += optind; return pkg_perform(argv); }
/* * ssl_choose_server_version - Choose server (D)TLS version. Called when the * client HELLO is received to select the final server protocol version and * the version specific method. * * @s: server SSL handle. * * Returns 0 on success or an SSL error reason number on failure. */ int ssl_choose_server_version(SSL *s, CLIENTHELLO_MSG *hello) { /*- * With version-flexible methods we have an initial state with: * * s->method->version == (D)TLS_ANY_VERSION, * s->version == (D)TLS_MAX_VERSION. * * So we detect version-flexible methods via the method version, not the * handle version. */ int server_version = s->method->version; int client_version = hello->legacy_version; const version_info *vent; const version_info *table; int disabled = 0; RAW_EXTENSION *suppversions; s->client_version = client_version; switch (server_version) { default: /* * TODO(TLS1.3): This check will fail if someone attempts to do * renegotiation in TLS1.3 at the moment. We need to ensure we disable * renegotiation for TLS1.3 */ if (version_cmp(s, client_version, s->version) < 0) return SSL_R_WRONG_SSL_VERSION; /* * If this SSL handle is not from a version flexible method we don't * (and never did) check min/max FIPS or Suite B constraints. Hope * that's OK. It is up to the caller to not choose fixed protocol * versions they don't want. If not, then easy to fix, just return * ssl_method_error(s, s->method) */ return 0; case TLS_ANY_VERSION: table = tls_version_table; break; case DTLS_ANY_VERSION: table = dtls_version_table; break; } suppversions = tls_get_extension_by_type(hello->pre_proc_exts, hello->num_extensions, TLSEXT_TYPE_supported_versions); if (suppversions != NULL && !SSL_IS_DTLS(s)) { unsigned int candidate_vers = 0; unsigned int best_vers = 0; const SSL_METHOD *best_method = NULL; PACKET versionslist; if (!PACKET_as_length_prefixed_1(&suppversions->data, &versionslist)) { /* Trailing or invalid data? */ return SSL_R_LENGTH_MISMATCH; } while (PACKET_get_net_2(&versionslist, &candidate_vers)) { /* TODO(TLS1.3): Remove this before release */ if (candidate_vers == TLS1_3_VERSION_DRAFT) candidate_vers = TLS1_3_VERSION; /* * TODO(TLS1.3): There is some discussion on the TLS list about * wheter to ignore versions <TLS1.2 in supported_versions. At the * moment we honour them if present. To be reviewed later */ if (version_cmp(s, candidate_vers, best_vers) <= 0) continue; for (vent = table; vent->version != 0 && vent->version != (int)candidate_vers; ++vent) continue; if (vent->version != 0 && vent->smeth != NULL) { const SSL_METHOD *method; method = vent->smeth(); if (ssl_method_error(s, method) == 0) { best_vers = candidate_vers; best_method = method; } } } if (PACKET_remaining(&versionslist) != 0) { /* Trailing data? */ return SSL_R_LENGTH_MISMATCH; } if (best_vers > 0) { s->version = best_vers; s->method = best_method; return 0; } return SSL_R_UNSUPPORTED_PROTOCOL; } /* * If the supported versions extension isn't present, then the highest * version we can negotiate is TLSv1.2 */ if (version_cmp(s, client_version, TLS1_3_VERSION) >= 0) client_version = TLS1_2_VERSION; /* * No supported versions extension, so we just use the version supplied in * the ClientHello. */ for (vent = table; vent->version != 0; ++vent) { const SSL_METHOD *method; if (vent->smeth == NULL || version_cmp(s, client_version, vent->version) < 0) continue; method = vent->smeth(); if (ssl_method_error(s, method) == 0) { s->version = vent->version; s->method = method; return 0; } disabled = 1; } return disabled ? SSL_R_UNSUPPORTED_PROTOCOL : SSL_R_VERSION_TOO_LOW; }
/** * Check version of servent, and if it's a gtk-gnutella more recent than we * are, record that fact and change the status bar. * * The `addr' is being passed solely for the tok_version_valid() call. * * @returns TRUE if we properly checked the version, FALSE if we got something * looking as gtk-gnutella but which failed the token-based sanity checks. */ bool version_check(const char *str, const char *token, const host_addr_t addr) { version_t their_version; version_ext_t their_version_ext; version_t *target_version; int cmp; const char *version; const char *end; bool extended; if (!version_parse(str, &their_version, &end)) return TRUE; /* Not gtk-gnutella, or unparseable */ /* * Check for extended version information (git commit ID, dirty status). */ ZERO(&their_version_ext); extended = version_ext_parse(end, &their_version_ext); if (!extended) { /* Structure could have been partially filled */ ZERO(&their_version_ext); } /* * Is their version a development one, or a release? */ if (their_version.tag == 'u') target_version = &last_dev_version; else target_version = &last_rel_version; cmp = version_cmp(target_version, &their_version); if (GNET_PROPERTY(version_debug) > 1) version_dump(str, &their_version, cmp == 0 ? "=" : cmp > 0 ? "-" : "+"); /* * Check timestamp. */ version_stamp(str, &their_version); their_version_ext.version = their_version; /* Struct copy */ if (GNET_PROPERTY(version_debug) > 3) g_debug("VERSION time=%d", (int) their_version.timestamp); /* * If version claims something older than TOKEN_START_DATE, then * there must be a token present. */ if (delta_time(their_version.timestamp, 0) >= TOKEN_START_DATE) { tok_error_t error; if (token == NULL) { if (GNET_PROPERTY(version_debug)) { g_debug("got GTKG vendor string \"%s\" without token!", str); } return FALSE; /* Can't be correct */ } error = tok_version_valid(str, token, strlen(token), addr); /* * Unfortunately, if our token has expired, we can no longer * validate the tokens of the remote peers, since they are using * a different set of keys. * * This means an expired GTKG will blindly trust well-formed remote * tokens at face value. But it's their fault, they should not run * an expired version! * --RAM, 2005-12-21 */ if (error == TOK_BAD_KEYS && tok_is_ancient(tm_time())) error = TOK_OK; /* Our keys have expired, cannot validate */ if (error != TOK_OK) { if (GNET_PROPERTY(version_debug)) { g_debug("vendor string \"%s\" [%s] has wrong token " "\"%s\": %s ", str, host_addr_to_string(addr), token, tok_strerror(error)); } return FALSE; } /* * OK, so now we know we can "trust" this version string as being * probably genuine. It makes sense to extract version information * out of it. */ } if (cmp > 0) /* We're more recent */ return TRUE; /* * If timestamp is greater and we were comparing against a stable * release, and cmp == 0, then this means an update in SVN about * a "released" version, probably alpha/beta. */ if ( cmp == 0 && (delta_time(their_version.timestamp, target_version->timestamp) > 0 || their_version.build > target_version->build) && target_version == &last_rel_version ) { if (GNET_PROPERTY(version_debug) > 3) g_debug("VERSION is a SVN update of a release"); if (version_build_cmp(&last_dev_version, &their_version) > 0) { if (GNET_PROPERTY(version_debug) > 3) g_debug("VERSION is less recent than latest dev we know"); return TRUE; } target_version = &last_dev_version; } /* * Their version is more recent, but is unstable -- only continue if * our version is also unstable. */ if (cmp < 0 && their_version.tag == 'u' && our_version.tag != 'u') return TRUE; if ( delta_time(their_version.timestamp, target_version->timestamp) < 0 || their_version.build <= target_version->build ) return TRUE; if ( delta_time(their_version.timestamp, our_version.timestamp) == 0 && their_version.build <= our_version.build ) return TRUE; /* * We found a more recent version than the last version seen. */ if (GNET_PROPERTY(version_debug) > 1) g_debug("more recent %s VERSION \"%s\"", target_version == &last_dev_version ? "dev" : "rel", str); *target_version = their_version; /* struct copy */ /* * Signal new version to user. * * Unless they run a development version, don't signal development * updates to them: they're probably not interested. */ version = version_ext_str(&their_version_ext, FALSE); /* No OS name */ g_message("more recent %s version of gtk-gnutella: %s", target_version == &last_dev_version ? "development" : "released", version); if (target_version == &last_rel_version) version_new_found(version, TRUE); else if (our_version.tag == 'u') version_new_found(version, FALSE); return TRUE; }
/** * Compare two gtk-gnutella versions, including build number (but not * the version timestamps). In theory, we could simply compare build numbers * but we can't ensure they won't ever be reset one day. * * @returns -1, 0 or +1 depending on the sign of "a - b". */ int version_build_cmp(const version_t *a, const version_t *b) { int cmp = version_cmp(a, b); return 0 == cmp ? CMP(a->build, b->build) : cmp; }