int main(int argc, char const *argv[]) { PKCS7 *p7; FILE *fp = NULL; PKCS7_SIGNER_INFO *si; STACK_OF(PKCS7_SIGNER_INFO) *sk; X509_STORE_CTX cert_ctx; X509_STORE *cert_store; BIO *mybio; int ret, len, i; unsigned char *errordesc; unsigned long errorno; unsigned char data[2028], *p, *buf; OpenSSL_add_all_algorithms(); fp = fopen("p7signed.cer", "rb"); if(fp == NULL) return 0; len = fread(data, 1, 2048, fp); fclose(fp); p = data; p7 = d2i_PKCS7(NULL, (const unsigned char **)&p, len); mybio = PKCS7_dataInit(p7, NULL); sk = PKCS7_get_signer_info(p7); if(sk == NULL) { printf("no signer in p7\n"); return 0; } cert_store=X509_STORE_new(); X509_STORE_set_verify_cb_func(cert_store,verify_callback);//必须要有回调设置 for(i = 0; i < sk_PKCS7_SIGNER_INFO_num(sk); i++) { si = sk_PKCS7_SIGNER_INFO_value(sk, i); ret = PKCS7_dataVerify(cert_store, &cert_ctx, mybio, p7, si); if(ret == 1) printf("succ in pkcs7 signed data verify\n"); else printf("fail in pkcs7 signed data verify\n"); } X509_STORE_free(cert_store); PKCS7_free(p7); return 1; }
static VALUE ossl_pkcs7_get_signer(VALUE self) { PKCS7 *pkcs7; STACK_OF(PKCS7_SIGNER_INFO) *sk; PKCS7_SIGNER_INFO *si; int num, i; VALUE ary; GetPKCS7(self, pkcs7); if (!(sk = PKCS7_get_signer_info(pkcs7))) { OSSL_Debug("OpenSSL::PKCS7#get_signer_info == NULL!"); return rb_ary_new(); } if ((num = sk_PKCS7_SIGNER_INFO_num(sk)) < 0) { ossl_raise(ePKCS7Error, "Negative number of signers!"); } ary = rb_ary_new2(num); for (i=0; i<num; i++) { si = sk_PKCS7_SIGNER_INFO_value(sk, i); rb_ary_push(ary, ossl_pkcs7si_new(si)); } return ary; }
long /* return serial on success, -1 on failure */ smime_get_signer_info(const char* signed_entity, int info_ix, /* 0 = first signer */ char** issuer) /* DN of the issuer */ { int serial = -1; PKCS7* p7 = NULL; STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL; PKCS7_SIGNER_INFO* si; if (!signed_entity || !issuer) GOTO_ERR("NULL arg(s)"); *issuer = NULL; if (!(p7 = get_pkcs7_from_pem(signed_entity))) goto err; if (!(sigs=PKCS7_get_signer_info(p7))) GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)"); if (info_ix >= sk_PKCS7_SIGNER_INFO_num(sigs)) GOTO_ERR("No more signers. info_ix too large."); if (!(si=sk_PKCS7_SIGNER_INFO_value(sigs,info_ix))) GOTO_ERR("NULL signer info"); *issuer = X509_NAME_oneline(si->issuer_and_serial->issuer, NULL,0); serial = ASN1_INTEGER_get(si->issuer_and_serial->serial); err: if (p7) PKCS7_free(p7); return serial; }
/******************************************************************************* 函数名称: cert_pkcs7_unwrap 功能描述: 解析从服务器收到的信息,包括验证签名以及解密。 输入参数: struct scep *s, SCEP操作的结构体指针。 输出参数: 无 返 回 值: 1,成功;-1,失败 -------------------------------------------------------------------------------- 最近一次修改记录: 修改作者:王朝 修改目的:添加新函数 修改日期:2009年12月28日 *********************************************************************************/ s32 cert_pkcs7_unwrap(struct scep *s) { BIO *memorybio = NULL; BIO *outbio = NULL; BIO *pkcs7bio = NULL; s32 bytes, used, retval = -1; STACK_OF(PKCS7_SIGNER_INFO) *sk = NULL; PKCS7 *p7enc = NULL; PKCS7_SIGNER_INFO *si = NULL; STACK_OF(X509_ATTRIBUTE) *attribs = NULL; s8 *p = NULL; u8 buffer[1024]; X509 *recipientcert = NULL; EVP_PKEY *recipientkey = NULL; /* Create new memory BIO for outer PKCS#7 */ memorybio = BIO_new(BIO_s_mem()); /* Read in data */ if ((BIO_write(memorybio, s->reply_payload, s->reply_len)) <= 0) { goto end; } BIO_set_flags(memorybio, BIO_FLAGS_MEM_RDONLY); s->reply_p7 = d2i_PKCS7_bio(memorybio, NULL); BIO_free(memorybio); memorybio = NULL; /* Make sure this is a signed PKCS#7 */ if (!PKCS7_type_is_signed(s->reply_p7)) { goto end; } /* Create BIO for content data */ pkcs7bio = PKCS7_dataInit(s->reply_p7, NULL); if (pkcs7bio == NULL) { goto end; } /* */ 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); /* Get signer */ sk = PKCS7_get_signer_info(s->reply_p7); if (sk == NULL) { goto end; } /* Verify signature */ si = sk_PKCS7_SIGNER_INFO_value(sk, 0); if (PKCS7_signatureVerify(pkcs7bio, s->reply_p7, si, cert_cacert) <= 0) { goto end; } /* Get signed attributes */ attribs = PKCS7_get_signed_attributes(si); if (attribs == NULL) { goto end; } /* Transaction id */ if (1 != cert_get_signed_attribute(attribs, nid_transId, V_ASN1_PRINTABLESTRING, &p)) { goto end; } if (strncmp(s->transaction_id, p, strlen(p))) { goto end; } /* Message type, should be of type CertRep */ if (1 != cert_get_signed_attribute(attribs, nid_messageType, V_ASN1_PRINTABLESTRING, &p)) { goto end; } if (atoi(p) != 3) { goto end; } /* Sender and recipient nonces: */ if (1 == cert_get_signed_attribute(attribs, nid_senderNonce, V_ASN1_OCTET_STRING, &p)) { s->reply_sender_nonce = (u8 *)p; } else { s->reply_sender_nonce = NULL; } if ( 1 != cert_get_signed_attribute(attribs, nid_recipientNonce,V_ASN1_OCTET_STRING, &p)) { goto end; } s->reply_recipient_nonce = (u8 *)p; /* Get pkiStatus */ if (1 != cert_get_signed_attribute(attribs, nid_pkiStatus,V_ASN1_PRINTABLESTRING, &p)) { goto end; } switch (atoi(p)) { case SCEP_PKISTATUS_SUCCESS: s->pki_status = SCEP_PKISTATUS_SUCCESS; break; case SCEP_PKISTATUS_FAILURE: s->pki_status = SCEP_PKISTATUS_FAILURE; break; case SCEP_PKISTATUS_PENDING: s->pki_status = SCEP_PKISTATUS_PENDING; break; default: goto end; } /* Get failInfo */ if (s->pki_status == SCEP_PKISTATUS_FAILURE) { if (1 != cert_get_signed_attribute(attribs, nid_failInfo,V_ASN1_PRINTABLESTRING, &p)) { goto end; } switch (atoi(p)) { case SCEP_FAILINFO_BADALG: s->fail_info = SCEP_FAILINFO_BADALG; break; case SCEP_FAILINFO_BADMSGCHK: s->fail_info = SCEP_FAILINFO_BADMSGCHK; break; case SCEP_FAILINFO_BADREQ: s->fail_info = SCEP_FAILINFO_BADREQ; break; case SCEP_FAILINFO_BADTIME: s->fail_info = SCEP_FAILINFO_BADTIME; break; case SCEP_FAILINFO_BADCERTID: s->fail_info = SCEP_FAILINFO_BADCERTID; break; default: goto end; } } /* If FAILURE or PENDING, we can return */ if (s->pki_status != SCEP_PKISTATUS_SUCCESS) { /* There shouldn't be any more data... */ retval = 1; goto end; } /* We got success and expect data */ if (used == 0) { goto end; } /* 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 = cert_localcert; recipientkey = cert_rsa; } p7enc = d2i_PKCS7_bio(outbio, NULL); if (p7enc == NULL) { goto end; } BIO_free(outbio); outbio = NULL; /* Decrypt the data */ outbio = BIO_new(BIO_s_mem()); if (PKCS7_decrypt(p7enc, recipientkey, recipientcert, outbio, 0) == 0) { goto end; } (void)BIO_flush(outbio); /* Write decrypted data */ s->reply_len = BIO_get_mem_data(outbio, &s->reply_payload); BIO_set_flags(outbio, BIO_FLAGS_MEM_RDONLY); s->reply_p7 = d2i_PKCS7_bio(outbio, NULL); retval = 1; end: if(NULL != outbio) { BIO_free(outbio); } if(NULL != memorybio) { BIO_free(memorybio); } if(NULL != pkcs7bio) { BIO_free(pkcs7bio); } if(NULL != p7enc) { PKCS7_free(p7enc); } return retval; }
static int pk7_verify(X509_STORE *cert_store, PKCS7 *p7, BIO *detached, char *ebuf, int ebufsize) { PKCS7_SIGNER_INFO *si; verify_context vctx; BIO *p7bio=NULL; char readbuf[1024*4]; int res = 1; int i; STACK_OF(PKCS7_SIGNER_INFO) *sk; vctx.err = X509_V_OK; ebuf[0] = 0; OpenSSL_add_all_algorithms(); EVP_add_digest(EVP_md5()); EVP_add_digest(EVP_sha1()); ERR_load_crypto_strings(); ERR_clear_error(); X509_VERIFY_PARAM_set_flags(cert_store->param, X509_V_FLAG_CB_ISSUER_CHECK); X509_STORE_set_verify_cb_func(cert_store, verify_callback); p7bio = PKCS7_dataInit(p7, detached); /* We now have to 'read' from p7bio to calculate digests etc. */ while (BIO_read(p7bio, readbuf, sizeof(readbuf)) > 0) ; /* We can now verify signatures */ sk = PKCS7_get_signer_info(p7); if (sk == NULL) { /* there are no signatures on this data */ res = 0; fz_strlcpy(ebuf, "No signatures", ebufsize); goto exit; } for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sk); i++) { int rc; si = sk_PKCS7_SIGNER_INFO_value(sk, i); rc = PKCS7_dataVerify(cert_store, &vctx.x509_ctx, p7bio,p7, si); if (rc <= 0 || vctx.err != X509_V_OK) { char tbuf[120]; if (rc <= 0) { fz_strlcpy(ebuf, ERR_error_string(ERR_get_error(), tbuf), ebufsize); } else { /* Error while checking the certificate chain */ snprintf(ebuf, ebufsize, "%s(%d): %s", X509_verify_cert_error_string(vctx.err), vctx.err, vctx.certdesc); } res = 0; goto exit; } } exit: X509_STORE_CTX_cleanup(&vctx.x509_ctx); ERR_free_strings(); return res; }
/* Load a DER formatted file into internal SCEP_MSG structure */ SCEP_MSG *d2i_SCEP_MSG_bio (BIO *inbio) { BIO *outbio = NULL; BIO *p7bio = NULL; PKCS7 *p7 = NULL; // BIO *bio_err = NULL; SCEP_MSG *msg = NULL; int bytes, length, fd, used; int nMessageType = -1, nPkiStatus = -1; PKCS7_SIGNER_INFO *si = NULL; PKCS7_RECIP_INFO *ri = NULL; STACK_OF(X509_ATTRIBUTE) *sig_attribs = NULL; PKCS7 *p7env = NULL; SCEP_RECIP_INFO *rinfo = NULL; char buffer[1024]; char *data = NULL; char *tmp_string = NULL; int debug = 0; int i; // if ((bio_err=BIO_new(BIO_s_file())) != NULL) // BIO_set_fp(bio_err,stderr,BIO_NOCLOSE|BIO_FP_TEXT); msg = (SCEP_MSG *) OPENSSL_malloc ( sizeof(SCEP_MSG)); if( msg == NULL ) return (NULL); /* decode the data */ p7 = d2i_PKCS7_bio(inbio, NULL); if (p7 == NULL) goto err; /* make sure this is a signed data PKCS#7 */ // if (!PKCS7_type_is_signed(p7)) { // BIO_printf(bio_err, "%s:%d: supplied PKCS#7 is not signed " // "data\n", __FILE__, __LINE__); // goto err; // } /* create BIOs to read signed content data from */ p7bio = PKCS7_dataInit(p7, NULL); if (p7bio == NULL) goto err; /* Use an outbio and fill it with data from the p7 */ outbio = BIO_new(BIO_s_mem()); used = 0; for (;;) { bytes = BIO_read(p7bio, buffer, sizeof(buffer)); used += bytes; if (bytes <= 0) break; BIO_write(outbio, buffer, bytes); } BIO_flush(outbio); /* there should be exactly one signer info */ msg->sk_signer_info = PKCS7_get_signer_info(p7); if (msg->sk_signer_info == NULL) { goto err; } if (sk_PKCS7_SIGNER_INFO_num(msg->sk_signer_info) != 1) { goto err; } si = sk_PKCS7_SIGNER_INFO_value(msg->sk_signer_info, 0); msg->signer_ias = si->issuer_and_serial; msg->signer_cert = PKCS7_cert_from_signer_info( p7, si ); /* If msg->signer_cert == NULL there is no signer certificate, * otherwise the certificate is included into the PKCS#7 envelope * this certificate may be self signed, but for the PKCS7_ * signatureVerify method, this does not matter */ /* verify the PKCS#7 using the store just constructed */ if (PKCS7_signatureVerify(p7bio, p7, si, msg->signer_cert) <= 0) { // BIO_printf(bio_err, "%s:%d: verification failed\n", __FILE__, // __LINE__); goto err; } /* extract the signed attributes */ msg->attrs = PKCS7_get_signed_attributes(si); if ((msg->attrs == NULL) || (sk_X509_ATTRIBUTE_num(msg->attrs) == 0)){ goto err; } tmp_string = (char *) SCEP_get_string_attr_by_name(msg->attrs, "messageType"); if( tmp_string != NULL ) { msg->messageType = atoi( tmp_string ); free( tmp_string ); tmp_string = NULL; } else { msg->messageType = -1; } /* unpack the internal PKCS#7 */ p7env = d2i_PKCS7_bio(outbio, NULL); if (p7env == NULL) return msg; i=OBJ_obj2nid(p7env->type); msg->env_data.NID_p7data = i; msg->env_data.p7env = p7env; /* use a commodity variable */ rinfo = &(msg->env_data.recip_info); switch(i) { case NID_pkcs7_signed: break; case NID_pkcs7_signedAndEnveloped: rinfo->sk_recip_info = p7env->d.signed_and_enveloped->recipientinfo; break; case NID_pkcs7_enveloped: rinfo->sk_recip_info = p7env->d.enveloped->recipientinfo; break; default: // BIO_printf( bio_err, "%s:%d: unknown PKCS7 structure\n", // __FILE__, __LINE__); break; } /* Lets do the pub key stuff :-) */ // FIXME: usaly only 1, but pix has 4 in structure - to be clarified... // so currently set to 4 to get it working with cisco-pix if( sk_PKCS7_RECIP_INFO_num(rinfo->sk_recip_info) > 4 ) { goto err; } /* Let's get the recipient info at stack num 0, the first and * hopefully, the only one */ ri = sk_PKCS7_RECIP_INFO_value( rinfo->sk_recip_info, 0); /* Usually certificates are not present, but in case the standard * will be updated... */ // if (debug && ri->cert == NULL) { // BIO_printf( bio_err, // "%s:%d: Recipient info cert %d missing\n", // __FILE__, __LINE__, 0); // } rinfo->ias = ri->issuer_and_serial; /* if( rinfo->ias != NULL ) { BIO_printf(bio_err, "%s:%d: Recip cert issued by ", __FILE__, __LINE__); X509_NAME_print_ex (bio_err, rinfo->ias->issuer, 0, XN_FLAG_RFC2253&(~ASN1_STRFLGS_ESC_MSB)); BIO_printf(bio_err, "\n%s:%d: Recip cert serial: %s\n", __FILE__, __LINE__, BN_bn2hex(ASN1_INTEGER_to_BN(rinfo->ias->serial, NULL))); }; */ if( ri->cert ) { /* Usually this does not happen to be included in * the pkcs7env data, but in case we just get it */ sk_X509_push( rinfo->sk_recip_certs, ri->cert ); /* if ( debug ) { BIO_printf(bio_err, "%s:%d: Recipient cert for ", __FILE__, __LINE__); X509_NAME_print_ex (bio_err, X509_get_subject_name(ri->cert), 0, XN_FLAG_RFC2253&(~ASN1_STRFLGS_ESC_MSB)); BIO_printf(bio_err, "\n"); } */ } /* perform some consistency checks */ /* UniCert 3.1.2 seems to out the message type, so fudge */ /* the value of 3 (CertRep) if it is missing (problem pointed */ /* out by Peter Onion */ /* if (NULL == req->messageType) { BIO_printf(bio_err, "%s:%d: no message type (setting to 3)\n", __FILE__, __LINE__); req->messageType = "3"; // XXX should we strdup here? } */ /* UniCert doesn't seem to bother to put in a senderNonce, */ /* so don't get upset if it is missing. */ /* if (NULL == scep->senderNonce) { BIO_printf(bio_err, "%s:%d: senderNonce missing\n", __FILE__, __LINE__); } */ /* perform some type/status dependent checks */ /* if ((used == 0) && (nMessageType != 3)) { BIO_printf(bio_err, "%s:%d: only CertRep message may be " "empty\n", __FILE__, __LINE__); goto err; } if ((used == 0) && (nMessageType == 3) && (nPkiStatus == 0)) { BIO_printf(bio_err, "%s:%d: CertRep may only be empty for " "failure or pending\n", __FILE__, __LINE__); goto err; } */ /* no content is only allowed if the message is a CertRep with */ /* a pkiStatus of failure or pending */ /* if (used == 0) { BIO_printf(bio_err, "%s:%d: empty PKCSReq, must be failure or " "pending\n", __FILE__, __LINE__); goto signedonly; } if (debug) BIO_printf(bio_err, "%s:%d: working on inner pkcs#7\n", __FILE__, __LINE__); */ BIO_free(outbio); signedonly: /* we were successfull in extracting the telescoping PKCS#7's */ return(msg); err: // if( debug ) ERR_print_errors(bio_err); return(NULL); }
/* * 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; }
static LUA_FUNCTION(openssl_pkcs7_verify_digest) { PKCS7 *p7 = CHECK_OBJECT(1, PKCS7, "openssl.pkcs7"); STACK_OF(X509) *certs = lua_isnoneornil(L, 2) ? NULL : openssl_sk_x509_fromtable(L, 2); X509_STORE *store = lua_isnoneornil(L, 3) ? NULL : CHECK_OBJECT(3, X509_STORE, "openssl.x509_store"); size_t len; const char* data = luaL_checklstring(L, 4, &len); long flags = luaL_optint(L, 5, 0); int hash = lua_isnoneornil(L, 6) ? 0 : lua_toboolean(L, 6); STACK_OF(X509) *signers; X509 *signer; STACK_OF(PKCS7_SIGNER_INFO) *sinfos; PKCS7_SIGNER_INFO *si; X509_STORE_CTX cert_ctx; int i, j = 0, k, ret = 0; if (!PKCS7_type_is_signed(p7)) { luaL_error(L, "pkcs7 must be signedData"); } /* Check for no data and no content: no data to verify signature */ if (!PKCS7_get_detached(p7)) { luaL_error(L, "pkcs7 must be detached signedData"); } sinfos = PKCS7_get_signer_info(p7); if (!sinfos || !sk_PKCS7_SIGNER_INFO_num(sinfos)) { luaL_error(L, "pkcs7 signedData without signature"); } signers = PKCS7_get0_signers(p7, certs, flags); if (!signers) { luaL_error(L, "pkcs7 signedData without signers"); } if (!store) flags |= PKCS7_NOVERIFY; /* Now verify the certificates */ if (!(flags & PKCS7_NOVERIFY)) for (k = 0; k < sk_X509_num(signers); k++) { signer = sk_X509_value(signers, k); if (!(flags & PKCS7_NOCHAIN)) { if (!X509_STORE_CTX_init(&cert_ctx, store, signer, p7->d.sign->cert)) { PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB); goto err; } X509_STORE_CTX_set_default(&cert_ctx, "smime_sign"); } else if (!X509_STORE_CTX_init(&cert_ctx, store, signer, NULL)) { PKCS7err(PKCS7_F_PKCS7_VERIFY, ERR_R_X509_LIB); goto err; } if (!(flags & PKCS7_NOCRL)) X509_STORE_CTX_set0_crls(&cert_ctx, p7->d.sign->crl); i = X509_verify_cert(&cert_ctx); if (i <= 0) j = X509_STORE_CTX_get_error(&cert_ctx); X509_STORE_CTX_cleanup(&cert_ctx); if (i <= 0) { PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_CERTIFICATE_VERIFY_ERROR); ERR_add_error_data(2, "Verify error:", X509_verify_cert_error_string(j)); goto err; } /* Check for revocation status here */ } /* Now Verify All Signatures */ if (!(flags & PKCS7_NOSIGS)) for (i = 0; i < sk_PKCS7_SIGNER_INFO_num(sinfos); i++) { si = sk_PKCS7_SIGNER_INFO_value(sinfos, i); signer = sk_X509_value(signers, i); j = PKCS7_signatureVerify_digest(p7, si, signer, (const unsigned char*) data, len, hash); if (j <= 0) { PKCS7err(PKCS7_F_PKCS7_VERIFY, PKCS7_R_SIGNATURE_FAILURE); goto err; } } ret = 1; err: if (certs) sk_X509_pop_free(certs, X509_free); sk_X509_free(signers); return openssl_pushresult(L, ret); }
/* * 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); }
char* /* returns contents of the signed message, NULL if error */ smime_verify_signature(const char* pubkey, const char* sig_entity, /* signed entity or just the sigature */ const char* detached_data, /* possibly NULL */ int detached_data_len) { X509* x509 = NULL; PKCS7* p7 = NULL; STACK_OF(PKCS7_SIGNER_INFO)* sigs = NULL; X509_STORE* certs=NULL; BIO* detached = NULL; BIO* p7bio = NULL; BIO* wbio = NULL; char* data = NULL; char buf[4096]; int i,x; if (!sig_entity || !pubkey) GOTO_ERR("NULL arg(s)"); if (!(p7 = get_pkcs7_from_pem(sig_entity))) goto err; /* Hmm, if its clear signed, we already provided the detached sig, but * if its one sig blob, may be PKCS7_get_detached() provides BIO connected * to the detached part. Go figure. */ if (detached_data && detached_data_len) { if (!(detached = set_read_BIO_from_buf(detached_data, detached_data_len))) goto err; } else { if (!PKCS7_get_detached(p7)) GOTO_ERR("15 cant extract signed data from signed entity (PKCS7_get_detached)"); } if (!(p7bio=PKCS7_dataInit(p7,detached))) GOTO_ERR("PKCS7_dataInit"); if (!(wbio = BIO_new(BIO_s_mem()))) GOTO_ERR("no memory?"); /* We now have to 'read' from p7bio to calculate message digest(s). * I also take the opportunity to save the signed data. */ for (;;) { i = BIO_read(p7bio,buf,sizeof(buf)); if (i <= 0) break; BIO_write(wbio, buf, i); } if (get_written_BIO_data(wbio, &data)==-1) goto err; BIO_free_all(wbio); wbio = NULL; /* We can now verify signatures */ if (!(sigs=PKCS7_get_signer_info(p7))) GOTO_ERR("13 no sigs? (PKCS7_get_signer_info)"); /* Ok, first we need to, for each subject entry, see if we can verify */ for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sigs); i++) { X509_STORE_CTX cert_ctx; PKCS7_SIGNER_INFO *si; ASN1_UTCTIME *tm; char *str1,*str2; si=sk_PKCS7_SIGNER_INFO_value(sigs,i); /* The bio is needed here only to lookup the message digest context * which presumably now contains the message digest. It will not be * read, and hence its good for any number of iterations. This is so * because MD bios pass the data right thru so they can be stacked * to calculate multiple message digests simultaneously. Clever, eh? */ #if 0 /* *** this is currently broken and thus disabled. --Sampo */ /* verifies by looking up the certificate from certs database, * verifying the validity of the certificate, and finally * validity of the signature */ x=PKCS7_dataVerify(certs, &cert_ctx, p7bio, p7, si); #else /* just verify the signature, given that we already have certificate * candidate (see crypto/pk7_doit.c around line 675) */ if (!(x509 = extract_certificate(pubkey))) goto err; x=PKCS7_signatureVerify(p7bio, p7, si, x509); #endif if (x <= 0) GOTO_ERR("14 sig verify failed"); #if 0 if ((tm=get_signed_time(si)) != NULL) { //fprintf(stderr,"Signed time:"); //ASN1_UTCTIME_print(bio_out,tm); ASN1_UTCTIME_free(tm); //BIO_printf(bio_out,"\n"); } #endif #if 0 if (get_signed_seq2string(si,&str1,&str2)) { fprintf(stderr,"String 1 is %s\n",str1); fprintf(stderr,"String 2 is %s\n",str2); } #endif } BIO_free_all(p7bio); PKCS7_free(p7); X509_STORE_free(certs); return data; /* return the signed plain text */ err: if (wbio) BIO_free_all(wbio); if (p7bio) BIO_free_all(p7bio); if (p7) PKCS7_free(p7); if (certs) X509_STORE_free(certs); if (data) Free(data); return NULL; }