1 /*
2  * sm-authentic.c: Secure Messaging procedures specific to Oberthur's card
3  * 		'COSMO v7' with PKI applet 'AuthentIC v3.1'
4  *
5  * Copyright (C) 2010  Viktor Tarasov <vtarasov@opentrust.com>
6  *                      OpenTrust <www.opentrust.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <stdio.h>
27 #include <stdlib.h>
28 
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 
33 #include <string.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <ctype.h>
37 #include <sys/stat.h>
38 
39 #include "libopensc/opensc.h"
40 #include "libopensc/log.h"
41 
42 #include "sm-module.h"
43 
44 static int
sm_oberthur_diversify_keyset(struct sc_context * ctx,struct sm_info * sm_info,unsigned char * idata,size_t idata_len)45 sm_oberthur_diversify_keyset(struct sc_context *ctx, struct sm_info *sm_info,
46 		unsigned char *idata, size_t idata_len)
47 {
48 	struct sm_gp_session *gp_session = &sm_info->session.gp;
49 	struct sm_gp_keyset *gp_keyset = &sm_info->session.gp.gp_keyset;
50 	unsigned char master_key[16] = {
51 		0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
52 	};
53 	unsigned char *keys[3] = {
54 		gp_keyset->enc,
55 		gp_keyset->mac,
56 		gp_keyset->kek
57 	};
58 	unsigned char key_buff[16];
59 	unsigned char *tmp;
60 	int rv = 0, ii, tmp_len;
61 
62 	if (gp_keyset->kmc_len == 48)   {
63 		for (ii=0; ii<3; ii++)
64 			memcpy(keys[ii], gp_keyset->kmc + 16*ii, 16);
65 	}
66 	else if (gp_keyset->kmc_len == 16 || gp_keyset->kmc_len == 0)   {
67 		if (gp_keyset->kmc_len == 16)
68 			memcpy(master_key, gp_keyset->kmc, 16);
69 		sc_debug(ctx, SC_LOG_DEBUG_SM, "KMC: %s", sc_dump_hex(master_key, sizeof(master_key)));
70 		for (ii=0; ii<3; ii++)   {
71 			key_buff[0] = key_buff[8] = 0;
72 			key_buff[1] = key_buff[9] = 0;
73 			key_buff[2] = key_buff[10] = *(idata + 6);
74 			key_buff[3] = key_buff[11] = *(idata + 7);
75 			key_buff[4] = key_buff[12] = *(idata + 8);
76 			key_buff[5] = key_buff[13] = *(idata + 9);
77 			key_buff[6] = 0xF0,  key_buff[14] = 0x0F;
78 			key_buff[7] = key_buff[15] = ii+1;
79 
80 			sc_debug(ctx, SC_LOG_DEBUG_SM, "key_buf:%s", sc_dump_hex(key_buff, 16));
81 
82 			rv = sm_encrypt_des_ecb3(master_key, key_buff, sizeof(key_buff), &tmp, &tmp_len);
83 			LOG_TEST_RET(ctx, rv, "GP init session: cannot derive key");
84 
85 			memcpy(keys[ii], tmp, sizeof(gp_keyset->enc));
86 			free(tmp);
87 		}
88 	}
89 	else   {
90 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "GP init session: invalid KMC data");
91 	}
92 
93 	if (!rv && ctx)   {
94 		sc_debug_hex(ctx, SC_LOG_DEBUG_SM, "Card challenge", gp_session->card_challenge, sizeof(gp_session->card_challenge));
95 		sc_debug_hex(ctx, SC_LOG_DEBUG_SM, "Host challenge", gp_session->host_challenge, sizeof(gp_session->host_challenge));
96 		sc_debug_hex(ctx, SC_LOG_DEBUG_SM, "ENC", gp_keyset->enc, sizeof(gp_keyset->enc));
97 		sc_debug_hex(ctx, SC_LOG_DEBUG_SM, "MAC", gp_keyset->mac, sizeof(gp_keyset->mac));
98 		sc_debug_hex(ctx, SC_LOG_DEBUG_SM, "KEK", gp_keyset->kek, sizeof(gp_keyset->kek));
99 	}
100 
101 	return rv;
102 
103 }
104 
105 
106 static int
sm_authentic_encode_apdu(struct sc_context * ctx,struct sm_info * sm_info)107 sm_authentic_encode_apdu(struct sc_context *ctx, struct sm_info *sm_info)
108 {
109 	struct sc_apdu *apdu = (struct sc_apdu *) sm_info->cmd_data;
110 	int rv = SC_ERROR_INVALID_ARGUMENTS;
111 
112 	LOG_FUNC_CALLED(ctx);
113 	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM encode APDU: offset:");
114 
115 	rv = sm_gp_securize_apdu(ctx, sm_info, NULL, apdu);
116 	LOG_TEST_RET(ctx, rv, "SM encode APDU: securize error");
117 
118 	LOG_FUNC_RETURN(ctx, rv);
119 }
120 
121 
122 int
sm_authentic_get_apdus(struct sc_context * ctx,struct sm_info * sm_info,unsigned char * init_data,size_t init_len,struct sc_remote_data * rdata,int release_sm)123 sm_authentic_get_apdus(struct sc_context *ctx, struct sm_info *sm_info,
124 		unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata,
125 		int release_sm)
126 {
127 	int rv = 0;
128 
129 	LOG_FUNC_CALLED(ctx);
130 	if (!sm_info)
131 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
132 
133 	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM get APDUs: rdata:%p, init_len:%"SC_FORMAT_LEN_SIZE_T"u",
134 	       rdata, init_len);
135 	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM get APDUs: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len));
136 
137 	if (init_data)   {
138 		rv = sm_gp_external_authentication(ctx, sm_info, init_data, init_len, rdata, sm_oberthur_diversify_keyset);
139 		LOG_TEST_RET(ctx, rv, "SM get APDUs: cannot authenticate card");
140 	}
141 
142 	switch (sm_info->cmd)  {
143 	case SM_CMD_APDU_TRANSMIT:
144 		rv = sm_authentic_encode_apdu(ctx, sm_info);
145 		LOG_TEST_RET(ctx, rv, "SM get APDUs: cannot encode APDU");
146 		break;
147 	case SM_CMD_INITIALIZE:
148 		break;
149 	default:
150 		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported SM command");
151 	}
152 
153 	LOG_FUNC_RETURN(ctx, rv);
154 }
155