pgp_get_card_features(sc_card_t *card)
{
	struct pgp_priv_data *priv = DRVDATA(card);
	u8 *hist_bytes = card->reader->atr_info.hist_bytes;
	size_t hist_bytes_len = card->reader->atr_info.hist_bytes_len;
	size_t i;
	pgp_blob_t *blob, *blob6e, *blob73;

	/* parse card capabilities from historical bytes in ATR */
	if (hist_bytes_len > 0) {
		/* category indicator 0x00, 0x10 or 0x80 => compact TLV (ISO) */
		switch (hist_bytes[0]) {
			case 0x00:
				pgp_parse_hist_bytes(card, hist_bytes+1, hist_bytes_len-4);
				break;
			case 0x80:
				pgp_parse_hist_bytes(card, hist_bytes+1, hist_bytes_len-1);
				break;
			case 0x10:
				pgp_parse_hist_bytes(card, hist_bytes+2, hist_bytes_len-2);
				break;
		}
	}

	/* v1.1 does not support lifecycle via ACTIVATE & TERMINATE: set default */
	priv->ext_caps &= ~EXT_CAP_LCS;

	if (priv->bcd_version >= OPENPGP_CARD_2_0) {
		/* get card capabilities from "historical bytes" DO */
		if ((pgp_get_blob(card, priv->mf, 0x5f52, &blob) >= 0) &&
		    (blob->data != NULL) && (blob->data[0] == 0x00)) {

			pgp_parse_hist_bytes(card, hist_bytes+1, hist_bytes_len-4);

			/* get card status from historical bytes status indicator */
			if ((blob->data[0] == 0x00) && (blob->len >= 4)) {
				priv->state = blob->data[blob->len-3];
				/* state not CARD_STATE_UNKNOWN => LCS supported */
				if (priv->state != CARD_STATE_UNKNOWN)
					priv->ext_caps |= EXT_CAP_LCS;
			}
		}
	}

	if (priv->bcd_version >= OPENPGP_CARD_3_1) {
		card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
	}

	if ((pgp_get_blob(card, priv->mf, 0x006e, &blob6e) >= 0) &&
	    (pgp_get_blob(card, blob6e, 0x0073, &blob73) >= 0)) {

		/* get "extended capabilities" DO */
		if ((pgp_get_blob(card, blob73, 0x00c0, &blob) >= 0) &&
		    (blob->data != NULL) && (blob->len > 0)) {
			/* v2.0+: bit 0x04 in first byte means "algorithm attributes changeable" */
			if ((blob->data[0] & 0x04) &&
					(priv->bcd_version >= OPENPGP_CARD_2_0))
				priv->ext_caps |= EXT_CAP_ALG_ATTR_CHANGEABLE;
			/* bit 0x08 in first byte means "support for private use DOs" */
			if (blob->data[0] & 0x08)
				priv->ext_caps |= EXT_CAP_PRIVATE_DO;
			/* bit 0x10 in first byte means "support for CHV status byte changeable" */
			if (blob->data[0] & 0x10)
				priv->ext_caps |= EXT_CAP_C4_CHANGEABLE;
			/* bit 0x20 in first byte means "support for Key Import" */
			if (blob->data[0] & 0x20)
				priv->ext_caps |= EXT_CAP_KEY_IMPORT;
			/* bit 0x40 in first byte means "support for Get Challenge" */
			if (blob->data[0] & 0x40) {
				card->caps |= SC_CARD_CAP_RNG;
				priv->ext_caps |= EXT_CAP_GET_CHALLENGE;
			}
			/* v2.0+: bit 0x80 in first byte means "support Secure Messaging" */
			if ((blob->data[0] & 0x80) &&
					(priv->bcd_version >= OPENPGP_CARD_2_0))
				priv->ext_caps |= EXT_CAP_SM;

			if ((priv->bcd_version >= OPENPGP_CARD_2_0) && (blob->len >= 10)) {
				/* v2.0+: max. challenge size is at bytes 3-4 */
				priv->max_challenge_size = bebytes2ushort(blob->data + 2);
				/* v2.0+: max. cert size it at bytes 5-6 */
				priv->max_cert_size = bebytes2ushort(blob->data + 4);

				if (priv->bcd_version < OPENPGP_CARD_3_0) {
					/* v2.x: SM algorithm is at byte 2: 0 == 3DES */
					priv->sm_algo = blob->data[0];
					if ((priv->sm_algo == SM_ALGO_NONE) && (priv->ext_caps & EXT_CAP_SM))
						priv->sm_algo = SM_ALGO_3DES;

					/* v2.x: max. send/receive sizes are at bytes 7-8 resp. 9-10 */
					card->max_send_size = bebytes2ushort(blob->data + 6);
					card->max_recv_size = bebytes2ushort(blob->data + 8);
				}
				else {
					/* v3.0+: SM algorithm is at byte 2: 0 == UNKNOWN */
					priv->sm_algo = blob->data[0];
					if ((priv->sm_algo == SM_ALGO_NONE) && (priv->ext_caps & EXT_CAP_SM))
						priv->sm_algo = SM_ALGO_UNKNOWN;
				}
			}
		}

		/* get max. PIN length from "CHV status bytes" DO */
		if ((pgp_get_blob(card, blob73, 0x00c4, &blob) >= 0) &&
			(blob->data != NULL) && (blob->len > 1)) {
			/* 2nd byte in "CHV status bytes" DO means "max. PIN length" */
			card->max_pin_len = blob->data[1];
		}

		/* get supported algorithms & key lengths from "algorithm attributes" DOs */
		for (i = 0x00c1; i <= 0x00c3; i++) {
			unsigned long flags;

			/* Is this correct? */
			/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 / v3.x section 7.2.11 & 7.2.12 */
			flags = SC_ALGORITHM_RSA_PAD_PKCS1;
			flags |= SC_ALGORITHM_RSA_HASH_NONE;
			/* Can be generated in card */
			flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;

			/* OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */
			if ((pgp_get_blob(card, blob73, i, &blob) >= 0) && (blob->data != NULL)) {
				if (blob->len >= 3 && blob->data[0] == 0x01) {	/* RSA [RFC 4880] */
					unsigned int keybits = bebytes2ushort(blob->data + 1);

					_sc_card_add_rsa_alg(card, keybits, flags, 0);
				}
				/* v3.0+: [RFC 4880 & 6637] 0x12 = ECDH, 0x13 = ECDSA */
			}
		}

		if (priv->bcd_version >= OPENPGP_CARD_3_0) {
			/* v3.0+: get length info from "extended length information" DO */
			if ((pgp_get_blob(card, blob6e, 0x7f66, &blob) >= 0) &&
				(blob->data != NULL) && (blob->len >= 8)) {
				/* kludge: treat as SIMPLE DO and use appropriate offsets */
				card->max_send_size = bebytes2ushort(blob->data + 2);
				card->max_recv_size = bebytes2ushort(blob->data + 6);
			}
		}
	}

	return SC_SUCCESS;
}