Diff

Differences From Artifact [e326e231e2]:

To Artifact [d2a004aade]:


   154    154   #define GSCIS_TAG_EXPIRE_DATE         0x53
   155    155   #define GSCIS_TAG_CARD_TYPE           0x54
   156    156   #define GSCIS_TAG_SECURITY_CODE       0x57
   157    157   #define GSCIS_TAG_CARDID_AID          0x58
   158    158   
   159    159   /*** PIV Codes ***/
   160    160   #define NISTSP800_73_3_INSTR_GET_DATA 0xCB
          161  +#define NISTSP800_73_3_INSTR_GENAUTH  0x87
   161    162   
   162    163   /*** PKI Information - EF 7000 ***/
   163    164   #define GSCIS_TAG_CERTIFICATE         0x70
   164    165   #define GSCIS_TAG_CERT_ISSUE_DATE     0x71
   165    166   #define GSCIS_TAG_CERT_EXPIRE_DATE    0x72
   166    167   
   167    168   /** Applet IDs **/
................................................................................
  1376   1377    *     cackey_pcsc_connect() if needed.
  1377   1378    *
  1378   1379    *     It will connect to the card in the reader attached to the slot
  1379   1380    *     specified.  It will reconnect to the card if the connection
  1380   1381    *     goes away.
  1381   1382    *
  1382   1383    */
  1383         -static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned char lc, unsigned char *data, unsigned char le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) {
         1384  +static cackey_ret cackey_send_apdu(struct cackey_slot *slot, unsigned char class, unsigned char instruction, unsigned char p1, unsigned char p2, unsigned int lc, unsigned char *data, unsigned int le, uint16_t *respcode, unsigned char *respdata, size_t *respdata_len) {
  1384   1385   	uint8_t major_rc, minor_rc;
  1385   1386   	size_t bytes_to_copy, tmp_respdata_len;
  1386   1387   	LPCSCARD_IO_REQUEST pioSendPci;
  1387   1388   	DWORD protocol;
  1388   1389   	DWORD xmit_len, recv_len;
  1389   1390   	LONG scard_xmit_ret, scard_reconn_ret;
  1390   1391   	BYTE xmit_buf[1024], recv_buf[1024];
................................................................................
  1425   1426   	/* Transmit */
  1426   1427   	xmit_len = 0;
  1427   1428   	xmit_buf[xmit_len++] = class;
  1428   1429   	xmit_buf[xmit_len++] = instruction;
  1429   1430   	xmit_buf[xmit_len++] = p1;
  1430   1431   	xmit_buf[xmit_len++] = p2;
  1431   1432   	if (data) {
  1432         -		xmit_buf[xmit_len++] = lc;
         1433  +		if (lc > 256) {
         1434  +			xmit_buf[xmit_len++] = 0x80; /* XXX UNTESTED */
         1435  +			xmit_buf[xmit_len++] = (lc & 0xff00) >> 8;
         1436  +			xmit_buf[xmit_len++] = lc & 0xff;
         1437  +		} else {
         1438  +			xmit_buf[xmit_len++] = lc;
         1439  +		}
  1433   1440   		for (idx = 0; idx < lc; idx++) {
  1434   1441   			xmit_buf[xmit_len++] = data[idx];
  1435   1442   		}
  1436   1443   	}
  1437   1444   
  1438   1445   	if (le != 0x00) {
  1439         -		xmit_buf[xmit_len++] = le;
         1446  +		if (le > 256) {
         1447  +			xmit_buf[xmit_len++] = 0x80; /* XXX UNTESTED */
         1448  +			xmit_buf[xmit_len++] = (le & 0xff00) >> 8;
         1449  +			xmit_buf[xmit_len++] = le & 0xff;
         1450  +		} else if (le == 256) {
         1451  +			xmit_buf[xmit_len++] = 0x00;
         1452  +		} else {
         1453  +			xmit_buf[xmit_len++] = le;
         1454  +		}
  1440   1455   	}
  1441   1456   
  1442   1457   	/* Begin Smartcard Transaction */
  1443   1458   	cackey_begin_transaction(slot);
  1444   1459   
  1445   1460   	if (class == GSCIS_CLASS_ISO7816 && instruction == GSCIS_INSTR_VERIFY && p1 == 0x00) {
  1446   1461   		CACKEY_DEBUG_PRINTF("Sending APDU: <<censored>>");
................................................................................
  2281   2296    *     ...
  2282   2297    *
  2283   2298    */
  2284   2299   static struct cackey_pcsc_identity *cackey_read_certs(struct cackey_slot *slot, struct cackey_pcsc_identity *certs, unsigned long *count) {
  2285   2300   	struct cackey_pcsc_identity *curr_id;
  2286   2301   	struct cackey_tlv_entity *ccc_tlv, *ccc_curr, *app_tlv, *app_curr;
  2287   2302   	unsigned char ccc_aid[] = {GSCIS_AID_CCC}, piv_aid[] = {NISTSP800_73_3_PIV_AID};
  2288         -	unsigned char piv_oid_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH};
         2303  +	unsigned char *piv_oid, piv_oid_pivauth[] = {NISTSP800_73_3_OID_PIVAUTH}, piv_oid_signature[] = {NISTSP800_73_3_OID_SIGNATURE}, piv_oid_keymgt[] = {NISTSP800_73_3_OID_KEYMGT};
  2289   2304   	unsigned char curr_aid[7];
  2290   2305   	unsigned char buffer[8192];
  2291   2306   	unsigned long outidx = 0;
  2292   2307   	cackey_ret transaction_ret;
  2293   2308   	ssize_t read_ret;
  2294   2309   	int certs_resizable;
  2295   2310   	int send_ret, select_ret;
  2296         -	int piv = 0;
         2311  +	int piv_key, piv = 0;
         2312  +	int idx;
  2297   2313   
  2298   2314   	CACKEY_DEBUG_PRINTF("Called.");
  2299   2315   
  2300   2316   	if (count == NULL) {
  2301   2317   		CACKEY_DEBUG_PRINTF("count is NULL, returning in failure");
  2302   2318   
  2303   2319   		return(NULL);
................................................................................
  2368   2384   			cackey_end_transaction(slot);
  2369   2385   
  2370   2386   			return(NULL);
  2371   2387   		}
  2372   2388   	}
  2373   2389   
  2374   2390   	if (piv) {
  2375         -		read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid_pivauth);
  2376         -
  2377         -		curr_id = &certs[outidx];
  2378         -		outidx++;
  2379         -
  2380         -		curr_id->keysize = -1;
  2381         -		curr_id->file = 0xFFFF;
  2382         -		curr_id->applet[0] = NISTSP800_78_3_KEY_PIVAUTH;
  2383         -
  2384         -		curr_id->certificate_len = read_ret;
  2385         -		curr_id->certificate = malloc(curr_id->certificate_len);
  2386         -		memcpy(curr_id->certificate, buffer + 4, curr_id->certificate_len - 4); /* XXX TODO PIV */
         2391  +		for (idx = 0; idx < 3; idx++) {
         2392  +			switch (idx) {
         2393  +				case 0:
         2394  +					piv_oid = piv_oid_pivauth;
         2395  +					piv_key = NISTSP800_78_3_KEY_PIVAUTH;
         2396  +					break;
         2397  +				case 1:
         2398  +					piv_oid = piv_oid_signature;
         2399  +					piv_key = NISTSP800_78_3_KEY_SIGNATURE;
         2400  +					break;
         2401  +				case 2:
         2402  +					piv_oid = piv_oid_keymgt;
         2403  +					piv_key = NISTSP800_78_3_KEY_KEYMGT;
         2404  +					break;
         2405  +			}
         2406  +
         2407  +			read_ret = cackey_get_data(slot, buffer, sizeof(buffer), piv_oid);
         2408  +
         2409  +			if (read_ret <= 0) {
         2410  +				continue;
         2411  +			}
         2412  +
         2413  +			curr_id = &certs[outidx];
         2414  +			outidx++;
         2415  +
         2416  +			curr_id->keysize = -1;
         2417  +			curr_id->file = 0xFFFF;
         2418  +			curr_id->applet[0] = piv_key;
         2419  +
         2420  +			curr_id->certificate_len = read_ret;
         2421  +			curr_id->certificate = malloc(curr_id->certificate_len);
         2422  +			memcpy(curr_id->certificate, buffer + 4, curr_id->certificate_len - 4); /* XXX TODO PIV (-4 header, -5 trailer == why ?) */
         2423  +			curr_id->certificate_len -= 4;
         2424  +			curr_id->certificate_len -= 5;
         2425  +		}
  2387   2426   	} else {
  2388   2427   		/* Read all the applets from the CCC's TLV */
  2389   2428   		ccc_tlv = cackey_read_tlv(slot);
  2390   2429   
  2391   2430   		/* Look for CARDURLs that coorespond to PKI applets */
  2392   2431   		for (ccc_curr = ccc_tlv; ccc_curr; ccc_curr = ccc_curr->_next) {
  2393   2432   			CACKEY_DEBUG_PRINTF("Found tag: %s ... ", CACKEY_DEBUG_FUNC_TAG_TO_STR(ccc_curr->tag));
................................................................................
  2500   2539    *     ...
  2501   2540    *
  2502   2541    * NOTES
  2503   2542    *     ...
  2504   2543    *
  2505   2544    */
  2506   2545   static ssize_t cackey_signdecrypt(struct cackey_slot *slot, struct cackey_identity *identity, unsigned char *buf, size_t buflen, unsigned char *outbuf, size_t outbuflen, int padInput, int unpadOutput) {
         2546  +	unsigned char dyn_auth_template[10];
  2507   2547   	unsigned char *tmpbuf, *tmpbuf_s, *outbuf_s;
  2508         -	unsigned char bytes_to_send, p1;
         2548  +	unsigned char bytes_to_send, p1, class;
  2509   2549   	unsigned char blocktype;
  2510   2550   	cackey_ret send_ret;
  2511   2551   	uint16_t respcode;
  2512   2552   	ssize_t retval = 0, unpadoffset;
  2513   2553   	size_t tmpbuflen, padlen, tmpoutbuflen;
  2514   2554   	int free_tmpbuf = 0;
  2515   2555   	int le;
................................................................................
  2597   2637   		free_tmpbuf = 0;
  2598   2638   		padlen = 0;
  2599   2639   	}
  2600   2640   
  2601   2641   	/* Begin transaction */
  2602   2642   	cackey_begin_transaction(slot);
  2603   2643   
  2604         -	/* Select correct applet */
         2644  +	/* Determine type of transaction */
  2605   2645   	if (identity->pcsc_identity->file == 0xFFFF) {
  2606   2646   		piv = 1;
  2607   2647   	} else {
  2608   2648   		piv = 0;
  2609   2649   	}
  2610   2650   
  2611         -	if (piv) {
  2612         -		CACKEY_DEBUG_PRINTF("Sign/Decrypt not implemented XXX TODO PIV");
  2613         -		cackey_end_transaction(slot);
  2614         -		return(-1);
  2615         -	} else {
         2651  +	/* Select correct applet */
         2652  +	if (!piv) {
  2616   2653   		CACKEY_DEBUG_PRINTF("Selecting applet found at %p ...", identity->pcsc_identity->applet);
  2617   2654   		cackey_select_applet(slot, identity->pcsc_identity->applet, sizeof(identity->pcsc_identity->applet));
  2618   2655   
  2619   2656   		/* Select correct file */
  2620   2657   		cackey_select_file(slot, identity->pcsc_identity->file);
         2658  +	} else {
         2659  +		dyn_auth_template[0] = 0x7C;
         2660  +		dyn_auth_template[1] = 0x82;
         2661  +		dyn_auth_template[2] = ((tmpbuflen + 6) & 0xff00) >> 8;
         2662  +		dyn_auth_template[3] = (tmpbuflen + 6) & 0x00ff;
         2663  +		dyn_auth_template[4] = 0x82;
         2664  +		dyn_auth_template[5] = 0x00;
         2665  +		dyn_auth_template[6] = 0x81;
         2666  +		dyn_auth_template[7] = 0x82;
         2667  +		dyn_auth_template[8] = (tmpbuflen & 0xff00) >> 8;
         2668  +		dyn_auth_template[9] = tmpbuflen & 0x00ff;
  2621   2669   
  2622         -		tmpbuf_s = tmpbuf;
  2623         -		outbuf_s = outbuf;
  2624         -		while (tmpbuflen) {
  2625         -			if (tmpbuflen > 245) {
  2626         -				bytes_to_send = 245;
  2627         -				p1 = 0x80;
         2670  +		send_ret = cackey_send_apdu(slot, 0x10, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->applet[0], sizeof(dyn_auth_template), dyn_auth_template, 0x00, NULL, NULL, NULL);
         2671  +	}
         2672  +
         2673  +	tmpbuf_s = tmpbuf;
         2674  +	outbuf_s = outbuf;
         2675  +	while (tmpbuflen) {
         2676  +		if (tmpbuflen > 245) {
         2677  +			bytes_to_send = 245;
         2678  +			if (piv) {
         2679  +				class = 0x10;
  2628   2680   				le = 0x00;
  2629   2681   			} else {
  2630         -				bytes_to_send = tmpbuflen;
         2682  +				p1 = 0x80;
         2683  +				le = 0x00;
         2684  +			}
         2685  +		} else {
         2686  +			bytes_to_send = tmpbuflen;
         2687  +			if (piv) {
         2688  +				class = GSCIS_CLASS_ISO7816;
         2689  +				le = 256;
         2690  +			} else {
  2631   2691   				p1 = 0x00;
  2632   2692   				le = 0x00;
  2633   2693   			}
         2694  +		}
  2634   2695   
  2635         -			tmpoutbuflen = outbuflen;
         2696  +		tmpoutbuflen = outbuflen;
  2636   2697   
         2698  +		if (piv) {
         2699  +			send_ret = cackey_send_apdu(slot, class, NISTSP800_73_3_INSTR_GENAUTH, NISTSP800_78_3_ALGO_RSA2048, identity->pcsc_identity->applet[0], bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
         2700  +		} else {
  2637   2701   			send_ret = cackey_send_apdu(slot, GSCIS_CLASS_GLOBAL_PLATFORM, GSCIS_INSTR_SIGNDECRYPT, p1, 0x00, bytes_to_send, tmpbuf, le, &respcode, outbuf, &tmpoutbuflen);
  2638         -			if (send_ret != CACKEY_PCSC_S_OK) {
  2639         -				CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");
  2640         -
  2641         -				if (free_tmpbuf) {
  2642         -					if (tmpbuf_s) {
  2643         -						free(tmpbuf_s);
  2644         -					}
  2645         -				}
  2646         -
  2647         -				/* End transaction */
  2648         -				cackey_end_transaction(slot);
  2649         -
  2650         -				if (respcode == 0x6982) {
  2651         -					CACKEY_DEBUG_PRINTF("Security status not satisified.  Returning NEEDLOGIN");
  2652         -
  2653         -					cackey_mark_slot_reset(slot);
  2654         -					slot->token_flags = CKF_LOGIN_REQUIRED;
  2655         -
  2656         -					return(CACKEY_PCSC_E_NEEDLOGIN);
  2657         -				}
  2658         -
  2659         -				if (send_ret == CACKEY_PCSC_E_TOKENABSENT) {
  2660         -					CACKEY_DEBUG_PRINTF("Token absent.  Returning TOKENABSENT");
  2661         -
  2662         -					cackey_mark_slot_reset(slot);
  2663         -
  2664         -					return(CACKEY_PCSC_E_TOKENABSENT);
  2665         -				}
  2666         -
  2667         -				return(-1);
  2668         -			}
  2669         -
  2670         -			tmpbuf += bytes_to_send;
  2671         -			tmpbuflen -= bytes_to_send;
  2672         -
  2673         -			outbuf += tmpoutbuflen;
  2674         -			outbuflen -= tmpoutbuflen;
  2675         -			retval += tmpoutbuflen;
  2676         -		}
         2702  +		}
         2703  +		if (send_ret != CACKEY_PCSC_S_OK) {
         2704  +			CACKEY_DEBUG_PRINTF("ADPU Sending Failed -- returning in error.");
         2705  +
         2706  +			if (free_tmpbuf) {
         2707  +				if (tmpbuf_s) {
         2708  +					free(tmpbuf_s);
         2709  +				}
         2710  +			}
         2711  +
         2712  +			/* End transaction */
         2713  +			cackey_end_transaction(slot);
         2714  +
         2715  +			if (respcode == 0x6982) {
         2716  +				CACKEY_DEBUG_PRINTF("Security status not satisified.  Returning NEEDLOGIN");
         2717  +
         2718  +				cackey_mark_slot_reset(slot);
         2719  +				slot->token_flags = CKF_LOGIN_REQUIRED;
         2720  +
         2721  +				return(CACKEY_PCSC_E_NEEDLOGIN);
         2722  +			}
         2723  +
         2724  +			if (send_ret == CACKEY_PCSC_E_TOKENABSENT) {
         2725  +				CACKEY_DEBUG_PRINTF("Token absent.  Returning TOKENABSENT");
         2726  +
         2727  +				cackey_mark_slot_reset(slot);
         2728  +
         2729  +				return(CACKEY_PCSC_E_TOKENABSENT);
         2730  +			}
         2731  +
         2732  +			return(-1);
         2733  +		}
         2734  +
         2735  +		tmpbuf += bytes_to_send;
         2736  +		tmpbuflen -= bytes_to_send;
         2737  +
         2738  +		outbuf += tmpoutbuflen;
         2739  +		outbuflen -= tmpoutbuflen;
         2740  +		retval += tmpoutbuflen;
  2677   2741   	}
  2678   2742   
  2679   2743   	if (free_tmpbuf) {
  2680   2744   		if (tmpbuf_s) {
  2681   2745   			free(tmpbuf_s);
  2682   2746   		}
  2683   2747   	}
................................................................................
  2692   2756   	if (outbuflen > _POSIX_SSIZE_MAX) {
  2693   2757   		CACKEY_DEBUG_PRINTF("Outbuflen exceeds maximum value, returning in failure. (max = %li, outbuflen = %lu)", (long) _POSIX_SSIZE_MAX, (unsigned long) outbuflen);
  2694   2758   
  2695   2759   		return(-1);
  2696   2760   	}
  2697   2761   #  endif
  2698   2762   #endif
         2763  +
         2764  +	/* We must remove the "7C" tag to get to the signature */
         2765  +	if (piv) {
         2766  +		if (outbuf[0] != 0x7C) {
         2767  +			CACKEY_DEBUG_PRINTF("Response from PIV for GENERATE AUTHENTICATION was not a 0x7C tag, returning in failure");
         2768  +
         2769  +
         2770  +			return(-1);
         2771  +		}
         2772  +
         2773  +		/* XXX TODO PIV */
         2774  +		memmove(outbuf, outbuf + 8, retval - 8);
         2775  +		retval -= 8;
         2776  +	}
  2699   2777   
  2700   2778   	/* Unpad reply */
  2701   2779   	if (unpadOutput) {
  2702   2780   		if (retval < 3) {
  2703   2781   			CACKEY_DEBUG_PRINTF("Reply is too small, we are not able to unpad -- passing back and hoping for the best!");
  2704   2782   
  2705   2783   			CACKEY_DEBUG_PRINTF("Returning in success, retval = %li (bytes)", (long) retval);