From 5d90231d2a06857d8295fee9c46808d12873a791 Mon Sep 17 00:00:00 2001 From: Pierangelo Masarati Date: Sat, 18 Oct 2008 08:33:40 +0000 Subject: [PATCH] apply Luca Tamburo's patch for Attribute Certificate and X.509 PMI support (with modifications, ITS#5695) --- servers/slapd/schema/pmi.schema | 464 +++++++++++++ servers/slapd/schema_init.c | 1118 +++++++++++++++++++++++++++---- 2 files changed, 1453 insertions(+), 129 deletions(-) create mode 100644 servers/slapd/schema/pmi.schema diff --git a/servers/slapd/schema/pmi.schema b/servers/slapd/schema/pmi.schema new file mode 100644 index 0000000000..ca24c449e7 --- /dev/null +++ b/servers/slapd/schema/pmi.schema @@ -0,0 +1,464 @@ +# OpenLDAP X.509 PMI schema +# $OpenLDAP$ +## This work is part of OpenLDAP Software . +## +## Copyright 1998-2008 The OpenLDAP Foundation. +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted only as authorized by the OpenLDAP +## Public License. +## +## A copy of this license is available in the file LICENSE in the +## top-level directory of the distribution or, alternatively, at +## . +# +## Portions Copyright (C) The Internet Society (1997-2006). +## All Rights Reserved. +## +## This document and translations of it may be copied and furnished to +## others, and derivative works that comment on or otherwise explain it +## or assist in its implementation may be prepared, copied, published +## and distributed, in whole or in part, without restriction of any +## kind, provided that the above copyright notice and this paragraph are +## included on all such copies and derivative works. However, this +## document itself may not be modified in any way, such as by removing +## the copyright notice or references to the Internet Society or other +## Internet organizations, except as needed for the purpose of +## developing Internet standards in which case the procedures for +## copyrights defined in the Internet Standards process must be +## followed, or as required to translate it into languages other than +## English. +## +## The limited permissions granted above are perpetual and will not be +## revoked by the Internet Society or its successors or assigns. +## +## This document and the information contained herein is provided on an +## "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING +## TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING +## BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION +## HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF +## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +# +# +# Includes LDAPv3 schema items from: +# ITU X.509 (08/2005) +# +## X.509 (08/2005) pp. 120-121 +## +## -- object identifier assignments -- +## -- object classes -- +## id-oc-pmiUser OBJECT IDENTIFIER ::= {id-oc 24} +## id-oc-pmiAA OBJECT IDENTIFIER ::= {id-oc 25} +## id-oc-pmiSOA OBJECT IDENTIFIER ::= {id-oc 26} +## id-oc-attCertCRLDistributionPts OBJECT IDENTIFIER ::= {id-oc 27} +## id-oc-privilegePolicy OBJECT IDENTIFIER ::= {id-oc 32} +## id-oc-pmiDelegationPath OBJECT IDENTIFIER ::= {id-oc 33} +## id-oc-protectedPrivilegePolicy OBJECT IDENTIFIER ::= {id-oc 34} +## -- directory attributes -- +## id-at-attributeCertificate OBJECT IDENTIFIER ::= {id-at 58} +## id-at-attributeCertificateRevocationList OBJECT IDENTIFIER ::= {id-at 59} +## id-at-aACertificate OBJECT IDENTIFIER ::= {id-at 61} +## id-at-attributeDescriptorCertificate OBJECT IDENTIFIER ::= {id-at 62} +## id-at-attributeAuthorityRevocationList OBJECT IDENTIFIER ::= {id-at 63} +## id-at-privPolicy OBJECT IDENTIFIER ::= {id-at 71} +## id-at-role OBJECT IDENTIFIER ::= {id-at 72} +## id-at-delegationPath OBJECT IDENTIFIER ::= {id-at 73} +## id-at-protPrivPolicy OBJECT IDENTIFIER ::= {id-at 74} +## id-at-xMLPrivilegeInfo OBJECT IDENTIFIER ::= {id-at 75} +## id-at-xMLPprotPrivPolicy OBJECT IDENTIFIER ::= {id-at 76} +## -- attribute certificate extensions -- +## id-ce-authorityAttributeIdentifier OBJECT IDENTIFIER ::= {id-ce 38} +## id-ce-roleSpecCertIdentifier OBJECT IDENTIFIER ::= {id-ce 39} +## id-ce-basicAttConstraints OBJECT IDENTIFIER ::= {id-ce 41} +## id-ce-delegatedNameConstraints OBJECT IDENTIFIER ::= {id-ce 42} +## id-ce-timeSpecification OBJECT IDENTIFIER ::= {id-ce 43} +## id-ce-attributeDescriptor OBJECT IDENTIFIER ::= {id-ce 48} +## id-ce-userNotice OBJECT IDENTIFIER ::= {id-ce 49} +## id-ce-sOAIdentifier OBJECT IDENTIFIER ::= {id-ce 50} +## id-ce-acceptableCertPolicies OBJECT IDENTIFIER ::= {id-ce 52} +## id-ce-targetInformation OBJECT IDENTIFIER ::= {id-ce 55} +## id-ce-noRevAvail OBJECT IDENTIFIER ::= {id-ce 56} +## id-ce-acceptablePrivilegePolicies OBJECT IDENTIFIER ::= {id-ce 57} +## id-ce-indirectIssuer OBJECT IDENTIFIER ::= {id-ce 61} +## id-ce-noAssertion OBJECT IDENTIFIER ::= {id-ce 62} +## id-ce-issuedOnBehalfOf OBJECT IDENTIFIER ::= {id-ce 64} +## -- PMI matching rules -- +## id-mr-attributeCertificateMatch OBJECT IDENTIFIER ::= {id-mr 42} +## id-mr-attributeCertificateExactMatch OBJECT IDENTIFIER ::= {id-mr 45} +## id-mr-holderIssuerMatch OBJECT IDENTIFIER ::= {id-mr 46} +## id-mr-authAttIdMatch OBJECT IDENTIFIER ::= {id-mr 53} +## id-mr-roleSpecCertIdMatch OBJECT IDENTIFIER ::= {id-mr 54} +## id-mr-basicAttConstraintsMatch OBJECT IDENTIFIER ::= {id-mr 55} +## id-mr-delegatedNameConstraintsMatch OBJECT IDENTIFIER ::= {id-mr 56} +## id-mr-timeSpecMatch OBJECT IDENTIFIER ::= {id-mr 57} +## id-mr-attDescriptorMatch OBJECT IDENTIFIER ::= {id-mr 58} +## id-mr-acceptableCertPoliciesMatch OBJECT IDENTIFIER ::= {id-mr 59} +## id-mr-delegationPathMatch OBJECT IDENTIFIER ::= {id-mr 61} +## id-mr-sOAIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 66} +## id-mr-indirectIssuerMatch OBJECT IDENTIFIER ::= {id-mr 67} +## +## +## X.509 (08/2005) pp. 71, 86-89 +## +## 14.4.1 Role attribute +## role ATTRIBUTE ::= { +## WITH SYNTAX RoleSyntax +## ID id-at-role } +## RoleSyntax ::= SEQUENCE { +## roleAuthority [0] GeneralNames OPTIONAL, +## roleName [1] GeneralName } +## +## 14.5 XML privilege information attribute +## xmlPrivilegeInfo ATTRIBUTE ::= { +## WITH SYNTAX UTF8String -- contains XML-encoded privilege information +## ID id-at-xMLPrivilegeInfo } +## +## 17.1 PMI directory object classes +## +## 17.1.1 PMI user object class +## pmiUser OBJECT-CLASS ::= { +## -- a PMI user (i.e., a "holder") +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN {attributeCertificateAttribute} +## ID id-oc-pmiUser } +## +## 17.1.2 PMI AA object class +## pmiAA OBJECT-CLASS ::= { +## -- a PMI AA +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN {aACertificate | +## attributeCertificateRevocationList | +## attributeAuthorityRevocationList} +## ID id-oc-pmiAA } +## +## 17.1.3 PMI SOA object class +## pmiSOA OBJECT-CLASS ::= { -- a PMI Source of Authority +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN {attributeCertificateRevocationList | +## attributeAuthorityRevocationList | +## attributeDescriptorCertificate} +## ID id-oc-pmiSOA } +## +## 17.1.4 Attribute certificate CRL distribution point object class +## attCertCRLDistributionPt OBJECT-CLASS ::= { +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN { attributeCertificateRevocationList | +## attributeAuthorityRevocationList } +## ID id-oc-attCertCRLDistributionPts } +## +## 17.1.5 PMI delegation path +## pmiDelegationPath OBJECT-CLASS ::= { +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN { delegationPath } +## ID id-oc-pmiDelegationPath } +## +## 17.1.6 Privilege policy object class +## privilegePolicy OBJECT-CLASS ::= { +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN {privPolicy } +## ID id-oc-privilegePolicy } +## +## 17.1.7 Protected privilege policy object class +## protectedPrivilegePolicy OBJECT-CLASS ::= { +## SUBCLASS OF {top} +## KIND auxiliary +## MAY CONTAIN {protPrivPolicy } +## ID id-oc-protectedPrivilegePolicy } +## +## 17.2 PMI Directory attributes +## +## 17.2.1 Attribute certificate attribute +## attributeCertificateAttribute ATTRIBUTE ::= { +## WITH SYNTAX AttributeCertificate +## EQUALITY MATCHING RULE attributeCertificateExactMatch +## ID id-at-attributeCertificate } +## +## 17.2.2 AA certificate attribute +## aACertificate ATTRIBUTE ::= { +## WITH SYNTAX AttributeCertificate +## EQUALITY MATCHING RULE attributeCertificateExactMatch +## ID id-at-aACertificate } +## +## 17.2.3 Attribute descriptor certificate attribute +## attributeDescriptorCertificate ATTRIBUTE ::= { +## WITH SYNTAX AttributeCertificate +## EQUALITY MATCHING RULE attributeCertificateExactMatch +## ID id-at-attributeDescriptorCertificate } +## +## 17.2.4 Attribute certificate revocation list attribute +## attributeCertificateRevocationList ATTRIBUTE ::= { +## WITH SYNTAX CertificateList +## EQUALITY MATCHING RULE certificateListExactMatch +## ID id-at-attributeCertificateRevocationList} +## +## 17.2.5 AA certificate revocation list attribute +## attributeAuthorityRevocationList ATTRIBUTE ::= { +## WITH SYNTAX CertificateList +## EQUALITY MATCHING RULE certificateListExactMatch +## ID id-at-attributeAuthorityRevocationList } +## +## 17.2.6 Delegation path attribute +## delegationPath ATTRIBUTE ::= { +## WITH SYNTAX AttCertPath +## ID id-at-delegationPath } +## AttCertPath ::= SEQUENCE OF AttributeCertificate +## +## 17.2.7 Privilege policy attribute +## privPolicy ATTRIBUTE ::= { +## WITH SYNTAX PolicySyntax +## ID id-at-privPolicy } +## +## 17.2.8 Protected privilege policy attribute +## protPrivPolicy ATTRIBUTE ::= { +## WITH SYNTAX AttributeCertificate +## EQUALITY MATCHING RULE attributeCertificateExactMatch +## ID id-at-protPrivPolicy } +## +## 17.2.9 XML Protected privilege policy attribute +## xmlPrivPolicy ATTRIBUTE ::= { +## WITH SYNTAX UTF8String -- contains XML-encoded privilege policy information +## ID id-at-xMLPprotPrivPolicy } +## + +## -- object identifier assignments -- +## -- object classes -- +objectidentifier id-oc-pmiUser 2.5.6.24 +objectidentifier id-oc-pmiAA 2.5.6.25 +objectidentifier id-oc-pmiSOA 2.5.6.26 +objectidentifier id-oc-attCertCRLDistributionPts 2.5.6.27 +objectidentifier id-oc-privilegePolicy 2.5.6.32 +objectidentifier id-oc-pmiDelegationPath 2.5.6.33 +objectidentifier id-oc-protectedPrivilegePolicy 2.5.6.34 +## -- directory attributes -- +objectidentifier id-at-attributeCertificate 2.5.4.58 +objectidentifier id-at-attributeCertificateRevocationList 2.5.4.59 +objectidentifier id-at-aACertificate 2.5.4.61 +objectidentifier id-at-attributeDescriptorCertificate 2.5.4.62 +objectidentifier id-at-attributeAuthorityRevocationList 2.5.4.63 +objectidentifier id-at-privPolicy 2.5.4.71 +objectidentifier id-at-role 2.5.4.72 +objectidentifier id-at-delegationPath 2.5.4.73 +objectidentifier id-at-protPrivPolicy 2.5.4.74 +objectidentifier id-at-xMLPrivilegeInfo 2.5.4.75 +objectidentifier id-at-xMLPprotPrivPolicy 2.5.4.76 +## -- attribute certificate extensions -- +## id-ce-authorityAttributeIdentifier OBJECT IDENTIFIER ::= {id-ce 38} +## id-ce-roleSpecCertIdentifier OBJECT IDENTIFIER ::= {id-ce 39} +## id-ce-basicAttConstraints OBJECT IDENTIFIER ::= {id-ce 41} +## id-ce-delegatedNameConstraints OBJECT IDENTIFIER ::= {id-ce 42} +## id-ce-timeSpecification OBJECT IDENTIFIER ::= {id-ce 43} +## id-ce-attributeDescriptor OBJECT IDENTIFIER ::= {id-ce 48} +## id-ce-userNotice OBJECT IDENTIFIER ::= {id-ce 49} +## id-ce-sOAIdentifier OBJECT IDENTIFIER ::= {id-ce 50} +## id-ce-acceptableCertPolicies OBJECT IDENTIFIER ::= {id-ce 52} +## id-ce-targetInformation OBJECT IDENTIFIER ::= {id-ce 55} +## id-ce-noRevAvail OBJECT IDENTIFIER ::= {id-ce 56} +## id-ce-acceptablePrivilegePolicies OBJECT IDENTIFIER ::= {id-ce 57} +## id-ce-indirectIssuer OBJECT IDENTIFIER ::= {id-ce 61} +## id-ce-noAssertion OBJECT IDENTIFIER ::= {id-ce 62} +## id-ce-issuedOnBehalfOf OBJECT IDENTIFIER ::= {id-ce 64} +## -- PMI matching rules -- +objectidentifier id-mr 2.5.13 +objectidentifier id-mr-attributeCertificateMatch id-mr:42 +objectidentifier id-mr-attributeCertificateExactMatch id-mr:45 +objectidentifier id-mr-holderIssuerMatch id-mr:46 +objectidentifier id-mr-authAttIdMatch id-mr:53 +objectidentifier id-mr-roleSpecCertIdMatch id-mr:54 +objectidentifier id-mr-basicAttConstraintsMatch id-mr:55 +objectidentifier id-mr-delegatedNameConstraintsMatch id-mr:56 +objectidentifier id-mr-timeSpecMatch id-mr:57 +objectidentifier id-mr-attDescriptorMatch id-mr:58 +objectidentifier id-mr-acceptableCertPoliciesMatch id-mr:59 +objectidentifier id-mr-delegationPathMatch id-mr:61 +objectidentifier id-mr-sOAIdentifierMatch id-mr:66 +objectidentifier id-mr-indirectIssuerMatch id-mr:67 +## -- syntaxes -- +## NOTE: 1.3.6.1.4.1.4203.666.11.10 is the oid arc assigned by OpenLDAP +## to this work in progress +objectidentifier AttributeCertificate 1.3.6.1.4.1.4203.666.11.10.2.1 +objectidentifier CertificateList 1.3.6.1.4.1.1466.115.121.1.9 +objectidentifier AttCertPath 1.3.6.1.4.1.4203.666.11.10.2.4 +objectidentifier PolicySyntax 1.3.6.1.4.1.4203.666.11.10.2.5 +objectidentifier RoleSyntax 1.3.6.1.4.1.4203.666.11.10.2.6 +# NOTE: OIDs from (expired) +#objectidentifier AttributeCertificate 1.2.826.0.1.3344810.7.5 +#objectidentifier AttCertPath 1.2.826.0.1.3344810.7.10 +#objectidentifier PolicySyntax 1.2.826.0.1.3344810.7.17 +#objectidentifier RoleSyntax 1.2.826.0.1.3344810.7.13 +## +## Substitute syntaxes +## +## AttCertPath +ldapsyntax ( 1.3.6.1.4.1.4203.666.11.10.2.4 + NAME 'AttCertPath' + DESC 'X.509 PMI attribute cartificate path: SEQUENCE OF AttributeCertificate' + X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' ) +## +## PolicySyntax +ldapsyntax ( 1.3.6.1.4.1.4203.666.11.10.2.5 + NAME 'PolicySyntax' + DESC 'X.509 PMI policy syntax' + X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' ) +## +## RoleSyntax +ldapsyntax ( 1.3.6.1.4.1.4203.666.11.10.2.6 + NAME 'RoleSyntax' + DESC 'X.509 PMI role syntax' + X-SUBST '1.3.6.1.4.1.1466.115.121.1.15' ) +## +## X.509 (08/2005) pp. 71, 86-89 +## +## 14.4.1 Role attribute +attributeType ( id-at-role + NAME 'role' + DESC 'X.509 Role attribute, use ;binary' + SYNTAX RoleSyntax ) +## +## 14.5 XML privilege information attribute +## -- contains XML-encoded privilege information +attributeType ( id-at-xMLPrivilegeInfo + NAME 'xmlPrivilegeInfo' + DESC 'X.509 XML privilege information attribute' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +## +## 17.2 PMI Directory attributes +## +## 17.2.1 Attribute certificate attribute +attributeType ( id-at-attributeCertificate + NAME 'attributeCertificateAttribute' + DESC 'X.509 Attribute certificate attribute, use ;binary' + SYNTAX AttributeCertificate + EQUALITY attributeCertificateExactMatch ) +## +## 17.2.2 AA certificate attribute +attributeType ( id-at-aACertificate + NAME 'aACertificate' + DESC 'X.509 AA certificate attribute, use ;binary' + SYNTAX AttributeCertificate + EQUALITY attributeCertificateExactMatch ) +## +## 17.2.3 Attribute descriptor certificate attribute +attributeType ( id-at-attributeDescriptorCertificate + NAME 'attributeDescriptorCertificate' + DESC 'X.509 Attribute descriptor certificate attribute, use ;binary' + SYNTAX AttributeCertificate + EQUALITY attributeCertificateExactMatch ) +## +## 17.2.4 Attribute certificate revocation list attribute +attributeType ( id-at-attributeCertificateRevocationList + NAME 'attributeCertificateRevocationList' + DESC 'X.509 Attribute certificate revocation list attribute, use ;binary' + SYNTAX CertificateList + X-EQUALITY 'certificateListExactMatch, not implemented yet' ) +## +## 17.2.5 AA certificate revocation list attribute +attributeType ( id-at-attributeAuthorityRevocationList + NAME 'attributeAuthorityRevocationList' + DESC 'X.509 AA certificate revocation list attribute, use ;binary' + SYNTAX CertificateList + X-EQUALITY 'certificateListExactMatch, not implemented yet' ) +## +## 17.2.6 Delegation path attribute +attributeType ( id-at-delegationPath + NAME 'delegationPath' + DESC 'X.509 Delegation path attribute, use ;binary' + SYNTAX AttCertPath ) +## AttCertPath ::= SEQUENCE OF AttributeCertificate +## +## 17.2.7 Privilege policy attribute +attributeType ( id-at-privPolicy + NAME 'privPolicy' + DESC 'X.509 Privilege policy attribute, use ;binary' + SYNTAX PolicySyntax ) +## +## 17.2.8 Protected privilege policy attribute +attributeType ( id-at-protPrivPolicy + NAME 'protPrivPolicy' + DESC 'X.509 Protected privilege policy attribute, use ;binary' + SYNTAX AttributeCertificate + EQUALITY attributeCertificateExactMatch ) +## +## 17.2.9 XML Protected privilege policy attribute +## -- contains XML-encoded privilege policy information +attributeType ( id-at-xMLPprotPrivPolicy + NAME 'xmlPrivPolicy' + DESC 'X.509 XML Protected privilege policy attribute' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 ) +## +## 17.1 PMI directory object classes +## +## 17.1.1 PMI user object class +## -- a PMI user (i.e., a "holder") +objectClass ( id-oc-pmiUser + NAME 'pmiUser' + DESC 'X.509 PMI user object class' + SUP top + AUXILIARY + MAY ( attributeCertificateAttribute ) ) +## +## 17.1.2 PMI AA object class +## -- a PMI AA +objectClass ( id-oc-pmiAA + NAME 'pmiAA' + DESC 'X.509 PMI AA object class' + SUP top + AUXILIARY + MAY ( aACertificate $ + attributeCertificateRevocationList $ + attributeAuthorityRevocationList + ) ) +## +## 17.1.3 PMI SOA object class +## -- a PMI Source of Authority +objectClass ( id-oc-pmiSOA + NAME 'pmiSOA' + DESC 'X.509 PMI SOA object class' + SUP top + AUXILIARY + MAY ( attributeCertificateRevocationList $ + attributeAuthorityRevocationList $ + attributeDescriptorCertificate + ) ) +## +## 17.1.4 Attribute certificate CRL distribution point object class +objectClass ( id-oc-attCertCRLDistributionPts + NAME 'attCertCRLDistributionPt' + DESC 'X.509 Attribute certificate CRL distribution point object class' + SUP top + AUXILIARY + MAY ( attributeCertificateRevocationList $ + attributeAuthorityRevocationList + ) ) +## +## 17.1.5 PMI delegation path +objectClass ( id-oc-pmiDelegationPath + NAME 'pmiDelegationPath' + DESC 'X.509 PMI delegation path' + SUP top + AUXILIARY + MAY ( delegationPath ) ) +## +## 17.1.6 Privilege policy object class +objectClass ( id-oc-privilegePolicy + NAME 'privilegePolicy' + DESC 'X.509 Privilege policy object class' + SUP top + AUXILIARY + MAY ( privPolicy ) ) +## +## 17.1.7 Protected privilege policy object class +objectClass ( id-oc-protectedPrivilegePolicy + NAME 'protectedPrivilegePolicy' + DESC 'X.509 Protected privilege policy object class' + SUP top + AUXILIARY + MAY ( protPrivPolicy ) ) + diff --git a/servers/slapd/schema_init.c b/servers/slapd/schema_init.c index 27bcb72824..28f2498a42 100644 --- a/servers/slapd/schema_init.c +++ b/servers/slapd/schema_init.c @@ -57,6 +57,32 @@ #define authzMatch octetStringMatch +/* X.509 PMI ldapSyntaxes */ +/* FIXME: need to create temporary OIDs under OpenLDAP's arc; + * these are currently hijacked + * + * 1.3.6.1.4.1.4203.666 OpenLDAP + * 1.3.6.1.4.1.4203.666.11 self-contained works + * 1.3.6.1.4.1.4203.666.11.10 X.509 PMI + * 1.3.6.1.4.1.4203.666.11.10.2 X.509 PMI ldapSyntaxes + * 1.3.6.1.4.1.4203.666.11.10.2.1 AttributeCertificate (supported) + * 1.3.6.1.4.1.4203.666.11.10.2.2 AttributeCertificateExactAssertion (supported) + * 1.3.6.1.4.1.4203.666.11.10.2.3 AttributeCertificateAssertion (not supported) + * 1.3.6.1.4.1.4203.666.11.10.2.4 AttCertPath (X-SUBST'ed right now in pmi.schema) + * 1.3.6.1.4.1.4203.666.11.10.2.5 PolicySyntax (X-SUBST'ed right now in pmi.schema) + * 1.3.6.1.4.1.4203.666.11.10.2.6 RoleSyntax (X-SUBST'ed right now in pmi.schema) + */ +#if 0 /* from (expired) */ +#define attributeCertificateSyntaxOID "1.2.826.0.1.3344810.7.5" +#define attributeCertificateExactAssertionSyntaxOID "1.2.826.0.1.3344810.7.6" +#define attributeCertificateAssertionSyntaxOID "1.2.826.0.1.3344810.7.7" +#else /* from OpenLDAP's experimental oid arc */ +#define X509_PMI_SyntaxOID "1.3.6.1.4.1.4203.666.11.10.2" +#define attributeCertificateSyntaxOID X509_PMI_SyntaxOID ".1" +#define attributeCertificateExactAssertionSyntaxOID X509_PMI_SyntaxOID ".2" +#define attributeCertificateAssertionSyntaxOID X509_PMI_SyntaxOID ".3" +#endif + unsigned int index_substr_if_minlen = SLAP_INDEX_SUBSTR_IF_MINLEN_DEFAULT; unsigned int index_substr_if_maxlen = SLAP_INDEX_SUBSTR_IF_MAXLEN_DEFAULT; unsigned int index_substr_any_len = SLAP_INDEX_SUBSTR_ANY_LEN_DEFAULT; @@ -139,6 +165,40 @@ enum { SLAP_X509_OPT_CL_CRLEXTENSIONS = SLAP_X509_OPTION + 0 }; +/* +GeneralName ::= CHOICE { + otherName [0] INSTANCE OF OTHER-NAME, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } +*/ +enum { + SLAP_X509_GN_OTHERNAME = SLAP_X509_OPTION + 0, + SLAP_X509_GN_RFC822NAME = SLAP_X509_OPTION + 1, + SLAP_X509_GN_DNSNAME = SLAP_X509_OPTION + 2, + SLAP_X509_GN_X400ADDRESS = SLAP_X509_OPTION + 3, + SLAP_X509_GN_DIRECTORYNAME = SLAP_X509_OPTION + 4, + SLAP_X509_GN_EDIPARTYNAME = SLAP_X509_OPTION + 5, + SLAP_X509_GN_URI = SLAP_X509_OPTION + 6, + SLAP_X509_GN_IPADDRESS = SLAP_X509_OPTION + 7, + SLAP_X509_GN_REGISTEREDID = SLAP_X509_OPTION + 8 +}; + +/* X.509 PMI related stuff */ +enum { + SLAP_X509AC_V1 = 0, + SLAP_X509AC_V2 = 1 +}; + +enum { + SLAP_X509AC_ISSUER = SLAP_X509_OPTION + 0 +}; + /* X.509 certificate validation */ static int certificateValidate( Syntax *syntax, struct berval *in ) @@ -280,6 +340,89 @@ certificateListValidate( Syntax *syntax, struct berval *in ) return LDAP_SUCCESS; } +/* X.509 PMI Attribute Certificate Validate */ +static int +attributeCertificateValidate( Syntax *syntax, struct berval *in ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + ber_len_t len; + ber_int_t version; + int cont = 0; + + ber_init2( ber, in, LBER_USE_DER ); + + tag = ber_skip_tag( ber, &len ); /* Signed wrapper */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + + tag = ber_skip_tag( ber, &len ); /* Sequence */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + + tag = ber_peek_tag( ber, &len ); /* Version */ + if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX; + tag = ber_get_int( ber, &version ); /* X.509 only allows v2 */ + if ( version != SLAP_X509AC_V2 ) return LDAP_INVALID_SYNTAX; + + tag = ber_skip_tag( ber, &len ); /* Holder */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Issuer */ + if ( tag != SLAP_X509AC_ISSUER ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Signature */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Serial number */ + if ( tag != LBER_INTEGER ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* AttCertValidityPeriod */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + tag = ber_skip_tag( ber, &len ); /* Attributes */ + if ( tag != LBER_SEQUENCE ) return LDAP_INVALID_SYNTAX; + ber_skip_data( ber, len ); + + ber_peek_tag( ber, &len ); + + if ( tag == LBER_BITSTRING ) { /* issuerUniqueID */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + tag = ber_peek_tag( ber, &len ); + } + + if ( tag == LBER_SEQUENCE ) { /* extensions or signatureAlgorithm */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + cont++; + tag = ber_peek_tag( ber, &len ); + } + + if ( tag == LBER_SEQUENCE ) { /* signatureAlgorithm */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + cont++; + tag = ber_peek_tag( ber, &len ); + } + + if ( tag == LBER_BITSTRING ) { /* Signature */ + tag = ber_skip_tag( ber, &len ); + ber_skip_data( ber, len ); + cont++; + tag = ber_peek_tag( ber, &len ); + } + + /* Must be at end now */ + if ( len != 0 || tag != LBER_DEFAULT || cont < 2 ) return LDAP_INVALID_SYNTAX; + + return LDAP_SUCCESS; +} + int octetStringMatch( int *matchp, @@ -3817,7 +3960,7 @@ issuerAndThisUpdateNormalize( p = lutil_strncopy( p, tu2.bv_val, tu2.bv_len ); p = lutil_strcopy( p, /*{*/ "\" }" ); - assert( p == & out->bv_val[out->bv_len] ); + assert( p == &out->bv_val[out->bv_len] ); func_leave: Debug( LDAP_DEBUG_TRACE, "<<< issuerAndThisUpdateNormalize: <%s> => <%s>\n", @@ -3923,164 +4066,851 @@ done: return rc; } +/* X.509 PMI serialNumberAndIssuerSerialCheck + +AttributeCertificateExactAssertion ::= SEQUENCE { + serialNumber CertificateSerialNumber, + issuer AttCertIssuer } + +CertificateSerialNumber ::= INTEGER + +AttCertIssuer ::= [0] SEQUENCE { +issuerName GeneralNames OPTIONAL, +baseCertificateID [0] IssuerSerial OPTIONAL, +objectDigestInfo [1] ObjectDigestInfo OPTIONAL } +-- At least one component shall be present + +GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + +GeneralName ::= CHOICE { + otherName [0] INSTANCE OF OTHER-NAME, + rfc822Name [1] IA5String, + dNSName [2] IA5String, + x400Address [3] ORAddress, + directoryName [4] Name, + ediPartyName [5] EDIPartyName, + uniformResourceIdentifier [6] IA5String, + iPAddress [7] OCTET STRING, + registeredID [8] OBJECT IDENTIFIER } + +IssuerSerial ::= SEQUENCE { + issuer GeneralNames, + serial CertificateSerialNumber, + issuerUID UniqueIdentifier OPTIONAL } + +ObjectDigestInfo ::= SEQUENCE { + digestedObjectType ENUMERATED { + publicKey (0), + publicKeyCert (1), + otherObjectTypes (2) }, + otherObjectTypeID OBJECT IDENTIFIER OPTIONAL, + digestAlgorithm AlgorithmIdentifier, + objectDigest BIT STRING } + + * The way I interpret it, an assertion should look like + + { serialNumber 'dd'H, + issuer { issuerName { directoryName:rdnSequence:"cn=yyy" }, -- optional + baseCertificateID { serial '1d'H, + issuer { directoryName:rdnSequence:"cn=zzz" }, + issuerUID -- optional + }, -- optional + objectDigestInfo { ... } -- optional + } + } + + * with issuerName, baseCertificateID and objectDigestInfo optional, + * at least one present; the way it's currently implemented, it is + + { serialNumber 'dd'H, + issuer { baseCertificateID { serial '1d'H, + issuer { directoryName:rdnSequence:"cn=zzz" } + } + } + } + + * with all the above parts mandatory. + */ static int -hexValidate( - Syntax *syntax, - struct berval *in ) +serialNumberAndIssuerSerialCheck( + struct berval *in, + struct berval *sn, + struct berval *is, + struct berval *i_sn, /* contain serial of baseCertificateID */ + void *ctx ) { - ber_len_t i; - - assert( in != NULL ); - assert( !BER_BVISNULL( in ) ); - - for ( i = 0; i < in->bv_len; i++ ) { - if ( !ASCII_HEX( in->bv_val[ i ] ) ) { - return LDAP_INVALID_SYNTAX; - } - } + /* Parse GSER format */ + enum { + HAVE_NONE = 0x0, + HAVE_SN = 0x1, + HAVE_ISSUER = 0x2, + HAVE_ALL = ( HAVE_SN | HAVE_ISSUER ) + } have = HAVE_NONE, have2 = HAVE_NONE; + int numdquotes = 0; + struct berval x = *in; + struct berval ni; - return LDAP_SUCCESS; -} + if ( in->bv_len < 3 ) return LDAP_INVALID_SYNTAX; -/* Normalize a SID as used inside a CSN: - * three-digit numeric string */ -static int -hexNormalize( - slap_mask_t usage, - Syntax *syntax, - MatchingRule *mr, - struct berval *val, - struct berval *normalized, - void *ctx ) -{ - ber_len_t i; + /* no old format */ + if ( in->bv_val[0] != '{' && in->bv_val[in->bv_len-1] != '}' ) return LDAP_INVALID_SYNTAX; - assert( val != NULL ); - assert( normalized != NULL ); + x.bv_val++; + x.bv_len -= 2; - ber_dupbv_x( normalized, val, ctx ); + do { - for ( i = 0; i < normalized->bv_len; i++ ) { - if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) { - ber_memfree_x( normalized->bv_val, ctx ); - BER_BVZERO( normalized ); - return LDAP_INVALID_SYNTAX; + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; } - normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] ); - } + /* should be at issuer or serialNumber NamedValue */ + if ( strncasecmp( x.bv_val, "issuer", STRLENOF("issuer") ) == 0 ) { + if ( have & HAVE_ISSUER ) { + return LDAP_INVALID_SYNTAX; + } - return LDAP_SUCCESS; -} + /* parse IssuerSerial */ + x.bv_val += STRLENOF("issuer"); + x.bv_len -= STRLENOF("issuer"); -static int -sidValidate ( - Syntax *syntax, - struct berval *in ) -{ - assert( in != NULL ); - assert( !BER_BVISNULL( in ) ); + if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; - if ( in->bv_len != 3 ) { - return LDAP_INVALID_SYNTAX; - } + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - return hexValidate( NULL, in ); -} + if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; -/* Normalize a SID as used inside a CSN: - * three-digit numeric string */ -static int -sidNormalize( - slap_mask_t usage, - Syntax *syntax, - MatchingRule *mr, - struct berval *val, - struct berval *normalized, - void *ctx ) -{ - if ( val->bv_len != 3 ) { - return LDAP_INVALID_SYNTAX; - } + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - return hexNormalize( 0, NULL, NULL, val, normalized, ctx ); -} + if ( strncasecmp( x.bv_val, "baseCertificateID ", STRLENOF("baseCertificateID ") ) != 0 ) { + return LDAP_INVALID_SYNTAX; + } + x.bv_val += STRLENOF("baseCertificateID "); + x.bv_len -= STRLENOF("baseCertificateID "); -static int -sidPretty( - Syntax *syntax, - struct berval *val, - struct berval *out, - void *ctx ) -{ - return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx ); -} + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } -/* Normalize a SID as used inside a CSN, either as-is - * (assertion value) or extracted from the CSN - * (attribute value) */ -static int -csnSidNormalize( - slap_mask_t usage, - Syntax *syntax, - MatchingRule *mr, - struct berval *val, - struct berval *normalized, - void *ctx ) -{ - struct berval bv; - char *ptr, - buf[ 4 ]; + if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + do { + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - if ( BER_BVISEMPTY( val ) ) { - return LDAP_INVALID_SYNTAX; - } + /* parse issuer of baseCertificateID */ + if ( strncasecmp( x.bv_val, "issuer ", STRLENOF("issuer ") ) == 0 ) { + if ( have2 & HAVE_ISSUER ) { + return LDAP_INVALID_SYNTAX; + } - if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) { - return sidNormalize( 0, NULL, NULL, val, normalized, ctx ); - } + x.bv_val += STRLENOF("issuer "); + x.bv_len -= STRLENOF("issuer "); - assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 ); + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - ptr = ber_bvchr( val, '#' ); - if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { - return LDAP_INVALID_SYNTAX; - } + if ( x.bv_val[0] != '{' /*}*/ ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; - bv.bv_val = ptr + 1; - bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val ); + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { - return LDAP_INVALID_SYNTAX; - } + if ( strncasecmp( x.bv_val, "directoryName:rdnSequence:", STRLENOF("directoryName:rdnSequence:") ) != 0 ) { + return LDAP_INVALID_SYNTAX; + } + x.bv_val += STRLENOF("directoryName:rdnSequence:"); + x.bv_len -= STRLENOF("directoryName:rdnSequence:"); + + if ( x.bv_val[0] != '"' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + is->bv_val = x.bv_val; + is->bv_len = 0; + + for ( ; is->bv_len < x.bv_len; ) { + if ( is->bv_val[is->bv_len] != '"' ) { + is->bv_len++; + continue; + } + if ( is->bv_val[is->bv_len + 1] == '"' ) { + /* double dquote */ + is->bv_len += 2; + continue; + } + break; + } + x.bv_val += is->bv_len + 1; + x.bv_len -= is->bv_len + 1; - bv.bv_val = ptr + 1; - bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val ); - - ptr = ber_bvchr( &bv, '#' ); - if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { - return LDAP_INVALID_SYNTAX; - } + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } - bv.bv_len = ptr - bv.bv_val; + if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; - if ( bv.bv_len == 2 ) { - /* OpenLDAP 2.3 SID */ - buf[ 0 ] = '0'; - buf[ 1 ] = bv.bv_val[ 0 ]; - buf[ 2 ] = bv.bv_val[ 1 ]; - buf[ 3 ] = '\0'; + have2 |= HAVE_ISSUER; - bv.bv_val = buf; - bv.bv_len = 3; - } + } else if ( strncasecmp( x.bv_val, "serial ", STRLENOF("serial ") ) == 0 ) { + if ( have2 & HAVE_SN ) { + return LDAP_INVALID_SYNTAX; + } - return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx ); -} + x.bv_val += STRLENOF("serial "); + x.bv_len -= STRLENOF("serial "); -static int + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len--) { + /* empty */; + } + + if ( checkNum( &x, i_sn ) ) { + return LDAP_INVALID_SYNTAX; + } + + x.bv_val += i_sn->bv_len; + x.bv_len -= i_sn->bv_len; + + have2 |= HAVE_SN; + + } else { + return LDAP_INVALID_SYNTAX; + } + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( have2 == HAVE_ALL ) { + break; + } + + if ( x.bv_val[0] != ',' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + } while ( 1 ); + + if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( x.bv_val[0] != /*{*/ '}' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + have |= HAVE_ISSUER; + + } else if ( strncasecmp( x.bv_val, "serialNumber", STRLENOF("serialNumber") ) == 0 ) { + if ( have & HAVE_SN ) { + return LDAP_INVALID_SYNTAX; + } + + /* parse serialNumber */ + x.bv_val += STRLENOF("serialNumber"); + x.bv_len -= STRLENOF("serialNumber"); + + if ( x.bv_val[0] != ' ' ) return LDAP_INVALID_SYNTAX; + x.bv_val++; + x.bv_len--; + + /* eat leading spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( checkNum( &x, sn ) ) { + return LDAP_INVALID_SYNTAX; + } + + x.bv_val += sn->bv_len; + x.bv_len -= sn->bv_len; + + have |= HAVE_SN; + + } else { + return LDAP_INVALID_SYNTAX; + } + + /* eat spaces */ + for ( ; (x.bv_val[0] == ' ') && x.bv_len; x.bv_val++, x.bv_len-- ) { + /* empty */; + } + + if ( have == HAVE_ALL ) { + break; + } + + if ( x.bv_val[0] != ',' ) { + return LDAP_INVALID_SYNTAX; + } + x.bv_val++ ; + x.bv_len--; + } while ( 1 ); + + /* should have no characters left... */ + if( x.bv_len ) return LDAP_INVALID_SYNTAX; + + if ( numdquotes == 0 ) { + ber_dupbv_x( &ni, is, ctx ); + + } else { + ber_int_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++ ) { + if ( is->bv_val[src] == '"' ) { + src++; + } + ni.bv_val[dst] = is->bv_val[src]; + } + ni.bv_val[dst] = '\0'; + } + + *is = ni; + + /* need to handle double dquotes here */ + return 0; +} + +/* X.509 PMI serialNumberAndIssuerSerialValidate */ +static int +serialNumberAndIssuerSerialValidate( + Syntax *syntax, + struct berval *in ) +{ + int rc; + struct berval sn, i, i_sn; + + Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialValidate: <%s>\n", + in->bv_val, 0, 0 ); + + rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, NULL ); + if ( rc ) { + goto done; + } + + /* validate DN -- doesn't handle double dquote */ + rc = dnValidate( NULL, &i ); + if ( rc ) { + rc = LDAP_INVALID_SYNTAX; + } + + if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) { + slap_sl_free( i.bv_val, NULL ); + } + +done:; + Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialValidate: <%s> err=%d\n", + in->bv_val, rc, 0 ); + + return rc; +} + +/* X.509 PMI serialNumberAndIssuerSerialPretty */ +static int +serialNumberAndIssuerSerialPretty( + Syntax *syntax, + struct berval *in, + struct berval *out, + void *ctx ) +{ + struct berval sn, i, i_sn, ni = BER_BVNULL; + char *p; + int rc; + + assert( in != NULL ); + assert( out != NULL ); + + Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialPretty: <%s>\n", + in->bv_val, 0, 0 ); + + rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx ); + if ( rc ) { + goto done; + } + + rc = dnPretty( syntax, &i, &ni, ctx ); + + if ( in->bv_val[0] == '{' && in->bv_val[in->bv_len-1] == '}' ) { + slap_sl_free( i.bv_val, ctx ); + } + + if ( rc ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + + /* make room from sn + "$" */ + out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }") + + sn.bv_len + ni.bv_len + i_sn.bv_len; + out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx ); + + if ( out->bv_val == NULL ) { + out->bv_len = 0; + rc = LDAP_OTHER; + goto done; + } + + p = out->bv_val; + p = lutil_strcopy( p, "{ serialNumber " ); + p = lutil_strncopy( p, sn.bv_val, sn.bv_len ); + p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" ); + p = lutil_strncopy( p, ni.bv_val, ni.bv_len ); + p = lutil_strcopy( p, "\" }, serial " ); + p = lutil_strncopy( p, i_sn.bv_val, i_sn.bv_len ); + p = lutil_strcopy( p, " } } }" ); + + assert( p == &out->bv_val[out->bv_len] ); + +done:; + Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialPretty: <%s> => <%s>\n", + in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 ); + + slap_sl_free( ni.bv_val, ctx ); + + return rc; +} + +/* X.509 PMI serialNumberAndIssuerSerialNormalize */ +/* + * This routine is called by attributeCertificateExactNormalize + * when attributeCertificateExactNormalize receives a search + * string instead of a attribute certificate. This routine + * checks if the search value is valid and then returns the + * normalized value + */ +static int +serialNumberAndIssuerSerialNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *in, + struct berval *out, + void *ctx ) +{ + struct berval i, ni = BER_BVNULL, + sn, sn2 = BER_BVNULL, sn3 = BER_BVNULL, + i_sn, i_sn2 = BER_BVNULL, i_sn3 = BER_BVNULL; + char sbuf2[SLAP_SN_BUFLEN], i_sbuf2[SLAP_SN_BUFLEN], + sbuf3[SLAP_SN_BUFLEN], i_sbuf3[SLAP_SN_BUFLEN]; + char *p; + int rc; + + assert( in != NULL ); + assert( out != NULL ); + + Debug( LDAP_DEBUG_TRACE, ">>> serialNumberAndIssuerSerialNormalize: <%s>\n", + in->bv_val, 0, 0 ); + + rc = serialNumberAndIssuerSerialCheck( in, &sn, &i, &i_sn, ctx ); + if ( rc ) { + goto func_leave; + } + + 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 ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + /* Convert sn to canonical hex */ + sn2.bv_val = sbuf2; + sn2.bv_len = sn.bv_len; + if ( sn.bv_len > sizeof( sbuf2 ) ) { + sn2.bv_val = slap_sl_malloc( sn.bv_len, ctx ); + } + if ( lutil_str2bin( &sn, &sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + /* Convert i_sn to canonical hex */ + i_sn2.bv_val = i_sbuf2; + i_sn2.bv_len = i_sn.bv_len; + if ( i_sn.bv_len > sizeof( i_sbuf2 ) ) { + i_sn2.bv_val = slap_sl_malloc( i_sn.bv_len, ctx ); + } + if ( lutil_str2bin( &i_sn, &i_sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + sn3.bv_val = sbuf3; + sn3.bv_len = sizeof(sbuf3); + if ( slap_bin2hex( &sn2, &sn3, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + i_sn3.bv_val = i_sbuf3; + i_sn3.bv_len = sizeof(i_sbuf3); + if ( slap_bin2hex( &i_sn2, &i_sn3, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto func_leave; + } + + out->bv_len = STRLENOF("{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }") + + sn3.bv_len + ni.bv_len + i_sn3.bv_len; + out->bv_val = slap_sl_malloc( out->bv_len + 1, ctx ); + + if ( out->bv_val == NULL ) { + out->bv_len = 0; + rc = LDAP_OTHER; + goto func_leave; + } + + p = out->bv_val; + + p = lutil_strcopy( p, "{ serialNumber " ); + p = lutil_strncopy( p, sn3.bv_val, sn3.bv_len ); + p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" ); + p = lutil_strncopy( p, ni.bv_val, ni.bv_len ); + p = lutil_strcopy( p, "\" }, serial " ); + p = lutil_strncopy( p, i_sn3.bv_val, i_sn3.bv_len ); + p = lutil_strcopy( p, " } } }" ); + + assert( p == &out->bv_val[out->bv_len] ); + +func_leave: + Debug( LDAP_DEBUG_TRACE, "<<< serialNumberAndIssuerSerialNormalize: <%s> => <%s>\n", + in->bv_val, rc == LDAP_SUCCESS ? out->bv_val : "(err)", 0 ); + + if ( sn2.bv_val != sbuf2 ) { + slap_sl_free( sn2.bv_val, ctx ); + } + + if ( i_sn2.bv_val != i_sbuf2 ) { + slap_sl_free( i_sn2.bv_val, ctx ); + } + + if ( sn3.bv_val != sbuf3 ) { + slap_sl_free( sn3.bv_val, ctx ); + } + + if ( i_sn3.bv_val != i_sbuf3 ) { + slap_sl_free( i_sn3.bv_val, ctx ); + } + + slap_sl_free( ni.bv_val, ctx ); + + return rc; +} + +/* X.509 PMI attributeCertificateExactNormalize */ +static int +attributeCertificateExactNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + BerElementBuffer berbuf; + BerElement *ber = (BerElement *)&berbuf; + ber_tag_t tag; + ber_len_t len; + char issuer_serialbuf[SLAP_SN_BUFLEN], serialbuf[SLAP_SN_BUFLEN]; + struct berval sn, i_sn, sn2, i_sn2; + struct berval issuer_dn = BER_BVNULL, bvdn; + char *p; + int rc = LDAP_INVALID_SYNTAX; + + if ( BER_BVISEMPTY( val ) ) { + goto done; + } + + if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) { + return serialNumberAndIssuerSerialNormalize( 0, NULL, NULL, val, normalized, ctx ); + } + + assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 ); + + ber_init2( ber, val, LBER_USE_DER ); + tag = ber_skip_tag( ber, &len ); /* Signed Sequence */ + tag = ber_skip_tag( ber, &len ); /* Sequence */ + tag = ber_skip_tag( ber, &len ); /* (Mandatory) version; must be v2(1) */ + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* Holder Sequence */ + ber_skip_data( ber, len ); + + /* Issuer */ + tag = ber_skip_tag( ber, &len ); /* Sequence */ + /* issuerName (GeneralNames sequence; optional)? */ + tag = ber_skip_tag( ber, &len ); /* baseCertificateID (sequence; optional)? */ + tag = ber_skip_tag( ber, &len ); /* GeneralNames (sequence) */ + tag = ber_skip_tag( ber, &len ); /* directoryName (we only accept this form of GeneralName) */ + if ( tag != SLAP_X509_GN_DIRECTORYNAME ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + tag = ber_peek_tag( ber, &len ); /* sequence of RDN */ + len = ber_ptrlen( ber ); + bvdn.bv_val = val->bv_val + len; + bvdn.bv_len = val->bv_len - len; + rc = dnX509normalize( &bvdn, &issuer_dn ); + if ( rc != LDAP_SUCCESS ) goto done; + + tag = ber_skip_tag( ber, &len ); /* sequence of RDN */ + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* serial number */ + if ( tag != LBER_INTEGER ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + i_sn.bv_val = (char *)ber->ber_ptr; + i_sn.bv_len = len; + i_sn2.bv_val = issuer_serialbuf; + i_sn2.bv_len = sizeof(issuer_serialbuf); + if ( slap_bin2hex( &i_sn, &i_sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + ber_skip_data( ber, len ); + + /* issuerUID (bitstring; optional)? */ + /* objectDigestInfo (sequence; optional)? */ + + tag = ber_skip_tag( ber, &len ); /* Signature (sequence) */ + ber_skip_data( ber, len ); + tag = ber_skip_tag( ber, &len ); /* serial number */ + if ( tag != LBER_INTEGER ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + sn.bv_val = (char *)ber->ber_ptr; + sn.bv_len = len; + sn2.bv_val = serialbuf; + sn2.bv_len = sizeof(serialbuf); + if ( slap_bin2hex( &sn, &sn2, ctx ) ) { + rc = LDAP_INVALID_SYNTAX; + goto done; + } + ber_skip_data( ber, len ); + + normalized->bv_len = STRLENOF( "{ serialNumber , issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"\" }, serial } } }" ) + + sn2.bv_len + issuer_dn.bv_len + i_sn2.bv_len; + normalized->bv_val = ch_malloc( normalized->bv_len + 1 ); + + p = normalized->bv_val; + + p = lutil_strcopy( p, "{ serialNumber " ); + p = lutil_strncopy( p, sn2.bv_val, sn2.bv_len ); + p = lutil_strcopy( p, ", issuer { baseCertificateID { issuer { directoryName:rdnSequence:\"" ); + p = lutil_strncopy( p, issuer_dn.bv_val, issuer_dn.bv_len ); + p = lutil_strcopy( p, "\" }, serial " ); + p = lutil_strncopy( p, i_sn2.bv_val, i_sn2.bv_len ); + p = lutil_strcopy( p, " } } }" ); + + Debug( LDAP_DEBUG_TRACE, "attributeCertificateExactNormalize: %s\n", + normalized->bv_val, NULL, NULL ); + + rc = LDAP_SUCCESS; + +done: + if ( issuer_dn.bv_val ) ber_memfree( issuer_dn.bv_val ); + if ( i_sn2.bv_val != issuer_serialbuf ) ber_memfree_x( i_sn2.bv_val, ctx ); + if ( sn2.bv_val != serialbuf ) ber_memfree_x( sn2.bv_val, ctx ); + + return rc; +} + + +static int +hexValidate( + Syntax *syntax, + struct berval *in ) +{ + ber_len_t i; + + assert( in != NULL ); + assert( !BER_BVISNULL( in ) ); + + for ( i = 0; i < in->bv_len; i++ ) { + if ( !ASCII_HEX( in->bv_val[ i ] ) ) { + return LDAP_INVALID_SYNTAX; + } + } + + return LDAP_SUCCESS; +} + +/* Normalize a SID as used inside a CSN: + * three-digit numeric string */ +static int +hexNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + ber_len_t i; + + assert( val != NULL ); + assert( normalized != NULL ); + + ber_dupbv_x( normalized, val, ctx ); + + for ( i = 0; i < normalized->bv_len; i++ ) { + if ( !ASCII_HEX( normalized->bv_val[ i ] ) ) { + ber_memfree_x( normalized->bv_val, ctx ); + BER_BVZERO( normalized ); + return LDAP_INVALID_SYNTAX; + } + + normalized->bv_val[ i ] = TOLOWER( normalized->bv_val[ i ] ); + } + + return LDAP_SUCCESS; +} + +static int +sidValidate ( + Syntax *syntax, + struct berval *in ) +{ + assert( in != NULL ); + assert( !BER_BVISNULL( in ) ); + + if ( in->bv_len != 3 ) { + return LDAP_INVALID_SYNTAX; + } + + return hexValidate( NULL, in ); +} + +/* Normalize a SID as used inside a CSN: + * three-digit numeric string */ +static int +sidNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + if ( val->bv_len != 3 ) { + return LDAP_INVALID_SYNTAX; + } + + return hexNormalize( 0, NULL, NULL, val, normalized, ctx ); +} + +static int +sidPretty( + Syntax *syntax, + struct berval *val, + struct berval *out, + void *ctx ) +{ + return sidNormalize( SLAP_MR_VALUE_OF_SYNTAX, NULL, NULL, val, out, ctx ); +} + +/* Normalize a SID as used inside a CSN, either as-is + * (assertion value) or extracted from the CSN + * (attribute value) */ +static int +csnSidNormalize( + slap_mask_t usage, + Syntax *syntax, + MatchingRule *mr, + struct berval *val, + struct berval *normalized, + void *ctx ) +{ + struct berval bv; + char *ptr, + buf[ 4 ]; + + + if ( BER_BVISEMPTY( val ) ) { + return LDAP_INVALID_SYNTAX; + } + + if ( SLAP_MR_IS_VALUE_OF_ASSERTION_SYNTAX(usage) ) { + return sidNormalize( 0, NULL, NULL, val, normalized, ctx ); + } + + assert( SLAP_MR_IS_VALUE_OF_ATTRIBUTE_SYNTAX(usage) != 0 ); + + ptr = ber_bvchr( val, '#' ); + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { + return LDAP_INVALID_SYNTAX; + } + + bv.bv_val = ptr + 1; + bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val ); + + ptr = ber_bvchr( &bv, '#' ); + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { + return LDAP_INVALID_SYNTAX; + } + + bv.bv_val = ptr + 1; + bv.bv_len = val->bv_len - ( ptr + 1 - val->bv_val ); + + ptr = ber_bvchr( &bv, '#' ); + if ( ptr == NULL || ptr == &val->bv_val[val->bv_len] ) { + return LDAP_INVALID_SYNTAX; + } + + bv.bv_len = ptr - bv.bv_val; + + if ( bv.bv_len == 2 ) { + /* OpenLDAP 2.3 SID */ + buf[ 0 ] = '0'; + buf[ 1 ] = bv.bv_val[ 0 ]; + buf[ 2 ] = bv.bv_val[ 1 ]; + buf[ 3 ] = '\0'; + + bv.bv_val = buf; + bv.bv_len = 3; + } + + return sidNormalize( 0, NULL, NULL, &bv, normalized, ctx ); +} + +static int csnValidate( Syntax *syntax, struct berval *in ) @@ -5184,6 +6014,10 @@ static slap_syntax_defs_rec syntax_defs[] = { X_BINARY X_NOT_H_R ")", SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, NULL, sequenceValidate, NULL}, + {"( " attributeCertificateSyntaxOID " DESC 'X.509 AttributeCertificate' " + X_BINARY X_NOT_H_R ")", + SLAP_SYNTAX_BINARY|SLAP_SYNTAX_BER, + NULL, attributeCertificateValidate, NULL}, #if 0 /* need to go __after__ printableString */ {"( 1.3.6.1.4.1.1466.115.121.1.11 DESC 'Country String' )", 0, "1.3.6.1.4.1.1466.115.121.1.44", @@ -5317,6 +6151,12 @@ static slap_syntax_defs_rec syntax_defs[] = { SLAP_SYNTAX_HIDE, NULL, NULL, NULL}, {"( 1.3.6.1.1.15.7 DESC 'Algorithm Identifier' )", SLAP_SYNTAX_HIDE, NULL, NULL, NULL}, + {"( " attributeCertificateExactAssertionSyntaxOID " DESC 'AttributeCertificate Exact Assertion' )", + SLAP_SYNTAX_HIDE, NULL, + serialNumberAndIssuerSerialValidate, + serialNumberAndIssuerSerialPretty}, + {"( " attributeCertificateAssertionSyntaxOID " DESC 'AttributeCertificate Assertion' )", + SLAP_SYNTAX_HIDE, NULL, NULL, NULL}, #ifdef SLAPD_AUTHPASSWD /* needs updating */ @@ -5356,13 +6196,20 @@ char *certificateListExactMatchSyntaxes[] = { "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */, NULL }; +char *attributeCertificateExactMatchSyntaxes[] = { + attributeCertificateSyntaxOID /* attributeCertificate */, + NULL +}; + #ifdef LDAP_COMP_MATCH char *componentFilterMatchSyntaxes[] = { "1.3.6.1.4.1.1466.115.121.1.8" /* certificate */, "1.3.6.1.4.1.1466.115.121.1.9" /* certificateList */, + attributeCertificateSyntaxOID /* attributeCertificate */, NULL }; #endif + char *directoryStringSyntaxes[] = { "1.3.6.1.4.1.1466.115.121.1.44" /* printableString */, NULL @@ -5711,6 +6558,19 @@ static slap_mrule_defs_rec mrule_defs[] = { NULL, NULL, NULL, NULL, NULL, NULL }, + {"( 2.5.13.45 NAME 'attributeCertificateExactMatch' " + "SYNTAX " attributeCertificateExactAssertionSyntaxOID " )", + SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, attributeCertificateExactMatchSyntaxes, + NULL, attributeCertificateExactNormalize, octetStringMatch, + octetStringIndexer, octetStringFilter, + NULL }, + + {"( 2.5.13.46 NAME 'attributeCertificateMatch' " + "SYNTAX " attributeCertificateAssertionSyntaxOID " )", + SLAP_MR_EQUALITY | SLAP_MR_EXT | SLAP_MR_HIDE, NULL, + NULL, NULL, NULL, NULL, NULL, + NULL }, + {"( 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, NULL, -- 2.39.5