Crypt-NSS-X509
view release on metacpan or search on metacpan
//PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
signedCrl = CERT_DecodeDERCrlWithFlags(NULL, &item, SEC_CRL_TYPE, CRL_DECODE_DEFAULT_OPTIONS);
if ( !signedCrl ) {
PRErrorCode err = PR_GetError();
croak( "Could not decode CRL %d = %s\n",
err, PORT_ErrorToString(err));
}
RETVAL = signedCrl;
OUTPUT:
RETVAL
SV*
issuer(crl)
Crypt::NSS::X509::CRL crl
PREINIT:
char* c;
CODE:
c = CERT_DerNameToAscii(&crl->crl.derName);
RETVAL = newSVpvf("%s", c);
PORT_Free(c);
OUTPUT:
RETVAL
SV*
version(crl)
Crypt::NSS::X509::CRL crl
PREINIT:
int version;
CODE:
version = crl->crl.version.len ? DER_GetInteger(&crl->crl.version) : 0;
version++;
RETVAL = newSViv(version);
OUTPUT:
RETVAL
void
verify(crl, cert, timedouble = NO_INIT)
Crypt::NSS::X509::CRL crl
Crypt::NSS::X509::Certificate cert
SV* timedouble
PREINIT:
SECStatus rv;
PRTime time = 0;
PPCODE:
if ( items < 3 || SvIV(timedouble) == 0 ) {
time = PR_Now();
} else {
double tmptime = SvNV(timedouble);
// time contains seconds since epoch - netscape expects microseconds
tmptime = tmptime * 1000000;
LL_D2L(time, tmptime); // and convert to 64-bit int
}
rv = CERT_VerifySignedData(&crl->signatureWrap, cert, time, NULL);
if ( rv != SECSuccess ) {
XSRETURN_NO;
}
XSRETURN_YES;
Crypt::NSS::X509::Certificate
find_issuer(crl, timedouble = NO_INIT)
Crypt::NSS::X509::CRL crl
SV* timedouble
ALIAS:
verify_db = 1
PREINIT:
PRTime time = 0;
CERTCertDBHandle *defaultDB;
SECItem* subject = NULL;
CERTCertificate* cert;
SECStatus rv;
CODE:
if ( items < 2 || SvIV(timedouble) == 0 ) {
time = PR_Now();
} else {
double tmptime = SvNV(timedouble);
// time contains seconds since epoch - netscape expects microseconds
tmptime = tmptime * 1000000;
LL_D2L(time, tmptime); // and convert to 64-bit int
}
defaultDB = CERT_GetDefaultCertDB();
subject = &crl->crl.derName;
cert = FindCrlIssuer(defaultDB, subject, time);
if ( !cert ) {
XSRETURN_UNDEF;
}
if ( ix == 1 ) {
rv = CERT_VerifySignedData(&crl->signatureWrap, cert, time, NULL);
CERT_DestroyCertificate(cert);
if ( rv != SECSuccess ) {
XSRETURN_NO;
}
XSRETURN_YES;
}
RETVAL = cert;
OUTPUT:
RETVAL
void
DESTROY(crl)
Crypt::NSS::X509::CRL crl
PPCODE:
if ( crl ) {
SEC_DestroyCrl(crl);
crl = 0;
}
void
entries(crl)
Crypt::NSS::X509::CRL crl
PREINIT:
CERTCrlEntry *entry;
int iv;
PPCODE:
if ( crl->crl.entries != NULL ) {
iv = 0;
while( (entry = crl->crl.entries[iv++]) != NULL) {
HV* h = newHV();
hv_store(h, "serial", 6, item_to_hhex(&entry->serialNumber), 0) ? : croak("Could not store data in hv");
{
// TODO: factor out to time_to_sv
int64 time;
SECStatus rv;
char *timeString;
PRExplodedTime printableTime;
SV* timeSV;
rv = DER_UTCTimeToTime(&time, &(entry->revocationDate));
if (rv != SECSuccess)
croak("Could not parse CRL element revocation time");
PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
timeString = PORT_Alloc(256);
if ( ! PR_FormatTimeUSEnglish(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime) ) {
croak("Could not format time string");
}
timeSV = newSVpvf("%s", timeString);
hv_store(h, "revocationDate", 14, timeSV, 0) ? : croak("Could not store data in hv");
}
{
CERTCertExtension **extensions = entry->extensions;
if ( extensions ) {
while ( *extensions ) {
hv_store_ent(h, oid_to_sv(&(*extensions)->id), extension_to_sv(*extensions), 0) ? : croak("Could not store data in hv");
extensions++;
}
}
}
mXPUSHs(newRV ((SV*)h) );
}
}
MODULE = Crypt::NSS::X509 PACKAGE = Crypt::NSS::X509::CertList
Crypt::NSS::X509::CertList
new(class)
PREINIT:
CERTCertList *certList;
CODE:
certList = CERT_NewCertList();
RETVAL = certList;
OUTPUT:
RETVAL
void
add(certlist, cert)
Crypt::NSS::X509::CertList certlist;
Crypt::NSS::X509::Certificate cert;
CODE:
CERTCertificate* addcert = CERT_DupCertificate(cert);
CERT_AddCertToListTail(certlist, addcert);
void
dump(certlist)
Crypt::NSS::X509::CertList certlist;
PREINIT:
CERTCertListNode *node;
PPCODE:
node = CERT_LIST_HEAD(certlist);
while ( !CERT_LIST_END(node, certlist) ) {
if ( node->cert ) {
CERTCertificate* currcert = CERT_DupCertificate(node->cert);
SV* cert = newSV(0);
sv_setref_pv(cert, "Crypt::NSS::X509::Certificate", currcert); // the beauty of this is that it should be cleaned by perl refcounting now
mXPUSHs(cert);
} else {
croak("Bad certificate list, encountered node without cert.");
}
node = CERT_LIST_NEXT(node);
}
void
DESTROY(certlist)
Crypt::NSS::X509::CertList certlist;
PPCODE:
if ( certlist ) {
CERT_DestroyCertList(certlist);
certlist = 0;
}
MODULE = Crypt::NSS::X509 PACKAGE = Crypt::NSS::X509::Certificate
SV*
curve(cert)
Crypt::NSS::X509::Certificate cert
PREINIT:
SECKEYPublicKey *key;
SECOidTag tag;
CODE:
// This function extracts the curve from a NSS Certificate
// As you will see, this is one of the moist straightforward
// things to do. Totally easy. Everyone can do that. And find
// out. Only took like 10 minutes.
// Srsly.
SECItem oid = { siBuffer, NULL, 0};
// this is the complicated part
key = SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo);
if ( key->keyType != ecKey ) {
SECKEY_DestroyPublicKey(key);
croak("Only ec-keys have a curve");
}
// ok, now it gets simple.
oid.len = key->u.ec.DEREncodedParams.len - 2;
oid.data = key->u.ec.DEREncodedParams.data + 2;
if ((key->u.ec.DEREncodedParams.data[0] != SEC_ASN1_OBJECT_ID) ||
((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) {
SECKEY_DestroyPublicKey(key);
croak("Unknown EC-key");
}
RETVAL = oid_to_sv(&oid);
SECKEY_DestroyPublicKey(key);
OUTPUT:
RETVAL
SV*
raw_spki(cert)
Crypt::NSS::X509::Certificate cert
PREINIT:
SV* out;
CODE:
out = item_to_sv(&cert->derPublicKey);
RETVAL = safe_item_to_sv(CERT_GetNameElement(NULL, &cert->subject, SEC_OID_AVA_POSTAL_CODE));
} else if ( ix == 12 ) {
RETVAL = oid_to_sv(&cert->signature.algorithm);
} else if ( ix == 13 ) {
RETVAL = oid_to_sv(&cert->subjectPublicKeyInfo.algorithm.algorithm);
} else if ( ix == 5 || ix == 6 ) {
int64 time;
SECStatus rv;
char *timeString;
PRExplodedTime printableTime;
if ( ix == 5 )
rv = DER_UTCTimeToTime(&time, &cert->validity.notBefore);
else if ( ix == 6 )
rv = DER_UTCTimeToTime(&time, &cert->validity.notAfter);
else
croak("not possible");
if (rv != SECSuccess)
croak("Could not parse time");
PR_ExplodeTime(time, PR_GMTParameters, &printableTime);
timeString = PORT_Alloc(256);
if ( ! PR_FormatTimeUSEnglish(timeString, 256, "%a %b %d %H:%M:%S %Y", &printableTime) ) {
croak("Could not format time string");
}
RETVAL = newSVpvf("%s", timeString);
PORT_Free(timeString);
} else if ( ix == 8 ) {
// if version is not specified it it 1 (0).
int version = cert->version.len ? DER_GetInteger(&cert->version) : 0;
RETVAL = newSViv(version+1);
} else {
croak("Unknown accessor %d", ix);
}
OUTPUT:
RETVAL
void
verify_certificate(cert, timedouble = NO_INIT, usage = certUsageSSLServer)
Crypt::NSS::X509::Certificate cert;
SV* timedouble;
I32 usage;
ALIAS:
verify_certificate_pkix = 1
verify_cert = 2
verify_certificate_log = 3
verify_certificate_pkix_log = 4
verify_cert_log = 5
PREINIT:
SECStatus secStatus;
PRTime time = 0;
CERTVerifyLog log;
CERTCertDBHandle *defaultDB;
PPCODE:
defaultDB = CERT_GetDefaultCertDB();
if ( items == 1 || SvIV(timedouble) == 0 ) {
time = PR_Now();
} else {
double tmptime = SvNV(timedouble);
// time contains seconds since epoch - netscape expects microseconds
tmptime = tmptime * 1000000;
LL_D2L(time, tmptime); // and convert to 64-bit int
}
if ( ix == 1 || ix == 4 )
CERT_SetUsePKIXForValidation(PR_TRUE);
else
CERT_SetUsePKIXForValidation(PR_FALSE);
log.arena = PORT_NewArena(512);
log.head = log.tail = NULL;
log.count = 0;
if ( ix == 2 ) {
secStatus = CERT_VerifyCert(defaultDB, cert,
PR_TRUE, // check sig
usage,
time,
NULL,
NULL);
} else if ( ix == 5) { // supplying log changes the return value
secStatus = CERT_VerifyCert(defaultDB, cert,
PR_TRUE, // check sig
usage,
time,
NULL,
&log);
} else {
secStatus = CERT_VerifyCertificate(defaultDB, cert,
PR_TRUE, // check sig
cert_usage_to_certificate_usage(usage),
time,
NULL,
&log, NULL);
}
if ( ix <= 2 ) { // no log
for (CERTVerifyLogNode *node = log.head; node; node = node->next) {
if (node->cert)
CERT_DestroyCertificate(node->cert);
}
PORT_FreeArena(log.arena, PR_FALSE);
if (secStatus != SECSuccess ) {
ST(0) = newSViv(PR_GetError());
} else {
ST(0) = newSViv(1); // return 1 on success
}
sv_2mortal(ST(0));
SECStatus rv;
SECItem item = {0, NULL, 0};
char* nick = NULL;
CODE:
// Note: nick functionality seems to not really work in NSS
if ( items == 3 ) {
nick = SvPV_nolen(nickSv);
}
defaultDB = CERT_GetDefaultCertDB();
rv = sv_to_item(string, &item);
if (rv != SECSuccess) {
croak("sv_to_item failed");
}
cert = CERT_NewTempCertificate(defaultDB, &item,
nick /* nickname */,
PR_FALSE /* isPerm */,
PR_TRUE /* copyDER */);
if (!cert) {
PRErrorCode err = PR_GetError();
croak( "couldn't import certificate %d = %s\n",
err, PORT_ErrorToString(err));
}
PORT_Free(item.data);
RETVAL = cert;
OUTPUT:
RETVAL
Crypt::NSS::X509::Certificate
new_from_nick(class, string)
SV* string
PREINIT:
CERTCertDBHandle *defaultDB;
char* nick = NULL;
CODE:
nick = SvPV_nolen(string);
defaultDB = CERT_GetDefaultCertDB();
RETVAL = CERT_FindCertByNickname(defaultDB, nick);
if ( RETVAL == NULL )
XSRETURN_UNDEF;
OUTPUT:
RETVAL
void DESTROY(cert)
Crypt::NSS::X509::Certificate cert;
PPCODE:
if ( cert ) {
if ( cert->nssCertificate ) {
//printf("Is nsscertificate\n");
//printf("Refcount: %d\n", cert->nssCertificate->object.refCount);
}
//printf("Certificate %s destroyed\n", cert->subjectName);
CERT_DestroyCertificate(cert);
cert = 0;
}
( run in 0.571 second using v1.01-cache-2.11-cpan-71847e10f99 )