Ejemplo n.º 1
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.º 2
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);

}