void pki_pkcs7::writeP7(XFile &file, bool PEM) const { if (!p7) return; if (PEM) PEM_write_PKCS7(file.fp(), p7); else i2d_PKCS7_fp(file.fp(), p7); openssl_error(); }
static int wdsheader(struct dm_buf *hdr, char *src, char *device, char **pkg, PKCS7 *sig) { FILE *fp; char path[PATH_MAX], tmp_entry[ENTRY_MAX], tmp_file[L_tmpnam+1]; char srcpath[PATH_MAX]; int i, n; int list_fd; int block_cnt; int len; char cwd[MAXPATHLEN + 1]; boolean_t making_sig = B_FALSE; making_sig = (sig != NULL) ? B_TRUE : B_FALSE; (void) ds_close(0); if (dstdev.pathname) ds_fd = creat(device, 0644); else ds_fd = open(device, 1); if (ds_fd < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), device, errno); return (1); } if (ds_ginit(device) < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_OPEN), device, errno); (void) ds_close(0); return (1); } /* * The loop below assures compatibility with tapes that don't * have a block size (e.g.: Exabyte) by forcing EOR at the end * of each 512 bytes. */ for (block_cnt = 0; block_cnt < hdr->allocation; block_cnt += BLK_SIZE) { (void) write(ds_fd, (hdr->text_buffer + block_cnt), BLK_SIZE); } /* * write the first cpio() archive to the datastream * which should contain the pkginfo & pkgmap files * for all packages */ (void) tmpnam(tmp_file); /* temporary file name */ if ((list_fd = open(tmp_file, O_RDWR | O_CREAT, 0644)) == -1) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); return (1); } /* * Create a cpio-compatible list of the requisite files in * the temporary file. */ if (!making_sig) { for (i = 0; pkg[i]; i++) { register ssize_t entry_size; /* * Copy pkginfo and pkgmap filenames into the * temporary string allowing for the first line * as a special case. */ entry_size = sprintf(tmp_entry, (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", pkg[i], PKGINFO, pkg[i], PKGMAP); if (write(list_fd, tmp_entry, entry_size) != entry_size) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); (void) close(list_fd); ecleanup(); return (1); } } } else { register ssize_t entry_size; /* * if we're making a signature, we must make a * temporary area full of symlinks to the requisite * files, plus an extra entry for the signature, so * that cpio will put all files and signature in the * same archive in a single invocation of cpio. */ tmpsymdir = xstrdup(tmpnam(NULL)); if (mkdir(tmpsymdir, S_IRWXU)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), tmpsymdir); return (1); } /* generate the signature */ if (((len = snprintf(path, PATH_MAX, "%s/%s", tmpsymdir, SIGNATURE_FILENAME)) >= PATH_MAX) || len < 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmpsymdir); cleanup(); return (1); } if ((fp = fopen(path, "w")) == NULL) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), path); cleanup(); return (1); } (void) PEM_write_PKCS7(fp, sig); (void) fclose(fp); for (i = 0; pkg[i]; i++) { (void) snprintf(path, sizeof (path), "%s/%s", tmpsymdir, pkg[i]); if (mkdir(path, 0755)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_MKDIR), path); cleanup(); return (1); } (void) snprintf(path, sizeof (path), "%s/%s/%s", tmpsymdir, pkg[i], PKGINFO); (void) snprintf(srcpath, sizeof (srcpath), "%s/%s/%s", src, pkg[i], PKGINFO); if (symlink(srcpath, path) != 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SYMLINK), path, srcpath); cleanup(); return (1); } (void) snprintf(path, sizeof (path), "%s/%s/%s", tmpsymdir, pkg[i], PKGMAP); (void) snprintf(srcpath, sizeof (srcpath), "%s/%s/%s", src, pkg[i], PKGMAP); if (symlink(srcpath, path) != 0) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_SYMLINK), path, srcpath); cleanup(); return (1); } /* * Copy pkginfo and pkgmap filenames into the * temporary string allowing for the first line * as a special case. */ entry_size = snprintf(tmp_entry, sizeof (tmp_entry), (i == 0) ? "%s/%s\n%s/%s" : "\n%s/%s\n%s/%s", pkg[i], PKGINFO, pkg[i], PKGMAP); if (write(list_fd, tmp_entry, entry_size) != entry_size) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); (void) close(list_fd); ecleanup(); cleanup(); return (1); } } /* add signature to list of files */ entry_size = snprintf(tmp_entry, sizeof (tmp_entry), "\n%s", SIGNATURE_FILENAME); if (write(list_fd, tmp_entry, entry_size) != entry_size) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_NOTMPFIL), tmp_file); (void) close(list_fd); ecleanup(); cleanup(); return (1); } } (void) lseek(list_fd, 0, SEEK_SET); if (!making_sig) { (void) snprintf(tmp_entry, sizeof (tmp_entry), "%s -ocD -C %d", CPIOPROC, (int)BLK_SIZE); } else { /* * when making a signature, we must make sure to follow * symlinks during the cpio so that we don't archive * the links themselves */ (void) snprintf(tmp_entry, sizeof (tmp_entry), "%s -ocDL -C %d", CPIOPROC, (int)BLK_SIZE); } if (making_sig) { /* save cwd and change to symlink dir for cpio invocation */ if (getcwd(cwd, MAXPATHLEN + 1) == NULL) { logerr(pkg_gt(ERR_GETWD)); progerr(pkg_gt(ERR_TRANSFER)); cleanup(); return (1); } if (chdir(tmpsymdir)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), tmpsymdir); cleanup(); return (1); } } if (n = esystem(tmp_entry, list_fd, ds_fd)) { rpterr(); progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CMDFAIL), tmp_entry, n); (void) close(list_fd); (void) unlink(tmp_file); cleanup(); return (1); } (void) close(list_fd); (void) unlink(tmp_file); if (making_sig) { /* change to back to src dir for subsequent operations */ if (chdir(cwd)) { progerr(pkg_gt(ERR_TRANSFER)); logerr(pkg_gt(MSG_CHDIR), cwd); cleanup(); return (1); } } return (0); }
/* * Wrap data in PKCS#7 envelopes and base64-encode the result. * Data is PKCS#10 request in PKCSReq, or pkcs7_issuer_and_subject * structure in GetCertInitial and PKCS7_ISSUER_AND_SERIAL in * GetCert and GETCrl. */ int pkcs7_wrap(struct scep *s, struct sscep_ctx *ctx, struct sscep_operation_info *op_info) { BIO *databio = NULL; BIO *encbio = NULL; BIO *pkcs7bio = NULL; BIO *memorybio = NULL; BIO *outbio = NULL; unsigned char *buffer = NULL; int len = 0; STACK_OF(X509) *recipients = NULL; PKCS7 *p7enc = NULL; PKCS7_SIGNER_INFO *si; STACK_OF(X509_ATTRIBUTE) *attributes; X509 *signercert = NULL; EVP_PKEY *signerkey = NULL; int ret = SCEP_PKISTATUS_P7; char *payload = NULL; int payload_len; /* Create a new sender nonce for all messages * XXXXXXXXXXXXXX should it be per transaction? */ s->sender_nonce_len = 16; free(s->sender_nonce);/* Clean up from previous runs */ s->sender_nonce = (char *)malloc(s->sender_nonce_len * sizeof(char)); RAND_bytes((unsigned char *) s->sender_nonce, s->sender_nonce_len); /* Prepare data payload */ switch (s->request_type) { case SCEP_REQUEST_PKCSREQ: /* * Set printable message type * We set this later as an autheticated attribute * "messageType". */ s->request_type_str = SCEP_REQUEST_PKCSREQ_STR; /* Signer cert */ signercert = s->signercert; signerkey = s->signerkey; /* Create inner PKCS#7 */ if (ctx->verbose){ qeo_log_i("creating inner PKCS#7"); } /* Read request in memory bio */ databio = BIO_new(BIO_s_mem()); if (i2d_X509_REQ_bio(databio, op_info->request) <= 0) { qeo_log_e("error writing certificate request in bio"); goto error; } (void)BIO_flush(databio); break; case SCEP_REQUEST_GETCERTINIT: /* Set printable message type */ s->request_type_str = SCEP_REQUEST_GETCERTINIT_STR; /* Signer cert */ signercert = s->signercert; signerkey = s->signerkey; /* Create inner PKCS#7 */ if (ctx->verbose){ qeo_log_i("creating inner PKCS#7"); } /* Read data in memory bio */ databio = BIO_new(BIO_s_mem()); if (i2d_pkcs7_issuer_and_subject_bio(databio, s->ias_getcertinit)) { qeo_log_e("error writing GetCertInitial data in bio"); goto error; } (void)BIO_flush(databio); break; } /* Below this is the common code for all request_type */ /* Read in the payload */ payload_len = BIO_get_mem_data(databio, &payload); if (ctx->verbose){ qeo_log_i("data payload size: %d bytes", payload_len); } /* Create encryption certificate stack */ if ((recipients = sk_X509_new(NULL) ) == NULL) { qeo_log_e("error creating certificate stack"); goto error; } if (sk_X509_push(recipients, op_info->racert) <= 0) { qeo_log_e("error adding recipient encryption certificate"); goto error; } /* Create BIO for encryption */ if ((encbio = BIO_new_mem_buf(payload, payload_len)) == NULL ) { qeo_log_e("error creating data bio"); goto error; } /* Encrypt */ if (!(p7enc = PKCS7_encrypt(recipients, encbio, ctx->enc_alg, PKCS7_BINARY))) { qeo_log_e("request payload encrypt failed"); goto error; } if (ctx->verbose){ qeo_log_i("successfully encrypted payload"); } /* Write encrypted data */ memorybio = BIO_new(BIO_s_mem()); if (i2d_PKCS7_bio(memorybio, p7enc) <= 0) { qeo_log_e("error writing encrypted data"); goto error; } (void)BIO_flush(memorybio); BIO_set_flags(memorybio, BIO_FLAGS_MEM_RDONLY); len = BIO_get_mem_data(memorybio, &buffer); BIO_free(memorybio); memorybio=NULL; if (ctx->verbose){ qeo_log_i("envelope size: %d bytes", len); } if (ctx->debug) { qeo_log_i("printing PEM fomatted PKCS#7"); PEM_write_PKCS7(stdout, p7enc); } /* Create outer PKCS#7 */ if (ctx->verbose){ qeo_log_i("creating outer PKCS#7"); } s->request_p7 = PKCS7_new(); if (s->request_p7 == NULL ) { qeo_log_e("failed creating PKCS#7 for signing"); goto error; } if (!PKCS7_set_type(s->request_p7, NID_pkcs7_signed)) { qeo_log_e("failed setting PKCS#7 type"); goto error; } /* Add signer certificate and signature */ PKCS7_add_certificate(s->request_p7, signercert); if ((si = PKCS7_add_signature(s->request_p7, signercert, signerkey, ctx->sig_alg)) == NULL ) { qeo_log_e("error adding PKCS#7 signature"); goto error; } if (ctx->verbose){ qeo_log_i("signature added successfully"); } /* Set signed attributes */ if (ctx->verbose){ qeo_log_i("adding signed attributes"); } attributes = sk_X509_ATTRIBUTE_new_null(); add_attribute_string(attributes, ctx->nid_transId, s->transaction_id, ctx); add_attribute_string(attributes, ctx->nid_messageType, s->request_type_str, ctx); add_attribute_octet(attributes, ctx->nid_senderNonce, s->sender_nonce, s->sender_nonce_len, ctx); PKCS7_set_signed_attributes(si, attributes); sk_X509_ATTRIBUTE_pop_free(attributes, X509_ATTRIBUTE_free); /* Add contentType */ if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data))) { qeo_log_e("error adding NID_pkcs9_contentType"); goto error; } /* Create new content */ if (!PKCS7_content_new(s->request_p7, NID_pkcs7_data)) { qeo_log_e("failed setting PKCS#7 content type"); goto error; } /* Write data */ pkcs7bio = PKCS7_dataInit(s->request_p7, NULL ); if (pkcs7bio == NULL ) { qeo_log_e("error opening bio for writing PKCS#7 data"); goto error; } if (len != BIO_write(pkcs7bio, buffer, len)) { qeo_log_e("error writing PKCS#7 data"); goto error; } if (ctx->verbose){ qeo_log_i("PKCS#7 data written successfully"); } /* Finalize PKCS#7 */ if (!PKCS7_dataFinal(s->request_p7, pkcs7bio)) { qeo_log_e("error finalizing outer PKCS#7"); goto error; } if (ctx->debug) { qeo_log_i("printing PEM fomatted PKCS#7"); PEM_write_PKCS7(stdout, s->request_p7); } /* base64-encode the data */ if (ctx->verbose){ qeo_log_i("applying base64 encoding"); } /* Create base64 filtering bio */ memorybio = BIO_new(BIO_s_mem()); outbio = BIO_push(BIO_new(BIO_f_base64()), memorybio); /* Copy PKCS#7 */ i2d_PKCS7_bio(outbio, s->request_p7); (void)BIO_flush(outbio); payload_len = BIO_get_mem_data(memorybio, &payload); s->request_payload = (char*) malloc(sizeof(char)*payload_len); if (!s->request_payload){ goto error; } s->request_len = payload_len; memcpy(s->request_payload, payload, s->request_len); if (ctx->verbose){ qeo_log_i("base64 encoded payload size: %d bytes", payload_len); } ret = 0; error: BIO_free(databio); BIO_free(encbio); BIO_free_all(pkcs7bio); BIO_free(memorybio); BIO_free(outbio); if (recipients != NULL){ sk_X509_free(recipients);/* Only free the stack, not the certificates */ } PKCS7_free(p7enc); OPENSSL_free(buffer); return ret; }
/* * Unwrap PKCS#7 data and decrypt if necessary */ int pkcs7_unwrap(struct scep *s, struct sscep_ctx *ctx, struct sscep_operation_info *op_info, char* data, int datalen) { BIO *memorybio = NULL; BIO *outbio = NULL; BIO *pkcs7bio = NULL; int i, bytes, used; STACK_OF(PKCS7_SIGNER_INFO) *sk; PKCS7 *p7enc = NULL; PKCS7_SIGNER_INFO *si; STACK_OF(X509_ATTRIBUTE) *attribs; char *p = NULL; unsigned char buffer[1024]; X509 *recipientcert; EVP_PKEY *recipientkey; int ret = SCEP_PKISTATUS_P7; /* Create new memory BIO for outer PKCS#7 */ memorybio = BIO_new(BIO_s_mem()); /* Read in data */ if (ctx->verbose){ qeo_log_i("reading outer PKCS#7"); } if (BIO_write(memorybio, data, datalen) <= 0) { qeo_log_e("error reading PKCS#7 data"); goto error; } if (ctx->verbose){ qeo_log_i("PKCS#7 payload size: %d bytes", datalen); } s->reply_p7 = d2i_PKCS7_bio(memorybio, NULL ); if (s->reply_p7 == NULL ) { qeo_log_e("error retrieving PKCS#7 data"); goto error; } if (ctx->debug) { qeo_log_i("printing PEM fomatted PKCS#7"); PEM_write_PKCS7(stdout, s->reply_p7); } /* Make sure this is a signed PKCS#7 */ if (!PKCS7_type_is_signed(s->reply_p7)) { qeo_log_e("PKCS#7 is not signed!"); goto error; } /* Create BIO for content data */ pkcs7bio = PKCS7_dataInit(s->reply_p7, NULL ); if (pkcs7bio == NULL ) { qeo_log_e("cannot get PKCS#7 data"); goto error; } /* Copy enveloped data from PKCS#7 */ outbio = BIO_new(BIO_s_mem()); used = 0; for (;;) { bytes = BIO_read(pkcs7bio, buffer, sizeof(buffer)); used += bytes; if (bytes <= 0) break; BIO_write(outbio, buffer, bytes); } (void)BIO_flush(outbio); if (ctx->verbose){ qeo_log_i("PKCS#7 contains %d bytes of enveloped data", used); } /* Get signer */ sk = PKCS7_get_signer_info(s->reply_p7); if (sk == NULL ) { qeo_log_e("cannot get signer info!"); goto error; } /* Verify signature */ if (ctx->verbose){ qeo_log_i("verifying signature"); } si = sk_PKCS7_SIGNER_INFO_value(sk, 0); if (PKCS7_signatureVerify(pkcs7bio, s->reply_p7, si, op_info->racert) <= 0) { qeo_log_e("error verifying signature"); goto error; } if (ctx->verbose){ qeo_log_i("signature ok"); } /* Get signed attributes */ if (ctx->verbose){ qeo_log_i("finding signed attributes"); } attribs = PKCS7_get_signed_attributes(si); if (attribs == NULL ) { qeo_log_e("no attributes found"); goto error; } /* Transaction id */ if ((get_signed_attribute(attribs, ctx->nid_transId, V_ASN1_PRINTABLESTRING, &p, ctx)) == 1) { qeo_log_e("cannot find transId"); goto error; } if (ctx->verbose){ qeo_log_i("reply transaction id: %s", p); } if (strncmp(s->transaction_id, p, strlen(p))) { qeo_log_e("transaction id mismatch"); goto error; } free(p); p=NULL; /* Message type, should be of type CertRep */ if (get_signed_attribute(attribs, ctx->nid_messageType, V_ASN1_PRINTABLESTRING, &p, ctx) == 1) { qeo_log_e("cannot find messageType"); goto error; } if (atoi(p) != 3) { qeo_log_e("wrong message type in reply"); goto error; } if (ctx->verbose){ qeo_log_i("reply message type is good"); } free(p); p=NULL; /* Recipient nonces: */ if (get_signed_attribute(attribs, ctx->nid_recipientNonce, V_ASN1_OCTET_STRING, &p, ctx) == 1) { qeo_log_e("cannot find recipientNonce"); goto error; } s->reply_recipient_nonce = p; p = NULL; if (ctx->verbose) { qeo_log_i("recipientNonce in reply"); } /* * Compare recipient nonce to original sender nonce * The draft says nothing about this, but it makes sense to me.. * XXXXXXXXXXXXXX check */ for (i = 0; i < 16; i++) { if (s->sender_nonce[i] != s->reply_recipient_nonce[i]) { if (ctx->verbose) qeo_log_e("corrupted nonce received"); /* Instead of exit, break out */ break; } } /* Get pkiStatus */ if (get_signed_attribute(attribs, ctx->nid_pkiStatus, V_ASN1_PRINTABLESTRING, &p, ctx) == 1) { qeo_log_e("cannot find pkiStatus"); /* This is a mandatory attribute.. */ goto error; } switch (atoi(p)) { case SCEP_PKISTATUS_SUCCESS: qeo_log_i("pkistatus: SUCCESS"); s->pki_status = SCEP_PKISTATUS_SUCCESS; break; case SCEP_PKISTATUS_FAILURE: qeo_log_i("pkistatus: FAILURE"); s->pki_status = SCEP_PKISTATUS_FAILURE; break; case SCEP_PKISTATUS_PENDING: qeo_log_i("pkistatus: PENDING"); s->pki_status = SCEP_PKISTATUS_PENDING; break; default: qeo_log_e("wrong pkistatus in reply"); goto error; } free(p); p=NULL; /* Get failInfo */ if (s->pki_status == SCEP_PKISTATUS_FAILURE) { if (get_signed_attribute(attribs, ctx->nid_failInfo, V_ASN1_PRINTABLESTRING, &p, ctx) == 1) { qeo_log_e("cannot find failInfo"); goto error; } switch (atoi(p)) { case SCEP_FAILINFO_BADALG: s->fail_info = SCEP_FAILINFO_BADALG; qeo_log_i("reason: %s", SCEP_FAILINFO_BADALG_STR); break; case SCEP_FAILINFO_BADMSGCHK: s->fail_info = SCEP_FAILINFO_BADMSGCHK; qeo_log_i("reason: %s", SCEP_FAILINFO_BADMSGCHK_STR); break; case SCEP_FAILINFO_BADREQ: s->fail_info = SCEP_FAILINFO_BADREQ; qeo_log_i("reason: %s", SCEP_FAILINFO_BADREQ_STR); break; case SCEP_FAILINFO_BADTIME: s->fail_info = SCEP_FAILINFO_BADTIME; qeo_log_i("reason: %s", SCEP_FAILINFO_BADTIME_STR); break; case SCEP_FAILINFO_BADCERTID: s->fail_info = SCEP_FAILINFO_BADCERTID; qeo_log_i("reason: %s", SCEP_FAILINFO_BADCERTID_STR); break; default: qeo_log_e("wrong failInfo in " "reply"); goto error; } free(p); p=NULL; } /* If FAILURE or PENDING, we can return */ if (s->pki_status != SCEP_PKISTATUS_SUCCESS) { /* There shouldn't be any more data... */ if (ctx->verbose && (used != 0)) { qeo_log_e("illegal size of payload"); } return (0); } /* We got success and expect data */ if (used == 0) { qeo_log_e("illegal size of payload"); goto error; } /* Decrypt the inner PKCS#7 */ recipientcert = s->signercert; recipientkey = s->signerkey; if (ctx->verbose){ qeo_log_i("reading inner PKCS#7"); } p7enc = d2i_PKCS7_bio(outbio, NULL ); if (p7enc == NULL ) { qeo_log_e("cannot read inner PKCS#7"); goto error; } BIO_free(outbio);/* No longer need it */ outbio = NULL; if (ctx->debug) { qeo_log_i("printing PEM fomatted PKCS#7"); PEM_write_PKCS7(stdout, p7enc); } /* Decrypt the data */ outbio = BIO_new(BIO_s_mem()); if (ctx->verbose){ qeo_log_i("decrypting inner PKCS#7"); } if (PKCS7_decrypt(p7enc, recipientkey, recipientcert, outbio, 0) == 0) { qeo_log_e("error decrypting inner PKCS#7"); goto error; } (void)BIO_flush(outbio); /* Write decrypted data */ PKCS7_free(s->reply_p7); s->reply_p7 = d2i_PKCS7_bio(outbio, NULL ); ret = 0; error: free(p); BIO_free(outbio); BIO_free_all(pkcs7bio); BIO_free(memorybio); PKCS7_free(p7enc); return ret; }
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); }
/* * Unwrap PKCS#7 data and decrypt if necessary */ int pkcs7_unwrap(struct scep *s) { BIO *memorybio; BIO *outbio; BIO *pkcs7bio; int i, len, bytes, used; STACK_OF(PKCS7_SIGNER_INFO) *sk; PKCS7 *p7enc; PKCS7_SIGNER_INFO *si; STACK_OF(X509_ATTRIBUTE) *attribs; char *p; unsigned char buffer[1024]; X509 *recipientcert; EVP_PKEY *recipientkey; /* Create new memory BIO for outer PKCS#7 */ memorybio = BIO_new(BIO_s_mem()); /* Read in data */ if (v_flag) printf("%s: reading outer PKCS#7\n",pname); if ((len = BIO_write(memorybio, s->reply_payload, s->reply_len)) <= 0) { fprintf(stderr, "%s: error reading PKCS#7 data\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: PKCS#7 payload size: %d bytes\n", pname, len); BIO_set_flags(memorybio, BIO_FLAGS_MEM_RDONLY); s->reply_p7 = d2i_PKCS7_bio(memorybio, NULL); if (d_flag) { printf("%s: printing PEM fomatted PKCS#7\n", pname); PEM_write_PKCS7(stdout, s->reply_p7); } /* Make sure this is a signed PKCS#7 */ if (!PKCS7_type_is_signed(s->reply_p7)) { fprintf(stderr, "%s: PKCS#7 is not signed!\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Create BIO for content data */ pkcs7bio = PKCS7_dataInit(s->reply_p7, NULL); if (pkcs7bio == NULL) { fprintf(stderr, "%s: cannot get PKCS#7 data\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Copy enveloped data from PKCS#7 */ outbio = BIO_new(BIO_s_mem()); used = 0; for (;;) { bytes = BIO_read(pkcs7bio, buffer, sizeof(buffer)); used += bytes; if (bytes <= 0) break; BIO_write(outbio, buffer, bytes); } BIO_flush(outbio); if (v_flag) printf("%s: PKCS#7 contains %d bytes of enveloped data\n", pname, used); /* Get signer */ sk = PKCS7_get_signer_info(s->reply_p7); if (sk == NULL) { fprintf(stderr, "%s: cannot get signer info!\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Verify signature */ if (v_flag) printf("%s: verifying signature\n", pname); si = sk_PKCS7_SIGNER_INFO_value(sk, 0); if (PKCS7_signatureVerify(pkcs7bio, s->reply_p7, si, cacert) <= 0) { fprintf(stderr, "%s: error verifying signature\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: signature ok\n", pname); /* Get signed attributes */ if (v_flag) printf("%s: finding signed attributes\n", pname); attribs = PKCS7_get_signed_attributes(si); if (attribs == NULL) { fprintf(stderr, "%s: no attributes found\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Transaction id */ if ((get_signed_attribute(attribs, nid_transId, V_ASN1_PRINTABLESTRING, &p)) == 1) { fprintf(stderr, "%s: cannot find transId\n", pname); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: reply transaction id: %s\n", pname, p); if (strncmp(s->transaction_id, p, strlen(p))) { fprintf(stderr, "%s: transaction id mismatch\n", pname); exit (SCEP_PKISTATUS_P7); } /* Message type, should be of type CertRep */ if ((i = get_signed_attribute(attribs, nid_messageType, V_ASN1_PRINTABLESTRING, &p)) == 1) { fprintf(stderr, "%s: cannot find messageType\n", pname); exit (SCEP_PKISTATUS_P7); } if (atoi(p) != 3) { fprintf(stderr, "%s: wrong message type in reply\n", pname); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: reply message type is good\n", pname); /* Sender and recipient nonces: */ if ((i = get_signed_attribute(attribs, nid_senderNonce, V_ASN1_OCTET_STRING, &p)) == 1) { if (v_flag) fprintf(stderr, "%s: cannot find senderNonce\n", pname); /* Some implementations don't put in on reply */ /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXX exit (SCEP_PKISTATUS_P7); */ } s->reply_sender_nonce = p; if (v_flag) { printf("%s: senderNonce in reply: ", pname); for (i = 0; i < 16; i++) { printf("%02X", s->reply_sender_nonce[i]); } printf("\n"); } if (( i = get_signed_attribute(attribs, nid_recipientNonce, V_ASN1_OCTET_STRING, &p)) == 1) { fprintf(stderr, "%s: cannot find recipientNonce\n", pname); exit (SCEP_PKISTATUS_P7); } s->reply_recipient_nonce = p; if (v_flag) { printf("%s: recipientNonce in reply: ", pname); for (i = 0; i < 16; i++) { printf("%02X", s->reply_recipient_nonce[i]); } printf("\n"); } /* * Compare recipient nonce to original sender nonce * The draft says nothing about this, but it makes sense to me.. * XXXXXXXXXXXXXX check */ for (i = 0; i < 16; i++) { if (s->sender_nonce[i] != s->reply_recipient_nonce[i]) { if (v_flag) fprintf(stderr, "%s: corrupted nonce " "received\n", pname); /* Instead of exit, break out */ break; } } /* Get pkiStatus */ if ((i = get_signed_attribute(attribs, nid_pkiStatus, V_ASN1_PRINTABLESTRING, &p)) == 1) { fprintf(stderr, "%s: cannot find pkiStatus\n", pname); /* This is a mandatory attribute.. */ exit (SCEP_PKISTATUS_P7); } switch (atoi(p)) { case SCEP_PKISTATUS_SUCCESS: printf("%s: pkistatus: SUCCESS\n",pname); s->pki_status = SCEP_PKISTATUS_SUCCESS; break; case SCEP_PKISTATUS_FAILURE: printf("%s: pkistatus: FAILURE\n",pname); s->pki_status = SCEP_PKISTATUS_FAILURE; break; case SCEP_PKISTATUS_PENDING: printf("%s: pkistatus: PENDING\n",pname); s->pki_status = SCEP_PKISTATUS_PENDING; break; default: fprintf(stderr, "%s: wrong pkistatus in reply\n",pname); exit (SCEP_PKISTATUS_P7); } /* Get failInfo */ if (s->pki_status == SCEP_PKISTATUS_FAILURE) { if ((i = get_signed_attribute(attribs, nid_failInfo, V_ASN1_PRINTABLESTRING, &p)) == 1) { fprintf(stderr, "%s: cannot find failInfo\n", pname); exit (SCEP_PKISTATUS_P7); } switch (atoi(p)) { case SCEP_FAILINFO_BADALG: s->fail_info = SCEP_FAILINFO_BADALG; printf("%s: reason: %s\n", pname, SCEP_FAILINFO_BADALG_STR); break; case SCEP_FAILINFO_BADMSGCHK: s->fail_info = SCEP_FAILINFO_BADMSGCHK; printf("%s: reason: %s\n", pname, SCEP_FAILINFO_BADMSGCHK_STR); break; case SCEP_FAILINFO_BADREQ: s->fail_info = SCEP_FAILINFO_BADREQ; printf("%s: reason: %s\n", pname, SCEP_FAILINFO_BADREQ_STR); break; case SCEP_FAILINFO_BADTIME: s->fail_info = SCEP_FAILINFO_BADTIME; printf("%s: reason: %s\n", pname, SCEP_FAILINFO_BADTIME_STR); break; case SCEP_FAILINFO_BADCERTID: s->fail_info = SCEP_FAILINFO_BADCERTID; printf("%s: reason: %s\n", pname, SCEP_FAILINFO_BADCERTID_STR); break; default: fprintf(stderr, "%s: wrong failInfo in " "reply\n",pname); exit (SCEP_PKISTATUS_P7); } } /* If FAILURE or PENDING, we can return */ if (s->pki_status != SCEP_PKISTATUS_SUCCESS) { /* There shouldn't be any more data... */ if (v_flag && (used != 0)) { fprintf(stderr, "%s: illegal size of payload\n", pname); } return (0); } /* We got success and expect data */ if (used == 0) { fprintf(stderr, "%s: illegal size of payload\n", pname); exit (SCEP_PKISTATUS_P7); } /* Decrypt the inner PKCS#7 */ if ((s->request_type == SCEP_REQUEST_PKCSREQ) || (s->request_type == SCEP_REQUEST_GETCERTINIT)) { recipientcert = s->signercert; recipientkey = s->signerkey; } else { recipientcert = localcert; recipientkey = rsa; } if (v_flag) printf("%s: reading inner PKCS#7\n",pname); p7enc = d2i_PKCS7_bio(outbio, NULL); if (p7enc == NULL) { fprintf(stderr, "%s: cannot read inner PKCS#7\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (d_flag) { printf("%s: printing PEM fomatted PKCS#7\n", pname); PEM_write_PKCS7(stdout, p7enc); } /* Decrypt the data */ outbio = BIO_new(BIO_s_mem()); if (v_flag) printf("%s: decrypting inner PKCS#7\n",pname); if (PKCS7_decrypt(p7enc, recipientkey, recipientcert, outbio, 0) == 0) { fprintf(stderr, "%s: error decrypting inner PKCS#7\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } BIO_flush(outbio); /* Write decrypted data */ s->reply_len = BIO_get_mem_data(outbio, &s->reply_payload); if (v_flag) printf("%s: PKCS#7 payload size: %d bytes\n", pname, s->reply_len); BIO_set_flags(outbio, BIO_FLAGS_MEM_RDONLY); s->reply_p7 = d2i_PKCS7_bio(outbio, NULL); return (0); }
/* * Wrap data in PKCS#7 envelopes and base64-encode the result. * Data is PKCS#10 request in PKCSReq, or pkcs7_issuer_and_subject * structure in GetCertInitial and PKCS7_ISSUER_AND_SERIAL in * GetCert and GETCrl. */ int pkcs7_wrap(struct scep *s) { BIO *databio = NULL; BIO *encbio = NULL; BIO *pkcs7bio = NULL; BIO *memorybio = NULL; BIO *outbio = NULL; BIO *base64bio = NULL; unsigned char *buffer = NULL; int rc, len = 0; STACK_OF(X509) *recipients; PKCS7 *p7enc; PKCS7_SIGNER_INFO *si; STACK_OF(X509_ATTRIBUTE) *attributes; X509 *signercert = NULL; EVP_PKEY *signerkey = NULL; /* Create a new sender nonce for all messages * XXXXXXXXXXXXXX should it be per transaction? */ s->sender_nonce_len = 16; s->sender_nonce = (unsigned char *)malloc(s->sender_nonce_len); RAND_bytes(s->sender_nonce, s->sender_nonce_len); /* Prepare data payload */ switch(s->request_type) { case SCEP_REQUEST_PKCSREQ: /* * Set printable message type * We set this later as an autheticated attribute * "messageType". */ s->request_type_str = SCEP_REQUEST_PKCSREQ_STR; /* Signer cert */ signercert = s->signercert; signerkey = s->signerkey; /* Create inner PKCS#7 */ if (v_flag) printf("%s: creating inner PKCS#7\n", pname); /* Read request in memory bio */ databio = BIO_new(BIO_s_mem()); if ((rc = i2d_X509_REQ_bio(databio, request)) <= 0) { fprintf(stderr, "%s: error writing " "certificate request in bio\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } BIO_flush(databio); BIO_set_flags(databio, BIO_FLAGS_MEM_RDONLY); break; case SCEP_REQUEST_GETCERTINIT: /* Set printable message type */ s->request_type_str = SCEP_REQUEST_GETCERTINIT_STR; /* Signer cert */ signercert = s->signercert; signerkey = s->signerkey; /* Create inner PKCS#7 */ if (v_flag) printf("%s: creating inner PKCS#7\n", pname); /* Read data in memory bio */ databio = BIO_new(BIO_s_mem()); if ((rc = i2d_pkcs7_issuer_and_subject_bio(databio, s->ias_getcertinit)) <= 0) { fprintf(stderr, "%s: error writing " "GetCertInitial data in bio\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } BIO_flush(databio); BIO_set_flags(databio, BIO_FLAGS_MEM_RDONLY); break; case SCEP_REQUEST_GETCERT: /* Set printable message type */ s->request_type_str = SCEP_REQUEST_GETCERT_STR; /* Signer cert */ signercert = localcert; signerkey = rsa; /* Read data in memory bio */ databio = BIO_new(BIO_s_mem()); if ((rc = i2d_PKCS7_ISSUER_AND_SERIAL_bio(databio, s->ias_getcert)) <= 0) { fprintf(stderr, "%s: error writing " "GetCert data in bio\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } BIO_flush(databio); BIO_set_flags(databio, BIO_FLAGS_MEM_RDONLY); break; case SCEP_REQUEST_GETCRL: /* Set printable message type */ s->request_type_str = SCEP_REQUEST_GETCRL_STR; /* Signer cert */ signercert = localcert; signerkey = rsa; /* Read data in memory bio */ databio = BIO_new(BIO_s_mem()); if ((rc = i2d_PKCS7_ISSUER_AND_SERIAL_bio(databio, s->ias_getcrl)) <= 0) { fprintf(stderr, "%s: error writing " "GetCert data in bio\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } BIO_flush(databio); BIO_set_flags(databio, BIO_FLAGS_MEM_RDONLY); break; } /* Below this is the common code for all request_type */ /* Read in the payload */ s->request_len = BIO_get_mem_data(databio, &s->request_payload); if (v_flag) printf("%s: data payload size: %d bytes\n", pname, s->request_len); BIO_free(databio); /* Create encryption certificate stack */ if ((recipients = sk_X509_new(NULL)) == NULL) { fprintf(stderr, "%s: error creating " "certificate stack\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Use different CA cert for encryption if requested */ if (e_flag) { if (sk_X509_push(recipients, encert) <= 0) { fprintf(stderr, "%s: error adding recipient encryption " "certificate\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Use same CA cert also for encryption */ } else { if (sk_X509_push(recipients, cacert) <= 0) { fprintf(stderr, "%s: error adding recipient encryption " "certificate\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } } /* Create BIO for encryption */ if ((encbio = BIO_new_mem_buf(s->request_payload, s->request_len)) == NULL) { fprintf(stderr, "%s: error creating data " "bio\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Encrypt */ if (!(p7enc = PKCS7_encrypt(recipients, encbio, enc_alg, PKCS7_BINARY))) { fprintf(stderr, "%s: request payload encrypt failed\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: successfully encrypted payload\n", pname); /* Write encrypted data */ memorybio = BIO_new(BIO_s_mem()); if (i2d_PKCS7_bio(memorybio, p7enc) <= 0) { fprintf(stderr, "%s: error writing encrypted data\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } BIO_flush(memorybio); BIO_set_flags(memorybio, BIO_FLAGS_MEM_RDONLY); len = BIO_get_mem_data(memorybio, &buffer); if (v_flag) printf("%s: envelope size: %d bytes\n", pname, len); if (d_flag) { printf("%s: printing PEM fomatted PKCS#7\n", pname); PEM_write_PKCS7(stdout, p7enc); } BIO_free(memorybio); /* Create outer PKCS#7 */ if (v_flag) printf("%s: creating outer PKCS#7\n", pname); s->request_p7 = PKCS7_new(); if (s->request_p7 == NULL) { fprintf(stderr, "%s: failed creating PKCS#7 for signing\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (!PKCS7_set_type(s->request_p7, NID_pkcs7_signed)) { fprintf(stderr, "%s: failed setting PKCS#7 type\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Add signer certificate and signature */ PKCS7_add_certificate(s->request_p7, signercert); if ((si = PKCS7_add_signature(s->request_p7, signercert, signerkey, sig_alg)) == NULL) { fprintf(stderr, "%s: error adding PKCS#7 signature\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: signature added successfully\n", pname); /* Set signed attributes */ if (v_flag) printf("%s: adding signed attributes\n", pname); attributes = sk_X509_ATTRIBUTE_new_null(); add_attribute_string(attributes, nid_transId, s->transaction_id); add_attribute_string(attributes, nid_messageType, s->request_type_str); add_attribute_octet(attributes, nid_senderNonce, s->sender_nonce, s->sender_nonce_len); PKCS7_set_signed_attributes(si, attributes); /* Add contentType */ if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, V_ASN1_OBJECT, OBJ_nid2obj(NID_pkcs7_data))) { fprintf(stderr, "%s: error adding NID_pkcs9_contentType\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Create new content */ if (!PKCS7_content_new(s->request_p7, NID_pkcs7_data)) { fprintf(stderr, "%s: failed setting PKCS#7 content type\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } /* Write data */ pkcs7bio = PKCS7_dataInit(s->request_p7, NULL); if (pkcs7bio == NULL) { fprintf(stderr, "%s: error opening bio for writing PKCS#7 " "data\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (len != BIO_write(pkcs7bio, buffer, len)) { fprintf(stderr, "%s: error writing PKCS#7 data\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (v_flag) printf("%s: PKCS#7 data written successfully\n", pname); /* Finalize PKCS#7 */ if (!PKCS7_dataFinal(s->request_p7, pkcs7bio)) { fprintf(stderr, "%s: error finalizing outer PKCS#7\n", pname); ERR_print_errors_fp(stderr); exit (SCEP_PKISTATUS_P7); } if (d_flag) { printf("%s: printing PEM fomatted PKCS#7\n", pname); PEM_write_PKCS7(stdout, s->request_p7); } /* base64-encode the data */ if (v_flag) printf("%s: applying base64 encoding\n",pname); /* Create base64 filtering bio */ memorybio = BIO_new(BIO_s_mem()); base64bio = BIO_new(BIO_f_base64()); outbio = BIO_push(base64bio, memorybio); /* Copy PKCS#7 */ i2d_PKCS7_bio(outbio, s->request_p7); BIO_flush(outbio); BIO_set_flags(memorybio, BIO_FLAGS_MEM_RDONLY); s->request_len = BIO_get_mem_data(memorybio, &s->request_payload); if (v_flag) printf("%s: base64 encoded payload size: %d bytes\n", pname, s->request_len); BIO_free(outbio); return (0); }