/* helper functions */ static void BIO_printf_CERTName(BIO *out, CERTName *cn, const char *msg) { CERTRDN **rdns; if (!cn) return; rdns = cn->rdns; if (!rdns) return; for (; *rdns; rdns++) { CERTAVA **avas = (*rdns)->avas; if (!avas) continue; for (; *avas; avas++) { CERTAVA *ava = *avas; BIO_printf(out, "%s", msg); { int tag = /*SECOidTag*/ CERT_GetAVATag(ava); const char* code; switch (tag) { case -1: code = "<unknown>"; break; case 31: code = "E"; break; case 41: code = "CN"; break; case 42: code = "C"; break; case 43: code = "L"; break; case 44: code = "ST"; break; case 45: code = "O"; break; case 46: code = "OU"; break; case 261: code = "SN"; break; case 262: code = "serialNumber"; break; case 268: code = "givenName"; break; default: code = "<?>"; break; } BIO_printf(out, "%s = ", code); } { SECItem *si_utf8; si_utf8 = CERT_DecodeAVAValue(&ava->value); BIO_printf(out, "'%.*s'\n", si_utf8->len, si_utf8->data); SECITEM_FreeItem(si_utf8, PR_TRUE); } } } }
char *CERT_FormatName (CERTName *name) { CERTRDN** rdns; CERTRDN * rdn; CERTAVA** avas; CERTAVA* ava; char * buf = 0; char * tmpbuf = 0; SECItem * cn = 0; SECItem * email = 0; SECItem * org = 0; SECItem * loc = 0; SECItem * state = 0; SECItem * country = 0; SECItem * dq = 0; unsigned len = 0; int tag; int i; int ou_count = 0; int dc_count = 0; PRBool first; SECItem * orgunit[MAX_OUS]; SECItem * dc[MAX_DC]; /* Loop over name components and gather the interesting ones */ rdns = name->rdns; while ((rdn = *rdns++) != 0) { avas = rdn->avas; while ((ava = *avas++) != 0) { tag = CERT_GetAVATag(ava); switch(tag) { case SEC_OID_AVA_COMMON_NAME: if (cn) { break; } cn = CERT_DecodeAVAValue(&ava->value); if (!cn) { goto loser; } len += cn->len; break; case SEC_OID_AVA_COUNTRY_NAME: if (country) { break; } country = CERT_DecodeAVAValue(&ava->value); if (!country) { goto loser; } len += country->len; break; case SEC_OID_AVA_LOCALITY: if (loc) { break; } loc = CERT_DecodeAVAValue(&ava->value); if (!loc) { goto loser; } len += loc->len; break; case SEC_OID_AVA_STATE_OR_PROVINCE: if (state) { break; } state = CERT_DecodeAVAValue(&ava->value); if (!state) { goto loser; } len += state->len; break; case SEC_OID_AVA_ORGANIZATION_NAME: if (org) { break; } org = CERT_DecodeAVAValue(&ava->value); if (!org) { goto loser; } len += org->len; break; case SEC_OID_AVA_DN_QUALIFIER: if (dq) { break; } dq = CERT_DecodeAVAValue(&ava->value); if (!dq) { goto loser; } len += dq->len; break; case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: if (ou_count < MAX_OUS) { orgunit[ou_count] = CERT_DecodeAVAValue(&ava->value); if (!orgunit[ou_count]) { goto loser; } len += orgunit[ou_count++]->len; } break; case SEC_OID_AVA_DC: if (dc_count < MAX_DC) { dc[dc_count] = CERT_DecodeAVAValue(&ava->value); if (!dc[dc_count]) { goto loser; } len += dc[dc_count++]->len; } break; case SEC_OID_PKCS9_EMAIL_ADDRESS: case SEC_OID_RFC1274_MAIL: if (email) { break; } email = CERT_DecodeAVAValue(&ava->value); if (!email) { goto loser; } len += email->len; break; default: break; } } } /* XXX - add some for formatting */ len += 128; /* allocate buffer */ buf = (char *)PORT_Alloc(len); if ( !buf ) { goto loser; } tmpbuf = buf; if ( cn ) { PORT_Memcpy(tmpbuf, cn->data, cn->len); tmpbuf += cn->len; PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } if ( email ) { PORT_Memcpy(tmpbuf, email->data, email->len); tmpbuf += ( email->len ); PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } for (i=ou_count-1; i >= 0; i--) { PORT_Memcpy(tmpbuf, orgunit[i]->data, orgunit[i]->len); tmpbuf += ( orgunit[i]->len ); PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } if ( dq ) { PORT_Memcpy(tmpbuf, dq->data, dq->len); tmpbuf += ( dq->len ); PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } if ( org ) { PORT_Memcpy(tmpbuf, org->data, org->len); tmpbuf += ( org->len ); PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } for (i=dc_count-1; i >= 0; i--) { PORT_Memcpy(tmpbuf, dc[i]->data, dc[i]->len); tmpbuf += ( dc[i]->len ); PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } first = PR_TRUE; if ( loc ) { PORT_Memcpy(tmpbuf, loc->data, loc->len); tmpbuf += ( loc->len ); first = PR_FALSE; } if ( state ) { if ( !first ) { PORT_Memcpy(tmpbuf, COMMA, COMMALEN); tmpbuf += COMMALEN; } PORT_Memcpy(tmpbuf, state->data, state->len); tmpbuf += ( state->len ); first = PR_FALSE; } if ( country ) { if ( !first ) { PORT_Memcpy(tmpbuf, COMMA, COMMALEN); tmpbuf += COMMALEN; } PORT_Memcpy(tmpbuf, country->data, country->len); tmpbuf += ( country->len ); first = PR_FALSE; } if ( !first ) { PORT_Memcpy(tmpbuf, BREAK, BREAKLEN); tmpbuf += BREAKLEN; } *tmpbuf = 0; /* fall through and clean */ loser: if ( cn ) { SECITEM_FreeItem(cn, PR_TRUE); } if ( email ) { SECITEM_FreeItem(email, PR_TRUE); } for (i=ou_count-1; i >= 0; i--) { SECITEM_FreeItem(orgunit[i], PR_TRUE); } if ( dq ) { SECITEM_FreeItem(dq, PR_TRUE); } if ( org ) { SECITEM_FreeItem(org, PR_TRUE); } for (i=dc_count-1; i >= 0; i--) { SECITEM_FreeItem(dc[i], PR_TRUE); } if ( loc ) { SECITEM_FreeItem(loc, PR_TRUE); } if ( state ) { SECITEM_FreeItem(state, PR_TRUE); } if ( country ) { SECITEM_FreeItem(country, PR_TRUE); } return(buf); }
int ldapu_member_certificate_match (void* cert, const char* desc) /* * Return Values: (same as ldapu_find) * LDAPU_SUCCESS cert matches desc * LDAPU_FAILED cert doesn't match desc * <rv> Something went wrong. */ { auto int err = LDAPU_FAILED; auto char*** descRDNs; if (!cert || !desc || desc[0] != '{') return LDAPU_FAILED; if (desc[1] == '\0') return LDAPU_SUCCESS; /* no AVAs */ descRDNs = _explode_dn (desc+1); if (descRDNs) { auto char** descAVAs = (char**)ldapu_malloc(sizeof(char*) * (_rdns_count(descRDNs)+1)); if (!descAVAs) { err = LDAPU_ERR_OUT_OF_MEMORY; } else { auto CERTName* subject = &(((CERTCertificate*)cert)->subject); auto char** descAVA; err = LDAPU_SUCCESS; { /* extract all the AVAs, but not duplicate types, except OU */ auto size_t descAVAsLen = 0; auto char*** descRDN; descAVAs[0] = NULL; for (descRDN = descRDNs; err == LDAPU_SUCCESS && *descRDN; ++descRDN) { for (descAVA = *descRDN; err == LDAPU_SUCCESS && *descAVA; ++descAVA) { err = _explode_AVA (*descAVA); if (err == LDAPU_SUCCESS) { if (_is_OU (*descAVA) || !_replaceAVA (*descAVA, descAVAs)) { descAVAs[descAVAsLen++] = *descAVA; descAVAs[descAVAsLen] = NULL; } } } } } /* match all the attributes except OU */ for (descAVA = descAVAs; err == LDAPU_SUCCESS && *descAVA; ++descAVA) { auto struct _attr_getter_pair* descAttr; err = LDAPU_FAILED; /* if no match */ for (descAttr = _attr_getter_table; descAttr->name1; ++descAttr) { if (!ldapu_strcasecmp (*descAVA, descAttr->name1) || (descAttr->name2 && !ldapu_strcasecmp (*descAVA, descAttr->name2))) { if (descAttr->getter == NULL) { /* OU attribute */ err = LDAPU_SUCCESS; /* for now */ } else { auto char* certVal = (*(descAttr->getter))(subject); if (certVal && _value_match (certVal, _AVA_value (*descAVA))) { err = LDAPU_SUCCESS; } PR_Free (certVal); } break; } } } /* match the OU attributes */ if (err == LDAPU_SUCCESS && descAVA != descAVAs) { /* Iterate over the OUs in the certificate subject */ auto CERTRDN** certRDN = subject->rdns; descAVA = _previous_OU (descAVA, descAVAs); for (; descAVA && *certRDN; ++certRDN) { auto CERTAVA** certAVA = (*certRDN)->avas; for (; descAVA && *certAVA; ++certAVA) { auto const int tag = CERT_GetAVATag (*certAVA); if (tag == SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME) { auto const size_t certValLen =(*certAVA)->value.len; auto const size_t lenLen = (certValLen < 128) ? 2 : 3; auto const size_t buflen = certValLen - lenLen; auto char* buf = (char*)ldapu_malloc(buflen+1); if (!buf) { err = LDAPU_ERR_OUT_OF_MEMORY; descAVA = NULL; } else { memcpy (buf, (*certAVA)->value.data+lenLen, buflen); buf[buflen] = 0; if (_value_match (buf, _AVA_value (*descAVA))) { descAVA = _previous_OU (descAVA, descAVAs); } free (buf); } } } } if (descAVA) { err = LDAPU_FAILED; /* no match for descAVA in subject */ } } free (descAVAs); } _rdns_free (descRDNs); } return err; }
NSAPI_PUBLIC int ldapu_get_cert_ava_val (void *cert_in, int which_dn, const char *attr, char ***val_out) { CERTCertificate *cert = (CERTCertificate *)cert_in; CERTName *cert_dn; CERTRDN **rdns; CERTRDN **rdn; CERTAVA **avas; CERTAVA *ava; int attr_tag = certmap_name_to_secoid(attr); char **val; char **ptr; int rv; *val_out = 0; if (attr_tag == SEC_OID_AVA_UNKNOWN) { return LDAPU_ERR_INVALID_ARGUMENT; } if (which_dn == LDAPU_SUBJECT_DN) cert_dn = &cert->subject; else if (which_dn == LDAPU_ISSUER_DN) cert_dn = &cert->issuer; else return LDAPU_ERR_INVALID_ARGUMENT; val = (char **)malloc(32*sizeof(char *)); if (!val) return LDAPU_ERR_OUT_OF_MEMORY; ptr = val; rdns = cert_dn->rdns; if (rdns) { for (rdn = rdns; *rdn; rdn++) { avas = (*rdn)->avas; while ((ava = *avas++) != NULL) { int tag = CERT_GetAVATag(ava); if (tag == attr_tag) { char buf[BIG_LINE]; int lenLen; int vallen; /* Found it */ /* Copied from ns/lib/libsec ... * XXX this code is incorrect in general * -- should use a DER template. */ lenLen = 2; if (ava->value.len >= 128) lenLen = 3; vallen = ava->value.len - lenLen; rv = CERT_RFC1485_EscapeAndQuote(buf, BIG_LINE, (char*) ava->value.data + lenLen, vallen); if (rv == SECSuccess) { *ptr++ = strdup(buf); } break; } } } } *ptr = 0; if (*val) { /* At least one value found */ *val_out = val; rv = LDAPU_SUCCESS; } else { free(val); rv = LDAPU_FAILED; } return rv; }