diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 6f56f81869..1116854d4d 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -3427,6 +3427,202 @@ integerBitOrMatch( return LDAP_SUCCESS; } +#ifdef HAVE_TLS +#include +#include +char digit[] = "0123456789"; + +/* + * Next function returns a string representation of a ASN1_INTEGER. + * It works for unlimited lengths. + */ + +static struct berval * +asn1_integer2str(ASN1_INTEGER *a) +{ + char buf[256]; + char *p; + + /* We work backwards, make it fill from the end of buf */ + p = buf + sizeof(buf) - 1; + *p = '\0'; + + if ( a == NULL || a->length == 0 ) { + *--p = '0'; + } else { + int i; + int n = a->length; + int base = 0; + unsigned int *copy; + + /* We want to preserve the original */ + copy = ch_malloc(n*sizeof(unsigned int)); + for (i = 0; idata[i]; + } + + /* + * base indicates the index of the most significant + * byte that might be nonzero. When it goes off the + * end, we now there is nothing left to do. + */ + while (base < n) { + unsigned int carry; + unsigned int temp; + + carry = 0; + for (i = base; itype == V_ASN1_NEG_INTEGER ) { + *--p = '-'; + } + + return ber_bvstrdup(p); +} + +static struct berval * +dn_openssl2ldap(X509_NAME *name) +{ + char issuer_dn[1024]; + BIO *bio; + + bio = BIO_new(BIO_s_mem()); + if ( !bio ) { + fprintf(stderr, ERR_error_string(ERR_get_error(),NULL)); + /* ERR_print_errors(bio_err); */ + return NULL; + } + X509_NAME_print_ex(bio, name, 0, XN_FLAG_RFC2253); + + BIO_gets(bio, issuer_dn, 1024); + + BIO_free(bio); + return ber_bvstrdup(issuer_dn); +} + +static int +serial_and_issuer_parse( + struct berval *assertion, + struct berval **serial, + struct berval **issuer_dn +) +{ + char *begin; + char *end; + char *p; + char *q; + + begin = assertion->bv_val; + end = assertion->bv_val+assertion->bv_len-1; + for (p=begin; p<=end && *p != '$'; p++) + ; + if ( p > end ) + return LDAP_INVALID_SYNTAX; + + /* p now points at the $ sign, now use begin and end to delimit the + serial number */ + while (ASCII_SPACE(*begin++)) + ; + end = p; + while (ASCII_SPACE(*end--)) + ; + + q = ch_malloc( (end-begin+1)+1 ); + AC_MEMCPY( q, begin, end-begin+1 ); + q[end-begin+1] = '\0'; + *serial = ber_bvstr(q); + + /* now extract the issuer, remember p was at the dollar sign */ + begin = p+1; + end = assertion->bv_val+assertion->bv_len-1; + while (ASCII_SPACE(*begin++)) + ; + /* should we trim spaces at the end too? is it safe always? */ + + q = ch_malloc( (end-begin+1)+1 ); + AC_MEMCPY( q, begin, end-begin+1 ); + q[end-begin+1] = '\0'; + *issuer_dn = ber_bvstr(q); + + return LDAP_SUCCESS; +} + +static int +certificateExactMatch( + int *matchp, + slap_mask_t flags, + Syntax *syntax, + MatchingRule *mr, + struct berval *value, + void *assertedValue ) +{ + X509 *xcert; + unsigned char *p = value->bv_val; + struct berval *serial; + struct berval *issuer_dn; + struct berval *asserted_serial; + struct berval *asserted_issuer_dn; + int ret; + + xcert = d2i_X509(NULL, &p, value->bv_len); + if ( !xcert ) { + ERR_error_string(ERR_get_error(),NULL); + } + + serial = asn1_integer2str(xcert->cert_info->serialNumber); + issuer_dn = dn_openssl2ldap(X509_get_issuer_name(xcert)); + + X509_free(xcert); + + serial_and_issuer_parse(assertedValue, + &asserted_serial, + &asserted_issuer_dn); + + ret = integerMatch( + matchp, + flags, + slap_schema.si_syn_integer, + slap_schema.si_mr_integerMatch, + serial, + asserted_serial); + if ( ret == LDAP_SUCCESS ) { + if ( *matchp == 0 ) { + ret = dnMatch( + matchp, + flags, + slap_schema.si_syn_distinguishedName, + slap_schema.si_mr_distinguishedNameMatch, + issuer_dn, + asserted_issuer_dn); + } + } + + ber_bvfree(serial); + ber_bvfree(issuer_dn); + ber_bvfree(asserted_serial); + ber_bvfree(asserted_issuer_dn); + + return ret; +} +#endif + static int check_time_syntax (struct berval *val, int start, @@ -3905,6 +4101,13 @@ struct syntax_defs_rec syntax_defs[] = { {"( 1.3.6.1.1.1.0.1 DESC 'RFC2307 Boot Parameter' )", 0, bootParameterValidate, NULL, NULL}, +#ifdef HAVE_TLS + /* From PKIX */ + /* These OIDs are not published yet, but have been assigned */ + {"( 1.3.6.1.4.1.1466.115.121.1.9999 DESC 'Serial Number and Issuer' )", + 0, NULL, NULL, NULL}, +#endif + /* OpenLDAP Experimental Syntaxes */ {"( 1.3.6.1.4.1.4203.666.2.1 DESC 'OpenLDAP Experimental ACI' )", 0, UTF8StringValidate /* THIS WILL CHANGE FOR NEW ACI SYNTAX */, @@ -3942,7 +4145,6 @@ struct mrule_defs_rec { * 2.5.13.31 directoryStringFirstComponentMatch * 2.5.13.32 wordMatch * 2.5.13.33 keywordMatch - * 2.5.13.34 certificateExactMatch * 2.5.13.35 certificateMatch * 2.5.13.36 certificatePairExactMatch * 2.5.13.37 certificatePairMatch @@ -4169,6 +4371,15 @@ struct mrule_defs_rec mrule_defs[] = { objectIdentifierFirstComponentMatch, NULL, NULL, NULL}, +#ifdef HAVE_TLS + {"( 2.5.13.34 NAME 'certificateExactMatch' " + "SYNTAX 1.3.6.1.4.1.1466.115.121.1.9999 )", + SLAP_MR_EQUALITY | SLAP_MR_EXT, + NULL, NULL, + certificateExactMatch, NULL, NULL, + NULL}, +#endif + {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' " "SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )", SLAP_MR_EQUALITY | SLAP_MR_EXT, diff --git a/servers/slapd/schema_prep.c b/servers/slapd/schema_prep.c index 16efb4c1ee..4ba2607d84 100644 --- a/servers/slapd/schema_prep.c +++ b/servers/slapd/schema_prep.c @@ -228,6 +228,28 @@ static AttributeType slap_at_undefined = { NULL /* next */ }; +struct slap_schema_mr_map { + char *ssmm_name; + size_t ssmm_offset; +} mr_map[] = { + { "distinguishedNameMatch", + offsetof(struct slap_internal_schema, si_mr_distinguishedNameMatch) }, + { "integerMatch", + offsetof(struct slap_internal_schema, si_mr_integerMatch) }, + { NULL, 0 } +}; + +struct slap_schema_syn_map { + char *sssm_name; + size_t sssm_offset; +} syn_map[] = { + { "1.3.6.1.4.1.1466.115.121.1.12", + offsetof(struct slap_internal_schema, si_syn_distinguishedName) }, + { "1.3.6.1.4.1.1466.115.121.1.27", + offsetof(struct slap_internal_schema, si_syn_integer) }, + { NULL, 0 } +}; + int schema_prep( void ) { @@ -281,6 +303,34 @@ schema_prep( void ) } slap_schema.si_at_undefined = &slap_at_undefined; + for( i=0; mr_map[i].ssmm_name; i++ ) { + MatchingRule ** mrp = (MatchingRule **) + &(((char *) &slap_schema)[mr_map[i].ssmm_offset]); + + *mrp = mr_find( mr_map[i].ssmm_name ); + + if( *mrp == NULL ) { + fprintf( stderr, + "No matching rule \"%s\" defined in schema\n", + mr_map[i].ssmm_name ); + return LDAP_INAPPROPRIATE_MATCHING; + } + } + + for( i=0; syn_map[i].sssm_name; i++ ) { + Syntax ** synp = (Syntax **) + &(((char *) &slap_schema)[syn_map[i].sssm_offset]); + + *synp = syn_find( syn_map[i].sssm_name ); + + if( *synp == NULL ) { + fprintf( stderr, + "No syntax \"%s\" defined in schema\n", + syn_map[i].sssm_name ); + return LDAP_INVALID_SYNTAX; + } + } + ++schema_init_done; return LDAP_SUCCESS; } diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 2e7d74a8d9..a8c770a03f 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -489,6 +489,14 @@ struct slap_internal_schema { /* Undefined Attribute Type */ AttributeType *si_at_undefined; + + /* Matching Rules */ + MatchingRule *si_mr_distinguishedNameMatch; + MatchingRule *si_mr_integerMatch; + + /* Syntaxes */ + Syntax *si_syn_distinguishedName; + Syntax *si_syn_integer; }; typedef struct slap_attr_assertion {