зеркало из https://github.com/mozilla/pjs.git
1316 строки
35 KiB
C
1316 строки
35 KiB
C
/*
|
|
* The contents of this file are subject to the Mozilla Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is the Netscape security libraries.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1994-2000 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*
|
|
* Alternatively, the contents of this file may be used under the
|
|
* terms of the GNU General Public License Version 2 or later (the
|
|
* "GPL"), in which case the provisions of the GPL are applicable
|
|
* instead of those above. If you wish to allow use of your
|
|
* version of this file only under the terms of the GPL and not to
|
|
* allow others to use your version of this file under the MPL,
|
|
* indicate your decision by deleting the provisions above and
|
|
* replace them with the notice and other provisions required by
|
|
* the GPL. If you do not delete the provisions above, a recipient
|
|
* may use your version of this file under either the MPL or the
|
|
* GPL.
|
|
*/
|
|
#include "oldfunc.h"
|
|
#include "newproto.h"
|
|
#include "messages.h"
|
|
|
|
/*
|
|
* All possible key size choices.
|
|
*/
|
|
static SECKeySizeChoiceInfo SECKeySizeChoiceList[] = {
|
|
{ NULL, 2048, 0 },
|
|
{ NULL, 1024, 1 },
|
|
{ NULL, 512, 1 },
|
|
{ NULL, 0, 0 }
|
|
};
|
|
|
|
DERTemplate CERTSubjectPublicKeyInfoTemplate[] = {
|
|
{ DER_SEQUENCE,
|
|
0, NULL, sizeof(CERTSubjectPublicKeyInfo) },
|
|
{ DER_INLINE,
|
|
offsetof(CERTSubjectPublicKeyInfo,algorithm),
|
|
SECAlgorithmIDTemplate, },
|
|
{ DER_BIT_STRING,
|
|
offsetof(CERTSubjectPublicKeyInfo,subjectPublicKey), },
|
|
{ 0, }
|
|
};
|
|
|
|
DERTemplate CERTPublicKeyAndChallengeTemplate[] =
|
|
{
|
|
{ DER_SEQUENCE, 0, NULL, sizeof(CERTPublicKeyAndChallenge) },
|
|
{ DER_ANY, offsetof(CERTPublicKeyAndChallenge,spki), },
|
|
{ DER_IA5_STRING, offsetof(CERTPublicKeyAndChallenge,challenge), },
|
|
{ 0, }
|
|
};
|
|
|
|
typedef struct {
|
|
SSMControlConnection * ctrl;
|
|
CERTCertificate * cert;
|
|
CERTDERCerts * derCerts;
|
|
} caImportCertArg;
|
|
|
|
/* Used for accepting CA certificate. */
|
|
static PRBool acceptssl, acceptmime, acceptobjectsign, acceptcacert;
|
|
|
|
static char *nickFmt=NULL, *nickFmtWithNum = NULL;
|
|
|
|
static int pqg_prime_bits(char *str);
|
|
static PQGParams * decode_pqg_params(char *str);
|
|
static char * GenKey(SSMControlConnection * ctrl, int keysize, char *challenge,
|
|
PRUint32 type, PQGParams *pqg, PK11SlotInfo * slot);
|
|
static SSMStatus handle_user_cert(SSMControlConnection * ctrl,
|
|
CERTCertificate *cert, CERTDERCerts *derCerts);
|
|
static SSMStatus handle_ca_cert(SSMControlConnection * ctrl,
|
|
CERTCertificate *cert, CERTDERCerts *derCerts);
|
|
static SSMStatus handle_email_cert(SSMControlConnection * ctrl,
|
|
CERTCertificate * cert,
|
|
CERTDERCerts * derCerts);
|
|
static void SSM_ImportCACert(void * arg);
|
|
|
|
static int init = 0;
|
|
|
|
SSMStatus SSM_EnableHighGradeKeyGen(void)
|
|
{
|
|
SECKeySizeChoiceList[0].enabled = 1;
|
|
return SSM_SUCCESS;
|
|
}
|
|
|
|
PRBool SSM_KeyGenAllowedForSize(int size)
|
|
{
|
|
int i;
|
|
int numChoices = sizeof(SECKeySizeChoiceList)/sizeof(SECKeySizeChoiceInfo);
|
|
|
|
for (i=0; i<numChoices; i++) {
|
|
if (SECKeySizeChoiceList[i].size == size &&
|
|
SECKeySizeChoiceList[i].enabled) {
|
|
return PR_TRUE;
|
|
}
|
|
}
|
|
return PR_FALSE;
|
|
}
|
|
|
|
SSMStatus InitChoiceList(void)
|
|
{
|
|
SSMTextGenContext *cx;
|
|
|
|
if (SSMTextGen_NewTopLevelContext(NULL, &cx) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (SSM_GetUTF8Text(cx, "high_grade",
|
|
&SECKeySizeChoiceList[0].name) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (SSM_GetUTF8Text(cx, "medium_grade",
|
|
&SECKeySizeChoiceList[1].name) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
|
|
if (SSM_GetUTF8Text(cx, "low_grade",
|
|
&SECKeySizeChoiceList[2].name) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
SSMTextGen_DestroyContext(cx);
|
|
return SSM_SUCCESS;
|
|
loser:
|
|
if (cx != NULL) {
|
|
SSMTextGen_DestroyContext(cx);
|
|
}
|
|
return SSM_FAILURE;
|
|
}
|
|
|
|
|
|
char ** SSM_GetKeyChoiceList(char * type, char * pqgString, int *nchoices)
|
|
{
|
|
char ** list, *pqg, *end;
|
|
int i, j, len, primeBits;
|
|
SSMStatus rv;
|
|
|
|
if (!init) {
|
|
rv = InitChoiceList();
|
|
if (rv != SSM_SUCCESS) {
|
|
PR_ASSERT(!"Could not initialize the choice list for key gen layout!!");
|
|
return NULL;
|
|
}
|
|
init = 1;
|
|
}
|
|
|
|
len = sizeof (SECKeySizeChoiceList) / sizeof (SECKeySizeChoiceInfo);
|
|
|
|
list = SSM_ZNEW_ARRAY(char*, len);
|
|
|
|
if (type && (PORT_Strcasecmp(type, "dsa") == 0)) {
|
|
if (pqgString == NULL) {
|
|
list[0] = NULL;
|
|
return list;
|
|
}
|
|
pqg = pqgString;
|
|
|
|
j = 0;
|
|
do {
|
|
end = PORT_Strchr(pqg, ',');
|
|
if (end != NULL)
|
|
*end = '\0';
|
|
primeBits = pqg_prime_bits(pqg);
|
|
for (i = 0; SECKeySizeChoiceList[i].size != 0; i++) {
|
|
if (SECKeySizeChoiceList[i].size == primeBits) {
|
|
list[j++] = strdup(SECKeySizeChoiceList[i].name);
|
|
break;
|
|
}
|
|
}
|
|
pqg = end + 1;
|
|
} while (end != NULL);
|
|
} else {
|
|
int maxKeyBits = SSM_MAX_KEY_BITS;
|
|
j = 0;
|
|
for (i = (policyType == ssmDomestic) ? 0 : 1;
|
|
SECKeySizeChoiceList[i].size != 0; i++) {
|
|
if (SECKeySizeChoiceList[i].size <= maxKeyBits)
|
|
list[j++] = strdup(SECKeySizeChoiceList[i].name);
|
|
}
|
|
}
|
|
|
|
if (pqgString != NULL)
|
|
PORT_Free(pqgString);
|
|
*nchoices = j;
|
|
return list;
|
|
}
|
|
|
|
|
|
char * SSMControlConnection_GenerateKeyOldStyle(SSMControlConnection * ctrl,
|
|
char *choiceString, char *challenge,
|
|
char *typeString, char *pqgString)
|
|
{
|
|
SECKeySizeChoiceInfo *choice = SECKeySizeChoiceList;
|
|
char *end, *str;
|
|
PQGParams *pqg = NULL;
|
|
int primeBits;
|
|
KeyType type;
|
|
char * keystring = NULL;
|
|
PK11SlotInfo *slot;
|
|
SSMKeyGenContext * ct = NULL;
|
|
SSMKeyGenContextCreateArg arg;
|
|
PRUint32 keyGenMechanism;
|
|
SSMStatus rv;
|
|
|
|
while (PORT_Strcmp(choice->name, choiceString) != 0)
|
|
choice++;
|
|
|
|
if (PORT_Strcmp(challenge, "null") == 0) {
|
|
challenge = NULL;
|
|
}
|
|
|
|
if ((PORT_Strcmp(typeString, "null") == 0) ||
|
|
(PORT_Strcasecmp(typeString, "rsa") == 0)) {
|
|
type = rsaKey;
|
|
keyGenMechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
|
|
} else if (PORT_Strcasecmp(typeString, "dsa") == 0) {
|
|
type = dsaKey;
|
|
keyGenMechanism = CKM_DSA_KEY_PAIR_GEN;
|
|
if (PORT_Strcmp(pqgString, "null") == 0)
|
|
goto loser;
|
|
str = pqgString;
|
|
do {
|
|
end = PORT_Strchr(str, ',');
|
|
if (end != NULL)
|
|
*end = '\0';
|
|
primeBits = pqg_prime_bits(str);
|
|
if (choice->size == primeBits)
|
|
goto found_match;
|
|
str = end + 1;
|
|
} while (end != NULL);
|
|
goto loser;
|
|
found_match:
|
|
pqg = decode_pqg_params(str);
|
|
} else {
|
|
goto loser;
|
|
}
|
|
|
|
/*
|
|
* To get slot we first create a keygen context, and
|
|
* use its facilities to find a slot for our key generation
|
|
*/
|
|
|
|
arg.parent = ctrl;
|
|
arg.type = SSM_OLD_STYLE_KEYGEN;
|
|
arg.param = NULL;
|
|
SSM_DEBUG("Creating key gen context.\n");
|
|
rv = SSMKeyGenContext_Create(&arg, ctrl, (SSMResource **)&ct);
|
|
if (rv != PR_SUCCESS) {
|
|
SSM_DEBUG("Could not create KeyGenContext for oldStyleKeyGen.\n");
|
|
goto loser;
|
|
}
|
|
rv = SSMKeyGenContext_GetSlot(ct, keyGenMechanism);
|
|
if (rv != SSM_SUCCESS)
|
|
goto loser;
|
|
|
|
slot = ct->slot;
|
|
keystring = GenKey(ctrl,choice->size, challenge, keyGenMechanism, pqg, slot);
|
|
/* received a Cancel event from UI */
|
|
if (ct->m_userCancel) {
|
|
PR_Free(keystring);
|
|
keystring = NULL;
|
|
}
|
|
|
|
loser:
|
|
if (ct)
|
|
SSMKeyGenContext_Shutdown((SSMResource *)ct, rv);
|
|
|
|
return keystring;
|
|
}
|
|
|
|
static PQGParams *
|
|
decode_pqg_params(char *str)
|
|
{
|
|
char *buf;
|
|
unsigned int len;
|
|
PRArenaPool *arena;
|
|
PQGParams *params;
|
|
SECStatus status;
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (arena == NULL)
|
|
return NULL;
|
|
|
|
params = (PQGParams *) PORT_ArenaZAlloc(arena, sizeof(PQGParams));
|
|
if (params == NULL)
|
|
goto loser;
|
|
params->arena = arena;
|
|
|
|
buf = (char *)ATOB_AsciiToData(str, &len);
|
|
if ((buf == NULL) || (len == 0))
|
|
goto loser;
|
|
|
|
status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, buf, len);
|
|
if (status != SECSuccess)
|
|
goto loser;
|
|
|
|
return params;
|
|
|
|
loser:
|
|
if (arena != NULL)
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return NULL;
|
|
}
|
|
|
|
static int
|
|
pqg_prime_bits(char *str)
|
|
{
|
|
PQGParams *params = NULL;
|
|
int primeBits = 0, i;
|
|
|
|
params = decode_pqg_params(str);
|
|
if (params == NULL)
|
|
goto done; /* lose */
|
|
|
|
for (i = 0; params->prime.data[i] == 0; i++)
|
|
/* empty */;
|
|
primeBits = (params->prime.len - i) * 8;
|
|
|
|
done:
|
|
if (params != NULL)
|
|
PQG_DestroyParams(params);
|
|
return primeBits;
|
|
}
|
|
|
|
static char *
|
|
GenKey(SSMControlConnection * ctrl, int keysize, char *challenge,
|
|
PRUint32 type, PQGParams *pqg, PK11SlotInfo *slot)
|
|
{
|
|
SECKEYPrivateKey *privateKey = NULL;
|
|
SECKEYPublicKey *publicKey = NULL;
|
|
CERTSubjectPublicKeyInfo *spkInfo = NULL;
|
|
PRArenaPool *arena = NULL;
|
|
SECStatus rv = SECFailure;
|
|
SECItem spkiItem;
|
|
SECItem pkacItem;
|
|
SECItem signedItem;
|
|
CERTPublicKeyAndChallenge pkac;
|
|
char *keystring = NULL;
|
|
CK_MECHANISM_TYPE mechanism = type;
|
|
PK11RSAGenParams rsaParams;
|
|
void *params;
|
|
SECOidTag algTag;
|
|
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (arena == NULL) {
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Create a new key pair.
|
|
*/
|
|
/* Switch statement goes here for DSA */
|
|
switch (mechanism) {
|
|
case CKM_RSA_PKCS_KEY_PAIR_GEN:
|
|
rsaParams.keySizeInBits = keysize;
|
|
rsaParams.pe = 65537L;
|
|
algTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
|
|
params = &rsaParams;
|
|
break;
|
|
case CKM_DSA_KEY_PAIR_GEN:
|
|
params = pqg;
|
|
algTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
|
|
break;
|
|
default:
|
|
goto done;
|
|
break;
|
|
}
|
|
privateKey = PK11_GenerateKeyPair(slot, mechanism, params,
|
|
&publicKey, PR_TRUE, PR_TRUE, NULL);
|
|
if (privateKey == NULL) {
|
|
goto done;
|
|
}
|
|
/* just in case we'll need to authenticate to the db -jp */
|
|
privateKey->wincx = ctrl;
|
|
/*
|
|
* Create a subject public key info from the public key.
|
|
*/
|
|
spkInfo = SECKEY_CreateSubjectPublicKeyInfo(publicKey);
|
|
if ( spkInfo == NULL ) {
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Now DER encode the whole subjectPublicKeyInfo.
|
|
*/
|
|
rv=DER_Encode(arena, &spkiItem, CERTSubjectPublicKeyInfoTemplate, spkInfo);
|
|
if (rv != SECSuccess) {
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* set up the PublicKeyAndChallenge data structure, then DER encode it
|
|
*/
|
|
pkac.spki = spkiItem;
|
|
if ( challenge ) {
|
|
pkac.challenge.len = PORT_Strlen(challenge);
|
|
} else {
|
|
pkac.challenge.len = 0;
|
|
}
|
|
pkac.challenge.data = (unsigned char *)challenge;
|
|
|
|
rv = DER_Encode(arena, &pkacItem, CERTPublicKeyAndChallengeTemplate, &pkac);
|
|
if ( rv != SECSuccess ) {
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* now sign the DER encoded PublicKeyAndChallenge
|
|
*/
|
|
rv = SEC_DerSignData(arena, &signedItem, pkacItem.data, pkacItem.len,
|
|
privateKey, algTag);
|
|
if ( rv != SECSuccess ) {
|
|
goto done;
|
|
}
|
|
|
|
/*
|
|
* Convert the signed public key and challenge into base64/ascii.
|
|
*/
|
|
keystring = BTOA_DataToAscii(signedItem.data, signedItem.len);
|
|
|
|
done:
|
|
/*
|
|
* Destroy the private key ASAP, so that we don't leave a copy in
|
|
* memory that some evil hacker can get at.
|
|
*/
|
|
if ( rv != SECSuccess ) {
|
|
if ( privateKey ) {
|
|
PK11_DestroyTokenObject(privateKey->pkcs11Slot,privateKey->pkcs11ID);
|
|
SECKEY_DestroyPrivateKey(privateKey);
|
|
}
|
|
if ( publicKey )
|
|
PK11_DestroyTokenObject(publicKey->pkcs11Slot,publicKey->pkcs11ID);
|
|
}
|
|
if ( spkInfo )
|
|
SECKEY_DestroySubjectPublicKeyInfo(spkInfo);
|
|
if ( publicKey )
|
|
SECKEY_DestroyPublicKey(publicKey);
|
|
if ( arena )
|
|
PORT_FreeArena(arena, PR_TRUE);
|
|
|
|
return keystring;
|
|
}
|
|
|
|
static SECStatus
|
|
collect_certs(void *arg, SECItem **certs, int numcerts)
|
|
{
|
|
CERTDERCerts *collectArgs;
|
|
SECItem *cert;
|
|
SECStatus rv;
|
|
|
|
collectArgs = (CERTDERCerts *)arg;
|
|
|
|
collectArgs->numcerts = numcerts;
|
|
collectArgs->rawCerts = (SECItem *) PORT_ArenaZAlloc(collectArgs->arena,
|
|
sizeof(SECItem) * numcerts);
|
|
if ( collectArgs->rawCerts == NULL )
|
|
return(SECFailure);
|
|
cert = collectArgs->rawCerts;
|
|
|
|
while ( numcerts-- ) {
|
|
rv = SECITEM_CopyItem(collectArgs->arena, cert, *certs);
|
|
if ( rv == SECFailure )
|
|
return(SECFailure);
|
|
cert++;
|
|
certs++;
|
|
}
|
|
|
|
return (SECSuccess);
|
|
}
|
|
|
|
static SSMStatus handle_user_cert(SSMControlConnection * ctrl,
|
|
CERTCertificate *cert, CERTDERCerts *derCerts)
|
|
{
|
|
PK11SlotInfo *slot;
|
|
char * nickname = NULL;
|
|
SECStatus rv;
|
|
int numCACerts;
|
|
SECItem *CACerts;
|
|
|
|
slot = PK11_KeyForCertExists(cert, NULL, ctrl);
|
|
if ( slot == NULL ) {
|
|
SSM_DEBUG("Can't find keydb with the key for the new cert!\n");
|
|
goto loser;
|
|
}
|
|
PK11_FreeSlot(slot);
|
|
if (!certificate_conflict(ctrl, &cert->derCert,
|
|
ctrl->m_certdb, PR_TRUE)) {
|
|
/*
|
|
* This cert is already in the database, no need to re-import.
|
|
*/
|
|
goto loser;
|
|
}
|
|
|
|
/* pick a nickname for the cert */
|
|
if (cert->subjectList && cert->subjectList->entry &&
|
|
cert->subjectList->entry->nickname)
|
|
nickname = cert->subjectList->entry->nickname;
|
|
else nickname = default_nickname(cert, ctrl);
|
|
|
|
/*
|
|
UI for cert installation goes here - no UI here?
|
|
*/
|
|
/* user wants to import the cert */
|
|
slot = PK11_ImportCertForKey(cert, nickname, ctrl);
|
|
if (!slot)
|
|
goto loser;
|
|
PK11_FreeSlot(slot);
|
|
SSM_UseAsDefaultEmailIfNoneSet(ctrl, cert, PR_FALSE);
|
|
numCACerts = derCerts->numcerts - 1;
|
|
|
|
if (numCACerts) {
|
|
CACerts = derCerts->rawCerts+1;
|
|
|
|
rv = CERT_ImportCAChain(CACerts, numCACerts, certUsageUserCertImport);
|
|
/* We really should send some notice to the user that importing the
|
|
* CA certs failed if rv is SECSuccess.
|
|
*/
|
|
}
|
|
|
|
return PR_SUCCESS;
|
|
loser:
|
|
CERT_DestroyCertificate(cert);
|
|
return PR_FAILURE;
|
|
|
|
}
|
|
|
|
static SSMStatus handle_ca_cert(SSMControlConnection * ctrl,
|
|
CERTCertificate *cert, CERTDERCerts *derCerts)
|
|
{
|
|
caImportCertArg * arg = NULL;
|
|
arg = (caImportCertArg *) PORT_ZAlloc(sizeof(caImportCertArg));
|
|
arg->ctrl = ctrl;
|
|
arg->cert = CERT_DupCertificate(cert);
|
|
arg->derCerts = derCerts;
|
|
|
|
SSM_CreateAndRegisterThread(PR_USER_THREAD, SSM_ImportCACert, (void *)arg,
|
|
PR_PRIORITY_NORMAL, PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0);
|
|
return PR_SUCCESS;
|
|
}
|
|
|
|
PRBool
|
|
certificate_conflict(SSMControlConnection * cx, SECItem * derCert,
|
|
CERTCertDBHandle * handle, PRBool sendUIEvent)
|
|
{
|
|
SECStatus rv;
|
|
SECItem key;
|
|
PRArenaPool *arena = NULL;
|
|
PRBool ret;
|
|
CERTCertificate *cert;
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if (!arena)
|
|
goto loser;
|
|
|
|
/* get the key (issuer+cn) from the cert */
|
|
rv = CERT_KeyFromDERCert(arena, derCert, &key);
|
|
if ( rv != SECSuccess )
|
|
goto loser;
|
|
|
|
/* check if the same cert already exists */
|
|
cert = CERT_FindCertByKey(handle, &key);
|
|
if ( cert ) {
|
|
if ( cert->isperm && ( cert->nickname == NULL ) &&
|
|
( cert->emailAddr == NULL ) ) {
|
|
/* if the cert doesn't have a nickname or email addr, it is
|
|
* bogus cruft, so delete it
|
|
*/
|
|
SEC_DeletePermCertificate(cert);
|
|
} else if ( cert->isperm ) {
|
|
SSM_DEBUG("Found existing cert with the same key!\n");
|
|
rv = SECFailure;
|
|
if (sendUIEvent && (SSMControlConnection_SendUIEvent(cx,
|
|
"get", "cert_already_exists",
|
|
NULL, NULL, NULL)) == SSM_SUCCESS)
|
|
rv = SECSuccess;
|
|
ret = PR_FALSE;
|
|
goto done;
|
|
} else
|
|
CERT_DestroyCertificate(cert);
|
|
} /* end of same-cert-exists */
|
|
|
|
ret = PR_TRUE;
|
|
goto done;
|
|
|
|
loser:
|
|
ret = PR_FALSE;
|
|
done:
|
|
if ( arena )
|
|
PORT_FreeArena(arena, PR_FALSE);
|
|
return ret;
|
|
}
|
|
|
|
typedef struct UserCertImprtArgStr {
|
|
SSMControlConnection *ctrl;
|
|
SECItem *msg;
|
|
} UserCertImportArg;
|
|
|
|
void ssm_import_user_cert_thread(void *arg) {
|
|
UserCertImportArg *impArg = (UserCertImportArg*)arg;
|
|
SSMControlConnection *ctrl = impArg->ctrl;
|
|
SECItem *msg = impArg->msg;
|
|
SSMStatus rv = PR_FAILURE;
|
|
CERTDERCerts * collectArgs;
|
|
PRArenaPool *arena;
|
|
CERTCertificate * cert=NULL;
|
|
SSMResourceID certID;
|
|
SSMResource * certResource;
|
|
PRBool noconflict;
|
|
DecodeAndCreateTempCertRequest request;
|
|
SingleNumMessage reply;
|
|
|
|
if (!msg || !msg->data)
|
|
goto loser;
|
|
|
|
SSM_RegisterThread("cert import", NULL);
|
|
|
|
if (CMT_DecodeMessage(DecodeAndCreateTempCertRequestTemplate, &request, (CMTItem*)msg) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
|
|
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
|
|
if ( arena == NULL )
|
|
goto loser;
|
|
|
|
collectArgs = (CERTDERCerts *)PORT_ArenaZAlloc(arena, sizeof(CERTDERCerts));
|
|
if ( collectArgs == NULL )
|
|
goto loser;
|
|
|
|
collectArgs->arena = arena;
|
|
|
|
rv = CERT_DecodeCertPackage((char *) request.cert.data, (int) request.cert.len, collect_certs,
|
|
(void *)collectArgs);
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
|
|
/* check for conflicts */
|
|
noconflict = certificate_conflict(ctrl,collectArgs->rawCerts,
|
|
ctrl->m_certdb, PR_TRUE);
|
|
if (!noconflict)
|
|
goto loser; /* certificate with this key already exists in the db */
|
|
|
|
cert = CERT_NewTempCertificate(ctrl->m_certdb, collectArgs->rawCerts,
|
|
(char *)NULL, PR_FALSE, PR_TRUE);
|
|
if (!cert)
|
|
goto loser;
|
|
|
|
/* create certificate resource so we can return it to client */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert, ctrl, &certID, &certResource);
|
|
if (rv != PR_SUCCESS) {
|
|
SSM_DEBUG("In decode&create tmp cert: can't create certificate resource.\n");
|
|
goto loser;
|
|
}
|
|
/* Get a client reference to it */
|
|
SSM_ClientGetResourceReference(certResource, &certID);
|
|
|
|
switch (request.type) {
|
|
case SEC_CERT_CLASS_USER:
|
|
rv = handle_user_cert(ctrl, cert, collectArgs);
|
|
break;
|
|
case SEC_CERT_CLASS_CA:
|
|
rv = handle_ca_cert(ctrl, cert, collectArgs);
|
|
break;
|
|
case SEC_CERT_CLASS_SERVER:
|
|
/* why destroy class server certs? */
|
|
CERT_DestroyCertificate(cert);
|
|
break;
|
|
case SEC_CERT_CLASS_EMAIL:
|
|
rv = handle_email_cert(ctrl, cert, collectArgs);
|
|
break;
|
|
default:
|
|
rv = PR_FAILURE;
|
|
SSM_DEBUG("ProcessDecodeAndCreateCertRequest: unknown cert class\n");
|
|
}
|
|
if (rv != PR_SUCCESS)
|
|
goto loser;
|
|
|
|
/* create reply */
|
|
msg->type = (SECItemType) (SSM_REPLY_OK_MESSAGE | SSM_CERT_ACTION | SSM_DECODE_TEMP_CERT);
|
|
msg->len = 0;
|
|
reply.value = certID;
|
|
if (CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply) != CMTSuccess) {
|
|
goto loser;
|
|
}
|
|
SSM_DEBUG("queueing reply: type %lx, len %ld.\n", msg->type, msg->len);
|
|
SSM_SendQMessage(ctrl->m_controlOutQ,
|
|
SSM_PRIORITY_NORMAL,
|
|
msg->type, msg->len,
|
|
(char *)msg->data, PR_TRUE);
|
|
if (rv == PR_SUCCESS)
|
|
goto done;
|
|
loser:
|
|
{
|
|
SingleNumMessage reply;
|
|
|
|
msg->type = (SECItemType) SSM_REPLY_ERR_MESSAGE;
|
|
reply.value = rv;
|
|
CMT_EncodeMessage(SingleNumMessageTemplate, (CMTItem*)msg, &reply);
|
|
if (!msg->data || msg->len == 0)
|
|
goto loser;
|
|
else rv = PR_SUCCESS;
|
|
}
|
|
SSM_DEBUG("queueing reply: type %lx, len %ld.\n", msg->type, msg->len);
|
|
SSM_SendQMessage(ctrl->m_controlOutQ,
|
|
SSM_PRIORITY_NORMAL,
|
|
msg->type, msg->len,
|
|
(char *)msg->data, PR_TRUE);
|
|
|
|
if (rv == PR_SUCCESS)
|
|
rv = PR_FAILURE;
|
|
if (arena)
|
|
PORT_FreeArena(arena, PR_TRUE);
|
|
done:
|
|
SECITEM_FreeItem(msg, PR_TRUE);
|
|
SSM_FreeResource(&ctrl->super.super);
|
|
if (cert != NULL)
|
|
CERT_DestroyCertificate(cert);
|
|
return;
|
|
|
|
}
|
|
|
|
SSMStatus
|
|
SSMControlConnection_ProcessDecodeAndCreateTempCert(SSMControlConnection *
|
|
ctrl, SECItem * msg)
|
|
{
|
|
UserCertImportArg *impArg;
|
|
|
|
impArg = SSM_ZNEW(UserCertImportArg);
|
|
if (impArg == NULL) {
|
|
return SSM_FAILURE;
|
|
}
|
|
|
|
impArg->ctrl = ctrl;
|
|
impArg->msg = SECITEM_DupItem(msg);
|
|
SSMControlConnection_RecycleItem(msg);
|
|
SSM_GetResourceReference(&ctrl->super.super);
|
|
if (SSM_CreateAndRegisterThread(PR_USER_THREAD,
|
|
ssm_import_user_cert_thread,
|
|
(void*)impArg,
|
|
PR_PRIORITY_NORMAL,
|
|
PR_LOCAL_THREAD,
|
|
PR_UNJOINABLE_THREAD, 0) == NULL) {
|
|
SSM_DEBUG("Couldn't create thread for importing cert.");
|
|
return SSM_FAILURE;
|
|
}
|
|
return SSM_ERR_DEFER_RESPONSE;
|
|
}
|
|
|
|
static SSMStatus
|
|
handle_email_cert(SSMControlConnection * ctrl, CERTCertificate * cert,
|
|
CERTDERCerts * derCerts)
|
|
{
|
|
SSMStatus rv = PR_FAILURE;
|
|
SECItem **rawCerts;
|
|
int numcerts;
|
|
int i;
|
|
|
|
numcerts = derCerts->numcerts;
|
|
|
|
rawCerts = (SECItem **) PORT_Alloc(sizeof(SECItem *) * numcerts);
|
|
if ( !rawCerts )
|
|
goto loser;
|
|
for ( i = 0; i < numcerts; i++ ) {
|
|
rawCerts[i] = &derCerts->rawCerts[i];
|
|
}
|
|
|
|
rv = CERT_ImportCerts(cert->dbhandle, certUsageEmailSigner,
|
|
numcerts, rawCerts, NULL, PR_TRUE, PR_FALSE,
|
|
NULL);
|
|
if ( rv == SECSuccess ) {
|
|
rv = CERT_SaveSMimeProfile(cert, NULL, NULL);
|
|
}
|
|
|
|
PORT_Free(rawCerts);
|
|
|
|
loser:
|
|
return rv;
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
default_nickname(CERTCertificate *cert, SSMControlConnection *conn)
|
|
{
|
|
char *username = NULL;
|
|
char *caname = NULL;
|
|
char *nickname = NULL;
|
|
char *tmp = NULL;
|
|
int count;
|
|
CERTCertificate *dummycert;
|
|
SSMTextGenContext *cx = NULL;
|
|
PK11SlotInfo *slot=NULL;
|
|
CK_OBJECT_HANDLE keyHandle;
|
|
|
|
username = CERT_GetCommonName(&cert->subject);
|
|
if ( username == NULL )
|
|
username = strdup("");
|
|
|
|
if ( username == NULL )
|
|
goto loser;
|
|
|
|
caname = CERT_GetOrgName(&cert->issuer);
|
|
if ( caname == NULL )
|
|
caname = strdup("");
|
|
|
|
if ( caname == NULL )
|
|
goto loser;
|
|
|
|
count = 1;
|
|
if (nickFmt == NULL) {
|
|
if (SSMTextGen_NewTopLevelContext(NULL, &cx) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (SSM_FindUTF8StringInBundles(cx, "nick_template",
|
|
&nickFmt) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
if (SSM_FindUTF8StringInBundles(cx, "nick_template_with_num",
|
|
&nickFmtWithNum) != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
}
|
|
nickname = PR_smprintf(nickFmt, username, caname);
|
|
/*
|
|
* We need to see if the private key exists on a token, if it does
|
|
* then we need to check for nicknames that already exist on the smart
|
|
* card.
|
|
*/
|
|
slot = PK11_KeyForCertExists(cert, &keyHandle, conn);
|
|
if (slot == NULL) {
|
|
goto loser;
|
|
}
|
|
if (!PK11_IsInternal(slot)) {
|
|
tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), nickname);
|
|
PR_Free(nickname);
|
|
nickname = tmp;
|
|
tmp = NULL;
|
|
}
|
|
tmp = nickname;
|
|
while ( 1 ) {
|
|
if ( count > 1 ) {
|
|
nickname = PR_smprintf("%s #%d", tmp, count);
|
|
}
|
|
|
|
|
|
if ( nickname == NULL )
|
|
goto loser;
|
|
|
|
_ssm_compress_spaces(nickname);
|
|
if (PK11_IsInternal(slot)) {
|
|
/* look up the nickname to make sure it isn't in use already */
|
|
dummycert = CERT_FindCertByNickname(conn->m_certdb, nickname);
|
|
|
|
} else {
|
|
/*
|
|
* Check the cert against others that already live on the smart
|
|
* card.
|
|
*/
|
|
dummycert = PK11_FindCertFromNickname(nickname, conn);
|
|
if (dummycert != NULL) {
|
|
/*
|
|
* Make sure the subject names are different.
|
|
*/
|
|
if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual)
|
|
{
|
|
/*
|
|
* There is another certificate with the same nickname and
|
|
* the same subject name on the smart card, so let's use this
|
|
* nickname.
|
|
*/
|
|
CERT_DestroyCertificate(dummycert);
|
|
dummycert = NULL;
|
|
}
|
|
}
|
|
}
|
|
if ( dummycert == NULL )
|
|
goto done;
|
|
|
|
/* found a cert, destroy it and loop */
|
|
CERT_DestroyCertificate(dummycert);
|
|
if (tmp != nickname) PR_Free(nickname);
|
|
count++;
|
|
} /* end of while(1) */
|
|
|
|
loser:
|
|
if ( nickname )
|
|
PORT_Free(nickname);
|
|
nickname = NULL;
|
|
done:
|
|
if ( caname )
|
|
PORT_Free(caname);
|
|
if ( username )
|
|
PORT_Free(username);
|
|
if ( cx )
|
|
SSMTextGen_DestroyContext(cx);
|
|
if (slot != NULL) {
|
|
PK11_FreeSlot(slot);
|
|
if (nickname != NULL) {
|
|
tmp = nickname;
|
|
nickname = PL_strchr(tmp, ':');
|
|
if (nickname != NULL) {
|
|
nickname++;
|
|
nickname = PL_strdup(nickname);
|
|
PR_Free(tmp);
|
|
} else {
|
|
nickname = tmp;
|
|
tmp = NULL;
|
|
}
|
|
}
|
|
}
|
|
PR_FREEIF(tmp);
|
|
return(nickname);
|
|
}
|
|
|
|
SSMStatus SSM_OKButtonCommandHandler(HTTPRequest * req)
|
|
{
|
|
char * tmpStr = NULL;
|
|
SSMStatus rv;
|
|
|
|
/* check the base ref */
|
|
rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
|
|
if (rv != SSM_SUCCESS ||
|
|
PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
|
|
goto loser;
|
|
}
|
|
/* close the window */
|
|
rv = SSM_HTTPCloseAndSleep(req);
|
|
|
|
loser:
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSM_CertCAImportCommandHandler1(HTTPRequest *req)
|
|
{
|
|
SSMStatus rv;
|
|
char * tmpStr = NULL;
|
|
|
|
/* make sure you got the right baseRef */
|
|
rv = SSM_HTTPParamValue(req, "baseRef", &tmpStr);
|
|
if (rv != SSM_SUCCESS ||
|
|
PL_strcmp(tmpStr, "windowclose_doclose_js") != 0) {
|
|
goto loser;
|
|
}
|
|
/* close the first window */
|
|
rv = SSM_HTTPCloseAndSleep(req);
|
|
if (rv != SSM_SUCCESS)
|
|
SSM_DEBUG("Errors closing ImportCAStep1 window: %d\n", rv);
|
|
|
|
/* figure out the buttons */
|
|
rv = SSM_HTTPParamValue(req, "do_cancel", &tmpStr);
|
|
if (rv == SSM_SUCCESS) {
|
|
/* cancel button was clicked */
|
|
return SSM_SUCCESS;
|
|
}
|
|
rv = SSM_HTTPParamValue(req, "do_ok", &tmpStr);
|
|
if (rv == SSM_SUCCESS) {
|
|
/* user wants to proceed */
|
|
rv=SSMControlConnection_SendUIEvent(req->ctrlconn,
|
|
"get", "import_ca_cert2",
|
|
req->target, NULL,
|
|
&req->target->m_clientContext);
|
|
if (rv != PR_SUCCESS) {
|
|
/* problem! */
|
|
SSM_DEBUG("Cannot fire second dialog for CA cert importation!\n");
|
|
SSM_NotifyUIEvent(req->target);
|
|
}
|
|
}
|
|
else
|
|
SSM_DEBUG("Cannot identify button pressed in first importCACert dialog!\n");
|
|
loser:
|
|
return rv;
|
|
}
|
|
|
|
|
|
SSMStatus SSM_CertCAImportCommandHandler2(HTTPRequest * req)
|
|
{
|
|
SSMStatus rv;
|
|
char * tmpStr = NULL;
|
|
|
|
/* if we got here, user must have hit OK for import CA cert */
|
|
acceptcacert = PR_TRUE;
|
|
|
|
/* check parameters */
|
|
rv = SSM_HTTPParamValue(req, "acceptssl", &tmpStr);
|
|
if (rv == SSM_SUCCESS)
|
|
acceptssl = PR_TRUE;
|
|
|
|
rv = SSM_HTTPParamValue(req, "acceptemail", &tmpStr);
|
|
if (rv == SSM_SUCCESS)
|
|
acceptmime = PR_TRUE;
|
|
|
|
rv = SSM_HTTPParamValue(req, "acceptobject", &tmpStr);
|
|
if (rv == SSM_SUCCESS)
|
|
acceptobjectsign = PR_TRUE;
|
|
|
|
|
|
SSM_NotifyUIEvent(req->target);
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSM_SubmitFormFromButtonAndFreeTarget(HTTPRequest *req)
|
|
{
|
|
SSMStatus rv;
|
|
|
|
rv = SSM_SubmitFormFromButtonHandler(req);
|
|
if (req->target) {
|
|
SSM_FreeResource(req->target);
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSM_SubmitFormFromButtonHandler(HTTPRequest *req)
|
|
{
|
|
SSMResource * res = NULL;
|
|
char * value;
|
|
SSMStatus rv = SSM_FAILURE;
|
|
|
|
res = (req->target) ? req->target : (SSMResource *) req->ctrlconn;
|
|
|
|
rv = SSM_HTTPParamValue(req, "do_cancel", &value);
|
|
if (rv == SSM_SUCCESS) {
|
|
/* user hit "Cancel", exit */
|
|
res->m_buttonType = SSM_BUTTON_CANCEL;
|
|
goto finished;
|
|
}
|
|
res->m_buttonType = SSM_BUTTON_OK;
|
|
/* set up the stage to process the main form */
|
|
rv = SSM_HTTPParamValue(req, "formName", &value);
|
|
if (rv != SSM_SUCCESS) {
|
|
SSM_DEBUG("Error in SubmitFormHandler: no form name given!\n");
|
|
goto finished;
|
|
}
|
|
if (res->m_formName) /* hmm... will it crash here? */
|
|
PR_Free(res->m_formName);
|
|
res->m_formName = PL_strdup(value);
|
|
|
|
rv = SSM_HTTPCloseAndSleep(req);
|
|
if (rv != PR_SUCCESS)
|
|
SSM_DEBUG("SubmitForm: Problem closing dialog box!\n");
|
|
|
|
return rv;
|
|
finished:
|
|
/* no more event handlers called on this event, notify ctrlconn */
|
|
SSM_HTTPCloseWindow(req);
|
|
/* if this is a UIEvent, notify owner connection */
|
|
if (res->m_UILock)
|
|
SSM_NotifyUIEvent(res);
|
|
return rv;
|
|
}
|
|
|
|
|
|
static void SSM_ImportCACert(void * arg)
|
|
{
|
|
CERTCertTrust trust;
|
|
char * nickname = NULL;
|
|
caImportCertArg * certArg = (caImportCertArg *)arg;
|
|
CERTCertificate * cert = certArg->cert;
|
|
SSMControlConnection * ctrl = certArg->ctrl;
|
|
CERTDERCerts * derCerts = certArg->derCerts;
|
|
SSMResource * certObj = NULL;
|
|
SSMResourceID certRID;
|
|
SSMStatus rv;
|
|
char * params;
|
|
char * htmlNickname;
|
|
|
|
/* UI asks - do you want to import this cert for
|
|
* 1) email
|
|
* 2) web sites
|
|
* 3) objects
|
|
* UI sets accept, acceptssl, acceptmime, acceptobjectsign
|
|
*/
|
|
acceptssl = acceptmime = acceptobjectsign = acceptcacert = PR_FALSE;
|
|
|
|
|
|
/* create resource for that cert */
|
|
rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert,
|
|
ctrl, &certRID, &certObj);
|
|
if (rv != SSM_SUCCESS) {
|
|
SSM_DEBUG("SSM_ImportCACert: can't create certificate resource!\n");
|
|
goto done;
|
|
}
|
|
|
|
/* pick a nickname for the cert */
|
|
nickname = CERT_GetCommonName(&cert->subject);
|
|
if (nickname == NULL) {
|
|
char *ou = NULL;
|
|
char *orgName = NULL;
|
|
/* Let's find something we can use as a nickname.*/
|
|
ou = CERT_GetOrgUnitName(&cert->subject);
|
|
orgName = CERT_GetOrgName(&cert->subject);
|
|
PR_ASSERT(orgName || ou);
|
|
nickname = PR_smprintf("%s%s%s", (orgName) ? orgName : "",
|
|
(orgName && ou) ? " - " : "",
|
|
(ou) ? ou : "");
|
|
PR_FREEIF(ou);
|
|
PR_FREEIF(orgName);
|
|
}
|
|
htmlNickname = SSM_ConvertStringToHTMLString(nickname);
|
|
PR_ASSERT(htmlNickname);
|
|
params = PR_smprintf("certresource=%d&nickname=%s", certRID, htmlNickname);
|
|
PR_Free(htmlNickname);
|
|
SSM_LockUIEvent(certObj);
|
|
rv = SSMControlConnection_SendUIEvent(ctrl, "get", "import_ca_cert1",
|
|
certObj, params,
|
|
&certObj->m_clientContext);
|
|
if (rv != PR_SUCCESS) {
|
|
SSM_DEBUG("Cannot fire up first import CA cert dialog!\n");
|
|
goto done;
|
|
}
|
|
SSM_WaitUIEvent(certObj, PR_INTERVAL_NO_TIMEOUT);
|
|
|
|
if (!acceptcacert)
|
|
goto done;
|
|
|
|
PORT_Memset((void *)&trust, 0, sizeof(trust));
|
|
if (acceptssl)
|
|
trust.sslFlags = CERTDB_VALID_CA | CERTDB_TRUSTED_CA;
|
|
else trust.sslFlags = CERTDB_VALID_CA;
|
|
if (acceptmime)
|
|
trust.emailFlags = CERTDB_VALID_CA | CERTDB_TRUSTED_CA;
|
|
else trust.emailFlags = CERTDB_VALID_CA;
|
|
if (acceptobjectsign)
|
|
trust.objectSigningFlags = CERTDB_VALID_CA | CERTDB_TRUSTED_CA;
|
|
else
|
|
trust.objectSigningFlags = CERTDB_VALID_CA;
|
|
|
|
rv = CERT_AddTempCertToPerm(cert, nickname, &trust);
|
|
if (rv != PR_SUCCESS) {
|
|
/* tell user we're having problems */;
|
|
goto done;
|
|
}
|
|
if (derCerts->numcerts > 1) {
|
|
rv = CERT_ImportCAChain(derCerts->rawCerts + 1, derCerts->numcerts - 1,
|
|
certUsageSSLCA);
|
|
if (rv != PR_SUCCESS)
|
|
/* tell user we're having problems */
|
|
SSM_DEBUG("Cannot import CA chain\n");
|
|
}
|
|
done:
|
|
if (certObj)
|
|
SSM_FreeResource(certObj);
|
|
if (nickname)
|
|
PR_Free(nickname);
|
|
CERT_DestroyCertificate(cert);
|
|
PR_Free(arg);
|
|
return;
|
|
}
|
|
|
|
SSMStatus SSM_CAPolicyKeywordHandler(SSMTextGenContext * cx)
|
|
{
|
|
SSMStatus rv = SSM_FAILURE;
|
|
char * policyString = NULL, * certresStr = NULL;
|
|
CERTCertificate * caCert;
|
|
SSMResource * resource;
|
|
SSMResourceID certRID;
|
|
SSMControlConnection * ctrl;
|
|
|
|
PR_ASSERT(cx != NULL);
|
|
PR_ASSERT(cx->m_request != NULL);
|
|
PR_ASSERT(cx->m_params != NULL);
|
|
PR_ASSERT(cx->m_result != NULL);
|
|
if (cx == NULL || cx->m_request == NULL || cx->m_params == NULL ||
|
|
cx->m_result == NULL) {
|
|
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
|
goto loser;
|
|
}
|
|
|
|
/* find the certificate we're talking about */
|
|
rv = SSM_HTTPParamValue(cx->m_request, "action", &certresStr);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
certRID = atoi(certresStr);
|
|
resource = SSMTextGen_GetTargetObject(cx);
|
|
if (!resource) {
|
|
SSM_DEBUG("SSM_CAPolicyKeywordHandler: can't get target object!\n");
|
|
goto loser;
|
|
}
|
|
if (SSM_IsAKindOf(resource, SSM_RESTYPE_CONTROL_CONNECTION)) {
|
|
ctrl = (SSMControlConnection *)resource;
|
|
rv = SSMControlConnection_GetResource(ctrl, certRID, &resource);
|
|
if (rv != SSM_SUCCESS) {
|
|
SSM_DEBUG("SSM_CAPolicyKeywordHandler: can't find cert resource %d\n",
|
|
certRID);
|
|
goto loser;
|
|
}
|
|
} else
|
|
PR_ASSERT(SSM_IsAKindOf(resource, SSM_RESTYPE_CERTIFICATE));
|
|
|
|
caCert = ((SSMResourceCert *)resource)->cert;
|
|
|
|
/* For some reason, this function is going to return policy */
|
|
policyString = CERT_GetCertCommentString(caCert);
|
|
if (!policyString) {
|
|
rv = SSM_GetUTF8Text(cx, "no_ca_policy", &policyString);
|
|
if (rv != SSM_SUCCESS) {
|
|
SSM_DEBUG("Could not find text %s in policy files.\n", "no_ca_policy");
|
|
goto loser;
|
|
}
|
|
SSM_DEBUG("No policy is available for new CA cert: %s!\n", policyString);
|
|
}
|
|
PR_FREEIF(cx->m_result);
|
|
cx->m_result = policyString;
|
|
policyString = NULL;
|
|
rv = SSM_SUCCESS;
|
|
goto done;
|
|
|
|
loser:
|
|
SSMTextGen_UTF8StringClear(&cx->m_result);
|
|
rv = SSM_FAILURE;
|
|
SSM_DEBUG("Failed formatting CA policy from signers cert\n");
|
|
done:
|
|
if (policyString)
|
|
PR_Free(policyString);
|
|
|
|
return rv;
|
|
}
|
|
|
|
SSMStatus SSM_CACertKeywordHandler(SSMTextGenContext* cx)
|
|
{
|
|
SSMStatus rv = SSM_FAILURE;
|
|
char* pattern = NULL;
|
|
char* key = NULL;
|
|
char * style = NULL;
|
|
const PRIntn CERT_FORMAT = (PRIntn)0;
|
|
const PRIntn CERT_WRAPPER = (PRIntn)1;
|
|
const PRIntn CERT_WRAPPER_NO_COMMENT = (PRIntn)2;
|
|
PRIntn wrapper;
|
|
CERTCertificate * caCert = NULL;
|
|
char * certresStr = NULL;
|
|
SSMControlConnection * ctrl;
|
|
SSMResource * resource;
|
|
SSMResourceID certRID;
|
|
|
|
|
|
PR_ASSERT(cx != NULL);
|
|
PR_ASSERT(cx->m_request != NULL);
|
|
PR_ASSERT(cx->m_params != NULL);
|
|
PR_ASSERT(cx->m_result != NULL);
|
|
if (cx == NULL || cx->m_request == NULL || cx->m_params == NULL ||
|
|
cx->m_result == NULL) {
|
|
PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
|
|
goto loser;
|
|
}
|
|
|
|
/* find the certificate we're talking about */
|
|
rv = SSM_HTTPParamValue(cx->m_request, "action", &certresStr);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
certRID = atoi(certresStr);
|
|
resource = SSMTextGen_GetTargetObject(cx);
|
|
if (!resource) {
|
|
SSM_DEBUG("SSM_CAPolicyKeywordHandler: can't get target object!\n");
|
|
goto loser;
|
|
}
|
|
if (SSM_IsAKindOf(resource, SSM_RESTYPE_CONTROL_CONNECTION)) {
|
|
ctrl = (SSMControlConnection *)resource;
|
|
rv = SSMControlConnection_GetResource(ctrl, certRID, &resource);
|
|
if (rv != SSM_SUCCESS) {
|
|
SSM_DEBUG("SSM_CACertKeywordHandler: can't find cert resource %d\n",
|
|
certRID);
|
|
goto loser;
|
|
}
|
|
} else
|
|
PR_ASSERT(SSM_IsAKindOf(resource, SSM_RESTYPE_CERTIFICATE));
|
|
|
|
caCert = ((SSMResourceCert *)resource)->cert;
|
|
|
|
/* form the MessageFormat object */
|
|
/* get the correct wrapper */
|
|
if (CERT_GetCertCommentString(caCert))
|
|
wrapper = CERT_WRAPPER;
|
|
else wrapper = CERT_WRAPPER_NO_COMMENT;
|
|
key = (char *) SSM_At(cx->m_params, wrapper);
|
|
|
|
/* second, grab and expand the keyword objects */
|
|
rv = SSM_GetAndExpandTextKeyedByString(cx, key, &pattern);
|
|
if (rv != SSM_SUCCESS) {
|
|
goto loser;
|
|
}
|
|
SSM_DebugUTF8String("ca cert info pattern <%s>", pattern);
|
|
|
|
style = (char *) SSM_At(cx->m_params, CERT_FORMAT);
|
|
PR_FREEIF(cx->m_result);
|
|
if (!strcmp(style, "pretty"))
|
|
rv = SSM_PrettyFormatCert(caCert, pattern, &cx->m_result);
|
|
else if (!strcmp(style, "simple"))
|
|
rv = SSM_FormatCert(caCert, pattern, &cx->m_result);
|
|
else {
|
|
SSM_DEBUG("SSM_CACertKeywordHandler: bad formatting parameter!\n");
|
|
rv = SSM_ERR_INVALID_FUNC;
|
|
}
|
|
goto done;
|
|
|
|
loser:
|
|
if (rv == SSM_SUCCESS)
|
|
rv = SSM_FAILURE;
|
|
done:
|
|
if (pattern != NULL) {
|
|
PR_Free(pattern);
|
|
}
|
|
return rv;
|
|
}
|