static int ssl_cipher_process_rulestr(const char *rule_str, CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p, const SSL_CIPHER **ca_list) { unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength; const char *l, *buf; int j, multi, found, rule, retval, ok, buflen; unsigned long cipher_id = 0; char ch; retval = 1; l = rule_str; for (;;) { ch = *l; if (ch == '\0') break; /* done */ if (ch == '-') { rule = CIPHER_DEL; l++; } else if (ch == '+') { rule = CIPHER_ORD; l++; } else if (ch == '!') { rule = CIPHER_KILL; l++; } else if (ch == '@') { rule = CIPHER_SPECIAL; l++; } else { rule = CIPHER_ADD; } if (ITEM_SEP(ch)) { l++; continue; } alg_mkey = 0; alg_auth = 0; alg_enc = 0; alg_mac = 0; alg_ssl = 0; algo_strength = 0; for (;;) { ch = *l; buf = l; buflen = 0; #ifndef CHARSET_EBCDIC while ( ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '-')) #else while ( isalnum(ch) || (ch == '-')) #endif { ch = *(++l); buflen++; } if (buflen == 0) { /* * We hit something we cannot deal with, * it is no command or separator nor * alphanumeric, so we call this an error. */ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND); retval = found = 0; l++; break; } if (rule == CIPHER_SPECIAL) { found = 0; /* unused -- avoid compiler warning */ break; /* special treatment */ } /* check for multi-part specification */ if (ch == '+') { multi=1; l++; } else multi=0; /* * Now search for the cipher alias in the ca_list. Be careful * with the strncmp, because the "buflen" limitation * will make the rule "ADH:SOME" and the cipher * "ADH-MY-CIPHER" look like a match for buflen=3. * So additionally check whether the cipher name found * has the correct length. We can save a strlen() call: * just checking for the '\0' at the right place is * sufficient, we have to strncmp() anyway. (We cannot * use strcmp(), because buf is not '\0' terminated.) */ j = found = 0; cipher_id = 0; while (ca_list[j]) { if (!strncmp(buf, ca_list[j]->name, buflen) && (ca_list[j]->name[buflen] == '\0')) { found = 1; break; } else j++; } if (!found) break; /* ignore this entry */ if (ca_list[j]->algorithm_mkey) { if (alg_mkey) { alg_mkey &= ca_list[j]->algorithm_mkey; if (!alg_mkey) { found = 0; break; } } else alg_mkey = ca_list[j]->algorithm_mkey; } if (ca_list[j]->algorithm_auth) { if (alg_auth) { alg_auth &= ca_list[j]->algorithm_auth; if (!alg_auth) { found = 0; break; } } else alg_auth = ca_list[j]->algorithm_auth; } if (ca_list[j]->algorithm_enc) { if (alg_enc) { alg_enc &= ca_list[j]->algorithm_enc; if (!alg_enc) { found = 0; break; } } else alg_enc = ca_list[j]->algorithm_enc; } if (ca_list[j]->algorithm_mac) { if (alg_mac) { alg_mac &= ca_list[j]->algorithm_mac; if (!alg_mac) { found = 0; break; } } else alg_mac = ca_list[j]->algorithm_mac; } if (ca_list[j]->algo_strength & SSL_EXP_MASK) { if (algo_strength & SSL_EXP_MASK) { algo_strength &= (ca_list[j]->algo_strength & SSL_EXP_MASK) | ~SSL_EXP_MASK; if (!(algo_strength & SSL_EXP_MASK)) { found = 0; break; } } else algo_strength |= ca_list[j]->algo_strength & SSL_EXP_MASK; } if (ca_list[j]->algo_strength & SSL_STRONG_MASK) { if (algo_strength & SSL_STRONG_MASK) { algo_strength &= (ca_list[j]->algo_strength & SSL_STRONG_MASK) | ~SSL_STRONG_MASK; if (!(algo_strength & SSL_STRONG_MASK)) { found = 0; break; } } else algo_strength |= ca_list[j]->algo_strength & SSL_STRONG_MASK; } if (ca_list[j]->valid) { /* explicit ciphersuite found; its protocol version * does not become part of the search pattern!*/ cipher_id = ca_list[j]->id; } else { /* not an explicit ciphersuite; only in this case, the * protocol version is considered part of the search pattern */ if (ca_list[j]->algorithm_ssl) { if (alg_ssl) { alg_ssl &= ca_list[j]->algorithm_ssl; if (!alg_ssl) { found = 0; break; } } else alg_ssl = ca_list[j]->algorithm_ssl; } } if (!multi) break; } /* * Ok, we have the rule, now apply it */ if (rule == CIPHER_SPECIAL) { /* special command */ ok = 0; if ((buflen == 8) && !strncmp(buf, "STRENGTH", 8)) ok = ssl_cipher_strength_sort(head_p, tail_p); else SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND); if (ok == 0) retval = 0; /* * We do not support any "multi" options * together with "@", so throw away the * rest of the command, if any left, until * end or ':' is found. */ while ((*l != '\0') && !ITEM_SEP(*l)) l++; } else if (found) { ssl_cipher_apply_rule(cipher_id, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, rule, -1, head_p, tail_p); } else { while ((*l != '\0') && !ITEM_SEP(*l)) l++; } if (*l == '\0') break; /* done */ } return(retval); }
static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, const char *rule_str, CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p) { uint32_t alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength; const char *l, *buf; int multi, rule, retval, ok, in_group = 0, has_group = 0; size_t j, buf_len; uint32_t cipher_id; char ch; retval = 1; l = rule_str; for (;;) { ch = *l; if (ch == '\0') { break; /* done */ } if (in_group) { if (ch == ']') { if (*tail_p) { (*tail_p)->in_group = 0; } in_group = 0; l++; continue; } if (ch == '|') { rule = CIPHER_ADD; l++; continue; } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9')) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); retval = in_group = 0; break; } else { rule = CIPHER_ADD; } } else if (ch == '-') { rule = CIPHER_DEL; l++; } else if (ch == '+') { rule = CIPHER_ORD; l++; } else if (ch == '!') { rule = CIPHER_KILL; l++; } else if (ch == '@') { rule = CIPHER_SPECIAL; l++; } else if (ch == '[') { if (in_group) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP); retval = in_group = 0; break; } in_group = 1; has_group = 1; l++; continue; } else { rule = CIPHER_ADD; } /* If preference groups are enabled, the only legal operator is +. * Otherwise the in_group bits will get mixed up. */ if (has_group && rule != CIPHER_ADD) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); retval = in_group = 0; break; } if (ITEM_SEP(ch)) { l++; continue; } multi = 0; cipher_id = 0; alg_mkey = ~0u; alg_auth = ~0u; alg_enc = ~0u; alg_mac = ~0u; alg_ssl = ~0u; algo_strength = ~0u; for (;;) { ch = *l; buf = l; buf_len = 0; while (((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) { ch = *(++l); buf_len++; } if (buf_len == 0) { /* We hit something we cannot deal with, it is no command or separator * nor alphanumeric, so we call this an error. */ OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); retval = in_group = 0; l++; break; } if (rule == CIPHER_SPECIAL) { break; } /* Look for a matching exact cipher. These aren't allowed in multipart * rules. */ if (!multi && ch != '+') { size_t num_ciphers = ssl_method->num_ciphers(); for (j = 0; j < num_ciphers; j++) { const SSL_CIPHER *cipher = ssl_method->get_cipher(j); if (cipher != NULL && rule_equals(cipher->name, buf, buf_len)) { cipher_id = cipher->id; break; } } } if (cipher_id == 0) { /* If not an exact cipher, look for a matching cipher alias. */ for (j = 0; j < NUM_CIPHER_ALIASES; j++) { if (rule_equals(kCipherAliases[j].name, buf, buf_len)) { alg_mkey &= kCipherAliases[j].algorithm_mkey; alg_auth &= kCipherAliases[j].algorithm_auth; alg_enc &= kCipherAliases[j].algorithm_enc; alg_mac &= kCipherAliases[j].algorithm_mac; alg_ssl &= kCipherAliases[j].algorithm_ssl; algo_strength &= kCipherAliases[j].algo_strength; break; } } if (j == NUM_CIPHER_ALIASES) { alg_mkey = alg_auth = alg_enc = alg_mac = alg_ssl = algo_strength = 0; } } /* Check for a multipart rule. */ if (ch != '+') { break; } l++; multi = 1; } /* Ok, we have the rule, now apply it. */ if (rule == CIPHER_SPECIAL) { /* special command */ ok = 0; if (buf_len == 8 && !strncmp(buf, "STRENGTH", 8)) { ok = ssl_cipher_strength_sort(head_p, tail_p); } else { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); } if (ok == 0) { retval = 0; } /* We do not support any "multi" options together with "@", so throw away * the rest of the command, if any left, until end or ':' is found. */ while (*l != '\0' && !ITEM_SEP(*l)) { l++; } } else { ssl_cipher_apply_rule(cipher_id, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, rule, -1, in_group, head_p, tail_p); } } if (in_group) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); retval = 0; } return retval; }
static int ssl_cipher_process_rulestr(const char *rule_str, CIPHER_ORDER *co_list, CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p, SSL_CIPHER **ca_list) { unsigned long algorithms, mask, algo_strength, mask_strength; const char *l, *start, *buf; int j, multi, found, rule, retval, ok, buflen; unsigned long cipher_id = 0, ssl_version = 0; char ch; retval = 1; l = rule_str; for (;;) { ch = *l; if (ch == '\0') break; /* done */ if (ch == '-') { rule = CIPHER_DEL; l++; } else if (ch == '+') { rule = CIPHER_ORD; l++; } else if (ch == '!') { rule = CIPHER_KILL; l++; } else if (ch == '@') { rule = CIPHER_SPECIAL; l++; } else { rule = CIPHER_ADD; } if (ITEM_SEP(ch)) { l++; continue; } algorithms = mask = algo_strength = mask_strength = 0; start=l; for (;;) { ch = *l; buf = l; buflen = 0; #ifndef CHARSET_EBCDIC while ( ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '-')) #else while ( isalnum(ch) || (ch == '-')) #endif { ch = *(++l); buflen++; } if (buflen == 0) { /* * We hit something we cannot deal with, * it is no command or separator nor * alphanumeric, so we call this an error. */ SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND); retval = found = 0; l++; break; } if (rule == CIPHER_SPECIAL) { found = 0; /* unused -- avoid compiler warning */ break; /* special treatment */ } /* check for multi-part specification */ if (ch == '+') { multi=1; l++; } else multi=0; /* * Now search for the cipher alias in the ca_list. Be careful * with the strncmp, because the "buflen" limitation * will make the rule "ADH:SOME" and the cipher * "ADH-MY-CIPHER" look like a match for buflen=3. * So additionally check whether the cipher name found * has the correct length. We can save a strlen() call: * just checking for the '\0' at the right place is * sufficient, we have to strncmp() anyway. (We cannot * use strcmp(), because buf is not '\0' terminated.) */ j = found = 0; cipher_id = 0; ssl_version = 0; while (ca_list[j]) { if (!strncmp(buf, ca_list[j]->name, buflen) && (ca_list[j]->name[buflen] == '\0')) { found = 1; break; } else j++; } if (!found) break; /* ignore this entry */ /* New algorithms: * 1 - any old restrictions apply outside new mask * 2 - any new restrictions apply outside old mask * 3 - enforce old & new where masks intersect */ algorithms = (algorithms & ~ca_list[j]->mask) | /* 1 */ (ca_list[j]->algorithms & ~mask) | /* 2 */ (algorithms & ca_list[j]->algorithms); /* 3 */ mask |= ca_list[j]->mask; algo_strength = (algo_strength & ~ca_list[j]->mask_strength) | (ca_list[j]->algo_strength & ~mask_strength) | (algo_strength & ca_list[j]->algo_strength); mask_strength |= ca_list[j]->mask_strength; /* explicit ciphersuite found */ if (ca_list[j]->valid) { cipher_id = ca_list[j]->id; ssl_version = ca_list[j]->algorithms & SSL_SSL_MASK; break; } if (!multi) break; } /* * Ok, we have the rule, now apply it */ if (rule == CIPHER_SPECIAL) { /* special command */ ok = 0; if ((buflen == 8) && !strncmp(buf, "STRENGTH", 8)) ok = ssl_cipher_strength_sort(co_list, head_p, tail_p); else SSLerr(SSL_F_SSL_CIPHER_PROCESS_RULESTR, SSL_R_INVALID_COMMAND); if (ok == 0) retval = 0; /* * We do not support any "multi" options * together with "@", so throw away the * rest of the command, if any left, until * end or ':' is found. */ while ((*l != '\0') && !ITEM_SEP(*l)) l++; } else if (found) { ssl_cipher_apply_rule(cipher_id, ssl_version, algorithms, mask, algo_strength, mask_strength, rule, -1, co_list, head_p, tail_p); } else { while ((*l != '\0') && !ITEM_SEP(*l)) l++; } if (*l == '\0') break; /* done */ } return(retval); }
static int ssl_cipher_process_rulestr(const char *rule_str, CIPHER_ORDER **head_p, CIPHER_ORDER **tail_p, const SSL_CIPHER **ca_list) { unsigned long alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength; const char *l, *buf; int j, multi, found, rule, retval, ok, buflen, in_group = 0, has_group = 0; unsigned long cipher_id = 0; char ch; retval = 1; l = rule_str; for (;;) { ch = *l; if (ch == '\0') { break; /* done */ } if (in_group) { if (ch == ']') { if (!in_group) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_UNEXPECTED_GROUP_CLOSE); retval = found = in_group = 0; break; } if (*tail_p) { (*tail_p)->in_group = 0; } in_group = 0; l++; continue; } if (ch == '|') { rule = CIPHER_ADD; l++; continue; } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9')) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); retval = found = in_group = 0; break; } else { rule = CIPHER_ADD; } } else if (ch == '-') { rule = CIPHER_DEL; l++; } else if (ch == '+') { rule = CIPHER_ORD; l++; } else if (ch == '!') { rule = CIPHER_KILL; l++; } else if (ch == '@') { rule = CIPHER_SPECIAL; l++; } else if (ch == '[') { if (in_group) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_NESTED_GROUP); retval = found = in_group = 0; break; } in_group = 1; has_group = 1; l++; continue; } else { rule = CIPHER_ADD; } /* If preference groups are enabled, the only legal operator is +. * Otherwise the in_group bits will get mixed up. */ if (has_group && rule != CIPHER_ADD) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); retval = found = in_group = 0; break; } if (ITEM_SEP(ch)) { l++; continue; } alg_mkey = 0; alg_auth = 0; alg_enc = 0; alg_mac = 0; alg_ssl = 0; algo_strength = 0; for (;;) { ch = *l; buf = l; buflen = 0; while (((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) || ((ch >= 'a') && (ch <= 'z')) || (ch == '-') || (ch == '.')) { ch = *(++l); buflen++; } if (buflen == 0) { /* We hit something we cannot deal with, it is no command or separator * nor alphanumeric, so we call this an error. */ OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); retval = found = in_group = 0; l++; break; } if (rule == CIPHER_SPECIAL) { found = 0; /* unused -- avoid compiler warning */ break; /* special treatment */ } /* check for multi-part specification */ if (ch == '+') { multi = 1; l++; } else { multi = 0; } /* Now search for the cipher alias in the ca_list. Be careful with the * strncmp, because the "buflen" limitation will make the rule "ADH:SOME" * and the cipher "ADH-MY-CIPHER" look like a match for buflen=3. So * additionally check whether the cipher name found has the correct * length. We can save a strlen() call: just checking for the '\0' at the * right place is sufficient, we have to strncmp() anyway. (We cannot use * strcmp(), because buf is not '\0' terminated.) */ j = found = 0; cipher_id = 0; while (ca_list[j]) { if (!strncmp(buf, ca_list[j]->name, buflen) && (ca_list[j]->name[buflen] == '\0')) { found = 1; break; } else { j++; } } if (!found) { break; /* ignore this entry */ } if (ca_list[j]->algorithm_mkey) { if (alg_mkey) { alg_mkey &= ca_list[j]->algorithm_mkey; if (!alg_mkey) { found = 0; break; } } else { alg_mkey = ca_list[j]->algorithm_mkey; } } if (ca_list[j]->algorithm_auth) { if (alg_auth) { alg_auth &= ca_list[j]->algorithm_auth; if (!alg_auth) { found = 0; break; } } else { alg_auth = ca_list[j]->algorithm_auth; } } if (ca_list[j]->algorithm_enc) { if (alg_enc) { alg_enc &= ca_list[j]->algorithm_enc; if (!alg_enc) { found = 0; break; } } else { alg_enc = ca_list[j]->algorithm_enc; } } if (ca_list[j]->algorithm_mac) { if (alg_mac) { alg_mac &= ca_list[j]->algorithm_mac; if (!alg_mac) { found = 0; break; } } else { alg_mac = ca_list[j]->algorithm_mac; } } if (ca_list[j]->algo_strength) { if (algo_strength) { algo_strength &= ca_list[j]->algo_strength; if (!algo_strength) { found = 0; break; } } else { algo_strength |= ca_list[j]->algo_strength; } } if (ca_list[j]->valid) { /* explicit ciphersuite found; its protocol version does not become * part of the search pattern! */ cipher_id = ca_list[j]->id; } else { /* not an explicit ciphersuite; only in this case, the protocol version * is considered part of the search pattern. */ if (ca_list[j]->algorithm_ssl) { if (alg_ssl) { alg_ssl &= ca_list[j]->algorithm_ssl; if (!alg_ssl) { found = 0; break; } } else { alg_ssl = ca_list[j]->algorithm_ssl; } } } if (!multi) { break; } } /* Ok, we have the rule, now apply it. */ if (rule == CIPHER_SPECIAL) { /* special command */ ok = 0; if (buflen == 8 && !strncmp(buf, "STRENGTH", 8)) { ok = ssl_cipher_strength_sort(head_p, tail_p); } else { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); } if (ok == 0) { retval = 0; } /* We do not support any "multi" options together with "@", so throw away * the rest of the command, if any left, until end or ':' is found. */ while (*l != '\0' && !ITEM_SEP(*l)) { l++; } } else if (found) { ssl_cipher_apply_rule(cipher_id, alg_mkey, alg_auth, alg_enc, alg_mac, alg_ssl, algo_strength, rule, -1, in_group, head_p, tail_p); } else { while (*l != '\0' && !ITEM_SEP(*l)) { l++; } } } if (in_group) { OPENSSL_PUT_ERROR(SSL, ssl_cipher_process_rulestr, SSL_R_INVALID_COMMAND); retval = 0; } return retval; }