I'm trying to verify the signature of a file I've signed but I don't
understand where to get the sigAlgorithm and hash to pass to
VFY_CreateContextWithAlgorithmID. I've googled looking for some sample
code using the VFY_ apis to verify signatures but I haven't found
anything that I could build off of. Shouldn't I be able to get these
from the public key and/or signature itself?


int spl_nssSignSHA256(const char *certNickname, const char *certpw,
const char *certdbpw, const char *certDir, const char *data, const
char *filename, unsigned char **signature, char **error)
{
       int result = 0;
       CERTCertificate   *cert = NULL;
       SECKEYPrivateKey  *pvtkey = NULL;
       unsigned char hash_buf[SHA256_LENGTH];
       SECItem hash, sign;
       PK11Context *hashcx = NULL;
       SECStatus rc;

       if ((data != NULL && filename != NULL) ||
           (data == NULL && filename == NULL)) {
               asprintf(error, "Error invalid arguments");
               result = -1;
               goto cleanup;
       }

       hash.len = sizeof(hash_buf); hash.data = hash_buf;

       if (certDir != NULL)
               rc = NSS_Init(certDir);
       else
               rc = NSS_Init(SPL_NSSCERTDIR);
       if (rc != SECSuccess) {
               asprintf(error, "Error initializing NSS (%d)",
                        PR_GetError());
               result = -1;
               goto cleanup;
       }

       PK11_SetPasswordFunc(spl_nssPasswdCB);

       cert = PK11_FindCertFromNickname(certNickname, (void
*)certdbpw);
       if (cert == NULL) {
               asprintf(error, "Couldn't find cert for %s in NSS db
(err %d)",
                        certNickname,
                        PR_GetError());
               result = -1;
               goto cleanup;
       }

       pvtkey = PK11_FindKeyByAnyCert(cert,  (void *)certpw);
       if (pvtkey == NULL) {
               asprintf(error, "Couldn't find private key for cert %s
(err %d)",
                        certNickname,
                        PR_GetError());
               result = -1;
               goto cleanup;
       }

       hashcx = PK11_CreateDigestContext(SEC_OID_SHA256);
       if (hashcx == NULL) {
               asprintf(error, "Error creating SHA526 digest (%d)",
                        PR_GetError());
               result = -1;
               goto cleanup;
       }

       if (filename != NULL) {
               int fd = 0;
               int bytesRead = 0;
               int buflen = 1024;
               char *buf = (char *)malloc(buflen);

               if ((fd = open(filename, O_RDONLY)) < 0) {
                       asprintf(error, "Error opening %s - %s",
                                filename,
                                strerror(errno));
                       result = -1;
                       goto cleanup;
               }

               while ((bytesRead = read(fd, buf, buflen)) > 0) {
                       PK11_DigestOp(hashcx, (const unsigned char
*)buf, bytesRead);
               }

               free(buf);
               close(fd);
               if (bytesRead < 0) {
                       asprintf(error, "Error reading %s - %s",
                                filename,
                                strerror(errno));
                       result = -1;
                       goto cleanup;
               }
       }
       else
               PK11_DigestOp(hashcx, (const unsigned char *)data,
strlen(data));

       PK11_DigestFinal(hashcx, hash.data, &hash.len, hash.len);
       if (hash.len != SHA256_LENGTH) {
               asprintf(error, "Digest length was not correct");
               result = -1;
               goto cleanup;
       }

       sign.len = PK11_SignatureLen(pvtkey);
       if (sign.len <= 0) {
               asprintf(error, "Invalid private key");
               result = -1;
               goto cleanup;

       }
       sign.data = (unsigned char *)malloc(sign.len);
       if (sign.data == NULL) {
               perror("Error allocating memory");
               result = -1;
               goto cleanup;
       }

       /* sign the hash */
       rc = PK11_Sign(pvtkey, &sign, &hash);
       if (rc != SECSuccess) {
               asprintf(error, "Error signing data %d",
                        PR_GetError());
               free(sign.data);
               result = -1;
               goto cleanup;
       }

       *signature = sign.data;
       result = 0;

 cleanup:
       if (cert)
               CERT_DestroyCertificate(cert);
       if (pvtkey)
               SECKEY_DestroyPrivateKey(pvtkey);
       if (hashcx)
               PK11_DestroyContext(hashcx, PR_TRUE);

       NSS_Shutdown();

       return result;
}

