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