/* * Given an X509 certificate, create a KeyNote assertion where * Issuer/Subject -> Authorizer/Licensees. * XXX RSA-specific. */ int x509_generate_kn(int id, X509 *cert) { static const char fmt[] = "Authorizer: \"rsa-hex:%s\"\nLicensees: \"rsa-hex:%s" "\"\nConditions: %s >= \"%s\" && %s <= \"%s\";\n"; char *ikey = NULL, *skey = NULL, *buf = NULL; char isname[256], subname[256]; static const char fmt2[] = "Authorizer: \"DN:%s\"\nLicensees: \"DN:%s\"\n" "Conditions: %s >= \"%s\" && %s <= \"%s\";\n"; X509_NAME *issuer, *subject; struct keynote_deckey dc; X509_STORE_CTX csc; X509_OBJECT obj; X509 *icert; RSA *key = NULL; time_t tt; char before[15], after[15], *timecomp, *timecomp2; ASN1_TIME *tm; int i; LOG_DBG((LOG_POLICY, 90, "x509_generate_kn: generating KeyNote policy for certificate %p", cert)); issuer = X509_get_issuer_name(cert); subject = X509_get_subject_name(cert); /* Missing or self-signed, ignore cert but don't report failure. */ if (!issuer || !subject || !X509_name_cmp(issuer, subject)) return 1; if (!x509_cert_get_key(cert, &key)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert")); return 0; } dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; ikey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (keynote_errno == ERROR_MEMORY) { log_print("x509_generate_kn: failed to get memory for " "public key"); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key")); goto fail; } if (!ikey) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get " "subject key")); goto fail; } RSA_free(key); key = NULL; /* Now find issuer's certificate so we can get the public key. */ X509_STORE_CTX_init(&csc, x509_cas, cert, NULL); if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) != X509_LU_X509) { X509_STORE_CTX_cleanup(&csc); X509_STORE_CTX_init(&csc, x509_certs, cert, NULL); if (X509_STORE_get_by_subject(&csc, X509_LU_X509, issuer, &obj) != X509_LU_X509) { X509_STORE_CTX_cleanup(&csc); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: no certificate found for " "issuer")); goto fail; } } X509_STORE_CTX_cleanup(&csc); icert = obj.data.x509; if (icert == NULL) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: " "missing certificates, cannot construct X509 chain")); goto fail; } if (!x509_cert_get_key(icert, &key)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to get public key from cert")); goto fail; } X509_OBJECT_free_contents(&obj); dc.dec_algorithm = KEYNOTE_ALGORITHM_RSA; dc.dec_key = key; skey = kn_encode_key(&dc, INTERNAL_ENC_PKCS1, ENCODING_HEX, KEYNOTE_PUBLIC_KEY); if (keynote_errno == ERROR_MEMORY) { log_error("x509_generate_kn: failed to get memory for public " "key"); LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key")); goto fail; } if (!skey) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: cannot get issuer " "key")); goto fail; } RSA_free(key); key = NULL; if (((tm = X509_get_notBefore(cert)) == NULL) || (tm->type != V_ASN1_UTCTIME && tm->type != V_ASN1_GENERALIZEDTIME)) { tt = time(0); strftime(before, 14, "%Y%m%d%H%M%S", localtime(&tt)); timecomp = "LocalTimeOfDay"; } else { if (tm->data[tm->length - 1] == 'Z') { timecomp = "GMTTimeOfDay"; i = tm->length - 2; } else { timecomp = "LocalTimeOfDay"; i = tm->length - 1; } for (; i >= 0; i--) { if (tm->data[i] < '0' || tm->data[i] > '9') { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidBefore time field")); goto fail; } } if (tm->type == V_ASN1_UTCTIME) { if ((tm->length < 10) || (tm->length > 13)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length " "of NotValidBefore time field (%d)", tm->length)); goto fail; } /* Validity checks. */ if ((tm->data[2] != '0' && tm->data[2] != '1') || (tm->data[2] == '0' && tm->data[3] == '0') || (tm->data[2] == '1' && tm->data[3] > '2') || (tm->data[4] > '3') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '3' && tm->data[5] > '1') || (tm->data[6] > '2') || (tm->data[6] == '2' && tm->data[7] > '3') || (tm->data[8] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field")); goto fail; } /* Stupid UTC tricks. */ if (tm->data[0] < '5') snprintf(before, sizeof before, "20%s", tm->data); else snprintf(before, sizeof before, "19%s", tm->data); } else { /* V_ASN1_GENERICTIME */ if ((tm->length < 12) || (tm->length > 15)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidBefore time field (%d)", tm->length)); goto fail; } /* Validity checks. */ if ((tm->data[4] != '0' && tm->data[4] != '1') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '1' && tm->data[5] > '2') || (tm->data[6] > '3') || (tm->data[6] == '0' && tm->data[7] == '0') || (tm->data[6] == '3' && tm->data[7] > '1') || (tm->data[8] > '2') || (tm->data[8] == '2' && tm->data[9] > '3') || (tm->data[10] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidBefore time field")); goto fail; } snprintf(before, sizeof before, "%s", tm->data); } /* Fix missing seconds. */ if (tm->length < 12) { before[12] = '0'; before[13] = '0'; } /* This will overwrite trailing 'Z'. */ before[14] = '\0'; } tm = X509_get_notAfter(cert); if (tm == NULL && (tm->type != V_ASN1_UTCTIME && tm->type != V_ASN1_GENERALIZEDTIME)) { tt = time(0); strftime(after, 14, "%Y%m%d%H%M%S", localtime(&tt)); timecomp2 = "LocalTimeOfDay"; } else { if (tm->data[tm->length - 1] == 'Z') { timecomp2 = "GMTTimeOfDay"; i = tm->length - 2; } else { timecomp2 = "LocalTimeOfDay"; i = tm->length - 1; } for (; i >= 0; i--) { if (tm->data[i] < '0' || tm->data[i] > '9') { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid data in " "NotValidAfter time field")); goto fail; } } if (tm->type == V_ASN1_UTCTIME) { if ((tm->length < 10) || (tm->length > 13)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length)); goto fail; } /* Validity checks. */ if ((tm->data[2] != '0' && tm->data[2] != '1') || (tm->data[2] == '0' && tm->data[3] == '0') || (tm->data[2] == '1' && tm->data[3] > '2') || (tm->data[4] > '3') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '3' && tm->data[5] > '1') || (tm->data[6] > '2') || (tm->data[6] == '2' && tm->data[7] > '3') || (tm->data[8] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field")); goto fail; } /* Stupid UTC tricks. */ if (tm->data[0] < '5') snprintf(after, sizeof after, "20%s", tm->data); else snprintf(after, sizeof after, "19%s", tm->data); } else { /* V_ASN1_GENERICTIME */ if ((tm->length < 12) || (tm->length > 15)) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid length of " "NotValidAfter time field (%d)", tm->length)); goto fail; } /* Validity checks. */ if ((tm->data[4] != '0' && tm->data[4] != '1') || (tm->data[4] == '0' && tm->data[5] == '0') || (tm->data[4] == '1' && tm->data[5] > '2') || (tm->data[6] > '3') || (tm->data[6] == '0' && tm->data[7] == '0') || (tm->data[6] == '3' && tm->data[7] > '1') || (tm->data[8] > '2') || (tm->data[8] == '2' && tm->data[9] > '3') || (tm->data[10] > '5')) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: invalid value in " "NotValidAfter time field")); goto fail; } snprintf(after, sizeof after, "%s", tm->data); } /* Fix missing seconds. */ if (tm->length < 12) { after[12] = '0'; after[13] = '0'; } after[14] = '\0'; /* This will overwrite trailing 'Z' */ } if (asprintf(&buf, fmt, skey, ikey, timecomp, before, timecomp2, after) == -1) { log_error("x509_generate_kn: " "failed to allocate memory for KeyNote credential"); goto fail; } free(ikey); ikey = NULL; free(skey); skey = NULL; if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential")); goto fail; } /* We could print the assertion here, but log_print() truncates... */ LOG_DBG((LOG_POLICY, 60, "x509_generate_kn: added credential")); free(buf); buf = NULL; if (!X509_NAME_oneline(issuer, isname, 256)) { LOG_DBG((LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (issuer, ...) failed")); goto fail; } if (!X509_NAME_oneline(subject, subname, 256)) { LOG_DBG((LOG_POLICY, 50, "x509_generate_kn: " "X509_NAME_oneline (subject, ...) failed")); goto fail; } if (asprintf(&buf, fmt2, isname, subname, timecomp, before, timecomp2, after) == -1) { log_error("x509_generate_kn: malloc failed"); return 0; } if (kn_add_assertion(id, buf, strlen(buf), ASSERT_FLAG_LOCAL) == -1) { LOG_DBG((LOG_POLICY, 30, "x509_generate_kn: failed to add new KeyNote credential")); goto fail; } LOG_DBG((LOG_POLICY, 80, "x509_generate_kn: added credential:\n%s", buf)); free(buf); return 1; fail: free(buf); free(skey); free(ikey); if (key) RSA_free(key); return 0; }
int initialize_keynote(char *str_nonce, char *str_date) { char *policy_assertions; // policy file char *root_key; // root of trust char policy_template[] = "" "KeyNote-Version: 2\n" "Authorizer: \"POLICY\"\n" "licensees:\n%s" "conditions: app_domain == \"%s\" && nonce == \"%s\" " "&& date >= \"%s\"-> \"true\";\n"; int sessionid, num, i, j; char **decomposed; int rlen; /* * create temporary KeyNote session. */ sessionid = kn_init(); if (sessionid == -1) { fprintf(stderr, "Failed to create a new session.\n"); return(-1); } /* create policy. We read in the root of trust key from * a file and create a policy file for the temporary session * that is a close match to this request */ if (read_file("auth_public_key", &root_key, &rlen) < 0) { fprintf(stderr, "failed to read file 'auth_public_key'.\n"); return(-1); } else { char *str_app_domain = APP_DOMAIN; // char *str_nonce = nonce; // we get this from our offer // char *str_date = "20140216"; // we get this from our offer printf(policy_template, root_key, str_app_domain, str_nonce, str_date); rlen = strlen(policy_template) + strlen(root_key) + strlen(str_app_domain) + strlen(str_nonce) + strlen(str_date); if ((policy_assertions = calloc(rlen, 1)) == NULL) { fprintf(stderr, "policy calloc failed to get %d bytes\n", rlen); return(-1); } snprintf(policy_assertions, rlen, policy_template, root_key, str_app_domain, str_nonce, str_date); printf("policy file = <<<%s>>>\n", policy_assertions); } /* Let's find how many policies we just "read". */ decomposed = kn_read_asserts(policy_assertions, strlen(policy_assertions), &num); if (decomposed == NULL) { fprintf(stderr, "Failed to allocate memory for policy assertions.\n"); return(-1); } /* * If there were no assertions in the first argument to kn_read_asserts, * we'll get a valid pointer back, which we need to free. Note that this * is an error; we always MUST have at least one policy assertion. */ if (num == 0) { free(decomposed); fprintf(stderr, "No policy assertions provided.\n"); return(-1); } /* * We no longer need a copy of policy_assertions, so we could * free it here. */ free(policy_assertions); /* * decomposed now contains num pointers to strings, each containing a * single assertion. We now add them all to the session. */ for (i = 0; i < num; i++) { // printf("kn_add_assertion(%s)\n", decomposed[i]); j = kn_add_assertion(sessionid, decomposed[i], strlen(decomposed[i]), ASSERT_FLAG_LOCAL); if (j == -1) { switch (keynote_errno) { case ERROR_MEMORY: fprintf(stderr, "Out of memory, trying to add policy " "assertion %d.\n", j); break; case ERROR_SYNTAX: fprintf(stderr, "Syntax error parsing policy " "assertion %d.\n", j); break; case ERROR_NOTFOUND: fprintf(stderr, "Session %d not found while adding " "policy assertion %d.\n", sessionid, j); default: fprintf(stderr, "Unspecified error %d (shouldn't happen) " "while adding policy assertion %d.\n", keynote_errno, j); break; } /* We don't need the assertion any more. */ free(decomposed[i]); } } /* Now free decomposed itself. */ free(decomposed); return(sessionid); }
int load_credential(int sessionid, char *credential_assertions) { int num; int i; int j; char **decomposed; /* Let's find how many credentials we just "received". */ decomposed = kn_read_asserts(credential_assertions, strlen(credential_assertions), &num); if (decomposed == NULL) { fprintf(stderr, "Failed to allocate memory for credential " "assertions.\n"); return(-1); } /* * If there were no assertions in the first argument to kn_read_asserts, * we'll get a valid pointer back, which we need to free. Note that * it is legal to have zero credentials. */ if (num == 0) { free(decomposed); fprintf(stderr, "No credential assertions provided.\n"); } /* * decomposed now contains num pointers to strings, each containing a * single assertion. We now add them all to the session. */ for (i = 0; i < num; i++) { // printf("kn_add_assertion<<<%s>>>\n", decomposed[i]); j = kn_add_assertion(sessionid, decomposed[i], strlen(decomposed[i]), 0); if (j == -1) { switch (keynote_errno) { case ERROR_MEMORY: fprintf(stderr, "Out of memory, trying to add credential " "assertion %d.\n", j); break; case ERROR_SYNTAX: fprintf(stderr, "Syntax error parsing credential " "assertion %d.\n", j); break; case ERROR_NOTFOUND: fprintf(stderr, "Session %d not found while adding " "credential assertion %d.\n", sessionid, j); default: fprintf(stderr, "Unspecified error %d (shouldn't happen) " "while adding credential assertion %d.\n", keynote_errno, j); break; } /* We don't need the assertion any more. */ free(decomposed[i]); } } free(decomposed); }
/* * Simple API for doing a single KeyNote query. */ int kn_query(struct environment *env, char **retvalues, int numval, char **trusted, int *trustedlen, int numtrusted, char **untrusted, int *untrustedlen, int numuntrusted, char **authorizers, int numauthorizers) { struct environment *en; int sessid, i, serrno; keynote_errno = 0; if ((sessid = kn_init()) == -1) return -1; /* Action set */ for (en = env; en != (struct environment *) NULL; en = en->env_next) if (kn_add_action(sessid, en->env_name, en->env_value, en->env_flags) == -1) { serrno = keynote_errno; kn_close(sessid); keynote_errno = serrno; return -1; } /* Locally trusted assertions */ for (i = 0; i < numtrusted; i++) if ((kn_add_assertion(sessid, trusted[i], trustedlen[i], ASSERT_FLAG_LOCAL) == -1) && (keynote_errno == ERROR_MEMORY)) { serrno = keynote_errno; kn_close(sessid); keynote_errno = serrno; return -1; } /* Untrusted assertions */ for (i = 0; i < numuntrusted; i++) if ((kn_add_assertion(sessid, untrusted[i], untrustedlen[i], 0) == -1) && (keynote_errno == ERROR_MEMORY)) { serrno = keynote_errno; kn_close(sessid); keynote_errno = serrno; return -1; } /* Authorizers */ for (i = 0; i < numauthorizers; i++) if (kn_add_authorizer(sessid, authorizers[i]) == -1) { serrno = keynote_errno; kn_close(sessid); keynote_errno = serrno; return -1; } i = kn_do_query(sessid, retvalues, numval); serrno = keynote_errno; kn_close(sessid); if (serrno) keynote_errno = serrno; return i; }