+ /* should have no characters left... */
+ if( x.bv_len ) return LDAP_INVALID_SYNTAX;
+
+ ber_dupbv_x( &ni, &i, ctx );
+ i = ni;
+
+ /* need to handle double dquotes here */
+ }
+
+ rc = dnNormalize( usage, syntax, mr, &i, &ni, ctx );
+
+ if( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) {
+ slap_sl_free( i.bv_val, ctx );
+ }
+
+ if( rc ) return LDAP_INVALID_SYNTAX;
+
+ /* make room from sn + "$" */
+ out->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
+ + sn.bv_len + ni.bv_len;
+ out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx );
+
+ if( out->bv_val == NULL ) {
+ out->bv_len = 0;
+ slap_sl_free( ni.bv_val, ctx );
+ return LDAP_OTHER;
+ }
+
+ n = 0;
+ AC_MEMCPY( &out->bv_val[n], "{ serialNumber ",
+ STRLENOF( "{ serialNumber " ));
+ n = STRLENOF( "{ serialNumber " );
+
+ AC_MEMCPY( &out->bv_val[n], sn.bv_val, sn.bv_len );
+ n += sn.bv_len;
+
+ AC_MEMCPY( &out->bv_val[n], ", issuer \"", STRLENOF( ", issuer \"" ));
+ n += STRLENOF( ", issuer \"" );
+
+ AC_MEMCPY( &out->bv_val[n], ni.bv_val, ni.bv_len );
+ n += ni.bv_len;
+
+ AC_MEMCPY( &out->bv_val[n], "\" }", STRLENOF( "\" }" ));
+ n += STRLENOF( "\" }" );
+
+ out->bv_val[n] = '\0';
+
+ assert( n == out->bv_len );
+
+ Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerNormalize: <%s>\n",
+ out->bv_val, 0, 0 );
+
+ slap_sl_free( ni.bv_val, ctx );
+
+ return LDAP_SUCCESS;
+}
+
+#ifdef HAVE_TLS
+static int
+certificateExactNormalize(
+ slap_mask_t usage,
+ Syntax *syntax,
+ MatchingRule *mr,
+ struct berval *val,
+ struct berval *normalized,
+ void *ctx )
+{
+ int rc = LDAP_INVALID_SYNTAX;
+ unsigned char *p;
+ char *serial = NULL;
+ ber_len_t seriallen;
+ struct berval issuer_dn = BER_BVNULL;
+ X509_NAME *name = NULL;
+ ASN1_INTEGER *sn = NULL;
+ X509 *xcert = NULL;
+
+ if( BER_BVISEMPTY( val ) ) goto done;
+
+ if( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) {
+ return serialNumberAndIssuerNormalize(0,NULL,NULL,val,normalized,ctx);
+ }
+
+ assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 );
+
+ p = (unsigned char *)val->bv_val;
+ xcert = d2i_X509( NULL, &p, val->bv_len);
+ if( xcert == NULL ) goto done;
+
+ sn=X509_get_serialNumber(xcert);
+ if ( sn == NULL ) goto done;
+ serial=i2s_ASN1_INTEGER(0, sn );
+ if( serial == NULL ) goto done;
+ seriallen=strlen(serial);
+
+ name=X509_get_issuer_name(xcert);
+ if( name == NULL ) goto done;
+ rc = dnX509normalize( name, &issuer_dn );
+ if( rc != LDAP_SUCCESS ) goto done;
+
+ normalized->bv_len = STRLENOF( "{ serialNumber , issuer \"\" }" )
+ + seriallen + issuer_dn.bv_len;
+ normalized->bv_val = ch_malloc(normalized->bv_len+1);
+
+ p = (unsigned char *)normalized->bv_val;
+
+ AC_MEMCPY(p, "{ serialNumber ", STRLENOF( "{ serialNumber " ));
+ p += STRLENOF( "{ serialNumber " );
+
+ AC_MEMCPY(p, serial, seriallen);
+ p += seriallen;
+
+ AC_MEMCPY(p, ", issuer \"", STRLENOF( ", issuer \"" ));
+ p += STRLENOF( ", issuer \"" );
+
+ AC_MEMCPY(p, issuer_dn.bv_val, issuer_dn.bv_len);
+ p += issuer_dn.bv_len;
+
+ AC_MEMCPY(p, "\" }", STRLENOF( "\" }" ));
+ p += STRLENOF( "\" }" );
+
+ *p = '\0';
+
+ Debug( LDAP_DEBUG_TRACE, "certificateExactNormalize: %s\n",
+ normalized->bv_val, NULL, NULL );
+
+ rc = LDAP_SUCCESS;
+
+done:
+ if (xcert) X509_free(xcert);
+ if (serial) ch_free(serial);
+ if (issuer_dn.bv_val) ber_memfree(issuer_dn.bv_val);
+
+ return rc;
+}
+#endif /* HAVE_TLS */
+
+
+#ifndef SUPPORT_OBSOLETE_UTC_SYNTAX
+/* slight optimization - does not need the start parameter */
+#define check_time_syntax(v, start, p, f) (check_time_syntax)(v, p, f)
+enum { start = 0 };
+#endif
+
+static int
+check_time_syntax (struct berval *val,
+ int start,
+ int *parts,
+ struct berval *fraction)
+{
+ /*
+ * start=0 GeneralizedTime YYYYmmddHH[MM[SS]][(./,)d...](Z|(+/-)HH[MM])
+ * start=1 UTCTime YYmmddHHMM[SS][Z|(+/-)HHMM]
+ * GeneralizedTime supports leap seconds, UTCTime does not.
+ */
+ static const int ceiling[9] = { 100, 100, 12, 31, 24, 60, 60, 24, 60 };
+ static const int mdays[2][12] = {
+ /* non-leap years */
+ { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ /* leap years */
+ { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ };
+ char *p, *e;
+ int part, c, c1, c2, tzoffset, leapyear = 0;
+
+ p = val->bv_val;
+ e = p + val->bv_len;
+
+#ifdef SUPPORT_OBSOLETE_UTC_SYNTAX
+ parts[0] = 20; /* century - any multiple of 4 from 04 to 96 */
+#endif
+ for (part = start; part < 7 && p < e; part++) {
+ c1 = *p;
+ if (!ASCII_DIGIT(c1)) {
+ break;