diff options
author | neil.williams%sun.com <devnull@localhost> | 2005-03-09 23:02:48 +0000 |
---|---|---|
committer | neil.williams%sun.com <devnull@localhost> | 2005-03-09 23:02:48 +0000 |
commit | 74b23e389221c2739b8c35b2023709c4c98cfeb4 (patch) | |
tree | 93faa85ca560ea3fdcf664ec4c0971c610bc55c9 /security/nss | |
parent | 06f84535b4407812bbd408aae18e9b26e3843c34 (diff) | |
download | nss-hg-74b23e389221c2739b8c35b2023709c4c98cfeb4.tar.gz |
r=nelson Bug=263779
Diffstat (limited to 'security/nss')
-rw-r--r-- | security/nss/cmd/certutil/certutil.c | 166 | ||||
-rw-r--r-- | security/nss/lib/certdb/cert.h | 27 | ||||
-rw-r--r-- | security/nss/lib/certdb/certxutl.c | 45 | ||||
-rw-r--r-- | security/nss/lib/certhigh/certreq.c | 98 | ||||
-rw-r--r-- | security/nss/lib/nss/nss.def | 4 |
5 files changed, 287 insertions, 53 deletions
diff --git a/security/nss/cmd/certutil/certutil.c b/security/nss/cmd/certutil/certutil.c index bbb1fd6c2..88eba3018 100644 --- a/security/nss/cmd/certutil/certutil.c +++ b/security/nss/cmd/certutil/certutil.c @@ -399,9 +399,20 @@ getSignatureOidTag(KeyType keyType, SECOidTag hashAlgTag) } static SECStatus +AddExtensions(void *, const char *, const char *, PRBool, PRBool, PRBool, PRBool, + PRBool, PRBool); + +static SECStatus CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, - const char *emailAddrs, const char *dnsNames, PRFileDesc *outFile) + const char *emailAddrs, const char *dnsNames, + PRBool keyUsage, + PRBool extKeyUsage, + PRBool basicConstraint, + PRBool authKeyID, + PRBool crlDistPoints, + PRBool nscpCertType, + PRFileDesc *outFile) { CERTSubjectPublicKeyInfo *spki; CERTCertificateRequest *cr; @@ -411,6 +422,7 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, SECStatus rv; PRArenaPool *arena; PRInt32 numBytes; + void *extHandle; /* Create info about public key */ spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); @@ -418,9 +430,9 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, SECU_PrintError(progName, "unable to create subject public key"); return SECFailure; } - + /* Generate certificate request */ - cr = CERT_CreateCertificateRequest(subject, spki, 0); + cr = CERT_CreateCertificateRequest(subject, spki, NULL); if (!cr) { SECU_PrintError(progName, "unable to make certificate request"); return SECFailure; @@ -432,6 +444,20 @@ CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, return SECFailure; } + extHandle = CERT_StartCertificateRequestAttributes(cr); + if (extHandle == NULL) { + PORT_FreeArena (arena, PR_FALSE); + return SECFailure; + } + if (AddExtensions(extHandle, emailAddrs, PR_FALSE, PR_FALSE, PR_FALSE, + PR_FALSE, PR_FALSE, PR_FALSE, PR_FALSE) + != SECSuccess) { + PORT_FreeArena (arena, PR_FALSE); + return SECFailure; + } + CERT_FinishExtensions(extHandle); + CERT_FinishCertificateRequestAttributes(cr); + /* Der encode the request */ encoding = SEC_ASN1EncodeItem(arena, NULL, cr, SEC_ASN1_GET(CERT_CertificateRequestTemplate)); @@ -2081,21 +2107,7 @@ AddCrlDistPoint(void *extHandle) } static SECStatus -CreateCert( - CERTCertDBHandle *handle, - char * issuerNickName, - PRFileDesc *inFile, - PRFileDesc *outFile, - SECKEYPrivateKey *selfsignprivkey, - void *pwarg, - SECOidTag hashAlgTag, - unsigned int serialNumber, - int warpmonths, - int validitylength, - const char *emailAddrs, - const char *dnsNames, - PRBool ascii, - PRBool selfsign, +AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames, PRBool keyUsage, PRBool extKeyUsage, PRBool basicConstraint, @@ -2103,38 +2115,8 @@ CreateCert( PRBool crlDistPoints, PRBool nscpCertType) { - void * extHandle; - SECItem * certDER; - PRArenaPool *arena = NULL; - CERTCertificate *subjectCert = NULL; - CERTCertificateRequest *certReq = NULL; - SECStatus rv = SECSuccess; - SECItem reqDER; - - reqDER.data = NULL; + SECStatus rv = SECSuccess; do { - arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); - if (!arena) { - GEN_BREAK (SECFailure); - } - - /* Create a certrequest object from the input cert request der */ - certReq = GetCertRequest(inFile, ascii); - if (certReq == NULL) { - GEN_BREAK (SECFailure) - } - - subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign, - serialNumber, warpmonths, validitylength); - if (subjectCert == NULL) { - GEN_BREAK (SECFailure) - } - - extHandle = CERT_StartCertExtensions (subjectCert); - if (extHandle == NULL) { - GEN_BREAK (SECFailure) - } - /* Add key usage extension */ if (keyUsage) { rv = AddKeyUsage(extHandle); @@ -2162,7 +2144,6 @@ CreateCert( break; } - if (crlDistPoints) { rv = AddCrlDistPoint (extHandle); if (rv) @@ -2186,6 +2167,83 @@ CreateCert( if (rv) break; } + } while (0); + return rv; +} + +static SECStatus +CreateCert( + CERTCertDBHandle *handle, + char * issuerNickName, + PRFileDesc *inFile, + PRFileDesc *outFile, + SECKEYPrivateKey *selfsignprivkey, + void *pwarg, + SECOidTag hashAlgTag, + unsigned int serialNumber, + int warpmonths, + int validitylength, + const char *emailAddrs, + const char *dnsNames, + PRBool ascii, + PRBool selfsign, + PRBool keyUsage, + PRBool extKeyUsage, + PRBool basicConstraint, + PRBool authKeyID, + PRBool crlDistPoints, + PRBool nscpCertType) +{ + void * extHandle; + SECItem * certDER; + PRArenaPool *arena = NULL; + CERTCertificate *subjectCert = NULL; + CERTCertificateRequest *certReq = NULL; + SECStatus rv = SECSuccess; + SECItem reqDER; + CERTCertExtension **CRexts; + + reqDER.data = NULL; + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + GEN_BREAK (SECFailure); + } + + /* Create a certrequest object from the input cert request der */ + certReq = GetCertRequest(inFile, ascii); + if (certReq == NULL) { + GEN_BREAK (SECFailure) + } + + subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign, + serialNumber, warpmonths, validitylength); + if (subjectCert == NULL) { + GEN_BREAK (SECFailure) + } + + + extHandle = CERT_StartCertExtensions (subjectCert); + if (extHandle == NULL) { + GEN_BREAK (SECFailure) + } + + rv = AddExtensions(extHandle, emailAddrs, dnsNames, keyUsage, extKeyUsage, + basicConstraint, authKeyID, crlDistPoints, nscpCertType); + if (rv != SECSuccess) { + GEN_BREAK (SECFailure) + } + + if (certReq->attributes != NULL && + SECOID_FindOIDTag(&(*certReq->attributes)->attrType) + == SEC_OID_PKCS9_EXTENSION_REQUEST) { + rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts); + if (rv != SECSuccess) + break; + rv = CERT_MergeExtensions(extHandle, CRexts); + if (rv != SECSuccess) + break; + } CERT_FinishExtensions(extHandle); @@ -2877,7 +2935,13 @@ secuCommandFlag certutil_options[] = certutil.options[opt_ASCIIForIO].activated, certutil.options[opt_ExtendedEmailAddrs].arg, certutil.options[opt_ExtendedDNSNames].arg, - outFile ? outFile : PR_STDOUT); + certutil.options[opt_AddKeyUsageExt].activated, + certutil.options[opt_AddExtKeyUsageExt].activated, + certutil.options[opt_AddBasicConstraintExt].activated, + certutil.options[opt_AddAuthorityKeyIDExt].activated, + certutil.options[opt_AddCRLDistPtsExt].activated, + certutil.options[opt_AddNSCertTypeExt].activated, + outFile ? outFile : PR_STDOUT); if (rv) goto shutdown; privkey->wincx = &pwdata; diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h index 15b7e3af4..9dfe8d775 100644 --- a/security/nss/lib/certdb/cert.h +++ b/security/nss/lib/certdb/cert.h @@ -251,6 +251,26 @@ CERT_CreateCertificateRequest (CERTName *name, CERTSubjectPublicKeyInfo *spki, extern void CERT_DestroyCertificateRequest(CERTCertificateRequest *r); /* +** Start adding extensions to a certificate request. +*/ +void * +CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req); + +/* +** Reformat the certifcate extension list into a CertificateRequest +** attribute list. +*/ +SECStatus +CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req); + +/* +** Extract the Extension Requests from a DER CertRequest attribute list. +*/ +SECStatus +CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req, + CERTCertExtension ***exts); + +/* ** Extract a public key object from a certificate */ extern SECKEYPublicKey *CERT_ExtractPublicKey(CERTCertificate *cert); @@ -823,6 +843,13 @@ CERT_EncodeAltNameExtension(PRArenaPool *arena, CERTGeneralName *value, SECIte */ extern SECStatus CERT_FinishExtensions(void *exthandle); +/* +** Merge an external list of extensions into a cert's extension list, adding one +** only when its OID matches none of the cert's existing extensions. Call this +** immediately before calling CERT_FinishExtensions(). +*/ +SECStatus +CERT_MergeExtensions(void *exthandle, CERTCertExtension **exts); /* If the extension is found, return its criticality and value. ** This allocate storage for the returning extension value. diff --git a/security/nss/lib/certdb/certxutl.c b/security/nss/lib/certdb/certxutl.c index bb59fe002..1f77e0db9 100644 --- a/security/nss/lib/certdb/certxutl.c +++ b/security/nss/lib/certdb/certxutl.c @@ -375,6 +375,51 @@ loser: return rv; } +SECStatus +CERT_MergeExtensions(void *exthandle, CERTCertExtension **extensions) +{ + CERTCertExtension *ext; + SECStatus rv = SECSuccess; + SECOidTag tag; + extNode *node; + extRec *handle = exthandle; + PRBool critical; + + if (!exthandle || !extensions) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + while ((ext = *extensions++) != NULL) { + tag = SECOID_FindOIDTag(&ext->id); + for (node=handle->head; node != NULL; node=node->next) { + if (tag == 0) { + if (SECITEM_ItemsAreEqual(&ext->id, &node->ext->id)) + break; + } + else { + if (SECOID_FindOIDTag(&node->ext->id) == tag) { + break; + } + } + } + if (node == NULL) { + PRBool critical = (ext->critical.len != 0 && + ext->critical.data[ext->critical.len - 1] != 0); + if (critical && tag == SEC_OID_UNKNOWN) { + PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); + rv = SECFailure; + break; + } + /* add to list */ + rv = CERT_AddExtensionByOID (exthandle, &ext->id, &ext->value, + critical, PR_TRUE); + if (rv != SECSuccess) + break; + } + } + return rv; +} + /* * get the value of the Netscape Certificate Type Extension */ diff --git a/security/nss/lib/certhigh/certreq.c b/security/nss/lib/certhigh/certreq.c index 243a2d960..300f15353 100644 --- a/security/nss/lib/certhigh/certreq.c +++ b/security/nss/lib/certhigh/certreq.c @@ -35,10 +35,12 @@ * ***** END LICENSE BLOCK ***** */ #include "cert.h" +#include "certt.h" #include "secder.h" #include "key.h" #include "secitem.h" #include "secasn1.h" +#include "secerr.h" const SEC_ASN1Template CERT_AttributeTemplate[] = { { SEC_ASN1_SEQUENCE, @@ -166,8 +168,7 @@ CERT_CreateCertificateRequest(CERTName *subject, /* allocate space for attributes */ while(attributes[i] != NULL) i++; - certreq->attributes = (SECItem**)PORT_ArenaZAlloc(arena, - sizeof(SECItem *) * (i + 1)); + certreq->attributes = PORT_ArenaZNewArray(arena,CERTAttribute*,i+1); if(!certreq->attributes) { goto loser; } @@ -231,3 +232,96 @@ CERT_DestroyCertificateRequest(CERTCertificateRequest *req) return; } +static void +setCRExt(void *o, CERTCertExtension **exts) +{ + ((CERTCertificateRequest *)o)->attributes = (struct CERTAttributeStr **)exts; +} + +/* +** Set up to start gathering cert extensions for a cert request. +** The list is created as CertExtensions and converted to an +** attribute list by CERT_FinishCRAttributes(). + */ +extern void *cert_StartExtensions(void *owner, PRArenaPool *ownerArena, + void (*setExts)(void *object, CERTCertExtension **exts)); +void * +CERT_StartCertificateRequestAttributes(CERTCertificateRequest *req) +{ + return (cert_StartExtensions ((void *)req, req->arena, setCRExt)); +} + +/* +** At entry req->attributes actually contains an list of cert extensions-- +** req-attributes is overloaded until the list is DER encoded (the first +** ...EncodeItem() below). +** We turn this into an attribute list by encapsulating it +** in a PKCS 10 Attribute structure + */ +SECStatus +CERT_FinishCertificateRequestAttributes(CERTCertificateRequest *req) +{ SECItem *extlist; + SECOidData *oidrec; + CERTAttribute *attribute; + + if (!req || !req->arena) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (req->attributes == NULL) + return SECSuccess; + + extlist = SEC_ASN1EncodeItem(req->arena, NULL, &req->attributes, + SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate)); + if (extlist == NULL) + return(SECFailure); + + oidrec = SECOID_FindOIDByTag(SEC_OID_PKCS9_EXTENSION_REQUEST); + if (oidrec == NULL) + return SECFailure; + + /* now change the list of cert extensions into a list of attributes + */ + req->attributes = PORT_ArenaZNewArray(req->arena, CERTAttribute*, 2); + + attribute = PORT_ArenaZNew(req->arena, CERTAttribute); + + if (req->attributes == NULL || attribute == NULL || + SECITEM_CopyItem(req->arena, &attribute->attrType, &oidrec->oid) != 0) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + attribute->attrValue = PORT_ArenaZNewArray(req->arena, SECItem*, 2); + + if (attribute->attrValue == NULL) + return SECFailure; + + attribute->attrValue[0] = extlist; + attribute->attrValue[1] = NULL; + req->attributes[0] = attribute; + req->attributes[1] = NULL; + + return SECSuccess; +} + +SECStatus +CERT_GetCertificateRequestExtensions(CERTCertificateRequest *req, + CERTCertExtension ***exts) +{ + if (req == NULL || exts == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (req->attributes == NULL || *req->attributes == NULL) + return SECSuccess; + + if ((*req->attributes)->attrValue == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + return(SEC_ASN1DecodeItem(req->arena, exts, + SEC_ASN1_GET(CERT_SequenceOfCertExtensionTemplate), + (*req->attributes)->attrValue[0])); +} diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index 2822c5daf..3ef2dc935 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -820,11 +820,15 @@ CERT_DecodeCRLDistributionPoints; CERT_DecodeNameConstraintsExtension; CERT_DecodePrivKeyUsagePeriodExtension; CERT_DestroyUserNotice; +CERT_FinishCertificateRequestAttributes; CERT_GetCertificateNames; +CERT_GetCertificateRequestExtensions; CERT_GetNextGeneralName; CERT_GetNextNameConstraint; CERT_GetPrevGeneralName; CERT_GetPrevNameConstraint; +CERT_MergeExtensions; +CERT_StartCertificateRequestAttributes; CERT_StartCRLEntryExtensions; CERT_StartCRLExtensions; CERT_UncacheCRL; |