Ejemplo n.º 1
0
/*
 * 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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
/*******************************************************************************
函数名称: 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;
}
Ejemplo n.º 4
0
/* 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);
}
Ejemplo n.º 5
0
/*
 * 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;
}
Ejemplo n.º 6
0
Archivo: pkcs7.c Proyecto: OPSF/uClinux
/*
 * 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);

}