Index: mozilla/security/nss/lib/certdb/genname.c |
=================================================================== |
--- mozilla/security/nss/lib/certdb/genname.c (revision 191424) |
+++ mozilla/security/nss/lib/certdb/genname.c (working copy) |
@@ -1,1861 +0,0 @@ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
- |
-#include "plarena.h" |
-#include "seccomon.h" |
-#include "secitem.h" |
-#include "secoidt.h" |
-#include "secasn1.h" |
-#include "secder.h" |
-#include "certt.h" |
-#include "cert.h" |
-#include "certi.h" |
-#include "xconst.h" |
-#include "secerr.h" |
-#include "secoid.h" |
-#include "prprf.h" |
-#include "genname.h" |
- |
-SEC_ASN1_MKSUB(SEC_AnyTemplate) |
-SEC_ASN1_MKSUB(SEC_IntegerTemplate) |
-SEC_ASN1_MKSUB(SEC_IA5StringTemplate) |
-SEC_ASN1_MKSUB(SEC_ObjectIDTemplate) |
-SEC_ASN1_MKSUB(SEC_OctetStringTemplate) |
- |
-static const SEC_ASN1Template CERTNameConstraintTemplate[] = { |
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraint) }, |
- { SEC_ASN1_ANY, offsetof(CERTNameConstraint, DERName) }, |
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0, |
- offsetof(CERTNameConstraint, min), |
- SEC_ASN1_SUB(SEC_IntegerTemplate) }, |
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1, |
- offsetof(CERTNameConstraint, max), |
- SEC_ASN1_SUB(SEC_IntegerTemplate) }, |
- { 0, } |
-}; |
- |
-const SEC_ASN1Template CERT_NameConstraintSubtreeSubTemplate[] = { |
- { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, 0, SEC_ASN1_SUB(SEC_AnyTemplate) } |
-}; |
- |
-static const SEC_ASN1Template CERTNameConstraintsTemplate[] = { |
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTNameConstraints) }, |
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
- offsetof(CERTNameConstraints, DERPermited), |
- CERT_NameConstraintSubtreeSubTemplate}, |
- { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 1, |
- offsetof(CERTNameConstraints, DERExcluded), |
- CERT_NameConstraintSubtreeSubTemplate}, |
- { 0, } |
-}; |
- |
- |
-static const SEC_ASN1Template CERTOthNameTemplate[] = { |
- { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(OtherName) }, |
- { SEC_ASN1_OBJECT_ID, |
- offsetof(OtherName, oid) }, |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | |
- SEC_ASN1_XTRN | 0, offsetof(OtherName, name), |
- SEC_ASN1_SUB(SEC_AnyTemplate) }, |
- { 0, } |
-}; |
- |
-static const SEC_ASN1Template CERTOtherNameTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | 0 , |
- offsetof(CERTGeneralName, name.OthName), CERTOthNameTemplate, |
- sizeof(CERTGeneralName) } |
-}; |
- |
-static const SEC_ASN1Template CERTOtherName2Template[] = { |
- { SEC_ASN1_SEQUENCE | SEC_ASN1_CONTEXT_SPECIFIC | 0 , |
- 0, NULL, sizeof(CERTGeneralName) }, |
- { SEC_ASN1_OBJECT_ID, |
- offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, oid) }, |
- { SEC_ASN1_ANY, |
- offsetof(CERTGeneralName, name.OthName) + offsetof(OtherName, name) }, |
- { 0, } |
-}; |
- |
-static const SEC_ASN1Template CERT_RFC822NameTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1 , |
- offsetof(CERTGeneralName, name.other), |
- SEC_ASN1_SUB(SEC_IA5StringTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
-static const SEC_ASN1Template CERT_DNSNameTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2 , |
- offsetof(CERTGeneralName, name.other), |
- SEC_ASN1_SUB(SEC_IA5StringTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
-static const SEC_ASN1Template CERT_X400AddressTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 3, |
- offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
-static const SEC_ASN1Template CERT_DirectoryNameTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_EXPLICIT | |
- SEC_ASN1_XTRN | 4, offsetof(CERTGeneralName, derDirectoryName), |
- SEC_ASN1_SUB(SEC_AnyTemplate), sizeof (CERTGeneralName)} |
-}; |
- |
- |
-static const SEC_ASN1Template CERT_EDIPartyNameTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_CONSTRUCTED | SEC_ASN1_XTRN | 5, |
- offsetof(CERTGeneralName, name.other), SEC_ASN1_SUB(SEC_AnyTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
-static const SEC_ASN1Template CERT_URITemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 6 , |
- offsetof(CERTGeneralName, name.other), |
- SEC_ASN1_SUB(SEC_IA5StringTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
-static const SEC_ASN1Template CERT_IPAddressTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 7 , |
- offsetof(CERTGeneralName, name.other), |
- SEC_ASN1_SUB(SEC_OctetStringTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
-static const SEC_ASN1Template CERT_RegisteredIDTemplate[] = { |
- { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 8 , |
- offsetof(CERTGeneralName, name.other), |
- SEC_ASN1_SUB(SEC_ObjectIDTemplate), |
- sizeof (CERTGeneralName)} |
-}; |
- |
- |
-const SEC_ASN1Template CERT_GeneralNamesTemplate[] = { |
- { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN , 0, SEC_ASN1_SUB(SEC_AnyTemplate) } |
-}; |
- |
- |
- |
-CERTGeneralName * |
-CERT_NewGeneralName(PLArenaPool *arena, CERTGeneralNameType type) |
-{ |
- CERTGeneralName *name = arena |
- ? PORT_ArenaZNew(arena, CERTGeneralName) |
- : PORT_ZNew(CERTGeneralName); |
- if (name) { |
- name->type = type; |
- name->l.prev = name->l.next = &name->l; |
- } |
- return name; |
-} |
- |
-/* Copy content of one General Name to another. |
-** Caller has allocated destination general name. |
-** This function does not change the destinate's GeneralName's list linkage. |
-*/ |
-SECStatus |
-cert_CopyOneGeneralName(PRArenaPool *arena, |
- CERTGeneralName *dest, |
- CERTGeneralName *src) |
-{ |
- SECStatus rv; |
- void *mark = NULL; |
- |
- PORT_Assert(dest != NULL); |
- dest->type = src->type; |
- |
- mark = PORT_ArenaMark(arena); |
- |
- switch (src->type) { |
- case certDirectoryName: |
- rv = SECITEM_CopyItem(arena, &dest->derDirectoryName, |
- &src->derDirectoryName); |
- if (rv == SECSuccess) |
- rv = CERT_CopyName(arena, &dest->name.directoryName, |
- &src->name.directoryName); |
- break; |
- |
- case certOtherName: |
- rv = SECITEM_CopyItem(arena, &dest->name.OthName.name, |
- &src->name.OthName.name); |
- if (rv == SECSuccess) |
- rv = SECITEM_CopyItem(arena, &dest->name.OthName.oid, |
- &src->name.OthName.oid); |
- break; |
- |
- default: |
- rv = SECITEM_CopyItem(arena, &dest->name.other, |
- &src->name.other); |
- break; |
- |
- } |
- if (rv != SECSuccess) { |
- PORT_ArenaRelease(arena, mark); |
- } else { |
- PORT_ArenaUnmark(arena, mark); |
- } |
- return rv; |
-} |
- |
- |
-void |
-CERT_DestroyGeneralNameList(CERTGeneralNameList *list) |
-{ |
- PZLock *lock; |
- |
- if (list != NULL) { |
- lock = list->lock; |
- PZ_Lock(lock); |
- if (--list->refCount <= 0 && list->arena != NULL) { |
- PORT_FreeArena(list->arena, PR_FALSE); |
- PZ_Unlock(lock); |
- PZ_DestroyLock(lock); |
- } else { |
- PZ_Unlock(lock); |
- } |
- } |
- return; |
-} |
- |
-CERTGeneralNameList * |
-CERT_CreateGeneralNameList(CERTGeneralName *name) { |
- PRArenaPool *arena; |
- CERTGeneralNameList *list = NULL; |
- |
- arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
- if (arena == NULL) { |
- goto done; |
- } |
- list = PORT_ArenaZNew(arena, CERTGeneralNameList); |
- if (!list) |
- goto loser; |
- if (name != NULL) { |
- SECStatus rv; |
- list->name = CERT_NewGeneralName(arena, (CERTGeneralNameType)0); |
- if (!list->name) |
- goto loser; |
- rv = CERT_CopyGeneralName(arena, list->name, name); |
- if (rv != SECSuccess) |
- goto loser; |
- } |
- list->lock = PZ_NewLock(nssILockList); |
- if (!list->lock) |
- goto loser; |
- list->arena = arena; |
- list->refCount = 1; |
-done: |
- return list; |
- |
-loser: |
- PORT_FreeArena(arena, PR_FALSE); |
- return NULL; |
-} |
- |
-CERTGeneralName * |
-CERT_GetNextGeneralName(CERTGeneralName *current) |
-{ |
- PRCList *next; |
- |
- next = current->l.next; |
- return (CERTGeneralName *) (((char *) next) - offsetof(CERTGeneralName, l)); |
-} |
- |
-CERTGeneralName * |
-CERT_GetPrevGeneralName(CERTGeneralName *current) |
-{ |
- PRCList *prev; |
- prev = current->l.prev; |
- return (CERTGeneralName *) (((char *) prev) - offsetof(CERTGeneralName, l)); |
-} |
- |
-CERTNameConstraint * |
-CERT_GetNextNameConstraint(CERTNameConstraint *current) |
-{ |
- PRCList *next; |
- |
- next = current->l.next; |
- return (CERTNameConstraint *) (((char *) next) - offsetof(CERTNameConstraint, l)); |
-} |
- |
-CERTNameConstraint * |
-CERT_GetPrevNameConstraint(CERTNameConstraint *current) |
-{ |
- PRCList *prev; |
- prev = current->l.prev; |
- return (CERTNameConstraint *) (((char *) prev) - offsetof(CERTNameConstraint, l)); |
-} |
- |
-SECItem * |
-CERT_EncodeGeneralName(CERTGeneralName *genName, SECItem *dest, PRArenaPool *arena) |
-{ |
- |
- const SEC_ASN1Template * template; |
- |
- PORT_Assert(arena); |
- if (arena == NULL) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return NULL; |
- } |
- /* TODO: mark arena */ |
- if (dest == NULL) { |
- dest = PORT_ArenaZNew(arena, SECItem); |
- if (!dest) |
- goto loser; |
- } |
- if (genName->type == certDirectoryName) { |
- if (genName->derDirectoryName.data == NULL) { |
- /* The field hasn't been encoded yet. */ |
- SECItem * pre_dest = |
- SEC_ASN1EncodeItem (arena, &(genName->derDirectoryName), |
- &(genName->name.directoryName), |
- CERT_NameTemplate); |
- if (!pre_dest) |
- goto loser; |
- } |
- if (genName->derDirectoryName.data == NULL) { |
- goto loser; |
- } |
- } |
- switch (genName->type) { |
- case certURI: template = CERT_URITemplate; break; |
- case certRFC822Name: template = CERT_RFC822NameTemplate; break; |
- case certDNSName: template = CERT_DNSNameTemplate; break; |
- case certIPAddress: template = CERT_IPAddressTemplate; break; |
- case certOtherName: template = CERTOtherNameTemplate; break; |
- case certRegisterID: template = CERT_RegisteredIDTemplate; break; |
- /* for this type, we expect the value is already encoded */ |
- case certEDIPartyName: template = CERT_EDIPartyNameTemplate; break; |
- /* for this type, we expect the value is already encoded */ |
- case certX400Address: template = CERT_X400AddressTemplate; break; |
- case certDirectoryName: template = CERT_DirectoryNameTemplate; break; |
- default: |
- PORT_Assert(0); goto loser; |
- } |
- dest = SEC_ASN1EncodeItem(arena, dest, genName, template); |
- if (!dest) { |
- goto loser; |
- } |
- /* TODO: unmark arena */ |
- return dest; |
-loser: |
- /* TODO: release arena back to mark */ |
- return NULL; |
-} |
- |
-SECItem ** |
-cert_EncodeGeneralNames(PRArenaPool *arena, CERTGeneralName *names) |
-{ |
- CERTGeneralName *current_name; |
- SECItem **items = NULL; |
- int count = 0; |
- int i; |
- PRCList *head; |
- |
- PORT_Assert(arena); |
- /* TODO: mark arena */ |
- current_name = names; |
- if (names != NULL) { |
- count = 1; |
- } |
- head = &(names->l); |
- while (current_name->l.next != head) { |
- current_name = CERT_GetNextGeneralName(current_name); |
- ++count; |
- } |
- current_name = CERT_GetNextGeneralName(current_name); |
- items = PORT_ArenaNewArray(arena, SECItem *, count + 1); |
- if (items == NULL) { |
- goto loser; |
- } |
- for (i = 0; i < count; i++) { |
- items[i] = CERT_EncodeGeneralName(current_name, (SECItem *)NULL, arena); |
- if (items[i] == NULL) { |
- goto loser; |
- } |
- current_name = CERT_GetNextGeneralName(current_name); |
- } |
- items[i] = NULL; |
- /* TODO: unmark arena */ |
- return items; |
-loser: |
- /* TODO: release arena to mark */ |
- return NULL; |
-} |
- |
-CERTGeneralName * |
-CERT_DecodeGeneralName(PRArenaPool *reqArena, |
- SECItem *encodedName, |
- CERTGeneralName *genName) |
-{ |
- const SEC_ASN1Template * template; |
- CERTGeneralNameType genNameType; |
- SECStatus rv = SECSuccess; |
- SECItem* newEncodedName; |
- |
- if (!reqArena) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return NULL; |
- } |
- /* make a copy for decoding so the data decoded with QuickDER doesn't |
- point to temporary memory */ |
- newEncodedName = SECITEM_ArenaDupItem(reqArena, encodedName); |
- if (!newEncodedName) { |
- return NULL; |
- } |
- /* TODO: mark arena */ |
- genNameType = (CERTGeneralNameType)((*(newEncodedName->data) & 0x0f) + 1); |
- if (genName == NULL) { |
- genName = CERT_NewGeneralName(reqArena, genNameType); |
- if (!genName) |
- goto loser; |
- } else { |
- genName->type = genNameType; |
- genName->l.prev = genName->l.next = &genName->l; |
- } |
- |
- switch (genNameType) { |
- case certURI: template = CERT_URITemplate; break; |
- case certRFC822Name: template = CERT_RFC822NameTemplate; break; |
- case certDNSName: template = CERT_DNSNameTemplate; break; |
- case certIPAddress: template = CERT_IPAddressTemplate; break; |
- case certOtherName: template = CERTOtherNameTemplate; break; |
- case certRegisterID: template = CERT_RegisteredIDTemplate; break; |
- case certEDIPartyName: template = CERT_EDIPartyNameTemplate; break; |
- case certX400Address: template = CERT_X400AddressTemplate; break; |
- case certDirectoryName: template = CERT_DirectoryNameTemplate; break; |
- default: |
- goto loser; |
- } |
- rv = SEC_QuickDERDecodeItem(reqArena, genName, template, newEncodedName); |
- if (rv != SECSuccess) |
- goto loser; |
- if (genNameType == certDirectoryName) { |
- rv = SEC_QuickDERDecodeItem(reqArena, &(genName->name.directoryName), |
- CERT_NameTemplate, |
- &(genName->derDirectoryName)); |
- if (rv != SECSuccess) |
- goto loser; |
- } |
- |
- /* TODO: unmark arena */ |
- return genName; |
-loser: |
- /* TODO: release arena to mark */ |
- return NULL; |
-} |
- |
-CERTGeneralName * |
-cert_DecodeGeneralNames (PRArenaPool *arena, |
- SECItem **encodedGenName) |
-{ |
- PRCList *head = NULL; |
- PRCList *tail = NULL; |
- CERTGeneralName *currentName = NULL; |
- |
- PORT_Assert(arena); |
- if (!encodedGenName || !arena) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return NULL; |
- } |
- /* TODO: mark arena */ |
- while (*encodedGenName != NULL) { |
- currentName = CERT_DecodeGeneralName(arena, *encodedGenName, NULL); |
- if (currentName == NULL) |
- break; |
- if (head == NULL) { |
- head = &(currentName->l); |
- tail = head; |
- } |
- currentName->l.next = head; |
- currentName->l.prev = tail; |
- tail = head->prev = tail->next = &(currentName->l); |
- encodedGenName++; |
- } |
- if (currentName) { |
- /* TODO: unmark arena */ |
- return CERT_GetNextGeneralName(currentName); |
- } |
- /* TODO: release arena to mark */ |
- return NULL; |
-} |
- |
-void |
-CERT_DestroyGeneralName(CERTGeneralName *name) |
-{ |
- cert_DestroyGeneralNames(name); |
-} |
- |
-SECStatus |
-cert_DestroyGeneralNames(CERTGeneralName *name) |
-{ |
- CERTGeneralName *first; |
- CERTGeneralName *next = NULL; |
- |
- |
- first = name; |
- do { |
- next = CERT_GetNextGeneralName(name); |
- PORT_Free(name); |
- name = next; |
- } while (name != first); |
- return SECSuccess; |
-} |
- |
-static SECItem * |
-cert_EncodeNameConstraint(CERTNameConstraint *constraint, |
- SECItem *dest, |
- PRArenaPool *arena) |
-{ |
- PORT_Assert(arena); |
- if (dest == NULL) { |
- dest = PORT_ArenaZNew(arena, SECItem); |
- if (dest == NULL) { |
- return NULL; |
- } |
- } |
- CERT_EncodeGeneralName(&(constraint->name), &(constraint->DERName), arena); |
- |
- dest = SEC_ASN1EncodeItem (arena, dest, constraint, |
- CERTNameConstraintTemplate); |
- return dest; |
-} |
- |
-SECStatus |
-cert_EncodeNameConstraintSubTree(CERTNameConstraint *constraints, |
- PRArenaPool *arena, |
- SECItem ***dest, |
- PRBool permited) |
-{ |
- CERTNameConstraint *current_constraint = constraints; |
- SECItem **items = NULL; |
- int count = 0; |
- int i; |
- PRCList *head; |
- |
- PORT_Assert(arena); |
- /* TODO: mark arena */ |
- if (constraints != NULL) { |
- count = 1; |
- } |
- head = &constraints->l; |
- while (current_constraint->l.next != head) { |
- current_constraint = CERT_GetNextNameConstraint(current_constraint); |
- ++count; |
- } |
- current_constraint = CERT_GetNextNameConstraint(current_constraint); |
- items = PORT_ArenaZNewArray(arena, SECItem *, count + 1); |
- if (items == NULL) { |
- goto loser; |
- } |
- for (i = 0; i < count; i++) { |
- items[i] = cert_EncodeNameConstraint(current_constraint, |
- (SECItem *) NULL, arena); |
- if (items[i] == NULL) { |
- goto loser; |
- } |
- current_constraint = CERT_GetNextNameConstraint(current_constraint); |
- } |
- *dest = items; |
- if (*dest == NULL) { |
- goto loser; |
- } |
- /* TODO: unmark arena */ |
- return SECSuccess; |
-loser: |
- /* TODO: release arena to mark */ |
- return SECFailure; |
-} |
- |
-SECStatus |
-cert_EncodeNameConstraints(CERTNameConstraints *constraints, |
- PRArenaPool *arena, |
- SECItem *dest) |
-{ |
- SECStatus rv = SECSuccess; |
- |
- PORT_Assert(arena); |
- /* TODO: mark arena */ |
- if (constraints->permited != NULL) { |
- rv = cert_EncodeNameConstraintSubTree(constraints->permited, arena, |
- &constraints->DERPermited, |
- PR_TRUE); |
- if (rv == SECFailure) { |
- goto loser; |
- } |
- } |
- if (constraints->excluded != NULL) { |
- rv = cert_EncodeNameConstraintSubTree(constraints->excluded, arena, |
- &constraints->DERExcluded, |
- PR_FALSE); |
- if (rv == SECFailure) { |
- goto loser; |
- } |
- } |
- dest = SEC_ASN1EncodeItem(arena, dest, constraints, |
- CERTNameConstraintsTemplate); |
- if (dest == NULL) { |
- goto loser; |
- } |
- /* TODO: unmark arena */ |
- return SECSuccess; |
-loser: |
- /* TODO: release arena to mark */ |
- return SECFailure; |
-} |
- |
- |
-CERTNameConstraint * |
-cert_DecodeNameConstraint(PRArenaPool *reqArena, |
- SECItem *encodedConstraint) |
-{ |
- CERTNameConstraint *constraint; |
- SECStatus rv = SECSuccess; |
- CERTGeneralName *temp; |
- SECItem* newEncodedConstraint; |
- |
- if (!reqArena) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return NULL; |
- } |
- newEncodedConstraint = SECITEM_ArenaDupItem(reqArena, encodedConstraint); |
- if (!newEncodedConstraint) { |
- return NULL; |
- } |
- /* TODO: mark arena */ |
- constraint = PORT_ArenaZNew(reqArena, CERTNameConstraint); |
- if (!constraint) |
- goto loser; |
- rv = SEC_QuickDERDecodeItem(reqArena, constraint, |
- CERTNameConstraintTemplate, |
- newEncodedConstraint); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- temp = CERT_DecodeGeneralName(reqArena, &(constraint->DERName), |
- &(constraint->name)); |
- if (temp != &(constraint->name)) { |
- goto loser; |
- } |
- |
- /* ### sjlee: since the name constraint contains only one |
- * CERTGeneralName, the list within CERTGeneralName shouldn't |
- * point anywhere else. Otherwise, bad things will happen. |
- */ |
- constraint->name.l.prev = constraint->name.l.next = &(constraint->name.l); |
- /* TODO: unmark arena */ |
- return constraint; |
-loser: |
- /* TODO: release arena back to mark */ |
- return NULL; |
-} |
- |
-CERTNameConstraint * |
-cert_DecodeNameConstraintSubTree(PRArenaPool *arena, |
- SECItem **subTree, |
- PRBool permited) |
-{ |
- CERTNameConstraint *current = NULL; |
- CERTNameConstraint *first = NULL; |
- CERTNameConstraint *last = NULL; |
- int i = 0; |
- |
- PORT_Assert(arena); |
- /* TODO: mark arena */ |
- while (subTree[i] != NULL) { |
- current = cert_DecodeNameConstraint(arena, subTree[i]); |
- if (current == NULL) { |
- goto loser; |
- } |
- if (last == NULL) { |
- first = last = current; |
- } |
- current->l.prev = &(last->l); |
- current->l.next = last->l.next; |
- last->l.next = &(current->l); |
- i++; |
- } |
- first->l.prev = &(current->l); |
- /* TODO: unmark arena */ |
- return first; |
-loser: |
- /* TODO: release arena back to mark */ |
- return NULL; |
-} |
- |
-CERTNameConstraints * |
-cert_DecodeNameConstraints(PRArenaPool *reqArena, |
- SECItem *encodedConstraints) |
-{ |
- CERTNameConstraints *constraints; |
- SECStatus rv; |
- SECItem* newEncodedConstraints; |
- |
- if (!reqArena) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return NULL; |
- } |
- PORT_Assert(encodedConstraints); |
- newEncodedConstraints = SECITEM_ArenaDupItem(reqArena, encodedConstraints); |
- |
- /* TODO: mark arena */ |
- constraints = PORT_ArenaZNew(reqArena, CERTNameConstraints); |
- if (constraints == NULL) { |
- goto loser; |
- } |
- rv = SEC_QuickDERDecodeItem(reqArena, constraints, |
- CERTNameConstraintsTemplate, |
- newEncodedConstraints); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- if (constraints->DERPermited != NULL && |
- constraints->DERPermited[0] != NULL) { |
- constraints->permited = |
- cert_DecodeNameConstraintSubTree(reqArena, |
- constraints->DERPermited, |
- PR_TRUE); |
- if (constraints->permited == NULL) { |
- goto loser; |
- } |
- } |
- if (constraints->DERExcluded != NULL && |
- constraints->DERExcluded[0] != NULL) { |
- constraints->excluded = |
- cert_DecodeNameConstraintSubTree(reqArena, |
- constraints->DERExcluded, |
- PR_FALSE); |
- if (constraints->excluded == NULL) { |
- goto loser; |
- } |
- } |
- /* TODO: unmark arena */ |
- return constraints; |
-loser: |
- /* TODO: release arena back to mark */ |
- return NULL; |
-} |
- |
-/* Copy a chain of one or more general names to a destination chain. |
-** Caller has allocated at least the first destination GeneralName struct. |
-** Both source and destination chains are circular doubly-linked lists. |
-** The first source struct is copied to the first destination struct. |
-** If the source chain has more than one member, and the destination chain |
-** has only one member, then this function allocates new structs for all but |
-** the first copy from the arena and links them into the destination list. |
-** If the destination struct is part of a list with more than one member, |
-** then this function traverses both the source and destination lists, |
-** copying each source struct to the corresponding dest struct. |
-** In that case, the destination list MUST contain at least as many |
-** structs as the source list or some dest entries will be overwritten. |
-*/ |
-SECStatus |
-CERT_CopyGeneralName(PRArenaPool *arena, |
- CERTGeneralName *dest, |
- CERTGeneralName *src) |
-{ |
- SECStatus rv; |
- CERTGeneralName *destHead = dest; |
- CERTGeneralName *srcHead = src; |
- |
- PORT_Assert(dest != NULL); |
- if (!dest) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
- } |
- /* TODO: mark arena */ |
- do { |
- rv = cert_CopyOneGeneralName(arena, dest, src); |
- if (rv != SECSuccess) |
- goto loser; |
- src = CERT_GetNextGeneralName(src); |
- /* if there is only one general name, we shouldn't do this */ |
- if (src != srcHead) { |
- if (dest->l.next == &destHead->l) { |
- CERTGeneralName *temp; |
- temp = CERT_NewGeneralName(arena, (CERTGeneralNameType)0); |
- if (!temp) |
- goto loser; |
- temp->l.next = &destHead->l; |
- temp->l.prev = &dest->l; |
- destHead->l.prev = &temp->l; |
- dest->l.next = &temp->l; |
- dest = temp; |
- } else { |
- dest = CERT_GetNextGeneralName(dest); |
- } |
- } |
- } while (src != srcHead && rv == SECSuccess); |
- /* TODO: unmark arena */ |
- return rv; |
-loser: |
- /* TODO: release back to mark */ |
- return SECFailure; |
-} |
- |
- |
-CERTGeneralNameList * |
-CERT_DupGeneralNameList(CERTGeneralNameList *list) |
-{ |
- if (list != NULL) { |
- PZ_Lock(list->lock); |
- list->refCount++; |
- PZ_Unlock(list->lock); |
- } |
- return list; |
-} |
- |
-/* Allocate space and copy CERTNameConstraint from src to dest */ |
-CERTNameConstraint * |
-CERT_CopyNameConstraint(PRArenaPool *arena, |
- CERTNameConstraint *dest, |
- CERTNameConstraint *src) |
-{ |
- SECStatus rv; |
- |
- /* TODO: mark arena */ |
- if (dest == NULL) { |
- dest = PORT_ArenaZNew(arena, CERTNameConstraint); |
- if (!dest) |
- goto loser; |
- /* mark that it is not linked */ |
- dest->name.l.prev = dest->name.l.next = &(dest->name.l); |
- } |
- rv = CERT_CopyGeneralName(arena, &dest->name, &src->name); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- rv = SECITEM_CopyItem(arena, &dest->DERName, &src->DERName); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- rv = SECITEM_CopyItem(arena, &dest->min, &src->min); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- rv = SECITEM_CopyItem(arena, &dest->max, &src->max); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- dest->l.prev = dest->l.next = &dest->l; |
- /* TODO: unmark arena */ |
- return dest; |
-loser: |
- /* TODO: release arena to mark */ |
- return NULL; |
-} |
- |
- |
-CERTGeneralName * |
-cert_CombineNamesLists(CERTGeneralName *list1, CERTGeneralName *list2) |
-{ |
- PRCList *begin1; |
- PRCList *begin2; |
- PRCList *end1; |
- PRCList *end2; |
- |
- if (list1 == NULL){ |
- return list2; |
- } else if (list2 == NULL) { |
- return list1; |
- } else { |
- begin1 = &list1->l; |
- begin2 = &list2->l; |
- end1 = list1->l.prev; |
- end2 = list2->l.prev; |
- end1->next = begin2; |
- end2->next = begin1; |
- begin1->prev = end2; |
- begin2->prev = end1; |
- return list1; |
- } |
-} |
- |
- |
-CERTNameConstraint * |
-cert_CombineConstraintsLists(CERTNameConstraint *list1, CERTNameConstraint *list2) |
-{ |
- PRCList *begin1; |
- PRCList *begin2; |
- PRCList *end1; |
- PRCList *end2; |
- |
- if (list1 == NULL){ |
- return list2; |
- } else if (list2 == NULL) { |
- return list1; |
- } else { |
- begin1 = &list1->l; |
- begin2 = &list2->l; |
- end1 = list1->l.prev; |
- end2 = list2->l.prev; |
- end1->next = begin2; |
- end2->next = begin1; |
- begin1->prev = end2; |
- begin2->prev = end1; |
- return list1; |
- } |
-} |
- |
- |
-/* Add a CERTNameConstraint to the CERTNameConstraint list */ |
-CERTNameConstraint * |
-CERT_AddNameConstraint(CERTNameConstraint *list, |
- CERTNameConstraint *constraint) |
-{ |
- PORT_Assert(constraint != NULL); |
- constraint->l.next = constraint->l.prev = &constraint->l; |
- list = cert_CombineConstraintsLists(list, constraint); |
- return list; |
-} |
- |
- |
-SECStatus |
-CERT_GetNameConstraintByType (CERTNameConstraint *constraints, |
- CERTGeneralNameType type, |
- CERTNameConstraint **returnList, |
- PRArenaPool *arena) |
-{ |
- CERTNameConstraint *current = NULL; |
- void *mark = NULL; |
- |
- *returnList = NULL; |
- if (!constraints) |
- return SECSuccess; |
- |
- mark = PORT_ArenaMark(arena); |
- |
- current = constraints; |
- do { |
- PORT_Assert(current->name.type); |
- if (current->name.type == type) { |
- CERTNameConstraint *temp; |
- temp = CERT_CopyNameConstraint(arena, NULL, current); |
- if (temp == NULL) |
- goto loser; |
- *returnList = CERT_AddNameConstraint(*returnList, temp); |
- } |
- current = CERT_GetNextNameConstraint(current); |
- } while (current != constraints); |
- PORT_ArenaUnmark(arena, mark); |
- return SECSuccess; |
- |
-loser: |
- PORT_ArenaRelease(arena, mark); |
- return SECFailure; |
-} |
- |
-void * |
-CERT_GetGeneralNameByType (CERTGeneralName *genNames, |
- CERTGeneralNameType type, PRBool derFormat) |
-{ |
- CERTGeneralName *current; |
- |
- if (!genNames) |
- return NULL; |
- current = genNames; |
- |
- do { |
- if (current->type == type) { |
- switch (type) { |
- case certDNSName: |
- case certEDIPartyName: |
- case certIPAddress: |
- case certRegisterID: |
- case certRFC822Name: |
- case certX400Address: |
- case certURI: |
- return (void *)¤t->name.other; /* SECItem * */ |
- |
- case certOtherName: |
- return (void *)¤t->name.OthName; /* OthName * */ |
- |
- case certDirectoryName: |
- return derFormat |
- ? (void *)¤t->derDirectoryName /* SECItem * */ |
- : (void *)¤t->name.directoryName; /* CERTName * */ |
- } |
- PORT_Assert(0); |
- return NULL; |
- } |
- current = CERT_GetNextGeneralName(current); |
- } while (current != genNames); |
- return NULL; |
-} |
- |
-int |
-CERT_GetNamesLength(CERTGeneralName *names) |
-{ |
- int length = 0; |
- CERTGeneralName *first; |
- |
- first = names; |
- if (names != NULL) { |
- do { |
- length++; |
- names = CERT_GetNextGeneralName(names); |
- } while (names != first); |
- } |
- return length; |
-} |
- |
-/* Creates new GeneralNames for any email addresses found in the |
-** input DN, and links them onto the list for the DN. |
-*/ |
-SECStatus |
-cert_ExtractDNEmailAddrs(CERTGeneralName *name, PLArenaPool *arena) |
-{ |
- CERTGeneralName *nameList = NULL; |
- const CERTRDN **nRDNs = (const CERTRDN **)(name->name.directoryName.rdns); |
- SECStatus rv = SECSuccess; |
- |
- PORT_Assert(name->type == certDirectoryName); |
- if (name->type != certDirectoryName) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
- } |
- /* TODO: mark arena */ |
- while (nRDNs && *nRDNs) { /* loop over RDNs */ |
- const CERTRDN *nRDN = *nRDNs++; |
- CERTAVA **nAVAs = nRDN->avas; |
- while (nAVAs && *nAVAs) { /* loop over AVAs */ |
- int tag; |
- CERTAVA *nAVA = *nAVAs++; |
- tag = CERT_GetAVATag(nAVA); |
- if ( tag == SEC_OID_PKCS9_EMAIL_ADDRESS || |
- tag == SEC_OID_RFC1274_MAIL) { /* email AVA */ |
- CERTGeneralName *newName = NULL; |
- SECItem *avaValue = CERT_DecodeAVAValue(&nAVA->value); |
- if (!avaValue) |
- goto loser; |
- rv = SECFailure; |
- newName = CERT_NewGeneralName(arena, certRFC822Name); |
- if (newName) { |
- rv = SECITEM_CopyItem(arena, &newName->name.other, avaValue); |
- } |
- SECITEM_FreeItem(avaValue, PR_TRUE); |
- if (rv != SECSuccess) |
- goto loser; |
- nameList = cert_CombineNamesLists(nameList, newName); |
- } /* handle one email AVA */ |
- } /* loop over AVAs */ |
- } /* loop over RDNs */ |
- /* combine new names with old one. */ |
- name = cert_CombineNamesLists(name, nameList); |
- /* TODO: unmark arena */ |
- return SECSuccess; |
- |
-loser: |
- /* TODO: release arena back to mark */ |
- return SECFailure; |
-} |
- |
-/* Extract all names except Subject Common Name from a cert |
-** in preparation for a name constraints test. |
-*/ |
-CERTGeneralName * |
-CERT_GetCertificateNames(CERTCertificate *cert, PRArenaPool *arena) |
-{ |
- return CERT_GetConstrainedCertificateNames(cert, arena, PR_FALSE); |
-} |
- |
-/* This function is called by CERT_VerifyCertChain to extract all |
-** names from a cert in preparation for a name constraints test. |
-*/ |
-CERTGeneralName * |
-CERT_GetConstrainedCertificateNames(CERTCertificate *cert, PRArenaPool *arena, |
- PRBool includeSubjectCommonName) |
-{ |
- CERTGeneralName *DN; |
- CERTGeneralName *SAN; |
- PRUint32 numDNSNames = 0; |
- SECStatus rv; |
- |
- if (!arena) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return NULL; |
- } |
- /* TODO: mark arena */ |
- DN = CERT_NewGeneralName(arena, certDirectoryName); |
- if (DN == NULL) { |
- goto loser; |
- } |
- rv = CERT_CopyName(arena, &DN->name.directoryName, &cert->subject); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- rv = SECITEM_CopyItem(arena, &DN->derDirectoryName, &cert->derSubject); |
- if (rv != SECSuccess) { |
- goto loser; |
- } |
- /* Extract email addresses from DN, construct CERTGeneralName structs |
- ** for them, add them to the name list |
- */ |
- rv = cert_ExtractDNEmailAddrs(DN, arena); |
- if (rv != SECSuccess) |
- goto loser; |
- |
- /* Now extract any GeneralNames from the subject name names extension. */ |
- SAN = cert_GetSubjectAltNameList(cert, arena); |
- if (SAN) { |
- numDNSNames = cert_CountDNSPatterns(SAN); |
- DN = cert_CombineNamesLists(DN, SAN); |
- } |
- if (!numDNSNames && includeSubjectCommonName) { |
- char *cn = CERT_GetCommonName(&cert->subject); |
- if (cn) { |
- CERTGeneralName *CN = CERT_NewGeneralName(arena, certDNSName); |
- if (CN) { |
- SECItem cnItem = {siBuffer, NULL, 0}; |
- cnItem.data = (unsigned char *)cn; |
- cnItem.len = strlen(cn); |
- rv = SECITEM_CopyItem(arena, &CN->name.other, &cnItem); |
- if (rv == SECSuccess) { |
- DN = cert_CombineNamesLists(DN, CN); |
- } |
- } |
- PORT_Free(cn); |
- } |
- } |
- if (rv == SECSuccess) { |
- /* TODO: unmark arena */ |
- return DN; |
- } |
-loser: |
- /* TODO: release arena to mark */ |
- return NULL; |
-} |
- |
-/* Returns SECSuccess if name matches constraint per RFC 3280 rules for |
-** URI name constraints. SECFailure otherwise. |
-** If the constraint begins with a dot, it is a domain name, otherwise |
-** It is a host name. Examples: |
-** Constraint Name Result |
-** ------------ --------------- -------- |
-** foo.bar.com foo.bar.com matches |
-** foo.bar.com FoO.bAr.CoM matches |
-** foo.bar.com www.foo.bar.com no match |
-** foo.bar.com nofoo.bar.com no match |
-** .foo.bar.com www.foo.bar.com matches |
-** .foo.bar.com nofoo.bar.com no match |
-** .foo.bar.com foo.bar.com no match |
-** .foo.bar.com www..foo.bar.com no match |
-*/ |
-static SECStatus |
-compareURIN2C(const SECItem *name, const SECItem *constraint) |
-{ |
- int offset; |
- /* The spec is silent on intepreting zero-length constraints. |
- ** We interpret them as matching no URI names. |
- */ |
- if (!constraint->len) |
- return SECFailure; |
- if (constraint->data[0] != '.') { |
- /* constraint is a host name. */ |
- if (name->len != constraint->len || |
- PL_strncasecmp((char *)name->data, |
- (char *)constraint->data, constraint->len)) |
- return SECFailure; |
- return SECSuccess; |
- } |
- /* constraint is a domain name. */ |
- if (name->len < constraint->len) |
- return SECFailure; |
- offset = name->len - constraint->len; |
- if (PL_strncasecmp((char *)(name->data + offset), |
- (char *)constraint->data, constraint->len)) |
- return SECFailure; |
- if (!offset || |
- (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1) |
- return SECSuccess; |
- return SECFailure; |
-} |
- |
-/* for DNSname constraints, RFC 3280 says, (section 4.2.1.11, page 38) |
-** |
-** DNS name restrictions are expressed as foo.bar.com. Any DNS name |
-** that can be constructed by simply adding to the left hand side of the |
-** name satisfies the name constraint. For example, www.foo.bar.com |
-** would satisfy the constraint but foo1.bar.com would not. |
-** |
-** But NIST's PKITS test suite requires that the constraint be treated |
-** as a domain name, and requires that any name added to the left hand |
-** side end in a dot ".". Sensible, but not strictly following the RFC. |
-** |
-** Constraint Name RFC 3280 NIST PKITS |
-** ------------ --------------- -------- ---------- |
-** foo.bar.com foo.bar.com matches matches |
-** foo.bar.com FoO.bAr.CoM matches matches |
-** foo.bar.com www.foo.bar.com matches matches |
-** foo.bar.com nofoo.bar.com MATCHES NO MATCH |
-** .foo.bar.com www.foo.bar.com matches matches? disallowed? |
-** .foo.bar.com foo.bar.com no match no match |
-** .foo.bar.com www..foo.bar.com matches probably not |
-** |
-** We will try to conform to NIST's PKITS tests, and the unstated |
-** rules they imply. |
-*/ |
-static SECStatus |
-compareDNSN2C(const SECItem *name, const SECItem *constraint) |
-{ |
- int offset; |
- /* The spec is silent on intepreting zero-length constraints. |
- ** We interpret them as matching all DNSnames. |
- */ |
- if (!constraint->len) |
- return SECSuccess; |
- if (name->len < constraint->len) |
- return SECFailure; |
- offset = name->len - constraint->len; |
- if (PL_strncasecmp((char *)(name->data + offset), |
- (char *)constraint->data, constraint->len)) |
- return SECFailure; |
- if (!offset || |
- (name->data[offset - 1] == '.') + (constraint->data[0] == '.') == 1) |
- return SECSuccess; |
- return SECFailure; |
-} |
- |
-/* Returns SECSuccess if name matches constraint per RFC 3280 rules for |
-** internet email addresses. SECFailure otherwise. |
-** If constraint contains a '@' then the two strings much match exactly. |
-** Else if constraint starts with a '.'. then it must match the right-most |
-** substring of the name, |
-** else constraint string must match entire name after the name's '@'. |
-** Empty constraint string matches all names. All comparisons case insensitive. |
-*/ |
-static SECStatus |
-compareRFC822N2C(const SECItem *name, const SECItem *constraint) |
-{ |
- int offset; |
- if (!constraint->len) |
- return SECSuccess; |
- if (name->len < constraint->len) |
- return SECFailure; |
- if (constraint->len == 1 && constraint->data[0] == '.') |
- return SECSuccess; |
- for (offset = constraint->len - 1; offset >= 0; --offset) { |
- if (constraint->data[offset] == '@') { |
- return (name->len == constraint->len && |
- !PL_strncasecmp((char *)name->data, |
- (char *)constraint->data, constraint->len)) |
- ? SECSuccess : SECFailure; |
- } |
- } |
- offset = name->len - constraint->len; |
- if (PL_strncasecmp((char *)(name->data + offset), |
- (char *)constraint->data, constraint->len)) |
- return SECFailure; |
- if (constraint->data[0] == '.') |
- return SECSuccess; |
- if (offset > 0 && name->data[offset - 1] == '@') |
- return SECSuccess; |
- return SECFailure; |
-} |
- |
-/* name contains either a 4 byte IPv4 address or a 16 byte IPv6 address. |
-** constraint contains an address of the same length, and a subnet mask |
-** of the same length. Compare name's address to the constraint's |
-** address, subject to the mask. |
-** Return SECSuccess if they match, SECFailure if they don't. |
-*/ |
-static SECStatus |
-compareIPaddrN2C(const SECItem *name, const SECItem *constraint) |
-{ |
- int i; |
- if (name->len == 4 && constraint->len == 8) { /* ipv4 addr */ |
- for (i = 0; i < 4; i++) { |
- if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+4]) |
- goto loser; |
- } |
- return SECSuccess; |
- } |
- if (name->len == 16 && constraint->len == 32) { /* ipv6 addr */ |
- for (i = 0; i < 16; i++) { |
- if ((name->data[i] ^ constraint->data[i]) & constraint->data[i+16]) |
- goto loser; |
- } |
- return SECSuccess; |
- } |
-loser: |
- return SECFailure; |
-} |
- |
-/* start with a SECItem that points to a URI. Parse it lookingg for |
-** a hostname. Modify item->data and item->len to define the hostname, |
-** but do not modify and data at item->data. |
-** If anything goes wrong, the contents of *item are undefined. |
-*/ |
-static SECStatus |
-parseUriHostname(SECItem * item) |
-{ |
- int i; |
- PRBool found = PR_FALSE; |
- for (i = 0; (unsigned)(i+2) < item->len; ++i) { |
- if (item->data[i ] == ':' && |
- item->data[i+1] == '/' && |
- item->data[i+2] == '/') { |
- i += 3; |
- item->data += i; |
- item->len -= i; |
- found = PR_TRUE; |
- break; |
- } |
- } |
- if (!found) |
- return SECFailure; |
- /* now look for a '/', which is an upper bound in the end of the name */ |
- for (i = 0; (unsigned)i < item->len; ++i) { |
- if (item->data[i] == '/') { |
- item->len = i; |
- break; |
- } |
- } |
- /* now look for a ':', which marks the end of the name */ |
- for (i = item->len; --i >= 0; ) { |
- if (item->data[i] == ':') { |
- item->len = i; |
- break; |
- } |
- } |
- /* now look for an '@', which marks the beginning of the hostname */ |
- for (i = 0; (unsigned)i < item->len; ++i) { |
- if (item->data[i] == '@') { |
- ++i; |
- item->data += i; |
- item->len -= i; |
- break; |
- } |
- } |
- return item->len ? SECSuccess : SECFailure; |
-} |
- |
-/* This function takes one name, and a list of constraints. |
-** It searches the constraints looking for a match. |
-** It returns SECSuccess if the name satisfies the constraints, i.e., |
-** if excluded, then the name does not match any constraint, |
-** if permitted, then the name matches at least one constraint. |
-** It returns SECFailure if the name fails to satisfy the constraints, |
-** or if some code fails (e.g. out of memory, or invalid constraint) |
-*/ |
-SECStatus |
-cert_CompareNameWithConstraints(CERTGeneralName *name, |
- CERTNameConstraint *constraints, |
- PRBool excluded) |
-{ |
- SECStatus rv = SECSuccess; |
- SECStatus matched = SECFailure; |
- CERTNameConstraint *current; |
- |
- PORT_Assert(constraints); /* caller should not call with NULL */ |
- if (!constraints) { |
- PORT_SetError(SEC_ERROR_INVALID_ARGS); |
- return SECFailure; |
- } |
- |
- current = constraints; |
- do { |
- rv = SECSuccess; |
- matched = SECFailure; |
- PORT_Assert(name->type == current->name.type); |
- switch (name->type) { |
- |
- case certDNSName: |
- matched = compareDNSN2C(&name->name.other, |
- ¤t->name.name.other); |
- break; |
- |
- case certRFC822Name: |
- matched = compareRFC822N2C(&name->name.other, |
- ¤t->name.name.other); |
- break; |
- |
- case certURI: |
- { |
- /* make a modifiable copy of the URI SECItem. */ |
- SECItem uri = name->name.other; |
- /* find the hostname in the URI */ |
- rv = parseUriHostname(&uri); |
- if (rv == SECSuccess) { |
- /* does our hostname meet the constraint? */ |
- matched = compareURIN2C(&uri, ¤t->name.name.other); |
- } |
- } |
- break; |
- |
- case certDirectoryName: |
- /* Determine if the constraint directory name is a "prefix" |
- ** for the directory name being tested. |
- */ |
- { |
- /* status defaults to SECEqual, so that a constraint with |
- ** no AVAs will be a wildcard, matching all directory names. |
- */ |
- SECComparison status = SECEqual; |
- const CERTRDN **cRDNs = |
- (const CERTRDN **)current->name.name.directoryName.rdns; |
- const CERTRDN **nRDNs = |
- (const CERTRDN **)name->name.directoryName.rdns; |
- while (cRDNs && *cRDNs && nRDNs && *nRDNs) { |
- /* loop over name RDNs and constraint RDNs in lock step */ |
- const CERTRDN *cRDN = *cRDNs++; |
- const CERTRDN *nRDN = *nRDNs++; |
- CERTAVA **cAVAs = cRDN->avas; |
- while (cAVAs && *cAVAs) { /* loop over constraint AVAs */ |
- CERTAVA *cAVA = *cAVAs++; |
- CERTAVA **nAVAs = nRDN->avas; |
- while (nAVAs && *nAVAs) { /* loop over name AVAs */ |
- CERTAVA *nAVA = *nAVAs++; |
- status = CERT_CompareAVA(cAVA, nAVA); |
- if (status == SECEqual) |
- break; |
- } /* loop over name AVAs */ |
- if (status != SECEqual) |
- break; |
- } /* loop over constraint AVAs */ |
- if (status != SECEqual) |
- break; |
- } /* loop over name RDNs and constraint RDNs */ |
- matched = (status == SECEqual) ? SECSuccess : SECFailure; |
- break; |
- } |
- |
- case certIPAddress: /* type 8 */ |
- matched = compareIPaddrN2C(&name->name.other, |
- ¤t->name.name.other); |
- break; |
- |
- /* NSS does not know how to compare these "Other" type names with |
- ** their respective constraints. But it does know how to tell |
- ** if the constraint applies to the type of name (by comparing |
- ** the constraint OID to the name OID). NSS makes no use of "Other" |
- ** type names at all, so NSS errs on the side of leniency for these |
- ** types, provided that their OIDs match. So, when an "Other" |
- ** name constraint appears in an excluded subtree, it never causes |
- ** a name to fail. When an "Other" name constraint appears in a |
- ** permitted subtree, AND the constraint's OID matches the name's |
- ** OID, then name is treated as if it matches the constraint. |
- */ |
- case certOtherName: /* type 1 */ |
- matched = (!excluded && |
- name->type == current->name.type && |
- SECITEM_ItemsAreEqual(&name->name.OthName.oid, |
- ¤t->name.name.OthName.oid)) |
- ? SECSuccess : SECFailure; |
- break; |
- |
- /* NSS does not know how to compare these types of names with their |
- ** respective constraints. But NSS makes no use of these types of |
- ** names at all, so it errs on the side of leniency for these types. |
- ** Constraints for these types of names never cause the name to |
- ** fail the constraints test. NSS behaves as if the name matched |
- ** for permitted constraints, and did not match for excluded ones. |
- */ |
- case certX400Address: /* type 4 */ |
- case certEDIPartyName: /* type 6 */ |
- case certRegisterID: /* type 9 */ |
- matched = excluded ? SECFailure : SECSuccess; |
- break; |
- |
- default: /* non-standard types are not supported */ |
- rv = SECFailure; |
- break; |
- } |
- if (matched == SECSuccess || rv != SECSuccess) |
- break; |
- current = CERT_GetNextNameConstraint(current); |
- } while (current != constraints); |
- if (rv == SECSuccess) { |
- if (matched == SECSuccess) |
- rv = excluded ? SECFailure : SECSuccess; |
- else |
- rv = excluded ? SECSuccess : SECFailure; |
- return rv; |
- } |
- |
- return SECFailure; |
-} |
- |
-/* Add and link a CERTGeneralName to a CERTNameConstraint list. Most |
-** likely the CERTNameConstraint passed in is either the permitted |
-** list or the excluded list of a CERTNameConstraints. |
-*/ |
-SECStatus |
-CERT_AddNameConstraintByGeneralName(PLArenaPool *arena, |
- CERTNameConstraint **constraints, |
- CERTGeneralName *name) |
-{ |
- SECStatus rv; |
- CERTNameConstraint *current = NULL; |
- CERTNameConstraint *first = *constraints; |
- void *mark = NULL; |
- |
- mark = PORT_ArenaMark(arena); |
- |
- current = PORT_ArenaZNew(arena, CERTNameConstraint); |
- if (current == NULL) { |
- rv = SECFailure; |
- goto done; |
- } |
- |
- rv = cert_CopyOneGeneralName(arena, ¤t->name, name); |
- if (rv != SECSuccess) { |
- goto done; |
- } |
- |
- current->name.l.prev = current->name.l.next = &(current->name.l); |
- |
- if (first == NULL) { |
- *constraints = current; |
- PR_INIT_CLIST(¤t->l); |
- } else { |
- PR_INSERT_BEFORE(¤t->l, &first->l); |
- } |
- |
-done: |
- if (rv == SECFailure) { |
- PORT_ArenaRelease(arena, mark); |
- } else { |
- PORT_ArenaUnmark(arena, mark); |
- } |
- return rv; |
-} |
- |
-/* Extract the name constraints extension from the CA cert. */ |
-SECStatus |
-CERT_FindNameConstraintsExten(PRArenaPool *arena, |
- CERTCertificate *cert, |
- CERTNameConstraints **constraints) |
-{ |
- SECStatus rv = SECSuccess; |
- SECItem constraintsExtension; |
- void *mark = NULL; |
- |
- *constraints = NULL; |
- |
- rv = CERT_FindCertExtension(cert, SEC_OID_X509_NAME_CONSTRAINTS, |
- &constraintsExtension); |
- if (rv != SECSuccess) { |
- if (PORT_GetError() == SEC_ERROR_EXTENSION_NOT_FOUND) { |
- rv = SECSuccess; |
- } |
- return rv; |
- } |
- |
- mark = PORT_ArenaMark(arena); |
- |
- *constraints = cert_DecodeNameConstraints(arena, &constraintsExtension); |
- if (*constraints == NULL) { /* decode failed */ |
- rv = SECFailure; |
- } |
- PORT_Free (constraintsExtension.data); |
- |
- if (rv == SECFailure) { |
- PORT_ArenaRelease(arena, mark); |
- } else { |
- PORT_ArenaUnmark(arena, mark); |
- } |
- |
- return rv; |
-} |
- |
-/* Verify name against all the constraints relevant to that type of |
-** the name. |
-*/ |
-SECStatus |
-CERT_CheckNameSpace(PRArenaPool *arena, |
- CERTNameConstraints *constraints, |
- CERTGeneralName *currentName) |
-{ |
- CERTNameConstraint *matchingConstraints; |
- SECStatus rv = SECSuccess; |
- |
- if (constraints->excluded != NULL) { |
- rv = CERT_GetNameConstraintByType(constraints->excluded, |
- currentName->type, |
- &matchingConstraints, arena); |
- if (rv == SECSuccess && matchingConstraints != NULL) { |
- rv = cert_CompareNameWithConstraints(currentName, |
- matchingConstraints, |
- PR_TRUE); |
- } |
- if (rv != SECSuccess) { |
- return(rv); |
- } |
- } |
- |
- if (constraints->permited != NULL) { |
- rv = CERT_GetNameConstraintByType(constraints->permited, |
- currentName->type, |
- &matchingConstraints, arena); |
- if (rv == SECSuccess && matchingConstraints != NULL) { |
- rv = cert_CompareNameWithConstraints(currentName, |
- matchingConstraints, |
- PR_FALSE); |
- } |
- if (rv != SECSuccess) { |
- return(rv); |
- } |
- } |
- |
- return(SECSuccess); |
-} |
- |
-/* Extract the name constraints extension from the CA cert. |
-** Test each and every name in namesList against all the constraints |
-** relevant to that type of name. |
-** Returns NULL in pBadCert for success, if all names are acceptable. |
-** If some name is not acceptable, returns a pointer to the cert that |
-** contained that name. |
-*/ |
-SECStatus |
-CERT_CompareNameSpace(CERTCertificate *cert, |
- CERTGeneralName *namesList, |
- CERTCertificate **certsList, |
- PRArenaPool *reqArena, |
- CERTCertificate **pBadCert) |
-{ |
- SECStatus rv = SECSuccess; |
- CERTNameConstraints *constraints; |
- CERTGeneralName *currentName; |
- int count = 0; |
- CERTCertificate *badCert = NULL; |
- |
- /* If no names to check, then no names can be bad. */ |
- if (!namesList) |
- goto done; |
- rv = CERT_FindNameConstraintsExten(reqArena, cert, &constraints); |
- if (rv != SECSuccess) { |
- count = -1; |
- goto done; |
- } |
- |
- currentName = namesList; |
- do { |
- if (constraints){ |
- rv = CERT_CheckNameSpace(reqArena, constraints, currentName); |
- if (rv != SECSuccess) { |
- break; |
- } |
- } |
- currentName = CERT_GetNextGeneralName(currentName); |
- count ++; |
- } while (currentName != namesList); |
- |
-done: |
- if (rv != SECSuccess) { |
- badCert = (count >= 0) ? certsList[count] : cert; |
- } |
- if (pBadCert) |
- *pBadCert = badCert; |
- |
- return rv; |
-} |
- |
-#if 0 |
-/* not exported from shared libs, not used. Turn on if we ever need it. */ |
-SECStatus |
-CERT_CompareGeneralName(CERTGeneralName *a, CERTGeneralName *b) |
-{ |
- CERTGeneralName *currentA; |
- CERTGeneralName *currentB; |
- PRBool found; |
- |
- currentA = a; |
- currentB = b; |
- if (a != NULL) { |
- do { |
- if (currentB == NULL) { |
- return SECFailure; |
- } |
- currentB = CERT_GetNextGeneralName(currentB); |
- currentA = CERT_GetNextGeneralName(currentA); |
- } while (currentA != a); |
- } |
- if (currentB != b) { |
- return SECFailure; |
- } |
- currentA = a; |
- do { |
- currentB = b; |
- found = PR_FALSE; |
- do { |
- if (currentB->type == currentA->type) { |
- switch (currentB->type) { |
- case certDNSName: |
- case certEDIPartyName: |
- case certIPAddress: |
- case certRegisterID: |
- case certRFC822Name: |
- case certX400Address: |
- case certURI: |
- if (SECITEM_CompareItem(¤tA->name.other, |
- ¤tB->name.other) |
- == SECEqual) { |
- found = PR_TRUE; |
- } |
- break; |
- case certOtherName: |
- if (SECITEM_CompareItem(¤tA->name.OthName.oid, |
- ¤tB->name.OthName.oid) |
- == SECEqual && |
- SECITEM_CompareItem(¤tA->name.OthName.name, |
- ¤tB->name.OthName.name) |
- == SECEqual) { |
- found = PR_TRUE; |
- } |
- break; |
- case certDirectoryName: |
- if (CERT_CompareName(¤tA->name.directoryName, |
- ¤tB->name.directoryName) |
- == SECEqual) { |
- found = PR_TRUE; |
- } |
- } |
- |
- } |
- currentB = CERT_GetNextGeneralName(currentB); |
- } while (currentB != b && found != PR_TRUE); |
- if (found != PR_TRUE) { |
- return SECFailure; |
- } |
- currentA = CERT_GetNextGeneralName(currentA); |
- } while (currentA != a); |
- return SECSuccess; |
-} |
- |
-SECStatus |
-CERT_CompareGeneralNameLists(CERTGeneralNameList *a, CERTGeneralNameList *b) |
-{ |
- SECStatus rv; |
- |
- if (a == b) { |
- return SECSuccess; |
- } |
- if (a != NULL && b != NULL) { |
- PZ_Lock(a->lock); |
- PZ_Lock(b->lock); |
- rv = CERT_CompareGeneralName(a->name, b->name); |
- PZ_Unlock(a->lock); |
- PZ_Unlock(b->lock); |
- } else { |
- rv = SECFailure; |
- } |
- return rv; |
-} |
-#endif |
- |
-#if 0 |
-/* This function is not exported from NSS shared libraries, and is not |
-** used inside of NSS. |
-** XXX it doesn't check for failed allocations. :-( |
-*/ |
-void * |
-CERT_GetGeneralNameFromListByType(CERTGeneralNameList *list, |
- CERTGeneralNameType type, |
- PRArenaPool *arena) |
-{ |
- CERTName *name = NULL; |
- SECItem *item = NULL; |
- OtherName *other = NULL; |
- OtherName *tmpOther = NULL; |
- void *data; |
- |
- PZ_Lock(list->lock); |
- data = CERT_GetGeneralNameByType(list->name, type, PR_FALSE); |
- if (data != NULL) { |
- switch (type) { |
- case certDNSName: |
- case certEDIPartyName: |
- case certIPAddress: |
- case certRegisterID: |
- case certRFC822Name: |
- case certX400Address: |
- case certURI: |
- if (arena != NULL) { |
- item = PORT_ArenaNew(arena, SECItem); |
- if (item != NULL) { |
-XXX SECITEM_CopyItem(arena, item, (SECItem *) data); |
- } |
- } else { |
- item = SECITEM_DupItem((SECItem *) data); |
- } |
- PZ_Unlock(list->lock); |
- return item; |
- case certOtherName: |
- other = (OtherName *) data; |
- if (arena != NULL) { |
- tmpOther = PORT_ArenaNew(arena, OtherName); |
- } else { |
- tmpOther = PORT_New(OtherName); |
- } |
- if (tmpOther != NULL) { |
-XXX SECITEM_CopyItem(arena, &tmpOther->oid, &other->oid); |
-XXX SECITEM_CopyItem(arena, &tmpOther->name, &other->name); |
- } |
- PZ_Unlock(list->lock); |
- return tmpOther; |
- case certDirectoryName: |
- if (arena) { |
- name = PORT_ArenaZNew(list->arena, CERTName); |
- if (name) { |
-XXX CERT_CopyName(arena, name, (CERTName *) data); |
- } |
- } |
- PZ_Unlock(list->lock); |
- return name; |
- } |
- } |
- PZ_Unlock(list->lock); |
- return NULL; |
-} |
-#endif |
- |
-#if 0 |
-/* This function is not exported from NSS shared libraries, and is not |
-** used inside of NSS. |
-** XXX it should NOT be a void function, since it does allocations |
-** that can fail. |
-*/ |
-void |
-CERT_AddGeneralNameToList(CERTGeneralNameList *list, |
- CERTGeneralNameType type, |
- void *data, SECItem *oid) |
-{ |
- CERTGeneralName *name; |
- |
- if (list != NULL && data != NULL) { |
- PZ_Lock(list->lock); |
- name = CERT_NewGeneralName(list->arena, type); |
- if (!name) |
- goto done; |
- switch (type) { |
- case certDNSName: |
- case certEDIPartyName: |
- case certIPAddress: |
- case certRegisterID: |
- case certRFC822Name: |
- case certX400Address: |
- case certURI: |
-XXX SECITEM_CopyItem(list->arena, &name->name.other, (SECItem *)data); |
- break; |
- case certOtherName: |
-XXX SECITEM_CopyItem(list->arena, &name->name.OthName.name, |
- (SECItem *) data); |
-XXX SECITEM_CopyItem(list->arena, &name->name.OthName.oid, |
- oid); |
- break; |
- case certDirectoryName: |
-XXX CERT_CopyName(list->arena, &name->name.directoryName, |
- (CERTName *) data); |
- break; |
- } |
- list->name = cert_CombineNamesLists(list->name, name); |
- list->len++; |
-done: |
- PZ_Unlock(list->lock); |
- } |
- return; |
-} |
-#endif |