/* * Verify the signature on an assertion. */ int kn_verify_assertion(char *buf, int len) { struct assertion *as; int res; keynote_errno = 0; as = keynote_parse_assertion(buf, len, ASSERT_FLAG_SIGVER); if (as == NULL) return -1; res = keynote_sigverify_assertion(as); keynote_free_assertion(as); return res; }
/* * Sign an assertion. */ static char * keynote_sign_assertion(struct assertion *as, char *sigalg, void *key, int keyalg, int verifyflag) { int slen, i, hashlen = 0, hashtype, alg, encoding, internalenc; unsigned char *sig = NULL, *finalbuf = NULL; unsigned char res2[LARGEST_HASH_SIZE], *sbuf = NULL; BIO *biokey = NULL; DSA *dsa = NULL; RSA *rsa = NULL; SHA_CTX shscontext; MD5_CTX md5context; int len; if (as->as_signature_string_s == NULL || as->as_startofsignature == NULL || as->as_allbutsignature == NULL || as->as_allbutsignature - as->as_startofsignature <= 0 || as->as_authorizer == NULL || key == NULL || as->as_signeralgorithm == KEYNOTE_ALGORITHM_NONE) { keynote_errno = ERROR_SYNTAX; return NULL; } alg = keynote_get_sig_algorithm(sigalg, &hashtype, &encoding, &internalenc); if (((alg != as->as_signeralgorithm) && !((alg == KEYNOTE_ALGORITHM_RSA) && (as->as_signeralgorithm == KEYNOTE_ALGORITHM_X509)) && !((alg == KEYNOTE_ALGORITHM_X509) && (as->as_signeralgorithm == KEYNOTE_ALGORITHM_RSA))) || ((alg != keyalg) && !((alg == KEYNOTE_ALGORITHM_RSA) && (keyalg == KEYNOTE_ALGORITHM_X509)) && !((alg == KEYNOTE_ALGORITHM_X509) && (keyalg == KEYNOTE_ALGORITHM_RSA)))) { keynote_errno = ERROR_SYNTAX; return NULL; } sig = strchr(sigalg, ':'); if (sig == NULL) { keynote_errno = ERROR_SYNTAX; return NULL; } sig++; switch (hashtype) { case KEYNOTE_HASH_SHA1: hashlen = 20; memset(res2, 0, hashlen); SHA1_Init(&shscontext); SHA1_Update(&shscontext, as->as_startofsignature, as->as_allbutsignature - as->as_startofsignature); SHA1_Update(&shscontext, sigalg, (char *) sig - sigalg); SHA1_Final(res2, &shscontext); break; case KEYNOTE_HASH_MD5: hashlen = 16; memset(res2, 0, hashlen); MD5_Init(&md5context); MD5_Update(&md5context, as->as_startofsignature, as->as_allbutsignature - as->as_startofsignature); MD5_Update(&md5context, sigalg, (char *) sig - sigalg); MD5_Final(res2, &md5context); break; case KEYNOTE_HASH_NONE: break; } if ((alg == KEYNOTE_ALGORITHM_DSA) && (hashtype == KEYNOTE_HASH_SHA1) && (internalenc == INTERNAL_ENC_ASN1) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { dsa = (DSA *) key; sbuf = calloc(DSA_size(dsa), sizeof(unsigned char)); if (sbuf == NULL) { keynote_errno = ERROR_MEMORY; return NULL; } if (DSA_sign(0, res2, hashlen, sbuf, &slen, dsa) <= 0) { free(sbuf); keynote_errno = ERROR_SYNTAX; return NULL; } } else if ((alg == KEYNOTE_ALGORITHM_RSA) && ((hashtype == KEYNOTE_HASH_SHA1) || (hashtype == KEYNOTE_HASH_MD5)) && (internalenc == INTERNAL_ENC_PKCS1) && ((encoding == ENCODING_HEX) || (encoding == ENCODING_BASE64))) { rsa = (RSA *) key; sbuf = calloc(RSA_size(rsa), sizeof(unsigned char)); if (sbuf == NULL) { keynote_errno = ERROR_MEMORY; return NULL; } if (RSA_sign_ASN1_OCTET_STRING(RSA_PKCS1_PADDING, res2, hashlen, sbuf, &slen, rsa) <= 0) { free(sbuf); keynote_errno = ERROR_SYNTAX; return NULL; } } else if ((alg == KEYNOTE_ALGORITHM_X509) && (hashtype == KEYNOTE_HASH_SHA1) && (internalenc == INTERNAL_ENC_ASN1)) { if ((biokey = BIO_new(BIO_s_mem())) == NULL) { keynote_errno = ERROR_SYNTAX; return NULL; } if (BIO_write(biokey, key, strlen(key) + 1) <= 0) { BIO_free(biokey); keynote_errno = ERROR_SYNTAX; return NULL; } /* RSA-specific */ rsa = (RSA *) PEM_read_bio_RSAPrivateKey(biokey, NULL, NULL, NULL); if (rsa == NULL) { BIO_free(biokey); keynote_errno = ERROR_SYNTAX; return NULL; } sbuf = calloc(RSA_size(rsa), sizeof(char)); if (sbuf == NULL) { BIO_free(biokey); RSA_free(rsa); keynote_errno = ERROR_MEMORY; return NULL; } if (RSA_sign(NID_shaWithRSAEncryption, res2, hashlen, sbuf, &slen, rsa) <= 0) { BIO_free(biokey); RSA_free(rsa); free(sbuf); keynote_errno = ERROR_SIGN_FAILURE; return NULL; } BIO_free(biokey); RSA_free(rsa); } else /* Other algorithms here */ { keynote_errno = ERROR_SYNTAX; return NULL; } /* ASCII encoding */ switch (encoding) { case ENCODING_HEX: i = kn_encode_hex(sbuf, (char **) &finalbuf, slen); free(sbuf); if (i != 0) return NULL; break; case ENCODING_BASE64: finalbuf = calloc(2 * slen, sizeof(unsigned char)); if (finalbuf == NULL) { keynote_errno = ERROR_MEMORY; free(sbuf); return NULL; } if ((slen = kn_encode_base64(sbuf, slen, finalbuf, 2 * slen)) == -1) { free(sbuf); return NULL; } break; default: free(sbuf); keynote_errno = ERROR_SYNTAX; return NULL; } /* Replace as->as_signature */ len = strlen(sigalg) + strlen(finalbuf) + 1; as->as_signature = calloc(len, sizeof(char)); if (as->as_signature == NULL) { free(finalbuf); keynote_errno = ERROR_MEMORY; return NULL; } /* Concatenate algorithm name and signature value */ snprintf(as->as_signature, len, "%s%s", sigalg, finalbuf); free(finalbuf); finalbuf = as->as_signature; /* Verify the newly-created signature if requested */ if (verifyflag) { /* Do the signature verification */ if (keynote_sigverify_assertion(as) != SIGRESULT_TRUE) { as->as_signature = NULL; free(finalbuf); if (keynote_errno == 0) keynote_errno = ERROR_SYNTAX; return NULL; } as->as_signature = NULL; } else as->as_signature = NULL; /* Everything ok */ return (char *) finalbuf; }
/* * Recurse on graph discovery. */ static int rec_evaluate_query(struct assertion *as) { struct assertion *ast; struct keylist *kl; int i, s; as->as_kresult = KRESULT_IN_PROGRESS; /* * If we get the minimum result or an error from evaluating this * assertion, we don't need to recurse. */ keynote_evaluate_assertion(as); if (keynote_errno != 0) { as->as_kresult = KRESULT_DONE; if (keynote_errno) as->as_error = keynote_errno; if (keynote_errno == ERROR_MEMORY) return -1; else { keynote_errno = 0; /* Ignore syntax errors for now */ return 0; } } if (as->as_result == 0) { as->as_kresult = KRESULT_DONE; return as->as_result; } for (kl = as->as_keylist; kl != (struct keylist *) NULL; kl = kl->key_next) { switch (keynote_in_action_authorizers(kl->key_key, kl->key_alg)) { case -1: as->as_kresult = KRESULT_DONE; if (keynote_errno == ERROR_MEMORY) { as->as_error = ERROR_MEMORY; return -1; } else { keynote_errno = 0; /* Reset */ continue; } case RESULT_FALSE: /* Not there, check for assertions instead */ break; case RESULT_TRUE: /* Ok, don't bother with assertions */ keynote_current_assertion = (struct assertion *) NULL; continue; } for (i = 0;; i++) { ast = keynote_find_assertion(kl->key_key, i, kl->key_alg); if (ast == (struct assertion *) NULL) break; if (ast->as_kresult == KRESULT_IN_PROGRESS) /* Cycle detected */ continue; if (ast->as_kresult == KRESULT_UNTOUCHED) /* Recurse if needed */ rec_evaluate_query(ast); /* Check for errors */ if (keynote_errno == ERROR_MEMORY) { as->as_error = ERROR_MEMORY; as->as_kresult = KRESULT_DONE; return -1; } else keynote_errno = 0; /* Reset */ } } keynote_current_assertion = as; s = keynote_parse_keypred(as, 0); keynote_current_assertion = (struct assertion *) NULL; if (keynote_errno == ERROR_MEMORY) { as->as_error = ERROR_MEMORY; as->as_kresult = KRESULT_DONE; return -1; } else if (keynote_errno) { keynote_errno = 0; s = 0; } /* Keep lower of two */ as->as_result = (as->as_result < s ? as->as_result : s); /* Check the signature now if we haven't done so already */ if (as->as_sigresult == SIGRESULT_UNTOUCHED) { if (!(as->as_flags & ASSERT_FLAG_LOCAL)) as->as_sigresult = keynote_sigverify_assertion(as); else as->as_sigresult = SIGRESULT_TRUE; /* Trusted assertion */ } if (as->as_sigresult != SIGRESULT_TRUE) { as->as_result = 0; as->as_sigresult = SIGRESULT_FALSE; if (keynote_errno != ERROR_MEMORY) keynote_errno = 0; /* Reset */ else { as->as_error = ERROR_MEMORY; as->as_kresult = KRESULT_DONE; return -1; } } as->as_kresult = KRESULT_DONE; return as->as_result; }