int spl_nssVerifySignature(const char *certNickname, const char
*certdbpw, const char *certDir, const char *data, const char
*filename, unsigned char *signature, char **error)
{
       int result = 0;
       CERTCertificate   *cert = NULL;
       CERTSubjectPublicKeyInfo *spki;
       SECKEYPublicKey  *pubkey = NULL;
       unsigned char hash_buf[SHA256_LENGTH];
       SECItem hash, sign;
       SECStatus rc;
       VFYContext vfy_context;

       if ((data != NULL && filename != NULL) ||
           (data == NULL && filename == NULL)) {
               asprintf(error, "Error invalid arguments");
               result = -1;
               goto cleanup;
       }

       hash.len = sizeof(hash_buf); hash.data = hash_buf;

       if (certDir != NULL)
               rc = NSS_Init(certDir);
       else
               rc = NSS_Init(SPL_NSSCERTDIR);
       if (rc != SECSuccess) {
               asprintf(error, "Error initializing NSS (%d)",
                        PR_GetError());
               result = -1;
               goto cleanup;
       }

       PK11_SetPasswordFunc(spl_nssPasswdCB);

       cert = PK11_FindCertFromNickname(certNickname, (void
*)certdbpw);
       if (cert == NULL) {
               asprintf(error, "Couldn't find cert for %s in NSS db
(err %d)",
                        certNickname,
                        PR_GetError());
               result = -1;
               goto cleanup;
       }

       spki = &cert->subjectPublicKeyInfo;
       pubkey = CERT_ExtractPublicKey(cert);
       if (pubkey == NULL) {
               asprintf(error, "Couldn't extract public key from cert
%s (err %d)",
                        certNickname,
                        PR_GetError());
               result = -1;
               goto cleanup;
       }
       /* SEC_OID_PKCS1_RSA_ENCRYPTION */

       PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
       if (!arena) {
               result = -1;
               goto cleanup;
       }

       SECAlgorithmID sig_alg_id;
       /*
       SECItem sig_alg_der;
       sig_alg_der.type = siBuffer;
       sig_alg_der.data = SEC_OID_PKCS1_RSA_ENCRYPTION; ????
       sig_alg_der.len = signature_algorithm_len;
       rc = SEC_QuickDERDecodeItem(arena, &sig_alg_id,
SECOID_AlgorithmIDTemplate,
                                   &sig_alg_der);
       if (rc != SECSuccess) {
               goto cleanup;
       }
       */

       SECItem sig;
       sig.type = siBuffer;
       sig.data = signature;
       sig.len = strlen(signature);
       SECOidTag hash_alg_tag;
       vfy_context = VFY_CreateContextWithAlgorithmID(pubkey, &sig,
                                                       &sig_alg_id,
&hash_alg_tag,
                                                 NULL);
       PORT_FreeArena(arena, PR_TRUE);  // Done with sig_alg_id.
       if (!vfy_context) {
               result = -1;
               goto cleanup;
       }

       rc = VFY_Begin(vfy_context);
       if (rc != SECSuccess) {
               result = -1;
               goto cleanup;
       }

       if (filename != NULL) {
               int fd = 0;
               int bytesRead = 0;
               int buflen = 1024;
               char *buf = (char *)malloc(buflen);

               if ((fd = open(filename, O_RDONLY)) < 0) {
                       asprintf(error, "Error opening %s - %s",
                                filename,
                                strerror(errno));
                       result = -1;
                       goto cleanup;
               }

               while ((bytesRead = read(fd, buf, buflen)) > 0) {
                       rc = VFY_Update(vfy_context, (const unsigned
char *)buf, bytesRead);
               }

               free(buf);
               close(fd);
               if (bytesRead < 0) {
                       asprintf(error, "Error reading %s - %s",
                                filename,
                                strerror(errno));
                       result = -1;
                       goto cleanup;
               }
       }
       else
               rc = VFY_Update(vfy_context, (const unsigned char
*)data, strlen);


       rc = VFY_End(vfy_context);
       if (rc != SECSuccess) {
               asprintf(error, "Signature verification failed");
               result = -1;
               goto cleanup;

       }
       result = 0;

 cleanup:
       if (cert)
               CERT_DestroyCertificate(cert);
       if (pubkey)
               SECKEY_DestroyPublicKey(pubkey);
       if (vfy_context != NULL)
               VFY_DestroyContext(vfy_context, PR_TRUE);
       if (arena)
               PORT_FreeArena(arena, PR_TRUE);

       NSS_Shutdown();

       return result;
}
-- 
dev-tech-crypto mailing list
dev-tech-crypto@lists.mozilla.org
https://lists.mozilla.org/listinfo/dev-tech-crypto

Reply via email to