Crypt-NSS-X509

 view release on metacpan or  search on metacpan

X509.xs  view on Meta::CPAN


  //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);

X509.xs  view on Meta::CPAN

    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));

X509.xs  view on Meta::CPAN

  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 )