/* print all known host keys for a given host, but skip keys of given type */ static int show_other_keys(struct hostkeys *hostkeys, Key *key) { int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_X509_RSA, KEY_X509_DSA, -1}; int i, ret = 0; char *fp, *ra; const struct hostkey_entry *found; for (i = 0; type[i] != -1; i++) { if (type[i] == key->type) continue; if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) continue; fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX); ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART); logit("WARNING: %s key found for host %s\n" "in %s:%lu\n" "%s key fingerprint %s.", key_type(found->key), found->host, found->file, found->line, key_type(found->key), fp); if (key_is_x509(found->key)) { char *subject = x509key_subject(found->key); logit("Distinguished name found is '%s'.", subject); xfree(subject); } if (options.visual_host_key) logit("%s", ra); xfree(ra); xfree(fp); ret = 1; } return ret; }
void pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) { char *fp, *extra; va_list ap; int i; extra = NULL; if (fmt != NULL) { va_start(ap, fmt); i = vasprintf(&extra, fmt, ap); va_end(ap); if (i < 0 || extra == NULL) fatal("%s: vasprintf failed", __func__); } if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", key_type(key), key->cert->key_id, (unsigned long long)key->cert->serial, key_type(key->cert->signature_key), fp, extra == NULL ? "" : ", ", extra == NULL ? "" : extra); free(fp); } else { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); auth_info(authctxt, "%s %s%s%s", key_type(key), fp, extra == NULL ? "" : ", ", extra == NULL ? "" : extra); free(fp); } free(extra); }
/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ int auth_key_is_revoked(Key *key) { char *key_fp; if (options.revoked_keys_file == NULL) return 0; switch (key_in_file(key, options.revoked_keys_file, 0)) { case 0: /* key not revoked */ return 0; case -1: /* Error opening revoked_keys_file: refuse all keys */ error("Revoked keys file is unreadable: refusing public key " "authentication"); return 1; case 1: /* Key revoked */ key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); error("WARNING: authentication attempt with a revoked " "%s key %s ", key_type(key), key_fp); xfree(key_fp); return 1; } fatal("key_in_file returned junk"); }
/* returns 0 if key verifies or -1 if key does NOT verify */ int verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) { int flags = 0; char *fp; fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); debug("Server host key: %s %s", key_type(host_key), fp); xfree(fp); /* XXX certs are not yet supported for DNS */ if (!key_is_cert(host_key) && options.verify_host_key_dns && verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) { if (flags & DNS_VERIFY_FOUND) { if (options.verify_host_key_dns == 1 && flags & DNS_VERIFY_MATCH && flags & DNS_VERIFY_SECURE) return 0; if (flags & DNS_VERIFY_MATCH) { matching_host_key_dns = 1; } else { warn_changed_key(host_key); error("Update the SSHFP RR in DNS with the new " "host key to get rid of this message."); } } } return check_host_key(host, hostaddr, options.port, host_key, RDRW, options.user_hostfiles, options.num_user_hostfiles, options.system_hostfiles, options.num_system_hostfiles); }
void pubkey_auth_info(Authctxt *authctxt, const Key *key) { char *fp; if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s", key_type(key), key->cert->key_id, (unsigned long long)key->cert->serial, key_type(key->cert->signature_key), fp); free(fp); } else { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); auth_info(authctxt, "%s %s", key_type(key), fp); free(fp); } }
void describe_key(const char *msg, Key *key, const char *comment) { char *fp; fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (!quiet) printf("%s: %u %s %s\n", msg, key_size(key), fp, comment); xfree(fp); }
/* Authenticate a certificate key against TrustedUserCAKeys */ static int user_cert_trusted_ca(struct passwd *pw, Key *key) { char *ca_fp, *principals_file = NULL; const char *reason; int ret = 0; if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) return 0; ca_fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); if (key_in_file(key->cert->signature_key, options.trusted_user_ca_keys, 1) != 1) { debug2("%s: CA %s %s is not listed in %s", __func__, key_type(key->cert->signature_key), ca_fp, options.trusted_user_ca_keys); goto out; } /* * If AuthorizedPrincipals is in use, then compare the certificate * principals against the names in that file rather than matching * against the username. */ if ((principals_file = authorized_principals_file(pw)) != NULL) { if (!match_principals_file(principals_file, pw, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: error("%s", reason); auth_debug_add("%s", reason); goto out; } } if (key_cert_check_authority(key, 0, 1, principals_file == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw) != 0) goto out; verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", key->cert->key_id, key_type(key->cert->signature_key), ca_fp, options.trusted_user_ca_keys); ret = 1; out: if (principals_file != NULL) xfree(principals_file); if (ca_fp != NULL) xfree(ca_fp); return ret; }
/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ int auth_key_is_revoked(Key *key, int hostkey) { char *key_fp; if (blacklisted_key(key, &key_fp) == 1) { if (options.permit_blacklisted_keys) { if (hostkey) error("Host key %s blacklisted (see " "ssh-vulnkey(1)); continuing anyway", key_fp); else logit("Public key %s from %s blacklisted (see " "ssh-vulnkey(1)); continuing anyway", key_fp, get_remote_ipaddr()); xfree(key_fp); } else { if (hostkey) error("Host key %s blacklisted (see " "ssh-vulnkey(1))", key_fp); else logit("Public key %s from %s blacklisted (see " "ssh-vulnkey(1))", key_fp, get_remote_ipaddr()); xfree(key_fp); return 1; } } if (options.revoked_keys_file == NULL) return 0; switch (key_in_file(key, options.revoked_keys_file, 0)) { case 0: /* key not revoked */ return 0; case -1: /* Error opening revoked_keys_file: refuse all keys */ error("Revoked keys file is unreadable: refusing public key " "authentication"); return 1; case 1: /* Key revoked */ key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); error("WARNING: authentication attempt with a revoked " "%s key %s ", key_type(key), key_fp); xfree(key_fp); return 1; } fatal("key_in_file returned junk"); }
/* print all known host keys for a given host, but skip keys of given type */ static int show_other_keys(struct hostkeys *hostkeys, Key *key) { int type[] = { KEY_RSA1, KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 }; int i, ret = 0; char *fp, *ra; const struct hostkey_entry *found; for (i = 0; type[i] != -1; i++) { if (type[i] == key->type) continue; if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found)) continue; fp = key_fingerprint(found->key, options.fingerprint_hash, SSH_FP_DEFAULT); ra = key_fingerprint(found->key, options.fingerprint_hash, SSH_FP_RANDOMART); logit("WARNING: %s key found for host %s\n" "in %s:%lu\n" "%s key fingerprint %s.", key_type(found->key), found->host, found->file, found->line, key_type(found->key), fp); if (options.visual_host_key) logit("%s", ra); free(ra); free(fp); ret = 1; } return ret; }
/* returns 0 if key verifies or -1 if key does NOT verify */ int verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key) { int flags = 0; char *fp; Key *plain = NULL; fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); debug("Server host key: %s %s", key_type(host_key), fp); free(fp); if (options.verify_host_key_dns) { /* * XXX certs are not yet supported for DNS, so downgrade * them and try the plain key. */ plain = key_from_private(host_key); if (key_is_cert(plain)) key_drop_cert(plain); if (verify_host_key_dns(host, hostaddr, plain, &flags) == 0) { if (flags & DNS_VERIFY_FOUND) { if (options.verify_host_key_dns == 1 && flags & DNS_VERIFY_MATCH && flags & DNS_VERIFY_SECURE) { key_free(plain); return 0; } if (flags & DNS_VERIFY_MATCH) { matching_host_key_dns = 1; } else { warn_changed_key(plain); error("Update the SSHFP RR in DNS " "with the new host key to get rid " "of this message."); } } } key_free(plain); } return check_host_key(host, hostaddr, options.port, host_key, RDRW, options.user_hostfiles, options.num_user_hostfiles, options.system_hostfiles, options.num_system_hostfiles); }
/* * Performs the RSA authentication dialog with the client. This returns * 0 if the client could not be authenticated, and 1 if authentication was * successful. This may exit if there is a serious protocol violation. */ int auth_rsa(Authctxt *authctxt, BIGNUM *client_n) { Key *key; char *fp; struct passwd *pw = authctxt->pw; /* no user given */ if (!authctxt->valid) return 0; if (!PRIVSEP(auth_rsa_key_allowed(pw, client_n, &key))) { auth_clear_options(); return (0); } /* Perform the challenge-response dialog for this key. */ if (!auth_rsa_challenge_dialog(key)) { /* Wrong response. */ verbose("Wrong response to RSA authentication challenge."); packet_send_debug("Wrong response to RSA authentication challenge."); /* * Break out of the loop. Otherwise we might send * another challenge and break the protocol. */ key_free(key); return (0); } /* * Correct response. The client has been successfully * authenticated. Note that we have not yet processed the * options; this will be reset if the options cause the * authentication to be rejected. */ fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(key), fp); xfree(fp); key_free(key); packet_send_debug("RSA authentication accepted."); return (1); }
static void warn_changed_key(Key *host_key) { char *fp; fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); error("It is also possible that a host key has just been changed."); error("The fingerprint for the %s key sent by the remote host is\n%s.", key_type(host_key), fp); error("Please contact your system administrator."); xfree(fp); }
/* check whether given key is in .ssh/authorized_keys* */ int user_key_allowed(struct passwd *pw, Key *key) { char *fp; int success; char *file; if (blacklisted_key(key)) { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (options.permit_blacklisted_keys) logit("Public key %s blacklisted (see " "ssh-vulnkey(1)); continuing anyway", fp); else logit("Public key %s blacklisted (see " "ssh-vulnkey(1))", fp); xfree(fp); if (!options.permit_blacklisted_keys) return 0; } if (auth_key_is_revoked(key)) return 0; if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) return 0; success = user_cert_trusted_ca(pw, key); if (success) return success; file = authorized_keys_file(pw); success = user_key_allowed2(pw, key, file); xfree(file); if (success) return success; /* try suffix "2" for backward compat, too */ file = authorized_keys_file2(pw); success = user_key_allowed2(pw, key, file); xfree(file); return success; }
/* check whether given key is in .ssh/authorized_keys* */ int user_key_allowed(struct passwd *pw, Key *key) { char *fp; u_int success, i; char *file; if (blacklisted_key(key)) { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (options.permit_blacklisted_keys) logit("Public key %s blacklisted (see " "ssh-vulnkey(1)); continuing anyway", fp); else logit("Public key %s blacklisted (see " "ssh-vulnkey(1))", fp); xfree(fp); if (!options.permit_blacklisted_keys) return 0; } if (auth_key_is_revoked(key)) return 0; if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) return 0; success = user_cert_trusted_ca(pw, key); if (success) return success; for (i = 0; !success && i < options.num_authkeys_files; i++) { file = expand_authorized_keys( options.authorized_keys_files[i], pw); success = user_key_allowed2(pw, key, file); xfree(file); } return success; }
/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */ int auth_key_is_revoked(Key *key) { char *key_fp; if (options.revoked_keys_file == NULL) return 0; switch (ssh_krl_file_contains_key(options.revoked_keys_file, key)) { case 0: return 0; /* Not revoked */ case -2: break; /* Not a KRL */ default: goto revoked; } debug3("%s: treating %s as a key list", __func__, options.revoked_keys_file); switch (key_in_file(key, options.revoked_keys_file, 0)) { case 0: /* key not revoked */ return 0; case -1: /* Error opening revoked_keys_file: refuse all keys */ error("Revoked keys file is unreadable: refusing public key " "authentication"); return 1; case 1: revoked: /* Key revoked */ key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); error("WARNING: authentication attempt with a revoked " "%s key %s ", key_type(key), key_fp); xfree(key_fp); return 1; } fatal("key_in_file returned junk"); }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char *line = NULL; const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; Key *found; char *fp; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { restore_uid(); return 0; } found_key = 0; found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); gs_auth_fingerprint = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (gs_auth_pubkey == NULL) { gs_auth_pubkey = get_pubkey(); } line = gs_auth_pubkey; while (line) { char *cp, *key_options = NULL; auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') break; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ break; } } if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) break; if (key_is_cert_authority) break; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } break; } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }
/* return 1 if given hostkey is allowed */ int hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost, Key *key) { const char *resolvedname, *ipaddr, *lookup, *reason; HostStatus host_status; int len; char *fp; if (auth_key_is_revoked(key)) return 0; resolvedname = get_canonical_hostname(options.use_dns); ipaddr = get_remote_ipaddr(); debug2("userauth_hostbased: chost %s resolvedname %s ipaddr %s", chost, resolvedname, ipaddr); if (((len = strlen(chost)) > 0) && chost[len - 1] == '.') { debug2("stripping trailing dot from chost %s", chost); chost[len - 1] = '\0'; } if (options.hostbased_uses_name_from_packet_only) { if (auth_rhosts2(pw, cuser, chost, chost) == 0) return 0; lookup = chost; } else { if (strcasecmp(resolvedname, chost) != 0) logit("userauth_hostbased mismatch: " "client sends %s, but we resolve %s to %s", chost, ipaddr, resolvedname); if (auth_rhosts2(pw, cuser, resolvedname, ipaddr) == 0) return 0; lookup = resolvedname; } debug2("userauth_hostbased: access allowed by auth_rhosts2"); if (key_is_cert(key) && key_cert_check_authority(key, 1, 0, lookup, &reason)) { error("%s", reason); auth_debug_add("%s", reason); return 0; } host_status = check_key_in_hostfiles(pw, key, lookup, _PATH_SSH_SYSTEM_HOSTFILE, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE); /* backward compat if no key has been found. */ if (host_status == HOST_NEW) { host_status = check_key_in_hostfiles(pw, key, lookup, _PATH_SSH_SYSTEM_HOSTFILE2, options.ignore_user_known_hosts ? NULL : _PATH_SSH_USER_HOSTFILE2); } if (host_status == HOST_OK) { if (key_is_cert(key)) { fp = key_fingerprint(key->cert->signature_key, SSH_FP_MD5, SSH_FP_HEX); verbose("Accepted certificate ID \"%s\" signed by " "%s CA %s from %s@%s", key->cert->key_id, key_type(key->cert->signature_key), fp, cuser, lookup); } else { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); verbose("Accepted %s public key %s from %s@%s", key_type(key), fp, cuser, lookup); } xfree(fp); } return (host_status == HOST_OK); }
int main(int argc, char **argv) { //ENGINE *e = NULL; int c, host_port = 80, count = 1; char *host_name, *p, *dir_name = NULL; char http_string[16384]; struct http_reply reply; unsigned int n; unsigned char md[EVP_MAX_MD_SIZE]; struct scep scep_t; FILE *fp = NULL; BIO *bp; STACK_OF(X509) *nextcara = NULL; X509 *cert=NULL; PKCS7 p7; int i; int required_option_space; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; int err; //printf("Starting sscep\n"); //fprintf(stdout, "%s: starting sscep on WIN32, sscep version %s\n", pname, VERSION); wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ return; } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); return; } #endif /* Initialize scep layer */ init_scep(); /* Set program name */ pname = argv[0]; /* Set timeout */ timeout = TIMEOUT; /* Check operation parameter */ if (!argv[1]) { usage(); } else if (!strncmp(argv[1], "getca", 5)) { operation_flag = SCEP_OPERATION_GETCA; } else if (!strncmp(argv[1], "enroll", 6)) { operation_flag = SCEP_OPERATION_ENROLL; } else if (!strncmp(argv[1], "getcert", 7)) { operation_flag = SCEP_OPERATION_GETCERT; } else if (!strncmp(argv[1], "getcrl", 6)) { operation_flag = SCEP_OPERATION_GETCRL; } else if (!strncmp(argv[1], "getnextca", 9)) { operation_flag = SCEP_OPERATION_GETNEXTCA; } else { fprintf(stderr, "%s: missing or illegal operation parameter\n", argv[0]); usage(); } /* Skip first parameter and parse the rest of the command */ optind++; while ((c = getopt(argc, argv, "c:C:de:E:f:g:hF:i:k:K:l:L:n:O:p:r:Rs:S:t:T:u:vw:m:HM:")) != -1) switch(c) { case 'c': c_flag = 1; c_char = optarg; break; case 'C': C_flag = 1; C_char = optarg; break; case 'd': d_flag = 1; break; case 'e': e_flag = 1; e_char = optarg; break; case 'E': E_flag = 1; E_char = optarg; break; case 'F': F_flag = 1; F_char = optarg; break; case 'f': f_flag = 1; f_char = optarg; break; case 'g': g_flag = 1; g_char = optarg; break; case 'h'://TODO change to eg. ID --inform=ID h_flag = 1; break; case 'H': H_flag = 1; break; case 'i': i_flag = 1; i_char = optarg; break; case 'k': k_flag = 1; k_char = optarg; break; case 'K': K_flag = 1; K_char = optarg; break; case 'l': l_flag = 1; l_char = optarg; break; case 'L': L_flag = 1; L_char = optarg; break; case 'm': m_flag = 1; m_char = optarg; break; case 'M': if(!M_flag) { /* if this is the first time the option appears, create a * new string. */ required_option_space = strlen(optarg) + 1; M_char = malloc(required_option_space); if(!M_char) error_memory(); strncpy(M_char, optarg, required_option_space); // set the flag, so we already have a string M_flag = 1; } else { /* we already have a string, just extend it. */ // old part + new part + &-sign + null byte required_option_space = strlen(M_char) + strlen(optarg) + 2; M_char = realloc(M_char, required_option_space); if(!M_char) error_memory(); strncat(M_char, "&", 1); strncat(M_char, optarg, strlen(optarg)); } break; case 'n': n_flag = 1; n_num = atoi(optarg); break; case 'O': O_flag = 1; O_char = optarg; break; case 'p': p_flag = 1; p_char = optarg; break; case 'r': r_flag = 1; r_char = optarg; break; case 'R': R_flag = 1; break; case 's': s_flag = 1; /*s_char = optarg;*/ s_char = handle_serial(optarg); break; case 'S': S_flag = 1; S_char = optarg; break; case 't': t_flag = 1; t_num = atoi(optarg); break; case 'T': T_flag = 1; T_num = atoi(optarg); break; case 'u': u_flag = 1; url_char = optarg; break; case 'v': v_flag = 1; break; case 'w': w_flag = 1; w_char = optarg; break; default: printf("argv: %s\n", argv[optind]); usage(); } argc -= optind; argv += optind; /* If we debug, include verbose messages also */ if (d_flag) v_flag = 1; if(f_char){ scep_conf_init(f_char); }else{ scep_conf = NULL; //moved init to here otherwise compile error on windows } /* Read in the configuration file: */ /*if (f_char) { #ifdef WIN32 if ((fopen_s(&fp, f_char, "r"))) #else if (!(fp = fopen(f_char, "r"))) #endif fprintf(stderr, "%s: cannot open %s\n", pname, f_char); else { init_config(fp); (void)fclose(fp); } }*/ if (v_flag) fprintf(stdout, "%s: starting sscep, version %s\n", pname, VERSION); /* * Create a new SCEP transaction and self-signed * certificate based on cert request */ if (v_flag) fprintf(stdout, "%s: new transaction\n", pname); new_transaction(&scep_t); /*enable Engine Support */ if (g_flag) { scep_t.e = scep_engine_init(scep_t.e); } /* * Check argument logic. */ if (!c_flag) { if (operation_flag == SCEP_OPERATION_GETCA) { fprintf(stderr, "%s: missing CA certificate filename (-c)\n", pname); exit (SCEP_PKISTATUS_ERROR); } else { fprintf(stderr, "%s: missing CA certificate (-c)\n", pname); exit (SCEP_PKISTATUS_ERROR); } if (operation_flag == SCEP_OPERATION_GETNEXTCA) { fprintf(stderr, "%s: missing nextCA certificate target filename (-c)\n", pname); exit (SCEP_PKISTATUS_ERROR); } else { fprintf(stderr, "%s: missing nextCA certificate target filename(-c)\n", pname); exit (SCEP_PKISTATUS_ERROR); } } if (!C_flag) { if (operation_flag == SCEP_OPERATION_GETNEXTCA) { fprintf(stderr, "%s: missing nextCA certificate chain filename (-C)\n", pname); exit (SCEP_PKISTATUS_ERROR); } } if (operation_flag == SCEP_OPERATION_ENROLL) { if (!k_flag) { fprintf(stderr, "%s: missing private key (-k)\n",pname); exit (SCEP_PKISTATUS_ERROR); } if (!r_flag) { fprintf(stderr, "%s: missing request (-r)\n",pname); exit (SCEP_PKISTATUS_ERROR); } if (!l_flag) { fprintf(stderr, "%s: missing local cert (-l)\n",pname); exit (SCEP_PKISTATUS_ERROR); } /* Set polling limits */ if (!n_flag) n_num = MAX_POLL_COUNT; if (!t_flag) t_num = POLL_TIME; if (!T_flag) T_num = MAX_POLL_TIME; } if (operation_flag == SCEP_OPERATION_GETCERT) { if (!l_flag) { fprintf(stderr, "%s: missing local cert (-l)\n",pname); exit (SCEP_PKISTATUS_ERROR); } if (!s_flag) { fprintf(stderr, "%s: missing serial no (-s)\n", pname); exit (SCEP_PKISTATUS_ERROR); } if (!w_flag) { fprintf(stderr, "%s: missing cert file (-w)\n",pname); exit (SCEP_PKISTATUS_ERROR); } if (!k_flag) { fprintf(stderr, "%s: missing private key (-k)\n",pname); exit (SCEP_PKISTATUS_ERROR); } } if (operation_flag == SCEP_OPERATION_GETCRL) { if (!l_flag) { fprintf(stderr, "%s: missing local cert (-l)\n",pname); exit (SCEP_PKISTATUS_ERROR); } if (!w_flag) { fprintf(stderr, "%s: missing crl file (-w)\n",pname); exit (SCEP_PKISTATUS_ERROR); } if (!k_flag) { fprintf(stderr, "%s: missing private key (-k)\n",pname); exit (SCEP_PKISTATUS_ERROR); } } /* Break down the URL */ if (!u_flag) { fprintf(stderr, "%s: missing URL (-u)\n", pname); exit (SCEP_PKISTATUS_ERROR); } if (strncmp(url_char, "http://", 7) && !p_flag) { fprintf(stderr, "%s: illegal URL %s\n", pname, url_char); exit (SCEP_PKISTATUS_ERROR); } if (p_flag) { #ifdef WIN32 host_name = _strdup(p_char); #else host_name = strdup(p_char); #endif dir_name = url_char; } /* Break down the URL */ if (!u_flag) { fprintf(stderr, "%s: missing URL (-u)\n", pname); exit (SCEP_PKISTATUS_ERROR); } if (strncmp(url_char, "http://", 7) && !p_flag) { fprintf(stderr, "%s: illegal URL %s\n", pname, url_char); exit (SCEP_PKISTATUS_ERROR); } if (p_flag) { #ifdef WIN32 host_name = _strdup(p_char); #else host_name = strdup(p_char); #endif dir_name = url_char; } #ifdef WIN32 else if (!(host_name = _strdup(url_char + 7))) #else else if (!(host_name = strdup(url_char + 7))) #endif error_memory(); p = host_name; c = 0; while (*p != '\0') { if (*p == '/' && !p_flag && !c) { *p = '\0'; if (*(p+1)) dir_name = p + 1; c = 1; } if (*p == ':') { *p = '\0'; if (*(p+1)) host_port = atoi(p+1); } p++; } if (!dir_name) { fprintf(stderr, "%s: illegal URL %s\n", pname, url_char); exit (SCEP_PKISTATUS_ERROR); } if (host_port < 1 || host_port > 65550) { fprintf(stderr, "%s: illegal port number %d\n", pname, host_port); exit (SCEP_PKISTATUS_ERROR); } if (v_flag) { fprintf(stdout, "%s: hostname: %s\n", pname, host_name); fprintf(stdout, "%s: directory: %s\n", pname, dir_name); fprintf(stdout, "%s: port: %d\n", pname, host_port); } /* Check algorithms */ if (!E_flag) { enc_alg = (EVP_CIPHER *)EVP_des_cbc(); } else if (!strncmp(E_char, "blowfish", 8)) { enc_alg = (EVP_CIPHER *)EVP_bf_cbc(); } else if (!strncmp(E_char, "des", 3)) { enc_alg = (EVP_CIPHER *)EVP_des_cbc(); } else if (!strncmp(E_char, "3des", 4)) { enc_alg = (EVP_CIPHER *)EVP_des_ede3_cbc(); } else if (!strncmp(E_char, "aes", 3)) { enc_alg = (EVP_CIPHER *)EVP_aes_256_cbc(); } else { fprintf(stderr, "%s: unsupported algorithm: %s\n", pname, E_char); exit (SCEP_PKISTATUS_ERROR); } if (!S_flag) { sig_alg = (EVP_MD *)EVP_md5(); } else if (!strncmp(S_char, "md5", 3)) { sig_alg = (EVP_MD *)EVP_md5(); } else if (!strncmp(S_char, "sha1", 4)) { sig_alg = (EVP_MD *)EVP_sha1(); } else { fprintf(stderr, "%s: unsupported algorithm: %s\n", pname, S_char); exit (SCEP_PKISTATUS_ERROR); } /* Fingerprint algorithm */ if (!F_flag) { fp_alg = (EVP_MD *)EVP_md5(); } else if (!strncmp(F_char, "md5", 3)) { fp_alg = (EVP_MD *)EVP_md5(); } else if (!strncmp(F_char, "sha1", 4)) { fp_alg = (EVP_MD *)EVP_sha1(); } else { fprintf(stderr, "%s: unsupported algorithm: %s\n", pname, F_char); exit (SCEP_PKISTATUS_ERROR); } /* * Switch to operation specific code */ switch(operation_flag) { case SCEP_OPERATION_GETCA: if (v_flag) fprintf(stdout, "%s: SCEP_OPERATION_GETCA\n", pname); /* Set CA identifier */ if (!i_flag) i_char = CA_IDENTIFIER; /* Forge the HTTP message */ if(!M_flag){ snprintf(http_string, sizeof(http_string), "GET %s%s?operation=GetCACert&message=%s " "HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name, i_char); }else{ snprintf(http_string, sizeof(http_string), "GET %s%s?operation=GetCACert&message=%s&%s " "HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name, i_char, M_char); } if (d_flag){ printf("%s: requesting CA certificate\n", pname); fprintf(stdout, "%s: scep msg: %s", pname, http_string); } /* * Send http message. * Response is written to http_response struct "reply". */ reply.payload = NULL; if ((c = send_msg (&reply, http_string, host_name, host_port, operation_flag)) == 1) { fprintf(stderr, "%s: error while sending " "message\n", pname); exit (SCEP_PKISTATUS_NET); } if (reply.payload == NULL) { fprintf(stderr, "%s: no data, perhaps you " "should define CA identifier (-i)\n", pname); exit (SCEP_PKISTATUS_SUCCESS); } if (v_flag){ printf("%s: valid response from server\n", pname); } if (reply.type == SCEP_MIME_GETCA_RA) { /* XXXXXXXXXXXXXXXXXXXXX chain not verified */ write_ca_ra(&reply); } /* Read payload as DER X.509 object: */ bp = BIO_new_mem_buf(reply.payload, reply.bytes); cacert = d2i_X509_bio(bp, NULL); /* Read and print certificate information */ if (!X509_digest(cacert, fp_alg, md, &n)) { ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_ERROR); } if (v_flag){ printf("%s: %s fingerprint: ", pname, OBJ_nid2sn(EVP_MD_type(fp_alg))); for (c = 0; c < (int)n; c++) { printf("%02X%c",md[c], (c + 1 == (int)n) ?'\n':':'); } } /* Write PEM-formatted file: */ #ifdef WIN32 if ((fopen_s(&fp,c_char , "w"))) #else if (!(fp = fopen(c_char, "w"))) #endif { fprintf(stderr, "%s: cannot open CA file for " "writing\n", pname); exit (SCEP_PKISTATUS_ERROR); } if (PEM_write_X509(fp, c_char) != 1) { fprintf(stderr, "%s: error while writing CA " "file\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_ERROR); } if (v_flag) printf("%s: CA certificate written as %s\n", pname, c_char); (void)fclose(fp); pkistatus = SCEP_PKISTATUS_SUCCESS; break; case SCEP_OPERATION_GETNEXTCA: if (v_flag) fprintf(stdout, "%s: SCEP_OPERATION_GETNEXTCA\n", pname); /* Set CA identifier */ if (!i_flag) i_char = CA_IDENTIFIER; /* Forge the HTTP message */ if(!M_flag){ snprintf(http_string, sizeof(http_string), "GET %s%s?operation=GetNextCACert&message=%s " "HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name, i_char); }else{ snprintf(http_string, sizeof(http_string), "GET %s%s?operation=GetNextCACert&message=%s&%s " "HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name, i_char, M_char); } if (d_flag){ printf("%s: requesting nextCA certificate\n", pname); fprintf(stdout, "%s: scep msg: %s", pname, http_string); } /* * Send http message. * Response is written to http_response struct "reply". */ reply.payload = NULL; if ((c = send_msg (&reply, http_string, host_name, host_port, operation_flag)) == 1) { if(v_flag){ fprintf(stderr, "%s: error while sending " "message\n", pname); fprintf(stderr, "%s: getnextCA might be not available" "\n", pname); } exit (SCEP_PKISTATUS_NET); } if (reply.payload == NULL) { fprintf(stderr, "%s: no data, perhaps you " "there is no nextCA available\n", pname); exit (SCEP_PKISTATUS_SUCCESS); } if(d_flag) printf("%s: valid response from server\n", pname); if (reply.type == SCEP_MIME_GETNEXTCA) { /* XXXXXXXXXXXXXXXXXXXXX chain not verified */ //write_ca_ra(&reply); /* Set the whole struct as 0 */ memset(&scep_t, 0, sizeof(scep_t)); scep_t.reply_payload = reply.payload; scep_t.reply_len = reply.bytes; scep_t.request_type = SCEP_MIME_GETNEXTCA; pkcs7_verify_unwrap(&scep_t , C_char); //pkcs7_unwrap(&scep_t); } /* Get certs */ p7 = *(scep_t.reply_p7); nextcara = scep_t.reply_p7->d.sign->cert; if (v_flag) { printf ("verify and unwrap: found %d cert(s)\n", sk_X509_num(nextcara)); } for (i = 0; i < sk_X509_num(nextcara); i++) { char buffer[1024]; char name[1024]; memset(buffer, 0, 1024); memset(name, 0, 1024); cert = sk_X509_value(nextcara, i); if (v_flag) { printf("%s: found certificate with\n" " subject: '%s'\n", pname, X509_NAME_oneline(X509_get_subject_name(cert), buffer, sizeof(buffer))); printf(" issuer: %s\n", X509_NAME_oneline(X509_get_issuer_name(cert), buffer, sizeof(buffer))); } /* Create name */ snprintf(name, 1024, "%s-%d", c_char, i); /* Write PEM-formatted file: */ if (!(fp = fopen(name, "w"))) { fprintf(stderr, "%s: cannot open cert file for writing\n", pname); exit (SCEP_PKISTATUS_FILE); } if (v_flag) printf("%s: writing cert\n", pname); if (d_flag) PEM_write_X509(stdout, cert); if (PEM_write_X509(fp, cert) != 1) { fprintf(stderr, "%s: error while writing certificate " "file\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_FILE); } if(v_flag) printf("%s: certificate written as %s\n", pname, name); (void)fclose(fp); } pkistatus = SCEP_PKISTATUS_SUCCESS; break; case SCEP_OPERATION_GETCERT: case SCEP_OPERATION_GETCRL: /* Read local certificate */ if (!l_flag) { fprintf(stderr, "%s: missing local cert (-l)\n", pname); exit (SCEP_PKISTATUS_FILE); } read_cert(&localcert, l_char); case SCEP_OPERATION_ENROLL: /* * Read in CA cert, private key and certificate * request in global variables. */ read_ca_cert(); if (!k_flag) { fprintf(stderr, "%s: missing private key (-k)\n", pname); exit (SCEP_PKISTATUS_FILE); } if(scep_conf != NULL) { sscep_engine_read_key_new(&rsa, k_char, scep_t.e); } else { read_key(&rsa, k_char); } if ((K_flag && !O_flag) || (!K_flag && O_flag)) { fprintf(stderr, "%s: -O also requires -K (and vice-versa)\n", pname); exit (SCEP_PKISTATUS_FILE); } if (K_flag) { //TODO auf hwcrhk prfen? if(scep_conf != NULL) { sscep_engine_read_key_old(&renewal_key, K_char, scep_t.e); } else { read_key(&renewal_key, K_char); } } if (O_flag) { read_cert(&renewal_cert, O_char); } if (operation_flag == SCEP_OPERATION_ENROLL) { read_request(); scep_t.transaction_id = key_fingerprint(request); if (v_flag) { printf("%s: Read request with transaction id: %s\n", pname, scep_t.transaction_id); } } if (operation_flag != SCEP_OPERATION_ENROLL) goto not_enroll; if (! O_flag) { if (v_flag) fprintf(stdout, "%s: generating selfsigned " "certificate\n", pname); new_selfsigned(&scep_t); } else { /* Use existing certificate */ scep_t.signercert = renewal_cert; scep_t.signerkey = renewal_key; } /* Write the selfsigned certificate if requested */ if (L_flag) { /* Write PEM-formatted file: */ #ifdef WIN32 if ((fopen_s(&fp, L_char, "w"))) { #else if (!(fp = fopen(L_char, "w"))) { #endif fprintf(stderr, "%s: cannot open " "file for writing\n", pname); exit (SCEP_PKISTATUS_ERROR); } if (PEM_write_X509(fp,scep_t.signercert) != 1) { fprintf(stderr, "%s: error while " "writing certificate file\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_ERROR); } printf("%s: selfsigned certificate written " "as %s\n", pname, L_char); (void)fclose(fp); } /* Write issuer name and subject (GetCertInitial): */ if (!(scep_t.ias_getcertinit->subject = X509_REQ_get_subject_name(request))) { fprintf(stderr, "%s: error getting subject " "for GetCertInitial\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_ERROR); } not_enroll: if (!(scep_t.ias_getcertinit->issuer = X509_get_issuer_name(cacert))) { fprintf(stderr, "%s: error getting issuer " "for GetCertInitial\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_ERROR); } /* Write issuer name and serial (GETC{ert,rl}): */ scep_t.ias_getcert->issuer = scep_t.ias_getcertinit->issuer; scep_t.ias_getcrl->issuer = scep_t.ias_getcertinit->issuer; if (!(scep_t.ias_getcrl->serial = X509_get_serialNumber(cacert))) { fprintf(stderr, "%s: error getting serial " "for GetCertInitial\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_ERROR); } /* User supplied serial number */ if (s_flag) { BIGNUM *bn; ASN1_INTEGER *ai; int len = BN_dec2bn(&bn , s_char); if (!len || !(ai = BN_to_ASN1_INTEGER(bn, NULL))) { fprintf(stderr, "%s: error converting serial\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_SS); } scep_t.ias_getcert->serial = ai; } break; } switch(operation_flag) { case SCEP_OPERATION_ENROLL: if (v_flag) fprintf(stdout, "%s: SCEP_OPERATION_ENROLL\n", pname); /* Resum mode: set GetCertInitial */ if (R_flag) { if (n_num == 0) exit (SCEP_PKISTATUS_SUCCESS); printf("%s: requesting certificate (#1)\n", pname); scep_t.request_type = SCEP_REQUEST_GETCERTINIT; count++; } else { printf("%s: sending certificate request\n", pname); scep_t.request_type = SCEP_REQUEST_PKCSREQ; } break; case SCEP_OPERATION_GETCERT: if (v_flag) fprintf(stdout, "%s: SCEP_OPERATION_GETCERT\n", pname); scep_t.request_type = SCEP_REQUEST_GETCERT; printf("%s: requesting certificate\n",pname); break; case SCEP_OPERATION_GETCRL: if (v_flag) fprintf(stdout, "%s: SCEP_OPERATION_GETCRL\n", pname); scep_t.request_type = SCEP_REQUEST_GETCRL; printf("%s: requesting crl\n",pname); break; } /* Enter polling loop */ while (scep_t.pki_status != SCEP_PKISTATUS_SUCCESS) { /* create payload */ pkcs7_wrap(&scep_t); /* URL-encode */ p = url_encode((char *)scep_t.request_payload, scep_t.request_len); /*Test mode print SCEP request and don't send it*/ if(m_flag){ /* Write output file : */ #ifdef WIN32 if ((fopen_s(&fp, m_char, "w"))) #else if (!(fp = fopen(m_char, "w"))) #endif { fprintf(stderr, "%s: cannot open output file for " "writing\n", m_char); }else { printf("%s: writing PEM fomatted PKCS#7\n", pname); PEM_write_PKCS7(fp, scep_t.request_p7); } //printf("Print SCEP Request:\n %s\n",scep_t.request_payload); return 0; } /* Forge the HTTP message */ /* snprintf(http_string, sizeof(http_string), "GET %s%s?operation=" "PKIOperation&message=" "%s HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name, p);*/ if(!M_flag){ snprintf(http_string, sizeof(http_string), "GET %s%s?operation=PKIOperation&message=%s " "HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name, p); }else{ snprintf(http_string, sizeof(http_string), "GET %s%s?operation=PKIOperation&message=%s&%s " "HTTP/1.0\r\n\r\n", p_flag ? "" : "/", dir_name,p, M_char); } if (d_flag) fprintf(stdout, "%s: scep msg: %s", pname, http_string); /* send http */ reply.payload = NULL; if ((c = send_msg (&reply, http_string, host_name, host_port, operation_flag)) == 1) { fprintf(stderr, "%s: error while sending " "message\n", pname); exit (SCEP_PKISTATUS_NET); } /* Verisign Onsite returns strange reply... * XXXXXXXXXXXXXXXXXXX */ if ((reply.status == 200) && (reply.payload == NULL)) { /* scep_t.pki_status = SCEP_PKISTATUS_PENDING; break; */ exit (SCEP_PKISTATUS_ERROR); } printf("%s: valid response from server\n", pname); /* Check payload */ scep_t.reply_len = reply.bytes; scep_t.reply_payload = (unsigned char *)reply.payload; pkcs7_unwrap(&scep_t); pkistatus = scep_t.pki_status; switch(scep_t.pki_status) { case SCEP_PKISTATUS_SUCCESS: break; case SCEP_PKISTATUS_PENDING: /* Check time limits */ if (((t_num * count) >= T_num) || (count > n_num)) { exit (pkistatus); } scep_t.request_type = SCEP_REQUEST_GETCERTINIT; /* Wait for poll interval */ if (v_flag) printf("%s: waiting for %d secs\n", pname, t_num); sleep(t_num); printf("%s: requesting certificate " "(#%d)\n", pname, count); /* Add counter */ count++; break; case SCEP_PKISTATUS_FAILURE: /* Handle failure */ switch (scep_t.fail_info) { case SCEP_FAILINFO_BADALG: exit (SCEP_PKISTATUS_BADALG); case SCEP_FAILINFO_BADMSGCHK: exit (SCEP_PKISTATUS_BADMSGCHK); case SCEP_FAILINFO_BADREQ: exit (SCEP_PKISTATUS_BADREQ); case SCEP_FAILINFO_BADTIME: exit (SCEP_PKISTATUS_BADTIME); case SCEP_FAILINFO_BADCERTID: exit (SCEP_PKISTATUS_BADCERTID); /* Shouldn't be there... */ default: exit (SCEP_PKISTATUS_ERROR); } default: fprintf(stderr, "%s: unknown " "pkiStatus\n", pname); exit (SCEP_PKISTATUS_ERROR); } } /* We got SUCCESS, analyze the reply */ switch (scep_t.request_type) { /* Local certificate */ case SCEP_REQUEST_PKCSREQ: case SCEP_REQUEST_GETCERTINIT: write_local_cert(&scep_t); break; /* Other end entity certificate */ case SCEP_REQUEST_GETCERT: write_other_cert(&scep_t); break; break; /* CRL */ case SCEP_REQUEST_GETCRL: write_crl(&scep_t); break; } //TODO //richtiger ort für disable?? // if(e){ // ENGINE_finish(*e); // ENGINE_free(*e); // hwEngine = NULL; // ENGINE_cleanup(); // } // return (pkistatus); } void usage() { fprintf(stdout, "\nsscep version %s\n\n" , VERSION); fprintf(stdout, "Usage: %s OPERATION [OPTIONS]\n" "\nAvailable OPERATIONs are\n" " getca Get CA/RA certificate(s)\n" " getnextca Get next CA/RA certificate(s)\n" " enroll Enroll certificate\n" " getcert Query certificate\n" " getcrl Query CRL\n" "\nGeneral OPTIONS\n" " -u <url> SCEP server URL\n" " -p <host:port> Use proxy server at host:port\n" " -M <string> Monitor Information String name=value&name=value ...\n" " -g Enable Engine support\n" " -h Keyforme=ID. \n"//TODO " -f <file> Use configuration file\n" " -c <file> CA certificate file (write if OPERATION is getca or getnextca)\n" " -E <name> PKCS#7 encryption algorithm (des|3des|blowfish|aes)\n" " -S <name> PKCS#7 signature algorithm (md5|sha1)\n" " -v Verbose operation\n" " -d Debug (even more verbose operation)\n" "\nOPTIONS for OPERATION getca are\n" " -i <string> CA identifier string\n" " -F <name> Fingerprint algorithm\n" "\nOPTIONS for OPERATION getnextca are\n" " -C <file> Local certificate chain file for signature verification in PEM format \n" " -F <name> Fingerprint algorithm\n" " -c <file> CA certificate file (write if OPERATION is getca or getnextca)\n" " -w <file> Write signer certificate in file (optional) \n" "\nOPTIONS for OPERATION enroll are\n" " -k <file> Private key file\n" " -r <file> Certificate request file\n" " -K <file> Signature private key file, use with -O\n" " -O <file> Signature certificate (used instead of self-signed)\n" " -l <file> Write enrolled certificate in file\n" " -e <file> Use different CA cert for encryption\n" " -L <file> Write selfsigned certificate in file\n" " -t <secs> Polling interval in seconds\n" " -T <secs> Max polling time in seconds\n" " -n <count> Max number of GetCertInitial requests\n" " -R Resume interrupted enrollment\n" "\nOPTIONS for OPERATION getcert are\n" " -k <file> Private key file\n" " -l <file> Local certificate file\n" " -s <number> Certificate serial number\n" " -w <file> Write certificate in file\n" "\nOPTIONS for OPERATION getcrl are\n" " -k <file> Private key file\n" " -l <file> Local certificate file\n" " -w <file> Write CRL in file\n\n", pname); exit(0); }
static int sc_read_pubkey(Key * k) { u_char buf[2], *n; char *p; int len, sw, status = -1; len = sw = 0; n = NULL; if (sc_fd < 0) { if (sc_init() < 0) goto err; } /* get key size */ sectok_apdu(sc_fd, CLA_SSH, INS_GET_KEYLENGTH, 0, 0, 0, NULL, sizeof(buf), buf, &sw); if (!sectok_swOK(sw)) { error("could not obtain key length: %s", sectok_get_sw(sw)); goto err; } len = (buf[0] << 8) | buf[1]; len /= 8; debug("INS_GET_KEYLENGTH: len %d sw %s", len, sectok_get_sw(sw)); n = xmalloc(len); /* get n */ sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw); if (sw == 0x6982) { if (try_AUT0() < 0) goto err; sectok_apdu(sc_fd, CLA_SSH, INS_GET_PUBKEY, 0, 0, 0, NULL, len, n, &sw); } if (!sectok_swOK(sw)) { error("could not obtain public key: %s", sectok_get_sw(sw)); goto err; } debug("INS_GET_KEYLENGTH: sw %s", sectok_get_sw(sw)); if (BN_bin2bn(n, len, k->rsa->n) == NULL) { error("c_read_pubkey: BN_bin2bn failed"); goto err; } /* currently the java applet just stores 'n' */ if (!BN_set_word(k->rsa->e, 35)) { error("c_read_pubkey: BN_set_word(e, 35) failed"); goto err; } status = 0; p = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX); debug("fingerprint %u %s", key_size(k), p); xfree(p); err: if (n != NULL) xfree(n); sc_close(); return status; }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; int found_key = 0; FILE *f; u_long linenum = 0; struct stat st; Key *found; char *fp; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); /* Fail quietly if file does not exist */ if (stat(file, &st) < 0) { /* Restore the privileged uid. */ restore_uid(); return 0; } /* Open the file containing the authorized keys. */ f = fopen(file, "r"); if (!f) { /* Restore the privileged uid. */ restore_uid(); return 0; } if (options.strict_modes && secure_filename(f, file, pw, line, sizeof(line)) != 0) { fclose(f); logit("Authentication refused: %s", line); restore_uid(); return 0; } found_key = 0; found = key_new(key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_equal(found, key) && auth_parse_options(pw, key_options, file, linenum) == 1) { found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }
static int check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port, Key *host_key, int readonly, char **user_hostfiles, u_int num_user_hostfiles, char **system_hostfiles, u_int num_system_hostfiles) { HostStatus host_status; HostStatus ip_status; Key *raw_key = NULL; char *ip = NULL, *host = NULL; char hostline[1000], *hostp, *fp, *ra; char msg[1024]; char extramsg[1024], *subject = NULL; const char *type; const struct hostkey_entry *host_found, *ip_found; int len, cancelled_forwarding = 0; int local = sockaddr_is_local(hostaddr); int r, want_cert = key_is_cert(host_key), host_ip_differ = 0; struct hostkeys *host_hostkeys, *ip_hostkeys; u_int i; /* * Force accepting of the host key for loopback/localhost. The * problem is that if the home directory is NFS-mounted to multiple * machines, localhost will refer to a different machine in each of * them, and the user will get bogus HOST_CHANGED warnings. This * essentially disables host authentication for localhost; however, * this is probably not a real problem. */ if (options.no_host_authentication_for_localhost == 1 && local && options.host_key_alias == NULL) { debug("Forcing accepting of host key for " "loopback/localhost."); return 0; } /* * Prepare the hostname and address strings used for hostkey lookup. * In some cases, these will have a port number appended. */ get_hostfile_hostname_ipaddr(hostname, hostaddr, port, &host, &ip); /* * Turn off check_host_ip if the connection is to localhost, via proxy * command or if we don't have a hostname to compare with */ if (options.check_host_ip && (local || strcmp(hostname, ip) == 0 || options.proxy_command != NULL)) options.check_host_ip = 0; host_hostkeys = init_hostkeys(); for (i = 0; i < num_user_hostfiles; i++) load_hostkeys(host_hostkeys, host, user_hostfiles[i]); for (i = 0; i < num_system_hostfiles; i++) load_hostkeys(host_hostkeys, host, system_hostfiles[i]); ip_hostkeys = NULL; if (!want_cert && options.check_host_ip) { ip_hostkeys = init_hostkeys(); for (i = 0; i < num_user_hostfiles; i++) load_hostkeys(ip_hostkeys, ip, user_hostfiles[i]); for (i = 0; i < num_system_hostfiles; i++) load_hostkeys(ip_hostkeys, ip, system_hostfiles[i]); } retry: /* Reload these as they may have changed on cert->key downgrade */ want_cert = key_is_cert(host_key); type = key_type(host_key); /* * Check if the host key is present in the user's list of known * hosts or in the systemwide list. */ host_status = check_key_in_hostkeys(host_hostkeys, host_key, &host_found); /* * Also perform check for the ip address, skip the check if we are * localhost, looking for a certificate, or the hostname was an ip * address to begin with. */ if (!want_cert && ip_hostkeys != NULL) { ip_status = check_key_in_hostkeys(ip_hostkeys, host_key, &ip_found); if (host_status == HOST_CHANGED && (ip_status != HOST_CHANGED || (ip_found != NULL && !key_equal(ip_found->key, host_found->key)))) host_ip_differ = 1; } else ip_status = host_status; switch (host_status) { case HOST_OK: /* The host is known and the key matches. */ debug("Host '%.200s' is known and matches the %s host %s.", host, type, want_cert ? "certificate" : "key"); debug("Found %s in %s:%lu", want_cert ? "CA key" : "key", host_found->file, host_found->line); if (want_cert && !check_host_cert(hostname, host_key)) goto fail; if (options.check_host_ip && ip_status == HOST_NEW) { if (readonly || want_cert) logit("%s host key for IP address " "'%.128s' not in list of known hosts.", type, ip); else if (!add_host_to_hostfile(user_hostfiles[0], ip, host_key, options.hash_known_hosts)) logit("Failed to add the %s host key for IP " "address '%.128s' to the list of known " "hosts (%.30s).", type, ip, user_hostfiles[0]); else logit("Warning: Permanently added the %s host " "key for IP address '%.128s' to the list " "of known hosts.", type, ip); } else if (options.visual_host_key) { fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ra = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_RANDOMART); logit("Host key fingerprint is %s\n%s\n", fp, ra); xfree(ra); xfree(fp); } break; case HOST_NEW: if (options.host_key_alias == NULL && port != 0 && port != SSH_DEFAULT_PORT) { debug("checking without port identifier"); if (check_host_key(hostname, hostaddr, 0, host_key, ROQUIET, user_hostfiles, num_user_hostfiles, system_hostfiles, num_system_hostfiles) == 0) { debug("found matching key w/out port"); break; } } if (readonly || want_cert) goto fail; /* The host is new. */ if (options.strict_host_key_checking == 1) { /* * User has requested strict host key checking. We * will not add the host key automatically. The only * alternative left is to abort. */ error("No %s host key is known for %.200s and you " "have requested strict checking.", type, host); goto fail; } else if (options.strict_host_key_checking == 2) { char msg1[1024], msg2[1024]; if (show_other_keys(host_hostkeys, host_key)) snprintf(msg1, sizeof(msg1), "\nbut keys of different type are already" " known for this host."); else snprintf(msg1, sizeof(msg1), "."); /* The default */ fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX); ra = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_RANDOMART); msg2[0] = '\0'; if (options.verify_host_key_dns) { if (matching_host_key_dns) snprintf(msg2, sizeof(msg2), "Matching host key fingerprint" " found in DNS.\n"); else snprintf(msg2, sizeof(msg2), "No matching host key fingerprint" " found in DNS.\n"); } if (key_is_x509(host_key)) { subject = x509key_subject(host_key); snprintf(extramsg, sizeof(extramsg), "Distinguished name is '%s'.\n", subject); } else { subject = NULL; *extramsg = '\0'; } snprintf(msg, sizeof(msg), "The authenticity of host '%.200s (%s)' can't be " "established%s\n" "%s key fingerprint is %s.%s%s\n%s" "%s" "Are you sure you want to continue connecting " "(yes/no)? ", host, ip, msg1, type, fp, options.visual_host_key ? "\n" : "", options.visual_host_key ? ra : "", msg2, extramsg); if(subject != NULL) { xfree(subject); subject = NULL; } xfree(ra); xfree(fp); if (!confirm(msg)) goto fail; } /* * If not in strict mode, add the key automatically to the * local known_hosts file. */ if (options.check_host_ip && ip_status == HOST_NEW) { snprintf(hostline, sizeof(hostline), "%s,%s", host, ip); hostp = hostline; if (options.hash_known_hosts) { /* Add hash of host and IP separately */ r = add_host_to_hostfile(user_hostfiles[0], host, host_key, options.hash_known_hosts) && add_host_to_hostfile(user_hostfiles[0], ip, host_key, options.hash_known_hosts); } else { /* Add unhashed "host,ip" */ r = add_host_to_hostfile(user_hostfiles[0], hostline, host_key, options.hash_known_hosts); } } else { r = add_host_to_hostfile(user_hostfiles[0], host, host_key, options.hash_known_hosts); hostp = host; } if (!r) logit("Failed to add the host to the list of known " "hosts (%.500s).", user_hostfiles[0]); else logit("Warning: Permanently added '%.200s' (%s) to the " "list of known hosts.", hostp, type); break; case HOST_REVOKED: error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: REVOKED HOST KEY DETECTED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("The %s host key for %s is marked as revoked.", type, host); error("This could mean that a stolen key is being used to"); error("impersonate this host."); /* * If strict host key checking is in use, the user will have * to edit the key manually and we can only abort. */ if (options.strict_host_key_checking) { error("%s host key for %.200s was revoked and you have " "requested strict checking.", type, host); goto fail; } goto continue_unsafe; case HOST_CHANGED: if (want_cert) { /* * This is only a debug() since it is valid to have * CAs with wildcard DNS matches that don't match * all hosts that one might visit. */ debug("Host certificate authority does not " "match %s in %s:%lu", CA_MARKER, host_found->file, host_found->line); goto fail; } if (readonly == ROQUIET) goto fail; if (options.check_host_ip && host_ip_differ) { const char *key_msg; if (ip_status == HOST_NEW) key_msg = "is unknown"; else if (ip_status == HOST_OK) key_msg = "is unchanged"; else key_msg = "has a different value"; error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @"); error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("The %s host key for %s has changed,", type, host); error("and the key for the corresponding IP address %s", ip); error("%s. This could either mean that", key_msg); error("DNS SPOOFING is happening or the IP address for the host"); error("and its host key have changed at the same time."); if (ip_status != HOST_NEW) error("Offending key for IP in %s:%lu", ip_found->file, ip_found->line); } /* The host key has changed. */ warn_changed_key(host_key); error("Add correct host key in %.100s to get rid of this message.", user_hostfiles[0]); error("Offending %s key in %s:%lu", key_type(host_found->key), host_found->file, host_found->line); /* * If strict host key checking is in use, the user will have * to edit the key manually and we can only abort. */ if (options.strict_host_key_checking) { error("%s host key for %.200s has changed and you have " "requested strict checking.", type, host); goto fail; } continue_unsafe: /* * If strict host key checking has not been requested, allow * the connection but without MITM-able authentication or * forwarding. */ if (options.password_authentication) { error("Password authentication is disabled to avoid " "man-in-the-middle attacks."); options.password_authentication = 0; cancelled_forwarding = 1; } if (options.kbd_interactive_authentication) { error("Keyboard-interactive authentication is disabled" " to avoid man-in-the-middle attacks."); options.kbd_interactive_authentication = 0; options.challenge_response_authentication = 0; cancelled_forwarding = 1; } if (options.challenge_response_authentication) { error("Challenge/response authentication is disabled" " to avoid man-in-the-middle attacks."); options.challenge_response_authentication = 0; cancelled_forwarding = 1; } if (options.forward_agent) { error("Agent forwarding is disabled to avoid " "man-in-the-middle attacks."); options.forward_agent = 0; cancelled_forwarding = 1; } if (options.forward_x11) { error("X11 forwarding is disabled to avoid " "man-in-the-middle attacks."); options.forward_x11 = 0; cancelled_forwarding = 1; } if (options.num_local_forwards > 0 || options.num_remote_forwards > 0) { error("Port forwarding is disabled to avoid " "man-in-the-middle attacks."); options.num_local_forwards = options.num_remote_forwards = 0; cancelled_forwarding = 1; } if (options.tun_open != SSH_TUNMODE_NO) { error("Tunnel forwarding is disabled to avoid " "man-in-the-middle attacks."); options.tun_open = SSH_TUNMODE_NO; cancelled_forwarding = 1; } if (options.exit_on_forward_failure && cancelled_forwarding) fatal("Error: forwarding disabled due to host key " "check failure"); /* * XXX Should permit the user to change to use the new id. * This could be done by converting the host key to an * identifying sentence, tell that the host identifies itself * by that sentence, and ask the user if he/she wishes to * accept the authentication. */ break; case HOST_FOUND: fatal("internal error"); break; } if (options.check_host_ip && host_status != HOST_CHANGED && ip_status == HOST_CHANGED) { snprintf(msg, sizeof(msg), "Warning: the %s host key for '%.200s' " "differs from the key for the IP address '%.128s'" "\nOffending key for IP in %s:%lu", type, host, ip, ip_found->file, ip_found->line); if (host_status == HOST_OK) { len = strlen(msg); snprintf(msg + len, sizeof(msg) - len, "\nMatching host key in %s:%lu", host_found->file, host_found->line); } if (options.strict_host_key_checking == 1) { logit("%s", msg); error("Exiting, you have requested strict checking."); goto fail; } else if (options.strict_host_key_checking == 2) { strlcat(msg, "\nAre you sure you want " "to continue connecting (yes/no)? ", sizeof(msg)); if (!confirm(msg)) goto fail; } else { logit("%s", msg); } } xfree(ip); xfree(host); if (host_hostkeys != NULL) free_hostkeys(host_hostkeys); if (ip_hostkeys != NULL) free_hostkeys(ip_hostkeys); return 0; fail: if (want_cert && host_status != HOST_REVOKED) { /* * No matching certificate. Downgrade cert to raw key and * search normally. */ debug("No matching CA found. Retry with plain key"); raw_key = key_from_private(host_key); if (key_drop_cert(raw_key) != 0) fatal("Couldn't drop certificate"); host_key = raw_key; goto retry; } if (raw_key != NULL) key_free(raw_key); xfree(ip); xfree(host); if (host_hostkeys != NULL) free_hostkeys(host_hostkeys); if (ip_hostkeys != NULL) free_hostkeys(ip_hostkeys); return -1; }
/** * Checks whether or not access is allowed based on a plugin specified * in sshd_config (PubKeyPlugin). * * Note that this expects a symbol in the loaded library that takes * the current user (pwd entry), the current RSA key and it's fingerprint. * The symbol is expected to return 1 on success and 0 on failure. * * While we could optimize this code to dlopen once in the process' lifetime, * sshd is already a slow beast, so this is really not a concern. * The overhead is basically a rounding error compared to everything else, and * it keeps this code minimally invasive. */ static int user_key_allowed_from_plugin(struct passwd *pw, Key *key) { RSA_SYM rsa_sym = NULL; DSA_SYM dsa_sym = NULL; char *fp = NULL; void *handle = NULL; int success = 0; if (options.pubkey_plugin == NULL || pw == NULL || key == NULL || (key->type != KEY_RSA && key->type != KEY_RSA1 && key->type != KEY_DSA && key->type != KEY_ECDSA)) return success; handle = dlopen(options.pubkey_plugin, RTLD_NOW); if ((handle == NULL)) { debug("Unable to open library %s: %s", options.pubkey_plugin, dlerror()); goto out; } fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (fp == NULL) { debug("failed to generate fingerprint"); goto out; } switch (key->type) { case KEY_RSA1: case KEY_RSA: rsa_sym = (RSA_SYM)dlsym(handle, RSA_SYM_NAME); if (rsa_sym == NULL) { debug("Unable to resolve symbol %s: %s", RSA_SYM_NAME, dlerror()); goto out; } debug2("Invoking %s from %s", RSA_SYM_NAME, options.pubkey_plugin); success = (*rsa_sym)(pw, key->rsa, fp); break; case KEY_DSA: case KEY_ECDSA: dsa_sym = (DSA_SYM)dlsym(handle, RSA_SYM_NAME); if (dsa_sym == NULL) { debug("Unable to resolve symbol %s: %s", DSA_SYM_NAME, dlerror()); goto out; } debug2("Invoking %s from %s", DSA_SYM_NAME, options.pubkey_plugin); success = (*dsa_sym)(pw, key->dsa, fp); break; default: debug2("user_key_plugins only support RSA keys"); } debug("sshd_plugin returned: %d", success); out: if (handle != NULL) { dlclose(handle); dsa_sym = NULL; rsa_sym = NULL; handle = NULL; } if (success) verbose("Found matching %s key: %s", key_type(key), fp); if (fp != NULL) { xfree(fp); fp = NULL; } return success; }
static int sc_read_pubkey(Key * k, const struct sc_pkcs15_object *cert_obj) { int r; sc_pkcs15_cert_t *cert = NULL; struct sc_priv_data *priv = NULL; sc_pkcs15_cert_info_t *cinfo = cert_obj->data; X509 *x509 = NULL; EVP_PKEY *pubkey = NULL; u8 *p; char *tmp; debug("sc_read_pubkey() with cert id %02X", cinfo->id.value[0]); r = sc_pkcs15_read_certificate(p15card, cinfo, &cert); if (r) { logit("Certificate read failed: %s", sc_strerror(r)); goto err; } x509 = X509_new(); if (x509 == NULL) { r = -1; goto err; } p = cert->data; if (!d2i_X509(&x509, &p, cert->data_len)) { logit("Unable to parse X.509 certificate"); r = -1; goto err; } sc_pkcs15_free_certificate(cert); cert = NULL; pubkey = X509_get_pubkey(x509); X509_free(x509); x509 = NULL; if (pubkey->type != EVP_PKEY_RSA) { logit("Public key is of unknown type"); r = -1; goto err; } k->rsa = EVP_PKEY_get1_RSA(pubkey); EVP_PKEY_free(pubkey); k->rsa->flags |= RSA_FLAG_SIGN_VER; RSA_set_method(k->rsa, sc_get_rsa_method()); priv = xmalloc(sizeof(struct sc_priv_data)); priv->cert_id = cinfo->id; priv->ref_count = 1; RSA_set_app_data(k->rsa, priv); k->flags = KEY_FLAG_EXT; tmp = key_fingerprint(k, SSH_FP_MD5, SSH_FP_HEX); debug("fingerprint %d %s", key_size(k), tmp); xfree(tmp); return 0; err: if (cert) sc_pkcs15_free_certificate(cert); if (pubkey) EVP_PKEY_free(pubkey); if (x509) X509_free(x509); return r; }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; Key *found; char *fp; /* Temporarily use the user's uid. */ temporarily_use_uid(pw); debug("trying public key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { restore_uid(); return 0; } found_key = 0; found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (!key_is_cert_authority) continue; fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (authorized_principals != NULL && !match_principals_option(authorized_principals, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: xfree(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } if (key_cert_check_authority(key, 0, 0, authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw) != 0) { xfree(fp); continue; } verbose("Accepted certificate ID \"%s\" " "signed by %s CA %s via %s", key->cert->key_id, key_type(found), fp, file); xfree(fp); found_key = 1; break; } else if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (key_is_cert_authority) continue; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }
int main(int argc, char *argv[]) { int c, poll = 0, reqversion = 0, rc = -1; char *cacertfile = NULL, *keyfile = NULL, *challenge = NULL, *savedrequestfile = NULL, *requestfile = NULL, *dn = NULL, *spkacfile = NULL, *endrequest = NULL; scep_t scep; BIO *repbio; char *url = "http://localhost/cgi-bin"; scepmsg_t *msg; unsigned char *checkNonce = NULL; /* initialize what you can */ scepinit(); scep_clear(&scep); /* we are a client */ scep.client = 1; /* parse command line */ while (EOF != (c = getopt(argc, argv, "dc:e:r:s:k:w:pu:2a:q:"))) switch (c) { case 'd': debug++; break; case 'e': endrequest = optarg; break; case 'c': cacertfile = optarg; break; case 's': savedrequestfile = optarg; case 'r': /* the request file will also contain the self */ /* signed certificate */ requestfile = optarg; break; case 'k': keyfile = optarg; break; case 'w': challenge = optarg; break; case 'p': poll = 1; break; case 'q': scep.community = optarg; break; case 'u': url = optarg; break; case '2': reqversion = 1; break; case 'a': spkacfile = optarg; break; } /* stop immediately if request or key is missing */ /* (even in the case of a version 2 proxied request, we need */ /* a request as the carrier of the proxy entities public key) */ if (keyfile == NULL) { BIO_printf(bio_err, "%s:%d: key file is required argument\n", __FILE__, __LINE__); goto err; } if (requestfile == NULL) { BIO_printf(bio_err, "%s:%d: request file is required " "argument\n", __FILE__, __LINE__); goto err; } /* we are preparing the request message */ msg = &scep.request; /* decode the URL */ if (parseurl(&scep, url) < 0) { BIO_printf(bio_err, "%s:%d: cannot parse url\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: decoded URL %s|%d|%s\n", __FILE__, __LINE__, scep.h.httphost, scep.h.httpport, scep.h.httppath); /* read the client key and request information */ if (read_clientstuff(&scep, requestfile, keyfile) < 0) { BIO_printf(bio_err, "%s:%d: failed to read client stuff\n", __FILE__, __LINE__); goto err; } /* now we have to decide about the payload we want to have */ /* with our scep request: */ /* - for a version 1 request, this will always be the original */ /* certificate signing request */ /* - for a version 2 request, it will be a payload structure */ switch (reqversion) { case 0: /* for a version 1 client, client pubkey and client req */ /* coincide */ scep.requestorpubkey = scep.clientpubkey; scep.requestorreq = scep.clientreq; if (debug) BIO_printf(bio_err, "%s:%d: end request coincides " "with SCEP client\n", __FILE__, __LINE__); break; case 1: msg->rd.payload = payload_new(); rc = -1; if (spkacfile) { if (debug) BIO_printf(bio_err, "%s:%d: reading spki " "from %s\n", __FILE__, __LINE__, spkacfile); rc = read_requestorstuff(&scep, 1, spkacfile); } else if (endrequest) { if (debug) BIO_printf(bio_err, "%s:%d: reading X509 req " "from %s\n", __FILE__, __LINE__, endrequest); rc = read_requestorstuff(&scep, 0, endrequest); } if (rc < 0) { BIO_printf(bio_err, "%s:%d: could not read end " "request data\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: end request read\n", __FILE__, __LINE__); break; } /* set the transaction id value */ scep.transId = key_fingerprint(scep.requestorpubkey); if (debug) BIO_printf(bio_err, "%s:%d: transaction ID is %s\n", __FILE__, __LINE__, scep.transId); /* read the CA certificate file */ if (read_castuff(&scep, cacertfile) < 0) { BIO_printf(bio_err, "%s:%d: read CA certificate info\n", __FILE__, __LINE__); } if (debug) BIO_printf(bio_err, "%s:%d: CA certificate read\n", __FILE__, __LINE__); /* for SPKI requests, there should be exactly one more argument */ /* namely the distinguished name */ if (spkacfile) { if ((argc - optind) != 1) { BIO_printf(bio_err, "%s:%d: DN argument needed\n", __FILE__, __LINE__); goto err; } dn = argv[optind]; if (debug) BIO_printf(bio_err, "%s:%d: DN argument is '%s'\n", __FILE__, __LINE__, dn); /* convert the DN into attributes and add them to the */ /* payload */ if (payload_dn_to_attrs(msg->rd.payload, dn) < 0) { BIO_printf(bio_err, "%s:%d: failed to add DN attrs\n", __FILE__, __LINE__); goto err; } } /* skip creation of a request message when polling */ if (poll) goto pollinginit; /* pack the request as a PKSCReq message, of type PKCSReq */ switch (reqversion) { case 0: msg->messageType = SCEP_MESSAGE_TYPE_PKCSREQ; msg->rd.req = scep.clientreq; break; case 1: /* build a version 2 payload */ if (debug) BIO_printf(bio_err, "%s:%d: building version 2 " "payload\n", __FILE__, __LINE__); if (scep.requestorreq) payload_set_req(msg->rd.payload, scep.requestorreq); if (scep.requestorspki) payload_set_spki(msg->rd.payload, scep.requestorspki); /* set the correct message type */ if (scep.community) { /* compute the authenticator from the original */ /* request and the community */ msg->messageType = SCEP_MESSAGE_TYPE_V2PROXY; } else { msg->messageType = SCEP_MESSAGE_TYPE_V2REQUEST; } break; } /* write the request to the request file, for later perusal */ if (savedrequestfile) { BIO *reqbio; reqbio = BIO_new(BIO_s_file()); BIO_write_filename(reqbio, savedrequestfile); switch (reqversion) { case 0: /* version 1 request has a X509_REQ payload */ PEM_write_bio_X509_REQ(reqbio, msg->rd.req); break; case 1: /* version 2 requests have a "real" payload */ i2d_payload_bio(reqbio, msg->rd.payload); break; } BIO_free(reqbio); } goto common; pollinginit: /* when polling, the request is a GetCertInitial message */ msg->messageType = SCEP_MESSAGE_TYPE_GETCERTINITIAL; /* the contents is the pair issuer and subject */ msg->rd.is = (issuer_and_subject_t *)malloc( sizeof(issuer_and_subject_t)); msg->rd.is->issuer = X509_get_subject_name(scep.cacert); msg->rd.is->subject = NULL; /* when polling we should read the request from request file */ /* (only needed for the distinguished name of the client) */ if (debug) BIO_printf(bio_err, "%s:%d: getting subject X509_NAME\n", __FILE__, __LINE__); switch (reqversion) { case 0: msg->rd.is->subject = X509_REQ_get_subject_name(scep.clientreq); break; case 1: if (scep.requestorreq) msg->rd.is->subject = X509_REQ_get_subject_name(scep.requestorreq); if (scep.requestorspki) { if (debug) BIO_printf(bio_err, "%s:%d: converting DN '%s' " "to X509_NAME\n", __FILE__, __LINE__, dn); msg->rd.is->subject = ldap_to_x509(dn); } break; } if (msg->rd.is->subject == NULL) { BIO_printf(bio_err, "%s:%d: no subject found\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: issuer and subject found\n", __FILE__, __LINE__); common: /* create a self signed certificate for use with SCEP */ if (selfsigned(&scep) < 0) { BIO_printf(bio_err, "%s:%d: failed to create self signed " "certificate\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: self signed certificate created\n", __FILE__, __LINE__); /* set the senderNonce */ scep.senderNonceLength = 16; scep.senderNonce = (unsigned char *)malloc(scep.senderNonceLength); RAND_bytes(scep.senderNonce, scep.senderNonceLength); if (debug) BIO_printf(bio_err, "%s:%d: senderNonce set\n", __FILE__, __LINE__); checkNonce = scep.senderNonce; /* all messages sent from the client are base 64 encoded */ msg->base64 = 1; /* encode */ if (encode(&scep) < 0) { BIO_printf(bio_err, "%s:%d: encoding the request failed\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: encoded bytes: %d\n", __FILE__, __LINE__, scep.request.length); /* send the request to the server, read the reply */ repbio = getrequest(&scep); if (repbio == NULL) { BIO_printf(bio_err, "%s:%d: failed to read correct reply\n", __FILE__, __LINE__); goto err; } /* analyze the reply */ if (decode(&scep, repbio) < 0) { BIO_printf(bio_err, "%s:%d: decoding the reply failed\n", __FILE__, __LINE__); goto err; } /* display some information about the reply */ printf("transaction id: %s\n", scep.transId); printf("PKIstatus: %s\n", (scep.reply.pkiStatus) ? scep.reply.pkiStatus : "(null)"); printf("reply message type: %s\n", scep.reply.messageType); if (scep.reply.failinfo) { printf("failinfo: %s\n", scep.reply.failinfo); } /* make sure we get a CertRep message back */ if (strcmp(scep.reply.messageType, SCEP_MESSAGE_TYPE_CERTREP)) { BIO_printf(bio_err, "%s:%d: only CertRep message acceptable " " in response to PKCSReq/GetCertInitial\n", __FILE__, __LINE__); goto err; } /* check for the Nonces */ if (memcmp(checkNonce, scep.recipientNonce, 16)) { BIO_printf(bio_err, "%s:%d: recipientNonce != sent " "senderNonce\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: Nonce check OK\n", __FILE__, __LINE__); if (scep.reply.pkiStatus == NULL) { BIO_printf(bio_err, "no pkiStatus returned\n"); exit(1); } switch (atoi(scep.reply.pkiStatus)) { case PKI_SUCCESS: /* Success */ scep.clientcert = extract_cert(&scep); if (debug) BIO_printf(bio_err, "%s:%d: certificate returned %p\n", __FILE__, __LINE__, scep.clientcert); if (scep.clientcert) { BIO *cb; cb = BIO_new(BIO_s_file()); BIO_set_fp(cb, stdout, BIO_NOCLOSE); PEM_write_bio_X509(cb, scep.clientcert); BIO_free(cb); } exit(EXIT_SUCCESS); break; case PKI_FAILURE: /* Failure */ if (debug) BIO_printf(bio_err, "%s:%d: request failed: %s\n", __FILE__, __LINE__, scep.reply.failinfo); exit(1); break; case PKI_PENDING: /* Pending */ if (debug) BIO_printf(bio_err, "%s:%d: request still pending\n", __FILE__, __LINE__); exit(2); break; } /* error return */ err: ERR_print_errors(bio_err); exit(EXIT_FAILURE); }
/* return 1 if user allows given key */ static int user_key_allowed2(struct passwd *pw, Key *key, char *file) { char line[SSH_MAX_PUBKEY_BYTES]; const char *reason; int found_key = 0; FILE *f; u_long linenum = 0; Key *found; char *fp; #ifdef WITH_LDAP_PUBKEY ldap_key_t * k; unsigned int i = 0; #endif /* Temporarily use the user's uid. */ temporarily_use_uid(pw); #ifdef WITH_LDAP_PUBKEY found_key = 0; /* allocate a new key type */ found = key_new(key->type); /* first check if the options is enabled, then try.. */ if (options.lpk.on) { debug("[LDAP] trying LDAP first uid=%s",pw->pw_name); if (ldap_ismember(&options.lpk, pw->pw_name) > 0) { if ((k = ldap_getuserkey(&options.lpk, pw->pw_name)) != NULL) { /* Skip leading whitespace, empty and comment lines. */ for (i = 0 ; i < k->num ; i++) { /* dont forget if multiple keys to reset options */ char *cp, *xoptions = NULL; for (cp = (char *)k->keys[i]->bv_val; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("[LDAP] user_key_allowed: check options: '%s'", cp); xoptions = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("[LDAP] user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_equal(found, key) && auth_parse_options(pw, xoptions, file, linenum) == 1) { found_key = 1; debug("[LDAP] matching key found"); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("[LDAP] Found matching %s key: %s", key_type(found), fp); /* restoring memory */ ldap_keys_free(k); xfree(fp); restore_uid(); key_free(found); return found_key; break; } }/* end of LDAP for() */ } else { logit("[LDAP] no keys found for '%s'!", pw->pw_name); } } else { logit("[LDAP] '%s' is not in '%s'", pw->pw_name, options.lpk.sgroup); } } #endif debug("trying public key file %s", file); f = auth_openkeyfile(file, pw, options.strict_modes); if (!f) { restore_uid(); return 0; } found_key = 0; found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (!key_is_cert_authority) continue; fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (authorized_principals != NULL && !match_principals_option(authorized_principals, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: xfree(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } if (key_cert_check_authority(key, 0, 0, authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw) != 0) { xfree(fp); continue; } verbose("Accepted certificate ID \"%s\" " "signed by %s CA %s via %s", key->cert->key_id, key_type(found), fp, file); xfree(fp); found_key = 1; break; } else if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (key_is_cert_authority) continue; found_key = 1; debug("matching key found: file %s, line %lu", file, linenum); fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); verbose("Found matching %s key: %s", key_type(found), fp); xfree(fp); break; } } restore_uid(); fclose(f); key_free(found); if (!found_key) debug2("key not found"); return found_key; }
void input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt) { Authctxt *authctxt = ctxt; Key *key = NULL; Buffer b; int pktype, sent = 0; u_int alen, blen; char *pkalg, *fp; u_char *pkblob; if (authctxt == NULL) fatal("input_userauth_pk_ok: no authentication context"); if (datafellows & SSH_BUG_PKOK) { /* this is similar to SSH_BUG_PKAUTH */ debug2("input_userauth_pk_ok: SSH_BUG_PKOK"); pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } packet_check_eom(); debug("Server accepts key: pkalg %s blen %u lastkey %p hint %d", pkalg, blen, authctxt->last_key, authctxt->last_key_hint); do { if (authctxt->last_key == NULL || authctxt->last_key_sign == NULL) { debug("no last key or no sign cb"); break; } if ((pktype = key_type_from_name(pkalg)) == KEY_UNSPEC) { debug("unknown pkalg %s", pkalg); break; } if ((key = key_from_blob(pkblob, blen)) == NULL) { debug("no key from blob. pkalg %s", pkalg); break; } if (key->type != pktype) { error("input_userauth_pk_ok: type mismatch " "for decoded key (received %d, expected %d)", key->type, pktype); break; } fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); debug2("input_userauth_pk_ok: fp %s", fp); xfree(fp); if (!key_equal(key, authctxt->last_key)) { debug("key != last_key"); break; } sent = sign_and_send_pubkey(authctxt, key, authctxt->last_key_sign); } while (0); if (key != NULL) key_free(key); xfree(pkalg); xfree(pkblob); /* unregister */ clear_auth_state(authctxt); dispatch_set(SSH2_MSG_USERAUTH_PK_OK, NULL); /* try another method if we did not send a packet */ if (sent == 0) userauth(authctxt, NULL); }
static int rsa_key_allowed_in_file(struct passwd *pw, char *file, const BIGNUM *client_n, Key **rkey) { char line[SSH_MAX_PUBKEY_BYTES]; int allowed = 0; u_int bits; FILE *f; u_long linenum = 0; Key *key; debug("trying public RSA key file %s", file); if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL) return 0; /* * Go though the accepted keys, looking for the current key. If * found, perform a challenge-response dialog to verify that the * user really has the corresponding private key. */ key = key_new(KEY_RSA1); while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp; char *key_options; int keybits; char *fp; /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; /* * Check if there are options for this key, and if so, * save their starting address and skip the option part * for now. If there are no options, set the starting * address to NULL. */ if (*cp < '0' || *cp > '9') { int quoted = 0; key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } } else key_options = NULL; /* Parse the key from the line. */ if (hostfile_read_key(&cp, &bits, key) == 0) { debug("%.100s, line %lu: non ssh1 key syntax", file, linenum); continue; } /* cp now points to the comment part. */ /* * Check if the we have found the desired key (identified * by its modulus). */ if (BN_cmp(key->rsa->n, client_n) != 0) continue; /* check the real bits */ keybits = BN_num_bits(key->rsa->n); if (keybits < 0 || bits != (u_int)keybits) logit("Warning: %s, line %lu: keysize mismatch: " "actual %d vs. announced %d.", file, linenum, BN_num_bits(key->rsa->n), bits); /* Never accept a revoked key */ if (auth_key_is_revoked(key)) break; if (blacklisted_key(key)) { fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX); if (options.permit_blacklisted_keys) logit("Public key %s blacklisted (see " "ssh-vulnkey(1)); continuing anyway", fp); else logit("Public key %s blacklisted (see " "ssh-vulnkey(1))", fp); xfree(fp); if (!options.permit_blacklisted_keys) continue; } /* We have found the desired key. */ /* * If our options do not allow this key to be used, * do not send challenge. */ if (!auth_parse_options(pw, key_options, file, linenum)) continue; if (key_is_cert_authority) continue; /* break out, this key is allowed */ allowed = 1; break; } /* Close the file. */ fclose(f); /* return key if allowed */ if (allowed && rkey != NULL) *rkey = key; else key_free(key); return allowed; }