From 77fe176a037c518efee29a13116a49fb0c169d48 Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 6 Mar 2025 18:29:23 -0500 Subject: [PATCH 1/9] Declare URI validation functions --- crypto/x509/v3_utl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 60aa31a7c7..0c28be3c72 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -35,6 +35,10 @@ static int ipv6_from_asc(unsigned char *v6, const char *in); static int ipv6_cb(const char *elem, int len, void *usr); static int ipv6_hex(unsigned char *out, const char *in, int inlen); +static int starts_with(const char *str, const char* prefix); +static int is_valid_uri_char(char c); +static int is_valid_uri(char *uri); + /* Add a CONF_VALUE name value pair to stack */ static int x509v3_add_len_value(const char *name, const char *value, From a5fa9147bc92fdc36dd4cc76fde29a0eaea9846a Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 6 Mar 2025 18:37:38 -0500 Subject: [PATCH 2/9] Implement starts_with() function --- crypto/x509/v3_utl.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 0c28be3c72..0394639e90 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1455,3 +1455,8 @@ int ossl_bio_print_hex(BIO *out, unsigned char *buf, int len) OPENSSL_free(hexbuf); return result; } + +static int starts_with(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} From 5b668258d968a9aeebee40e9e6b70a11f1a1d644 Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 6 Mar 2025 19:06:10 -0500 Subject: [PATCH 3/9] Implement is_valid_uri_char() --- crypto/x509/v3_utl.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 0394639e90..bb6cf212ad 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1460,3 +1460,13 @@ static int starts_with(const char *str, const char *prefix) { return strncmp(str, prefix, strlen(prefix)) == 0; } + +static int is_valid_uri_char(char c) +{ + /* Valid characters include alphanumeric, '-', '_', '.', '~', and reserved characters */ + return isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || + c == '!'|| c == '$' || c == '&' || c == '\'' || c == '(' || + c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || + c == '=' || c == ':' || c == '@' || c == '/' || c == '#' || + c == '[' || c == ']'; +} From d2c3addd1e470fdb7b3da86ee5ae41e4052c1e5f Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 6 Mar 2025 22:15:51 -0500 Subject: [PATCH 4/9] Implement is_valid_uri() --- crypto/x509/v3_utl.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index bb6cf212ad..2d8f5c3c1a 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -37,7 +37,7 @@ static int ipv6_hex(unsigned char *out, const char *in, int inlen); static int starts_with(const char *str, const char* prefix); static int is_valid_uri_char(char c); -static int is_valid_uri(char *uri); +static int is_valid_uri(const char *uri); /* Add a CONF_VALUE name value pair to stack */ @@ -1468,5 +1468,23 @@ static int is_valid_uri_char(char c) c == '!'|| c == '$' || c == '&' || c == '\'' || c == '(' || c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || c == '=' || c == ':' || c == '@' || c == '/' || c == '#' || - c == '[' || c == ']'; + c == '[' || c == ']' || c == '?'; +} + +static int is_valid_uri(const char *uri) +{ + /* Check if URI begins with a valid scheme */ + if (!(starts_with(uri, "http://") || starts_with(uri, "https://") || + starts_with(uri, "ftp://"))) { + return 0; + } + + /* Check the validity of each character in the URI */ + for (const char *p = uri; *p != '\0'; ++p) { + if (!is_valid_uri_char(*p)) { + return 0; + } + } + + return 1; /* URI is valid */ } From 262ad64944e53764e4c3f8432ea10adb708e8478 Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Fri, 7 Mar 2025 01:05:32 -0500 Subject: [PATCH 5/9] Implement validation check --- crypto/x509/v3_utl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 2d8f5c3c1a..61dec5be5e 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -64,6 +64,10 @@ static int x509v3_add_len_value(const char *name, const char *value, ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB); goto err; } + if (!is_valid_uri(value) && strncmp(name, "URI", 3) == 0) { + /* Figure out proper error to raise here */ + goto err; + } vtmp->section = NULL; vtmp->name = tname; vtmp->value = tvalue; From b04d2d81d0a28cd56f5bd184b73958cd8578c9a0 Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Fri, 7 Mar 2025 01:33:12 -0500 Subject: [PATCH 6/9] Throw error on bad URI --- crypto/x509/v3_utl.c | 6 +++++- crypto/x509/v3err.c | 1 + include/openssl/x509v3err.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 61dec5be5e..463c91d6b4 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -64,8 +64,12 @@ static int x509v3_add_len_value(const char *name, const char *value, ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB); goto err; } + int err_raised = 0; if (!is_valid_uri(value) && strncmp(name, "URI", 3) == 0) { - /* Figure out proper error to raise here */ + ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_URI); + err_raised = 1; + } + if (err_raised) { goto err; } vtmp->section = NULL; diff --git a/crypto/x509/v3err.c b/crypto/x509/v3err.c index 5512f1b317..355ad437f2 100644 --- a/crypto/x509/v3err.c +++ b/crypto/x509/v3err.c @@ -85,6 +85,7 @@ static const ERR_STRING_DATA X509V3_str_reasons[] = { {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SAFI), "invalid safi"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SECTION), "invalid section"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SYNTAX), "invalid syntax"}, + {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_URI), "invalid URI"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ISSUER_DECODE_ERROR), "issuer decode error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_MISSING_VALUE), "missing value"}, diff --git a/include/openssl/x509v3err.h b/include/openssl/x509v3err.h index 1ed1b2e5b0..2800de25c4 100644 --- a/include/openssl/x509v3err.h +++ b/include/openssl/x509v3err.h @@ -64,6 +64,7 @@ # define X509V3_R_INVALID_SAFI 164 # define X509V3_R_INVALID_SECTION 135 # define X509V3_R_INVALID_SYNTAX 143 +# define X509V3_R_INVALID_URI 173 # define X509V3_R_ISSUER_DECODE_ERROR 126 # define X509V3_R_MISSING_VALUE 124 # define X509V3_R_NEED_ORGANIZATION_AND_NUMBERS 142 From 504a8c5eed6e52a541394c17e4d4a8e9c14b2cb3 Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 1 May 2025 15:33:49 -0400 Subject: [PATCH 7/9] remove unnecessary starts_with() function --- crypto/x509/v3_utl.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 463c91d6b4..e44f722104 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -35,7 +35,6 @@ static int ipv6_from_asc(unsigned char *v6, const char *in); static int ipv6_cb(const char *elem, int len, void *usr); static int ipv6_hex(unsigned char *out, const char *in, int inlen); -static int starts_with(const char *str, const char* prefix); static int is_valid_uri_char(char c); static int is_valid_uri(const char *uri); @@ -1464,11 +1463,6 @@ int ossl_bio_print_hex(BIO *out, unsigned char *buf, int len) return result; } -static int starts_with(const char *str, const char *prefix) -{ - return strncmp(str, prefix, strlen(prefix)) == 0; -} - static int is_valid_uri_char(char c) { /* Valid characters include alphanumeric, '-', '_', '.', '~', and reserved characters */ @@ -1482,8 +1476,8 @@ static int is_valid_uri_char(char c) static int is_valid_uri(const char *uri) { /* Check if URI begins with a valid scheme */ - if (!(starts_with(uri, "http://") || starts_with(uri, "https://") || - starts_with(uri, "ftp://"))) { + if (!(strncmp(uri, "http://", 7) == 0 || strncmp(uri, "https://", 8) == 0 || + strncmp(uri, "ftp://", 6) == 0)) { return 0; } From 722a2e76e6fb74ee9fec0fdcbf5cac2859efd55e Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 1 May 2025 15:53:51 -0400 Subject: [PATCH 8/9] replace if statements in is_valid_uri_char() with switch statement --- crypto/x509/v3_utl.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index e44f722104..811ec189b2 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1466,11 +1466,22 @@ int ossl_bio_print_hex(BIO *out, unsigned char *buf, int len) static int is_valid_uri_char(char c) { /* Valid characters include alphanumeric, '-', '_', '.', '~', and reserved characters */ - return isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~' || - c == '!'|| c == '$' || c == '&' || c == '\'' || c == '(' || - c == ')' || c == '*' || c == '+' || c == ',' || c == ';' || - c == '=' || c == ':' || c == '@' || c == '/' || c == '#' || - c == '[' || c == ']' || c == '?'; + switch (c) { + // Unreserved characters + case '-': case '_': case '.': case '~': + // Reserved characters + case '!': case '*': case '\'': case '(': case ')': + case ';': case ':': case '@': case '&': case '=': + case '+': case '$': case ',': case '/': case '?': + case '#': case '[': case ']': + return 1; + default: + // Check if alphanumeric + if (isalnum(c)) { + return 1; + } + return 0; + } } static int is_valid_uri(const char *uri) From ab445c2507d56fd555cbc3879bad54f20c7a32d7 Mon Sep 17 00:00:00 2001 From: Bender Dev Date: Thu, 1 May 2025 16:27:34 -0400 Subject: [PATCH 9/9] Implement is_valid_uri_scheme() and isalnum() without requiring ctype --- crypto/x509/v3_utl.c | 46 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/crypto/x509/v3_utl.c b/crypto/x509/v3_utl.c index 811ec189b2..f9d4817f0b 100644 --- a/crypto/x509/v3_utl.c +++ b/crypto/x509/v3_utl.c @@ -1463,20 +1463,27 @@ int ossl_bio_print_hex(BIO *out, unsigned char *buf, int len) return result; } +static int isalnum(int c) +{ + return ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9')); +} + static int is_valid_uri_char(char c) { /* Valid characters include alphanumeric, '-', '_', '.', '~', and reserved characters */ switch (c) { - // Unreserved characters + /* Unreserved characters */ case '-': case '_': case '.': case '~': - // Reserved characters + /* Reserved characters */ case '!': case '*': case '\'': case '(': case ')': case ';': case ':': case '@': case '&': case '=': case '+': case '$': case ',': case '/': case '?': case '#': case '[': case ']': return 1; default: - // Check if alphanumeric + /* Check if alphanumeric */ if (isalnum(c)) { return 1; } @@ -1484,14 +1491,39 @@ static int is_valid_uri_char(char c) } } -static int is_valid_uri(const char *uri) +static int is_valid_uri_scheme(const char *input) { - /* Check if URI begins with a valid scheme */ - if (!(strncmp(uri, "http://", 7) == 0 || strncmp(uri, "https://", 8) == 0 || - strncmp(uri, "ftp://", 6) == 0)) { + int i; + char c; + + /* Input may not be null and first character must be a letter */ + if (input == NULL || !((input[0] >= 'A' && input[0] <= 'Z') || (input[0] >= 'a' && input[0] <= 'z'))) { return 0; } + for (i = 1; input[i] != '\0'; i++) { + c = input[i]; + + if (c == ':') { + /* Valid scheme found */ + return 1; + } + + /* Characters must be alphanumeric or '+', '-', '.' */ + if (!isalnum(c) && c != '+' && c != '-' && c != '.') { + return 0; + } + } + return 0; +} + +static int is_valid_uri(const char *uri) +{ + /* Check if URI begins with a valid scheme */ + if (!is_valid_uri_scheme(uri)) { + return 0; + } + /* Check the validity of each character in the URI */ for (const char *p = uri; *p != '\0'; ++p) { if (!is_valid_uri_char(*p)) {