autorenewal.c
来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 554 行
C
554 行
/* * 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 "ctrlconn.h"#include "cert.h"#include "secasn1.h"#include "secder.h"#include "xconst.h"#include "secerr.h"#include "newproto.h"#include "messages.h"#include "certres.h"#include "pk11func.h"#include "secoid.h"typedef struct CERTRenewalWindow { SECItem begin; SECItem end;} CERTRenewalWindow;const static SEC_ASN1Template CERT_RenewalWindowTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTRenewalWindow) }, { SEC_ASN1_GENERALIZED_TIME, offsetof(CERTRenewalWindow,begin) }, { SEC_ASN1_OPTIONAL | SEC_ASN1_GENERALIZED_TIME, offsetof(CERTRenewalWindow,end) }, { 0 }};PRBool CERT_HasRenewalExtension(CERTCertificate *cert){ int rv; SECItem *derWindow = NULL; PRBool ret = PR_FALSE; /* Allocate from the heap, so that we can free eveything later */ derWindow = SECITEM_AllocItem(NULL, NULL, 0); if (derWindow == NULL) { goto loser; } /* Get the renewal window extension */ rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME, derWindow); if (rv == SECSuccess) { ret = PR_TRUE; }loser: if (derWindow) { SECITEM_FreeItem(derWindow, PR_TRUE); } return ret;}PRBool CERT_InRenewalWindow(CERTCertificate *cert, int64 t){ int rv; int64 begin, end; CERTRenewalWindow *window = NULL; SECItem *derWindow = NULL; PRArenaPool *arena = NULL; PRBool ret = PR_FALSE; /* Allocate from the heap, so that we can free eveything later */ derWindow = SECITEM_AllocItem(NULL, NULL, 0); if (derWindow == NULL) { goto loser; } /* Get the renewal window extension */ rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME, derWindow); if (rv == SECFailure) { goto loser; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) goto loser; window = (CERTRenewalWindow*)PORT_ArenaZAlloc(arena, sizeof(CERTRenewalWindow)); if (window == NULL) { goto loser; } /* Decode the extension */ rv = SEC_ASN1DecodeItem(arena, window, CERT_RenewalWindowTemplate, derWindow); if (rv) { goto loser; } /* Decode the times */ rv = DER_GeneralizedTimeToTime(&begin, &window->begin); if (window->end.data) { rv = DER_GeneralizedTimeToTime(&end, &window->end); } else { rv = DER_UTCTimeToTime(&end, &cert->validity.notAfter); } /* Is this cert in the renewal window */ if (LL_CMP(t,>,begin) && LL_CMP(t,<,end)) { ret = PR_TRUE; } else { ret = PR_FALSE; }loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (derWindow) { SECITEM_FreeItem(derWindow, PR_TRUE); } return ret;}PRBool CERT_RenewalWindowExpired(CERTCertificate *cert, int64 t){ int rv; int64 begin, end; CERTRenewalWindow *window = NULL; SECItem *derWindow = NULL; PRArenaPool *arena = NULL; PRBool ret = PR_FALSE; /* Allocate from the heap, so that we can free eveything later */ derWindow = SECITEM_AllocItem(NULL, NULL, 0); if (derWindow == NULL) { goto loser; } /* Get the renewal window extension */ rv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME, derWindow); if (rv == SECFailure) { goto loser; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) goto loser; window = (CERTRenewalWindow*)PORT_ArenaZAlloc(arena, sizeof(CERTRenewalWindow)); if (window == NULL) { goto loser; } /* Decode the extension */ rv = SEC_ASN1DecodeItem(arena, window, CERT_RenewalWindowTemplate, derWindow); if (rv) { goto loser; } /* Decode the times */ rv = DER_GeneralizedTimeToTime(&begin, &window->begin); if (window->end.data) { rv = DER_GeneralizedTimeToTime(&end, &window->end); } else { rv = DER_UTCTimeToTime(&end, &cert->validity.notAfter); } /* Has the renewal window expired */ if (LL_CMP(t,>,end)) { ret = PR_TRUE; } else { ret = PR_FALSE; }loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } if (derWindow) { SECITEM_FreeItem(derWindow, PR_TRUE); } return ret;}char * CERT_GetAuthorityInfoAccessLocation(CERTCertificate *cert, int method){ CERTGeneralName *locname = NULL; SECItem *location = NULL; SECItem *encodedAuthInfoAccess = NULL; CERTAuthInfoAccess **authInfoAccess = NULL; char *locURI = NULL; PRArenaPool *arena = NULL; SECStatus rv; int i; /* * Allocate this one from the heap because it will get filled in * by CERT_FindCertExtension which will also allocate from the heap, * and we can free the entire thing on our way out. */ encodedAuthInfoAccess = SECITEM_AllocItem(NULL, NULL, 0); if (encodedAuthInfoAccess == NULL) goto loser; rv = CERT_FindCertExtension(cert, SEC_OID_X509_AUTH_INFO_ACCESS, encodedAuthInfoAccess); if (rv == SECFailure) goto loser; /* * The rest of the things allocated in the routine will come out of * this arena, which is temporary just for us to decode and get at the * AIA extension. The whole thing will be destroyed on our way out, * after we have copied the location string (url) itself (if found). */ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) goto loser; authInfoAccess = cert_DecodeAuthInfoAccessExtension(arena, encodedAuthInfoAccess); if (authInfoAccess == NULL) goto loser; for (i = 0; authInfoAccess[i] != NULL; i++) { if (SECOID_FindOIDTag(&authInfoAccess[i]->method) == method) locname = authInfoAccess[i]->location; } /* * If we found an AIA extension, but it did not include an OCSP method, * that should look to our caller as if we did not find the extension * at all, because it is only an OCSP method that we care about. * So set the same error that would be set if the AIA extension was * not there at all. */ if (locname == NULL) { PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND); goto loser; } /* * The following is just a pointer back into locname (i.e. not a copy); * thus it should not be freed. */ location = CERT_GetGeneralNameByType(locname, certURI, PR_FALSE); if (location == NULL) { /* * XXX Appears that CERT_GetGeneralNameByType does not set an * error if there is no name by that type. For lack of anything * better, act as if the extension was not found. In the future * this should probably be something more like the extension was * badly formed. */ PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND); goto loser; } /* * That location is really a string, but it has a specified length * without a null-terminator. We need a real string that does have * a null-terminator, and we need a copy of it anyway to return to * our caller -- so allocate and copy. */ locURI = PORT_Alloc(location->len + 1); if (locURI == NULL) { goto loser; } PORT_Memcpy(locURI, location->data, location->len); locURI[location->len] = '\0';loser: if (arena != NULL) PORT_FreeArena(arena, PR_FALSE); if (encodedAuthInfoAccess != NULL) SECITEM_FreeItem(encodedAuthInfoAccess, PR_TRUE); return locURI;}SSMStatus SendRenewalUIEvent(SSMControlConnection *conn, char *url){ SECItem event; SSMStatus rv = PR_SUCCESS; SSMResourceID rid = 0; UIEvent reply; if (!conn->m_doesUI) { return SSM_FAILURE; } /* Generate the actual message to send to the client. */ reply.resourceID = rid; reply.width = 715; reply.height = 545; reply.isModal = 3; reply.url = url; reply.clientContext.len = 0; reply.clientContext.data = NULL; if (CMT_EncodeMessage(UIEventTemplate, (CMTItem*)&event, &reply) != CMTSuccess) { goto loser; } /* Post the message on the outgoing control channel. */ rv = SSM_SendQMessage(conn->m_controlOutQ, SSM_PRIORITY_NORMAL, SSM_EVENT_MESSAGE | SSM_UI_EVENT, (int) event.len, (char *) event.data, PR_FALSE); if (rv != PR_SUCCESS) goto loser; goto done; loser: if (rv == PR_SUCCESS) rv = PR_FAILURE; done: PR_FREEIF(event.data); return rv;}SECStatus CheckCertificate(CERTCertificate * cert, void * arg){ char *url = NULL; SSMControlConnection *ctrl = (SSMControlConnection *)arg; SSMStatus rv; SSMResourceID certID; SSMResourceCert * certRes = NULL; CERTCertificate *otherCert = NULL; CERTCertList *certs = NULL; CERTCertListNode *node; /* Is this cert in the renewal window */ if (CERT_InRenewalWindow(cert, PR_Now()) == PR_FALSE) { goto done; } /* Get the AIA */ url = CERT_GetAuthorityInfoAccessLocation(cert, SEC_OID_CERT_RENEWAL_LOCATOR); if (!url) { goto done; } /* Should we renew this cert? Check the case where it has already been renewed */ /* but the old cert is still there waith a valid renewal window */ certs = PK11_FindCertsFromNickname(cert->nickname, ctrl); if (!cert) { goto done; } /* Interate through the certs */ node = CERT_LIST_HEAD(certs); while (!CERT_LIST_END(node, certs)) { otherCert = node->cert; /* This is the cert we are renewing */ if (otherCert == cert) { goto endloop; } /* This cert has expired */ if (CERT_CheckCertValidTimes(otherCert, PR_Now(), PR_FALSE) != secCertTimeValid) { goto endloop; } /* This cert has different key usage */ if (cert->keyUsage != otherCert->keyUsage) { goto endloop; } /* This cert renewal window has not expired - don't renew our cert */ if (CERT_HasRenewalExtension(otherCert) && !CERT_RenewalWindowExpired(otherCert, PR_Now())) { goto done; }endloop: node = CERT_LIST_NEXT(node); } /* Create a resource for this cert and get an id */ rv = SSM_CreateResource(SSM_RESTYPE_CERTIFICATE, cert, ctrl, &certID, (SSMResource**)&certRes); if (rv != PR_SUCCESS) { goto done; } SSM_LockUIEvent((SSMResource*)certRes); /* Send a UI event to client */ rv = SSMControlConnection_SendUIEvent(ctrl, "get", "cert_renewal", &(certRes->super), NULL, &(&(ctrl->super.super))->m_clientContext, PR_TRUE); if (rv != SSM_SUCCESS) { goto loser; } SSM_WaitUIEvent((SSMResource*)certRes, PR_INTERVAL_NO_TIMEOUT); if ((certRes->super.m_buttonType == SSM_BUTTON_OK) && (certRes->m_renewCert == PR_TRUE)) { /* Send a UI event asking about renewal */ /* Send UI prompting the user */ /* SendRenewalUIEvent(ctrl, url); */ }loser:done: if (certs) { CERT_DestroyCertList(certs); } if (certRes) { SSM_FreeResource(certRes); } PR_FREEIF(url); return SECSuccess;}void SSM_CertificateRenewalThread(void * arg){ int series, slotSeries[255], i = 0; PK11SlotList * slots = NULL; PK11SlotListElement * le = NULL; SSMControlConnection *ctrl = (SSMControlConnection *)arg; /* Initialize slot series array to zero */ memset(slotSeries, 0, sizeof(slotSeries)); /* Get a list of tokens installed */ slots = PK11_GetAllTokens(CKM_INVALID_MECHANISM, PR_FALSE, PR_FALSE, ctrl); if (!slots) { return; } while (1) { /* Interate over the list of slots */ for (le = slots->head, i= 0; le; le = le->next, i++) { /* If there is no token present then we are no interested */ if (!PK11_IsPresent(le->slot)) { continue; } /* If token not logged in, then we are not interested */ if (!PK11_IsLoggedIn(le->slot, ctrl)) { continue; } /* If token is read-only, then we are not interested */ if (PK11_IsReadOnly(le->slot)) { continue; } /* Get the series and mark as checked */ series = PK11_GetSlotSeries(le->slot); if (slotSeries[i] == series) { continue; } slotSeries[i] = series; /* Interate all the certs on the token */ PK11_TraverseCertsInSlot(le->slot, CheckCertificate, ctrl); } /* Sleep for one minute */ PR_Sleep(PR_TicksPerSecond()*60); } if (slots) { PK11_FreeSlotList(slots); }}SSMStatus SSM_RenewalCertInfoHandler(SSMTextGenContext* cx){ SSMStatus rv; SSMResource* target = NULL; SSMResourceCert* renewalCertRes = NULL; CERTCertificate* renewalCert = NULL; char *url = NULL; char *fmt = NULL, *issuerCN = NULL; char *validNotBefore = NULL, *validNotAfter = NULL; PR_ASSERT(cx != NULL); PR_ASSERT(cx->m_request != NULL); PR_ASSERT(cx->m_params != NULL); PR_ASSERT(cx->m_result != NULL); /* retrieve the renewal cert */ target = SSMTextGen_GetTargetObject(cx); renewalCertRes = (SSMResourceCert*)target; renewalCert = renewalCertRes->cert; if (renewalCert == NULL) { goto loser; } /* Get the info */ /* This is: Name, issuer, valid from and valid to */ issuerCN = CERT_GetCommonName(&renewalCert->issuer), validNotBefore = DER_UTCDayToAscii(&renewalCert->validity.notBefore); validNotAfter = DER_UTCDayToAscii(&renewalCert->validity.notAfter); url = CERT_GetAuthorityInfoAccessLocation(renewalCert, SEC_OID_CERT_RENEWAL_LOCATOR); rv = SSM_GetAndExpandTextKeyedByString(cx, "cert_renewal_cert_info", &fmt); if (rv != SSM_SUCCESS) { goto loser; } cx->m_result = PR_smprintf(fmt, renewalCert->nickname, validNotBefore, validNotAfter, issuerCN, url); PR_FREEIF(fmt); PR_FREEIF(issuerCN); PR_FREEIF(validNotBefore); PR_FREEIF(validNotAfter); PR_FREEIF(url); return SSM_SUCCESS;loser: PR_FREEIF(fmt); PR_FREEIF(issuerCN); PR_FREEIF(validNotBefore); PR_FREEIF(validNotAfter); return SSM_FAILURE;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?