db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose Library for rule based certificate to user mapping - KRB5 matching rules
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose Sumit Bose <sbose@redhat.com>
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose Copyright (C) 2017 Red Hat
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose This program is free software; you can redistribute it and/or modify
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose it under the terms of the GNU General Public License as published by
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose the Free Software Foundation; either version 3 of the License, or
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose (at your option) any later version.
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose This program is distributed in the hope that it will be useful,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose but WITHOUT ANY WARRANTY; without even the implied warranty of
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose GNU General Public License for more details.
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose You should have received a copy of the GNU General Public License
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose along with this program. If not, see <http://www.gnu.org/licenses/>.
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic bool is_dotted_decimal(const char *s, size_t len)
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return false;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose while ((len == 0 && s[c] != '\0') || (len != 0 && c < len)) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose return false;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose struct component_list *comp = talloc_get_type(data, struct component_list);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * The syntax of the MIT Kerberos style matching rules is:
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * [KRB5:][relation-operator]component-rule ...
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * relation-operator
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * can be either &&, meaning all component rules must match, or ||,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * meaning only one component rule must match. The default is &&.
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * component-rule
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * can be one of the following. Note that there is no punctuation or whitespace between component rules.
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * <SUBJECT>regular-expression
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * <ISSUER>regular-expression
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * <SAN>regular-expression
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * <EKU>extended-key-usage
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * <KU>key-usage
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * see man sss-certmap for more details
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char **cur,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose comp = talloc_zero(mem_ctx, struct component_list);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose talloc_set_destructor((TALLOC_CTX *) comp, component_list_destructor);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose comp->val = talloc_strndup(comp, *cur, end - *cur);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic int parse_krb5_get_eku_value(TALLOC_CTX *mem_ctx,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char **cur,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char *o;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* RFC 3280 section 4.2.1.13 */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* RFC 4556 section 3.2.2 */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography*/
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose {"msScLogin", "1.3.6.1.4.1.311.20.2.2"},
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = get_comp_value(mem_ctx, ctx, cur, &comp);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (ret != 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose CM_DEBUG(ctx, "Failed to parse regexp.");
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = split_on_separator(mem_ctx, comp->val, ',', true, true,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose &eku_list, &eku_list_size);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (ret != 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose CM_DEBUG(ctx, "Failed to split list.");
f5a8cd60c6f377af1954b58f007d16cf3f6dc846Sumit Bose comp->eku_oid_list = talloc_zero_array(comp, const char *,
f5a8cd60c6f377af1954b58f007d16cf3f6dc846Sumit Bose eku_list_size + 1);
f5a8cd60c6f377af1954b58f007d16cf3f6dc846Sumit Bose if (comp->eku_oid_list == NULL) {
f5a8cd60c6f377af1954b58f007d16cf3f6dc846Sumit Bose ret = ENOMEM;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose for (c = 0; eku_list[c] != NULL; c++) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose for (k = 0; ext_key_usage[k].name != NULL; k++) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit BoseCM_DEBUG(ctx, "[%s][%s].", eku_list[c], ext_key_usage[k].name);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (strcasecmp(eku_list[c], ext_key_usage[k].name) == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ext_key_usage[k].oid);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (comp->eku_oid_list[e] == NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = ENOMEM;
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (ext_key_usage[k].name == NULL) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* check for an dotted-decimal OID */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* looks like a OID, only '.' and digits */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose comp->eku_oid_list[e] = talloc_strdup(comp->eku_oid_list,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose CM_DEBUG(ctx, "No matching extended key usage found.");
f5a8cd60c6f377af1954b58f007d16cf3f6dc846Sumit Bose if (e == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic int parse_krb5_get_ku_value(TALLOC_CTX *mem_ctx,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char **cur,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = split_on_separator(mem_ctx, comp->val, ',', true, true,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (strcasecmp(ku_list[c], key_usage[k].name) == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* FIXME: add check for numerical ku */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic int parse_krb5_get_component_value(TALLOC_CTX *mem_ctx,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char **cur,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = regcomp(&(comp->regexp), comp->val, REG_EXTENDED);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* https://www.ietf.org/rfc/rfc3280.txt section 4.2.1.7 */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* https://www.ietf.org/rfc/rfc4556.txt section 3.2.2 */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* both previous principal types */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose {"stringOtherName", SAN_STRING_OTHER_NAME, true},
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic int parse_krb5_get_san_option(TALLOC_CTX *mem_ctx,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char **cur,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (strncasecmp(*cur, san_names[c].name, len) == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose *str_other_name_oid = talloc_strndup(mem_ctx, *cur, len);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bosestatic int parse_krb5_get_san_value(TALLOC_CTX *mem_ctx,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose const char **cur,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = parse_krb5_get_san_option(mem_ctx, ctx, cur, &san_opt,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = parse_krb5_get_component_value(mem_ctx, ctx, cur, &comp);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose comp->bin_val = sss_base64_decode(comp, comp->val,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* for some reasons the NSS version of sss_base64_decode might
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * return a non-NULL value on error but len is still 0, so better
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose * check both. */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose if (comp->bin_val == NULL || comp->bin_val_len == 0) {
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose comp->str_other_name_oid = talloc_steal(comp, str_other_name_oid);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Boseint parse_krb5_match_rule(struct sss_certmap_ctx *ctx,
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* check relation */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose /* new component must start with '<' */
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = parse_krb5_get_component_value(rule, ctx, &cur, &comp);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = parse_krb5_get_ku_value(rule, ctx, &cur, &comp);
db36dca3d45e6eefbb30042ee65876566f1a6014Sumit Bose ret = parse_krb5_get_eku_value(rule, ctx, &cur, &comp);