/* * read an attribute of type string */ char *sigattr_string(scep_t *scep, char *attrname) { STACK_OF(X509_ATTRIBUTE) *sig_attribs; ASN1_OBJECT *asn1_obj; ASN1_TYPE *asn1_type; X509_ATTRIBUTE *attr; int len, i; char *data = NULL; scepmsg_t *msg; if (debug) BIO_printf(bio_err, "%s:%d: looking for attribute '%s'\n", __FILE__, __LINE__, attrname); /* decide which message to study: client reads attrs from reply */ if (scep->client) msg = &scep->reply; else msg = &scep->request; /* find the object we by name */ asn1_obj = OBJ_nid2obj(OBJ_sn2nid(attrname)); asn1_type = NULL; /* retrieve the stack of signed attributes */ if (NULL == (sig_attribs = PKCS7_get_signed_attributes(msg->si))) { BIO_printf(bio_err, "%s:%d: no signed attributes\n", __FILE__, __LINE__); return NULL; } /* scan all attributes for the one we are looking for */ for (i = 0; i < sk_X509_ATTRIBUTE_num(sig_attribs); i++) { attr = sk_X509_ATTRIBUTE_value(sig_attribs, i); if (OBJ_cmp(attr->object, asn1_obj) == 0) { if (debug) BIO_printf(bio_err, "%s:%d: found attribute\n", __FILE__, __LINE__); asn1_type = sk_ASN1_TYPE_value(attr->value.set, 0); break; } } /* if we cannot find the required argument, we just return NULL */ if (asn1_type == NULL) { BIO_printf(bio_err, "%s:%d: cannot find attribute\n", __FILE__, __LINE__); goto err; } if (ASN1_TYPE_get(asn1_type) != V_ASN1_PRINTABLESTRING) { BIO_printf(bio_err, "%s:%d: attribute has wrong type\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: found attribute '%s'\n", __FILE__, __LINE__, attrname); /* unpack the ASN1_STRING into a C-String (0-terminated) */ len = ASN1_STRING_length(asn1_type->value.asn1_string); data = (char *)malloc(1 + len); memcpy(data, ASN1_STRING_data(asn1_type->value.asn1_string), len); data[len] = '\0'; if (debug) BIO_printf(bio_err, "%s:%d: value of %d bytes retrieved\n", __FILE__, __LINE__, len); /* return the data */ return data; err: ERR_print_errors(bio_err); return NULL; }
ASN1_OCTET_STRING *sigattr_asn1_octet(scep_t *scep, char *attrname) { STACK_OF(X509_ATTRIBUTE) *sig_attribs; ASN1_OBJECT *asn1_obj; ASN1_TYPE *asn1_type; X509_ATTRIBUTE *attr; int i; scepmsg_t *msg; int single; if (debug) BIO_printf(bio_err, "%s:%d: looking for attribute '%s'\n", __FILE__, __LINE__, attrname); /* decide which message to study: client reads attrs from reply */ if (scep->client) msg = &scep->reply; else msg = &scep->request; /* find the object we by name */ asn1_obj = OBJ_nid2obj(OBJ_sn2nid(attrname)); asn1_type = NULL; /* retrieve the stack of signed attributes */ if (NULL == (sig_attribs = PKCS7_get_signed_attributes(msg->si))) { BIO_printf(bio_err, "%s:%d: signed attributes not found\n", __FILE__, __LINE__); return NULL; } /* scan all attributes for the one we are looking for */ for (i = 0; i < sk_X509_ATTRIBUTE_num(sig_attribs); i++) { attr = sk_X509_ATTRIBUTE_value(sig_attribs, i); if (OBJ_cmp(attr->object, asn1_obj) == 0) { #if OPENSSL_VERSION_NUMBER < 0x00907000L /* attr->set was replaced with attr->single (with opposite meaning) somewhere between 0.9.6m-engine and 0.9.7d */ single = !attr->set; #else single = attr->single; #endif if (single || (sk_ASN1_TYPE_num(attr->value.set) == 0)) { BIO_printf(bio_err, "%s:%d: attr has no val\n",__FILE__, __LINE__); goto err; BIO_printf(bio_err, "%s:%d: attr has no val\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: found matching " "attribute with %d values\n", __FILE__, __LINE__, sk_ASN1_TYPE_num(attr->value.set)); asn1_type = sk_ASN1_TYPE_value(attr->value.set, 0); if (debug) BIO_printf(bio_err, "%s:%d: type found: %p\n", __FILE__, __LINE__, asn1_type); break; } } /* if we cannot find the required argument, we just return NULL */ if (debug) BIO_printf(bio_err, "%s:%d: checking for attribute\n", __FILE__, __LINE__); if (asn1_type == NULL) { BIO_printf(bio_err, "%s:%d: attribute has no type\n", __FILE__, __LINE__); goto err; } if (ASN1_TYPE_get(asn1_type) != V_ASN1_OCTET_STRING) { BIO_printf(bio_err, "%s:%d: attribute has wrong type\n", __FILE__, __LINE__); goto err; } if (debug) BIO_printf(bio_err, "%s:%d: found attribute '%s'\n", __FILE__, __LINE__, attrname); /* this is an ASN1_OCTET_STRING, so we can retrieve the */ /* appropriate element of the union */ return asn1_type->value.octet_string; /* error return, or attribute not found */ err: if (debug) BIO_printf(bio_err, "%s:%d: attribute not found or error\n", __FILE__, __LINE__); ERR_print_errors(bio_err); return NULL; }
/******************************************************************************* 函数名称: 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; }
/* 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; }
/* * 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); }