/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 1998-2008 The OpenLDAP Foundation.
+ * Copyright 1998-2009 The OpenLDAP Foundation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
enum {
SLAP_X509_OPT_C_VERSION = SLAP_X509_OPTION + 0,
- SLAP_X509_OPT_C_ISSUERUNIQUEID = SLAP_X509_OPTION + 1,
- SLAP_X509_OPT_C_SUBJECTUNIQUEID = SLAP_X509_OPTION + 2,
+ SLAP_X509_OPT_C_ISSUERUNIQUEID = LBER_CLASS_CONTEXT + 1,
+ SLAP_X509_OPT_C_SUBJECTUNIQUEID = LBER_CLASS_CONTEXT + 2,
SLAP_X509_OPT_C_EXTENSIONS = SLAP_X509_OPTION + 3
};
}
/* X.509 certificate list validation */
+static int
+checkTime( struct berval *in, struct berval *out );
+
static int
certificateListValidate( Syntax *syntax, struct berval *in )
{
BerElementBuffer berbuf;
BerElement *ber = (BerElement *)&berbuf;
ber_tag_t tag;
- ber_len_t len;
+ ber_len_t len, wrapper_len;
+ char *wrapper_start;
+ int wrapper_ok = 0;
ber_int_t version = SLAP_X509_V1;
+ struct berval bvdn, bvtu;
ber_init2( ber, in, LBER_USE_DER );
- tag = ber_skip_tag( ber, &len ); /* Signed wrapper */
+ tag = ber_skip_tag( ber, &wrapper_len ); /* Signed wrapper */
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
+ wrapper_start = ber->ber_ptr;
tag = ber_skip_tag( ber, &len ); /* Sequence */
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
tag = ber_peek_tag( ber, &len );
tag = ber_skip_tag( ber, &len ); /* Signature Algorithm */
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
ber_skip_data( ber, len );
- tag = ber_skip_tag( ber, &len ); /* Issuer DN */
+ tag = ber_peek_tag( ber, &len ); /* Issuer DN */
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
+ len = ber_ptrlen( ber );
+ bvdn.bv_val = in->bv_val + len;
+ bvdn.bv_len = in->bv_len - len;
+ tag = ber_skip_tag( ber, &len );
ber_skip_data( ber, len );
tag = ber_skip_tag( ber, &len ); /* thisUpdate */
/* Time is a CHOICE { UTCTime, GeneralizedTime } */
if ( tag != SLAP_TAG_UTCTIME && tag != SLAP_TAG_GENERALIZEDTIME ) return LDAP_INVALID_SYNTAX;
+ bvtu.bv_val = (char *)ber->ber_ptr;
+ bvtu.bv_len = len;
ber_skip_data( ber, len );
/* Optional nextUpdate */
tag = ber_skip_tag( ber, &len );
tag = ber_skip_tag( ber, &len );
}
}
- /* Optional Extensions */
+ /* Optional Extensions - Sequence of Sequence */
if ( tag == SLAP_X509_OPT_CL_CRLEXTENSIONS ) { /* ? */
+ ber_len_t seqlen;
if ( version != SLAP_X509_V2 ) return LDAP_INVALID_SYNTAX;
- tag = ber_skip_tag( ber, &len );
+ tag = ber_peek_tag( ber, &seqlen );
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
ber_skip_data( ber, len );
tag = ber_skip_tag( ber, &len );
/* Signature */
if ( tag != LBER_BITSTRING ) return LDAP_INVALID_SYNTAX;
ber_skip_data( ber, len );
+ if ( ber->ber_ptr == wrapper_start + wrapper_len ) wrapper_ok = 1;
tag = ber_skip_tag( ber, &len );
/* Must be at end now */
- if ( len || tag != LBER_DEFAULT ) return LDAP_INVALID_SYNTAX;
+ /* NOTE: OpenSSL tolerates CL with garbage past the end */
+ if ( len || tag != LBER_DEFAULT ) {
+ struct berval issuer_dn = BER_BVNULL, thisUpdate;
+ char tubuf[STRLENOF("YYYYmmddHHMMSSZ") + 1];
+ int rc;
+
+ if ( ! wrapper_ok ) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ rc = dnX509normalize( &bvdn, &issuer_dn );
+ if ( rc != LDAP_SUCCESS ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ thisUpdate.bv_val = tubuf;
+ thisUpdate.bv_len = sizeof(tubuf);
+ if ( checkTime( &bvtu, &thisUpdate ) ) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto done;
+ }
+
+ Debug( LDAP_DEBUG_ANY,
+ "certificateListValidate issuer=\"%s\", thisUpdate=%s: extra cruft past end of certificateList\n",
+ issuer_dn.bv_val, thisUpdate.bv_val, 0 );
+
+done:;
+ if ( ! BER_BVISNULL( &issuer_dn ) ) {
+ ber_memfree( issuer_dn.bv_val );
+ }
+
+ return rc;
+ }
+
return LDAP_SUCCESS;
}
if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX;
ber_skip_data( ber, len );
- ber_peek_tag( ber, &len );
+ tag = ber_peek_tag( ber, &len );
if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */
tag = ber_skip_tag( ber, &len );
...
*
- * Note: normalization strips any leading "0"s, unless the
- * bit string is exactly "'0'B", so the normalized example,
- * in slapd, would result in
- *
- * 1.3.6.1.4.1.1466.0=#04024869,o=test,c=gb#'101'B
- *
+ * Note:
* RFC 4514 clarifies that SHARP, i.e. "#", doesn't have to
* be escaped except when at the beginning of a value, the
* definition of Name and Optional UID appears to be flawed,
*
* in fact "com#'1'B" is a valid IA5 string.
*
- * As a consequence, current slapd code assumes that the
- * presence of portions of a BitString at the end of the string
- * representation of a NameAndOptionalUID means a BitString
- * is expected, and cause an error otherwise. This is quite
- * arbitrary, and might change in the future.
+ * As a consequence, current slapd code takes the presence of
+ * #<valid BitString> at the end of the string representation
+ * of a NameAndOptionalUID to mean this is indeed a BitString.
+ * This is quite arbitrary - it has changed the past and might
+ * change in the future.
*/
if ( rc == LDAP_SUCCESS ) {
ber_dupbv_x( &dnval, val, ctx );
- dnval.bv_len -= uidval.bv_len + 1;
+ uidval.bv_val--;
+ dnval.bv_len -= ++uidval.bv_len;
dnval.bv_val[dnval.bv_len] = '\0';
} else {
}
if( !BER_BVISNULL( &uidval ) ) {
- int i, c, got1;
char *tmp;
tmp = slap_sl_realloc( out->bv_val, out->bv_len
- + STRLENOF( "#" ) + uidval.bv_len + 1,
+ + uidval.bv_len + 1,
ctx );
if( tmp == NULL ) {
ber_memfree_x( out->bv_val, ctx );
return LDAP_OTHER;
}
out->bv_val = tmp;
- out->bv_val[out->bv_len++] = '#';
- out->bv_val[out->bv_len++] = '\'';
-
- got1 = uidval.bv_len < sizeof("'0'B");
- for( i = 1; i < uidval.bv_len - 2; i++ ) {
- c = uidval.bv_val[i];
- switch(c) {
- case '0':
- if( got1 ) out->bv_val[out->bv_len++] = c;
- break;
- case '1':
- got1 = 1;
- out->bv_val[out->bv_len++] = c;
- break;
- }
- }
-
- out->bv_val[out->bv_len++] = '\'';
- out->bv_val[out->bv_len++] = 'B';
+ memcpy( out->bv_val + out->bv_len, uidval.bv_val, uidval.bv_len );
+ out->bv_len += uidval.bv_len;
out->bv_val[out->bv_len] = '\0';
}
}
} else {
slap_sl_free( normalized->bv_val, ctx );
+ BER_BVZERO( normalized );
return LDAP_INVALID_SYNTAX;
}
rc = generalizedTimeValidate( NULL, &bv );
if ( rc == LDAP_SUCCESS && out != NULL ) {
+ if ( out->bv_len > bv.bv_len ) {
+ out->bv_val[ bv.bv_len ] = '\0';
+ }
out->bv_len = bv.bv_len;
}
ber_dupbv_x( &ni, is, ctx );
} else {
- ber_int_t src, dst;
-
+ ber_len_t src, dst;
+
ni.bv_len = is->bv_len - numdquotes;
ni.bv_val = ber_memalloc_x( ni.bv_len + 1, ctx );
for ( src = 0, dst = 0; src < is->bv_len; src++, dst++ ) {
{"( 1.3.6.1.4.1.4203.666.11.2.3 NAME 'CSNOrderingMatch' "
"SYNTAX 1.3.6.1.4.1.4203.666.11.2.1 )",
SLAP_MR_HIDE | SLAP_MR_ORDERING | SLAP_MR_ORDERED_INDEX, NULL,
- NULL, NULL, csnOrderingMatch,
+ NULL, csnNormalize, csnOrderingMatch,
NULL, NULL,
"CSNMatch" },