OSDN Git Service

deleted ASSERTs and added many checks, also cleanup the codes
[openpts/openpts.git] / src / imv.c
1 /*
2  * This file is part of the OpenPTS project.
3  *
4  * The Initial Developer of the Original Code is International
5  * Business Machines Corporation. Portions created by IBM
6  * Corporation are Copyright (C) 2010 International Business
7  * Machines Corporation. All Rights Reserved.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the Common Public License as published by
11  * IBM Corporation; either version 1 of the License, or (at your option)
12  * any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * Common Public License for more details.
18  *
19  * You should have received a copy of the Common Public License
20  * along with this program; if not, a copy can be viewed at
21  * http://www.opensource.org/licenses/cpl1.0.php.
22  */
23
24 /**
25  * \file src/imv.c
26  * \brief TCG TNC IF-IMV v1.2 R8
27  * @author Seiji Munetoh <munetoh@users.sourceforge.jp>
28  * @date 2010-05-07
29  * cleanup 2011-08-22 SM
30  *
31  * http://www.trustedcomputinggroup.org/resources/tnc_ifimv_specification
32  * http://www.trustedcomputinggroup.org/files/static_page_files/646808C3-1D09-3519-AD2E60765779A42A/TNC_IFIMV_v1_2_r8.pdf
33  *
34  *  handshake
35  *    0 IMC -> IMV hello
36  *    1 IMC <- IMV capability 
37  *    2 IMC -> IMV capability
38  *
39  *    3 IMC <- IMV DH-nonce param req
40  *    4 IMC -> IMV DH-nonce param res
41  *    5 IMC <- IMV DH-nonce done
42  *    6 IMC -> IMV ack
43  *
44  *    7 IMC <- IMV template RIMM req
45  *    8 IMC -> IMV RIMM
46  *    9 IMC <- IMV template IR req
47  *   10 IMC -> IMV IR
48  */
49 #include <stdio.h>
50 #include <string.h>
51
52 #include <tncifimv.h>
53 #include <openpts.h>
54 // #include <log.h>
55
56 // ifm.c
57 BYTE* getPtsTlvMessage(OPENPTS_CONTEXT *ctx, int type, int *len);
58
59 /* global */
60 static TNC_IMVID imv_id = -1;
61 static int initialized = 0;
62
63 static OPENPTS_CONFIG *conf = NULL;
64 static OPENPTS_CONTEXT *ctx = NULL;
65 static int result = OPENPTS_RESULT_UNKNOWN;
66
67 // int verbose = 0;
68 // int verbose = DEBUG_IFM_FLAG;
69 // int verbose = DEBUG_FLAG | DEBUG_IFM_FLAG;
70
71 static TNC_Result sendMessage(
72     /*in*/ TNC_IMVID imvID,
73     /*in*/ TNC_ConnectionID connectionID,
74     /*in*/ TNC_BufferReference message,
75     /*in*/ TNC_UInt32 messageLength,
76     /*in*/ TNC_MessageType messageType);
77
78 static TNC_Result provideRecommendation(
79     /*in*/ TNC_IMVID imvID,
80     /*in*/ TNC_ConnectionID connectionID,
81     /*in*/ TNC_IMV_Action_Recommendation recommendation,
82     /*in*/ TNC_IMV_Evaluation_Result evaluation);
83
84 static TNC_Result setAttribute(
85     /*in*/ TNC_IMVID imvID,
86     /*in*/ TNC_ConnectionID connectionID,
87     /*in*/  TNC_AttributeID attributeID,
88     /*in*/  TNC_UInt32 bufferLength,
89     /*out*/ TNC_BufferReference buffer);
90
91 /* Call back */
92 static TNC_TNCS_ReportMessageTypesPointer    reportMessageTypesPtr;
93 static TNC_TNCS_RequestHandshakeRetryPointer requestHandshakeRetryPtr;
94 static TNC_TNCS_ProvideRecommendationPointer provideRecommendationPtr;
95 static TNC_TNCS_GetAttributePointer          getAttributePtr;
96 static TNC_TNCS_SetAttributePointer          setAttributePtr;
97 static TNC_TNCS_SendMessagePointer           sendMessagePtr;
98
99
100 /* List of receive message types */
101 // static TNC_MessageType messageTypes[] = {
102 //    TNCMESSAGENUM(TNC_VENDORID_TCG, TNC_SUBTYPE_ANY),  // generic
103 //    TNCMESSAGENUM(VENDORID,  0),
104 //    TNCMESSAGENUM(VENDORID,  2),
105 //    TNCMESSAGENUM(VENDORID,  4),
106 //    TNCMESSAGENUM(VENDORID,  6),
107 //    TNCMESSAGENUM(VENDORID,  8),
108 //    TNCMESSAGENUM(VENDORID, 10),
109 // };
110 static TNC_MessageType messageTypes[] = {
111     ((TNC_VENDORID_PA_TNC << 8) | TNC_VENDORID_PA_TNC),   // TNC generic (Error)
112 //    ((TNC_VENDORID_TCG_PEN << 8) | TNC_SUBTYPE_TCG_PTS),  // PTS generic
113     ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS)   // OpenPTS
114 };
115
116
117 /* IMV Functions */
118
119 /**
120  * from IMV spec.
121  *
122  * TNC_IMV_Initialize (MANDATORY)
123  *
124  * The TNC Server calls this function to initialize the IMV and agree on the API version number to
125  * be used. It also supplies the IMV ID, an IMV identifier that the IMV must use when calling TNC
126  * Server callback functions. All IMVs MUST implement this function.
127  *
128  * The TNC Server MUST NOT call any other IF-IMV API functions for an IMV until it has
129  * successfully completed a call to TNC_IMV_Initialize(). Once a call to this function has
130  * completed successfully, this function MUST NOT be called again for a particular IMV-TNCS pair
131  * until a call to TNC_IMV_Terminate has completed successfully.
132  *
133  * The TNC Server MUST set minVersion to the minimum IF-IMV API version number that it
134  * supports and MUST set maxVersion to the maximum API version number that it supports. The
135  * TNC Server also MUST set pOutActualVersion so that the IMV can use it as an output
136  * parameter to provide the actual API version number to be used. With the C binding, this would
137  * involve setting pOutActualVersion to point to a suitable storage location.
138  *
139  * The IMV MUST check these to determine whether there is an API version number that it supports
140  * in this range. If not, the IMV MUST return TNC_RESULT_NO_COMMON_VERSION. Otherwise, the
141  * IMV SHOULD select a mutually supported version number, store that version number at
142  * pOutActualVersion, and initialize the IMV. If the initialization completes successfully, the IMV
143  * SHOULD return TNC_RESULT_SUCCESS. Otherwise, it SHOULD return another result code.
144  *
145  * If an IMV determines that pOutActualVersion is not set properly to allow the IMV to use it as
146  * an output parameter, the IMV SHOULD return TNC_RESULT_INVALID_PARAMETER. With the C
147  * binding, this might involve checking for a NULL pointer. IMVs are not required to make this check
148  * and there is no guarantee that IMVs will be able to perform it adequately (since it is often
149  * impossible or very hard to detect invalid pointers).
150  * 
151  * @praram  imvID - IMV ID assigned by TNCS
152  * @praram  minVersion - Minimum API version supported by TNCS
153  * @praram  maxVersion - Maximum API version supported by TNCS
154  * @praram  pOutActualVersion - Mutually supported API version number
155  */
156 TNC_IMV_API TNC_Result TNC_IMV_Initialize(
157     /*in*/  TNC_IMVID imvID,
158     /*in*/  TNC_Version minVersion,
159     /*in*/  TNC_Version maxVersion,
160     /*in*/  TNC_Version *pOutActualVersion) {
161     int rc;
162     DEBUG("TNC_IMV_Initialize() - imvID=%d, minVersion=%d, maxVersion=%d\n",
163         (int)imvID, (int)minVersion, (int)maxVersion);
164
165     /* */
166     if (initialized) {
167         ERROR("Not initialized");
168         return TNC_RESULT_ALREADY_INITIALIZED;
169     }
170
171     /* Only support version 1 */
172     if ((minVersion < TNC_IFIMV_VERSION_1 ) ||
173         (maxVersion > TNC_IFIMV_VERSION_1)) {
174         ERROR("TNC_RESULT_NO_COMMON_VERSION\n");
175         return TNC_RESULT_NO_COMMON_VERSION;
176     }
177
178     if (!pOutActualVersion) {
179         ERROR("TNC_RESULT_INVALID_PARAMETER\n");
180         return TNC_RESULT_INVALID_PARAMETER;
181     }
182
183     *pOutActualVersion = TNC_IFIMV_VERSION_1;
184     imv_id = imvID;
185
186     /* initialize PTS */
187     conf =  newPtsConfig();
188     if (conf == NULL) {
189         ERROR("Can not allocate OPENPTS_CONFIG\n");
190         rc = TNC_RESULT_FATAL;
191         goto error;
192     }
193
194     ctx =  newPtsContext(conf);
195     if (ctx == NULL) {
196         ERROR("Can not allocate OPENPTS_CONTEXT\n");
197         rc = TNC_RESULT_FATAL;
198         goto error;
199     }
200
201     /* configure PTS Verifier (System wide) */
202     rc = readPtsConfig(conf, PTSV_CONFIG_FILE);
203     if (rc != PTS_SUCCESS) {
204         ERROR("read config file, '%s' was failed - abort\n",
205             PTSV_CONFIG_FILE);
206         rc = TNC_RESULT_FATAL;
207         goto error;
208     }
209     DEBUG_IFM("config file                 : %s\n", PTSV_CONFIG_FILE);
210
211     /* check the IMV settings */
212     // UUID
213     if (conf->uuid->status == OPENPTS_UUID_FILENAME_ONLY) {
214         /* 1st use?,  create new UUID */
215         rc = genOpenptsUuid(conf->uuid);
216         if (rc != PTS_SUCCESS) {
217             ERROR("generation of UUID was failed\n");
218             rc = TNC_RESULT_FATAL;
219             goto error;
220         }
221         /* save to the file */
222         rc = writeOpenptsUuidFile(conf->uuid, 1);
223         if (rc != PTS_SUCCESS) {
224             ERROR("Creation of UUID file, %s was failed\n",
225                 conf->uuid->filename);
226             rc = TNC_RESULT_FATAL;
227             goto error;
228         }
229         DEBUG_IFM("conf->uuid->filename        : %s (new UUID)\n", conf->uuid->filename);
230         DEBUG_IFM("conf->uuid->str             : %s (new UUID)\n", conf->uuid->str);
231     } else {
232         DEBUG_IFM("conf->uuid->filename        : %s\n", conf->uuid->filename);
233         DEBUG_IFM("conf->uuid->str             : %s\n", conf->uuid->str);
234     }
235
236     // Targets
237     DEBUG_IFM("conf->enrollment            : 0x%x (none:%x, cred:%x, auto:%x)\n",
238         conf->enrollment,
239         IMV_ENROLLMENT_NONE, IMV_ENROLLMENT_CREDENTIAL, IMV_ENROLLMENT_AUTO);
240
241     DEBUG_IFM("conf->config_dir            : %s\n",
242         conf->config_dir);
243
244     // TODO IIDB
245
246     initialized++;
247
248     DEBUG_IFM("V    imvID=%d - TNC_IMV_Initialize\n", (int) imvID);
249
250     return TNC_RESULT_SUCCESS;
251
252   error:
253     if (ctx != NULL) freePtsContext(ctx);
254     ctx = NULL;
255     if (conf != NULL) freePtsConfig(conf);
256     conf = NULL;
257
258     return rc;
259 }
260
261
262 /**
263  * TNC_IMV_NotifyConnectionChange (OPTIONAL)
264  */
265 TNC_IMV_API TNC_Result TNC_IMV_NotifyConnectionChange(
266 /*in*/  TNC_IMVID imvID,
267 /*in*/  TNC_ConnectionID connectionID,
268 /*in*/  TNC_ConnectionState newState) {
269     DEBUG("TNC_IMV_NotifyConnectionChange\n");
270
271     if (!initialized) {
272         ERROR("Not initialized");
273         return TNC_RESULT_NOT_INITIALIZED;
274     }
275
276     if (imvID != imv_id)
277         ERROR("imvID != imv_id");
278         return TNC_RESULT_INVALID_PARAMETER;
279
280     DEBUG_IFM("V    imvID=%d, connectionID=%d - TNC_IMV_NotifyConnectionChange\n",
281         (int)imvID, (int)connectionID);
282
283     return TNC_RESULT_SUCCESS;
284 }
285
286
287 /**
288  * TNC_IMV_ReceiveMessage (OPTIONAL)
289  *
290  * The TNC Server calls this function to deliver a message to the IMV. The message is contained in
291  * the buffer referenced by message and contains the number of octets (bytes) indicated by
292  * messageLength. The type of the message is indicated by messageType. The message MUST be
293  * from an IMC (or a TNCC or other party acting as an IMC).
294  *
295  * The IMV SHOULD send any IMC-IMV messages it wants to send as soon as possible after this
296  * function is called and then return from this function to indicate that it is finished sending
297  * messages in response to this message.
298  *
299  * As with all IMV functions, the IMV SHOULD NOT wait a long time before returning from
300  * TNC_IMV_ReceiveMessage. To do otherwise would risk delaying the handshake indefinitely. A
301  * long delay might frustrate users or exceed network timeouts (PDP, PEP or otherwise).
302  *
303  * The IMV should implement this function if it wants to receive messages. Most IMVs will do so,
304  * since they will base their IMV Action Recommendations on measurements received from the
305  * IMC. However, some IMVs may base their IMV Action Recommendations on other data such as
306  * reports from intrusion detection systems or scanners. Those IMVs need not implement this
307  * function.
308  *
309  * The IMV MUST NOT ever modify the buffer contents and MUST NOT access the buffer after
310  * TNC_IMV_ReceiveMessage has returned. If the IMV wants to retain the message, it should
311  * copy it before returning from TNC_IMV_ReceiveMessage.
312  *
313  * In the imvID parameter, the TNCS MUST pass the IMV ID value provided to
314  * TNC_IMV_Initialize. In the connectionID parameter, the TNCS MUST pass a valid
315  * network connection ID. In the message parameter, the TNCS MUST pass a reference to a buffer
316  * containing the message being delivered to the IMV. In the messageLength parameter, the
317  * TNCS MUST pass the number of octets in the message. If the value of the messageLength
318  * parameter is zero (0), the message parameter may be NULL with platform bindings that have
319  * such a value. In the messageType parameter, the TNCS MUST pass the type of the message.
320  *
321  * This value MUST match one of the TNC_MessageType values previously supplied by the IMV to
322  * the TNCS in the IMV’s most recent call to TNC_TNCS_ReportMessageTypes. IMVs MAY check
323  * these parameters to make sure they are valid and return an error if not, but IMVs are not required
324  * to make these checks.
325  *
326  * @praram  imvID          - IMV ID assigned by TNCS
327  * @praram  connectionID   - Network connection ID on which message was received
328  * @praram  message        - Reference to buffer containing message
329  * @praram  messageLength  - Number of octets in message
330  * @praram  messageType    - Message type of message
331  *
332  *
333  *  TODO add AIDE
334  *
335  */
336 TNC_IMV_API TNC_Result TNC_IMV_ReceiveMessage(
337     /*in*/  TNC_IMVID imvID,
338     /*in*/  TNC_ConnectionID connectionID,
339     /*in*/  TNC_BufferReference messageBuffer,
340     /*in*/  TNC_UInt32 messageLength,
341     /*in*/  TNC_MessageType messageType) {
342     PTS_IF_M_Attribute *read_tlv;
343     UINT32 type;
344     int length;
345     BYTE * value;
346     int rc = 0;
347     BYTE* msg;
348     int len;
349     OPENPTS_IF_M_Capability *cap;
350     UINT32 vid;
351     int enrollment = 0;
352     OPENPTS_CONFIG *target_conf;
353     int mode = 0;
354
355
356 /* verifier.c */
357     int verifierHandleCapability(
358         OPENPTS_CONTEXT *ctx,
359         char *conf_dir,
360         char *host,
361         OPENPTS_IF_M_Capability *cap);
362
363     int verifierHandleRimmSet(
364         OPENPTS_CONTEXT *ctx,
365         BYTE *buf);
366
367     int verifierHandleIR(
368         OPENPTS_CONTEXT *ctx,
369         int length,
370         BYTE *value,
371         int mode,
372         int *result);
373
374     DEBUG("TNC_IMV_ReceiveMessage  msg[%d] type=0x%x\n",
375         messageLength, (int)messageType);
376
377     if (!initialized) {
378         ERROR("Not initialized");
379         return TNC_RESULT_NOT_INITIALIZED;
380     }
381
382     DEBUG_IFM("[C->V] imvID=%d, connectionID=%d, type=0x%x, msg[%d]\n",
383         (int)imvID, (int)connectionID, (int)messageType, (int)messageLength);
384
385
386
387     /* handshake */
388     if (messageType == ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS)) {
389         /* OPENPTS */
390         read_tlv = (PTS_IF_M_Attribute*)messageBuffer;  // NBO
391
392         if (read_tlv == NULL) {
393             ERROR("null input");
394             return TNC_RESULT_FATAL;
395         }
396
397         /* check VID */
398         vid = read_tlv->vid[0] << 16;
399         vid += read_tlv->vid[1] << 8;
400         vid += read_tlv->vid[2];
401         if (vid != TNC_VENDORID_OPENPTS) {
402             ERROR("read_tlv->vid = 0x%X (!= 0x%X)",
403                 vid, TNC_VENDORID_OPENPTS);
404             return TNC_RESULT_FATAL;
405         }
406
407         /* type and length */
408         type = ntohl(read_tlv->type);
409         length = ntohl(read_tlv->length);
410         value = &messageBuffer[12];
411
412         /* check length */
413         if (messageLength != (TNC_UInt32) (12 + length)) {
414             ERROR("Bad message %d != %d\n",
415                 messageLength, 12 + length);
416             return TNC_RESULT_FATAL;
417         }
418
419         DEBUG_IFM("[C->V] vid=%X, type=%08X, length=%d\n", vid, type, length);
420
421         /* message type */
422         switch (type) {
423         case OPENPTS_CAPABILITIES:
424             /* Check Collector */
425             DEBUG_IFM("[C->V] OPENPTS_CAPABILITIES[%d]\n", 12 + length);
426             if (ctx->tnc_state != TNC_STATE_START) {
427                 /* Bad message order */
428                 ERROR("Bad message order state=%d != %d, type=%08x",
429                     ctx->tnc_state, TNC_STATE_START, type);
430                 return TNC_RESULT_FATAL;
431             }
432
433             /* Capability */
434             cap =  (OPENPTS_IF_M_Capability *) value;
435
436             rc = verifierHandleCapability(ctx, conf->config_dir, NULL, cap);
437
438             if (rc == PTS_NOT_INITIALIZED) {
439                 if (conf->enrollment ==  IMV_ENROLLMENT_AUTO) {
440                     /* enroll with this collector */
441                     DEBUG_IFM("Auto Mode, Trust 1st connection -> start enrollment!!!"
442                         " #######################################\n");
443
444                     if (ctx->target_conf == NULL) {
445                         ctx->target_conf = newPtsConfig();
446                     }
447                     target_conf = ctx->target_conf;
448
449                     /* intialize the target_conf */
450                     target_conf->uuid = ctx->collector_uuid;
451                     ctx->collector_uuid = NULL;
452                     target_conf->rm_uuid = ctx->rm_uuid;
453                     ctx->rm_uuid = NULL;
454
455                     target_conf->config_dir =
456                         getFullpathName(conf->config_dir, target_conf->uuid->str);
457                     target_conf->config_file =
458                         getFullpathName(target_conf->config_dir, "target.conf");
459                     target_conf->uuid->filename =
460                         getFullpathName(target_conf->config_dir, "uuid");
461                     target_conf->rm_basedir =
462                         getFullpathName(target_conf->config_dir, target_conf->rm_uuid->str);
463
464                     target_conf->ir_filename =
465                         getFullpathName(target_conf->config_dir, "./ir.xml");
466                     target_conf->prop_filename =
467                         getFullpathName(target_conf->config_dir, "./vr.properties");
468                     target_conf->policy_filename =
469                         getFullpathName(target_conf->config_dir, "./policy.conf");
470
471 #ifdef CONFIG_AIDE
472                     target_conf->aide_database_filename =
473                         getFullpathName(target_conf->config_dir, "aide.db.gz");
474                     target_conf->aide_ignorelist_filename =
475                         getFullpathName(target_conf->config_dir, "aide.ignore");
476 #ifdef CONFIG_SQLITE
477                     target_conf->aide_sqlite_filename =
478                         getFullpathName(target_conf->config_dir, "aide.sqlite.db");
479 #endif
480 #endif
481
482                     /* create */
483                     rc = makeDir(target_conf->config_dir);
484                     // TODO check rc
485
486                     DEBUG("conf dir               : %s\n", target_conf->config_dir);
487                     DEBUG("rm dir                 : %s\n", target_conf->rm_basedir);
488                     DEBUG("AIDE DB                : %s\n", target_conf->aide_database_filename);
489 #ifdef CONFIG_SQLITE
490                     DEBUG("AIDE SQLite DB         : %s\n", target_conf->aide_sqlite_filename);
491 #endif
492
493                     /* get Key */
494                     /* get RM */
495                     /* verify and create policy */
496                     /* then allow the 1st connection */
497                     enrollment = 1;
498                 } else if (conf->enrollment == IMV_ENROLLMENT_CREDENTIAL) {
499                     TODO("TBD\n");
500                     return rc;
501                 } else {
502                     ERROR("Collector is not initialized yet\n");
503                     return rc;
504                 }
505             } else if (rc != PTS_SUCCESS) {
506                 return rc;
507             } else {
508                 enrollment = 0;
509                 ctx->tnc_state = TNC_STATE_CAP;
510                 // TODO load target
511             }
512
513             /* send IMV's capability  to IMC */
514             msg = getPtsTlvMessage(ctx, OPENPTS_CAPABILITIES, &len);
515             rc = sendMessage(
516                     imvID,
517                     connectionID,
518                     (TNC_BufferReference)msg,
519                     len,
520                     ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
521             xfree(msg);
522             DEBUG_IFM("[C<-V] OPENPTS_CAPABILITIES[%d]\n", len);
523
524
525             if (enrollment == 1) {
526                 /* start enrollment */
527                 ctx->tnc_state = TNC_STATE_KEY_REQ;
528                 msg = getPtsTlvMessage(ctx, REQUEST_TPM_PUBKEY, &len);
529                 rc = sendMessage(
530                         imvID,
531                         connectionID,
532                         (TNC_BufferReference)msg,
533                         len,
534                         ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
535                 xfree(msg);
536                 DEBUG_IFM("[C<-V] REQUEST_TPM_PUBKEY[%d]\n", len);
537             } else {
538                 /*start verify, send NONCE and IR REQ*/
539                 /* Next : Send NONCE */
540                 ctx->nonce->nonce_length = 20;
541                 ctx->nonce->nonce = xmalloc_assert(20);
542                 rc = getRandom(ctx->nonce->nonce, 20);
543                 if (rc != PTS_SUCCESS) {
544                     ERROR("getRandom() fail\n");
545                 }
546
547                 ctx->tnc_state = TNC_STATE_NONCE;
548                 msg = getPtsTlvMessage(ctx, NONCE, &len);
549                 rc = sendMessage(
550                         imvID,
551                         connectionID,
552                         (TNC_BufferReference)msg,
553                         len,
554                         ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
555                 xfree(msg);
556                 DEBUG_IFM("[C<-V] NONCE[%d]\n", len);
557
558                 /* Next : REQ IR */
559                 ctx->tnc_state = TNC_STATE_IR;
560                 msg = getPtsTlvMessage(ctx, REQUEST_INTEGRITY_REPORT, &len);
561                 rc = sendMessage(
562                         imvID,
563                         connectionID,
564                         (TNC_BufferReference)msg,
565                         len,
566                         ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
567                 xfree(msg);
568                 DEBUG_IFM("[C<-V] REQUEST_INTEGRITY_REPORT[%d]\n", len);
569             }
570             break;
571
572         case TPM_PUBKEY:
573             DEBUG_IFM("[C->V] TPM_PUBKEY[%d]\n", 12 + length);
574             // TODO check the state
575
576             if (ctx->target_conf == NULL) {
577                 ERROR("Bad sequence\n");
578             } else {
579                 /* PUBKEY -> target_conf */
580                 ctx->target_conf->pubkey_length = length;
581                 ctx->target_conf->pubkey = xmalloc(ctx->target_conf->pubkey_length);
582                 if (ctx->target_conf->pubkey == NULL) {
583                     return TNC_RESULT_FATAL;
584                 }
585
586                 memcpy(
587                     ctx->target_conf->pubkey,
588                     value,  // NG read_tlv->value
589                     ctx->target_conf->pubkey_length);
590                 ctx->tnc_state = TNC_STATE_KEY;
591
592
593                 /* Next: send RM REQ - continue enrollment */
594                 ctx->tnc_state = TNC_STATE_RM_REQ;
595                 msg = getPtsTlvMessage(ctx, REQUEST_RIMM_SET, &len);
596                 rc = sendMessage(
597                         imvID,
598                         connectionID,
599                         (TNC_BufferReference)msg,
600                         len,
601                         ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
602                 xfree(msg);
603                 DEBUG_IFM("[C<-V] REQUEST_RIMM_SET[%d]\n", len);
604             }
605             break;
606
607         case RIMM_SET:
608             DEBUG_IFM("[C->V] RIMM_SET[%d]\n", 12 + length);
609
610             /* save to the file, UUID/UUID/rmN.xml*/
611             rc = verifierHandleRimmSet(ctx, value);
612             if (rc != PTS_SUCCESS) {
613                 ERROR("verifierHandleRimmSet() fail\n");
614                 return TNC_RESULT_FATAL;
615             }
616
617             /* save target conf */
618             writeTargetConf(
619                 ctx->target_conf,
620                 ctx->target_conf->uuid->uuid,
621                 ctx->target_conf->config_file);  // ctx.c
622
623             /* Next : Send NONCE */
624             ctx->nonce->nonce_length = 20;
625             ctx->nonce->nonce = xmalloc_assert(20);
626             rc = getRandom(ctx->nonce->nonce, 20);
627             if (rc != PTS_SUCCESS) {
628                 ERROR("getRandom() fail\n");
629             }
630
631             ctx->tnc_state = TNC_STATE_NONCE_ENROLL;
632             msg = getPtsTlvMessage(ctx, NONCE, &len);
633             rc = sendMessage(
634                     imvID,
635                     connectionID,
636                     (TNC_BufferReference)msg,
637                     len,
638                     ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
639             xfree(msg);
640             DEBUG_IFM("[C<-V] NONCE[%d]\n", len);
641
642             /* Next : REQ IR */
643             ctx->tnc_state = TNC_STATE_IR_ENROLL;
644             msg = getPtsTlvMessage(ctx, REQUEST_INTEGRITY_REPORT, &len);
645             rc = sendMessage(
646                     imvID,
647                     connectionID,
648                     (TNC_BufferReference)msg,
649                     len,
650                     ((TNC_VENDORID_OPENPTS << 8) | TNC_SUBTYPE_OPENPTS));
651             xfree(msg);
652             DEBUG_IFM("[C<-V] REQUEST_INTEGRITY_REPORT[%d]\n", len);
653
654             break;
655
656         case INTEGRITY_REPORT:
657             if (ctx->tnc_state == TNC_STATE_IR_ENROLL) {
658                 /* Enrollment, create default policy */
659                 DEBUG_IFM("[C->V] INTEGRITY_REPORT[%d] (Enrollment)\n", 12 + length);
660                 mode = OPENPTS_UPDATE_MODE;
661             } else if (ctx->tnc_state == TNC_STATE_IR) {
662                 /* Just verify */
663                 DEBUG_IFM("[C->V] INTEGRITY_REPORT[%d]\n", 12 + length);
664                 mode = OPENPTS_VERIFY_MODE;
665             } else {
666                 /* BAD STATE */
667                 ERROR("bad state");
668             }
669
670
671             /* verify */
672             rc = verifierHandleIR(ctx, length, value, mode, &result);
673             if (rc != PTS_SUCCESS) {
674                 ERROR("verifierHandleIR() fail rc = %d\n", rc);
675                 // 25 PTS_INVALID_SNAPSHOT?
676                 // return TNC_RESULT_FATAL;
677             }
678             // DEBUG("result = %d => recomandation\n", result);
679             // TODO create
680             break;
681         case OPENPTS_ERROR:
682             ERROR("The corrector returns ERROR message");
683             // TODO invalid
684             result = OPENPTS_RESULT_UNKNOWN;
685             // break;
686             return TNC_RESULT_FATAL;
687         default:
688             ERROR("Unknown type %08X", type);
689             result = OPENPTS_RESULT_UNKNOWN;
690             break;
691         }
692         return rc;
693     } else if (messageType == ((TNC_VENDORID_TCG_PEN << 8) | TNC_SUBTYPE_TCG_PTS)) {
694         /* TCG */
695         ERROR("TBD\n");
696         return TNC_RESULT_FATAL;
697     } else {
698         ERROR("bad msg from collector");
699         return TNC_RESULT_FATAL;
700     }
701
702     return TNC_RESULT_SUCCESS;
703 }
704
705
706 /**
707  * from IMV spec.
708  *
709  * TNC_IMV_SolicitRecommendation (MANDATORY)
710  *
711  * The TNC Server calls this function at the end of an Integrity Check Handshake (after all IMC-IMV
712  * messages have been delivered) to solicit recommendations from IMVs that have not yet provided
713  * a recommendation. The TNCS SHOULD NOT call this method for an IMV and a particular
714  * connection if that IMV has already called TNC_TNCS_ProvideRecommendation with that
715  * connection since the TNCS last called TNC_IMV_NotifyConnectionChange for that IMV and
716  * connection. If an IMV is not able to provide a recommendation at this time, it SHOULD call
717  * TNC_TNCS_ProvideRecommendation with the recommendation parameter set to
718  * TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION. If an IMV returns from this
719  * function without calling TNC_TNCS_ProvideRecommendation, the TNCS MAY consider the
720  * IMV’s Action Recommendation to be
721  * TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION. The TNCS MAY take other
722  * actions, such as logging this IMV behavior, which is erroneous.
723  * 
724  * All IMVs MUST implement this function.
725  * 
726  * Note that a TNCC or TNCS MAY cut off IMC-IMV communications at any time for any reason,
727  * including limited support for long conversations in underlying protocols, user or administrator
728  * intervention, or policy. If this happens, the TNCS will return TNC_RESULT_ILLEGAL_OPERATION
729  * from TNC_TNCS_SendMessage and call TNC_IMV_SolicitRecommendation to elicit IMV
730  * Action Recommendations based on the data they have gathered so far.
731  * In the imvID parameter, the TNCS MUST pass the IMV ID value provided to
732  * 
733  * TNC_IMV_Initialize. In the connectionID parameter, the TNCS MUST pass a valid
734  * network connection ID. IMVs MAY check these values to make sure they are valid and return an
735  * error if not, but IMVs are not required to make these checks.
736  * 
737  * @param imvID - IMV ID assigned by TNCS
738  * @param connectionID - Network connection ID for which a recommendation is requested
739  *
740  */
741 TNC_IMV_API TNC_Result TNC_IMV_SolicitRecommendation(
742     /*in*/  TNC_IMVID imvID,
743     /*in*/  TNC_ConnectionID connectionID) {
744     TNC_BufferReference lang = (TNC_BufferReference) "en";   // BYTE*
745     TNC_BufferReference str;
746     TNC_IMV_Action_Recommendation recommendation;
747     TNC_IMV_Evaluation_Result evaluation;
748     int len;
749
750     DEBUG("TNC_IMV_SolicitRecommendation\n");
751
752     if (!initialized) {
753         ERROR("Not initialized");
754         return TNC_RESULT_NOT_INITIALIZED;
755     }
756
757     if (imvID != imv_id) {
758         ERROR("Bad ID");
759         return TNC_RESULT_INVALID_PARAMETER;
760     }
761
762
763     if (result == OPENPTS_RESULT_VALID) {
764         DEBUG("verifier() result      : VALID");
765         str            = (TNC_BufferReference)"valid";
766         recommendation = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
767         evaluation     = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
768     } else if (result == OPENPTS_RESULT_UNVERIFIED) {
769         DEBUG("verifier() result      : UNVERIFIED");
770         str            = (TNC_BufferReference)"unverified";
771         recommendation = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
772         evaluation     = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR;
773     } else if (result == OPENPTS_RESULT_INVALID) {
774         TODO("verifier() result      : INVALID");
775         str            = (TNC_BufferReference)"invalid";
776         recommendation = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
777         evaluation     = TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR;
778     } else if (result == OPENPTS_RESULT_UNKNOWN) {
779         DEBUG("verifier() result      : UNKNOWN");
780         str            = (TNC_BufferReference)"unknown";
781         recommendation = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
782         evaluation     = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
783     } else if (result == OPENPTS_RESULT_IGNORE) {
784         DEBUG("verifier() result      : IGNORE");
785         str            = (TNC_BufferReference)"ignore";
786         recommendation = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
787         evaluation     = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
788     } else {
789         DEBUG("verifier() result      : ERROR");
790         str            = (TNC_BufferReference)"error";
791         recommendation = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
792         evaluation     = TNC_IMV_EVALUATION_RESULT_ERROR;
793     }
794
795
796     // Just for testing, provide a recommendation:
797     // IMVs may tell the TNCS about languages and resons
798     len = strlen((char*)lang) + 1;
799     setAttribute(
800             imvID,
801             connectionID,
802             TNC_ATTRIBUTEID_REASON_LANGUAGE,
803             len,
804             lang);
805
806     len = strlen((char*)str) + 1;
807     setAttribute(
808             imvID,
809             connectionID,
810             TNC_ATTRIBUTEID_REASON_STRING,
811             len,
812             str);
813
814     DEBUG_IFM("[C<-V] imvID=%d, connectionID=%d - TNC_IMV_SolicitRecommendation\n",
815         (int)imvID, (int)connectionID);
816
817     return provideRecommendation(
818                 imvID,
819                 connectionID,
820                 recommendation,
821                 evaluation);
822 }
823
824
825 /**
826  * from IMV spec.
827  *
828  * TNC_IMV_BatchEnding (OPTIONAL)
829  *
830  * The TNC Server calls this function to notify IMVs that all IMC messages received in a batch have
831  * been delivered and this is the IMV’s last chance to send a message in the batch of IMV
832  * messages currently being collected.. An IMV MAY implement this function if it wants to perform
833  * some actions after all the IMC messages received during a batch have been delivered (using
834  * TNC_IMV_ReceiveMessage). For instance, if an IMV has not received any messages from an
835  * IMC it may conclude that its IMC is not installed on the endpoint and may decide to call
836  * TNC_TNCS_ProvideRecommendation with the recommendation parameter set to
837  * TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS.
838  *
839  * An IMV MAY call TNC_TNCS_SendMessage from this function. As with all IMV functions, the IMV
840  * SHOULD NOT wait a long time before returning from TNC_IMV_BatchEnding. To do otherwise
841  * would risk delaying the handshake indefinitely. A long delay might frustrate users or exceed
842  * network timeouts (PDP, PEP or otherwise).
843  *
844  * In the imvID parameter, the TNCS MUST pass the IMV ID value provided to
845  * TNC_IMV_Initialize. In the connectionID parameter, the TNCS MUST pass a valid
846  * network connection ID. IMVs MAY check these values to make sure they are valid and return an
847  * error if not, but IMVs are not required to make these checks.
848  *
849  */
850 TNC_IMV_API TNC_Result TNC_IMV_BatchEnding(
851     /*in*/  TNC_IMVID imvID,
852     /*in*/  TNC_ConnectionID connectionID) {
853     DEBUG("TNC_IMV_BatchEnding\n");
854
855     if (!initialized) {
856         ERROR("Not initialized");
857         return TNC_RESULT_NOT_INITIALIZED;
858     }
859
860     if (imvID != imv_id) {
861         ERROR("imvID != imv_id");
862         return TNC_RESULT_INVALID_PARAMETER;
863     }
864
865     DEBUG_IFM("V    imvID=%d, connectionID=%d - TNC_IMV_BatchEnding\n",
866         (int)imvID, (int)connectionID);
867
868     return TNC_RESULT_SUCCESS;
869 }
870
871
872 /**
873  * TNC_IMV_Terminate (OPTIONAL)
874  */
875 TNC_IMV_API TNC_Result TNC_IMV_Terminate(
876     /*in*/  TNC_IMVID imvID) {
877     DEBUG("TNC_IMV_Terminate\n");
878
879     if (!initialized) {
880         ERROR("Not initialized");
881         return TNC_RESULT_NOT_INITIALIZED;
882     }
883
884     if (imvID != imv_id) {
885         ERROR("Bad id");
886         return TNC_RESULT_INVALID_PARAMETER;
887     }
888
889     /* PTS */
890     freePtsContext(ctx);
891     freePtsConfig(conf);
892
893     initialized = 0;
894
895     DEBUG_IFM("V    imvID=%d - TNC_IMV_Terminate\n",
896         (int)imvID);
897
898     return TNC_RESULT_SUCCESS;
899 }
900
901
902 /* TNC Server Functions */
903
904 /**
905  * Call TNC_TNCS_ReportMessageTypes (MANDATORY) in the TNCS
906  */
907 static TNC_Result reportMessageTypes(
908     /*in*/ TNC_IMVID imvID,
909     /*in*/ TNC_MessageTypeList supportedTypes,
910     /*in*/ TNC_UInt32 typeCount) {
911     DEBUG("reportMessageTypes %d\n", (int)imvID);
912
913     if (!reportMessageTypesPtr) {
914         ERROR("null input");
915         return TNC_RESULT_FATAL;
916     }
917
918     DEBUG_IFM("[C<-V] imvID=%d - reportMessageTypes\n",
919         (int)imvID);
920
921     // Call the function in the TMCC
922     return (*reportMessageTypesPtr)(imvID, supportedTypes, typeCount);
923 }
924
925
926 /**
927  * Call TNC_TNCS_SendMessage (MANDATORY) in the TNCS
928  */
929 static TNC_Result sendMessage(
930     /*in*/ TNC_IMVID imvID,
931     /*in*/ TNC_ConnectionID connectionID,
932     /*in*/ TNC_BufferReference message,
933     /*in*/ TNC_UInt32 messageLength,
934     /*in*/ TNC_MessageType messageType) {
935     DEBUG("sendMessage\n");
936
937     if (!sendMessagePtr) {
938         ERROR("null input");
939         return TNC_RESULT_FATAL;
940     }
941
942     DEBUG_IFM("[C<-V] imvID=%d, connectionID=%d, type=0x%x, msg[%d]\n",
943         (int)imvID, (int)connectionID, (int)messageType, (int)messageLength);
944
945     // Call the function in the TMCC
946     return (*sendMessagePtr)(
947                 imvID,
948                 connectionID,
949                 message,
950                 messageLength,
951                 messageType);
952 }
953
954
955 #if 0
956 // imv.c:343: error: ‘requestHandshakeRetry’ defined but not used
957
958 /**
959  * Call TNC_TNCS_RequestHandshakeRetry (MANDATORY) in the TNCS
960  */
961 static TNC_Result requestHandshakeRetry(
962     /*in*/ TNC_IMVID imvID,
963     /*in*/ TNC_ConnectionID connectionID,
964     /*in*/ TNC_RetryReason reason) {
965     DEBUG("requestHandshakeRetry\n");
966
967     if (!requestHandshakeRetryPtr)
968         return TNC_RESULT_FATAL;
969
970     // Call the function in the TMCC
971     return (*requestHandshakeRetryPtr)(imvID, connectionID, reason);
972 }
973 #endif
974
975
976 /**
977  * Call TNC_TNCS_ProvideRecommendation (MANDATORY) in the TNCS
978  */
979 static TNC_Result provideRecommendation(
980     /*in*/ TNC_IMVID imvID,
981     /*in*/ TNC_ConnectionID connectionID,
982     /*in*/ TNC_IMV_Action_Recommendation recommendation,
983     /*in*/ TNC_IMV_Evaluation_Result evaluation) {
984     DEBUG("provideRecommendation\n");
985
986     if (!provideRecommendationPtr) {
987         ERROR("null input");
988         return TNC_RESULT_FATAL;
989     }
990
991     DEBUG_IFM("[C<-V] imvID=%d, connectionID=%d - provideRecommendation\n",
992         (int)imvID, (int)connectionID);
993
994     return (*provideRecommendationPtr)(
995                 imvID,
996                 connectionID,
997                 recommendation,
998                 evaluation);
999 }
1000
1001
1002 #if 0
1003 // imv.c:381: error: ‘getAttribute’ defined but not used
1004 /**
1005  * Call TNC_TNCS_GetAttribute (OPTIONAL) in the TNCS
1006  */
1007 static TNC_Result getAttribute(
1008     /*in*/  TNC_IMVID imvID,
1009     /*in*/  TNC_ConnectionID connectionID,
1010     /*in*/  TNC_AttributeID attributeID,
1011     /*in*/  TNC_UInt32 bufferLength,
1012     /*out*/ TNC_BufferReference buffer,
1013     /*out*/ TNC_UInt32 *pOutValueLength) {
1014     DEBUG("getAttribute\n");
1015
1016     if (!getAttributePtr)
1017         return TNC_RESULT_FATAL;
1018
1019     return (*getAttributePtr)(
1020             imvID,
1021             connectionID,
1022             attributeID,
1023             bufferLength,
1024             buffer,
1025             pOutValueLength);
1026 }
1027 #endif
1028
1029 /**
1030  * Call TNC_TNCS_SetAttribute (OPTIONAL) in the TNCS
1031  */
1032 static TNC_Result setAttribute(
1033     /*in*/ TNC_IMVID imvID,
1034     /*in*/ TNC_ConnectionID connectionID,
1035     /*in*/  TNC_AttributeID attributeID,
1036     /*in*/  TNC_UInt32 bufferLength,
1037     /*out*/ TNC_BufferReference buffer) {
1038     DEBUG("setAttribute\n");
1039
1040     if (!setAttributePtr) {
1041         ERROR("null input");
1042         return TNC_RESULT_FATAL;
1043     }
1044
1045     DEBUG_IFM("[C<-V] imvID=%d, connectionID=%d - setAttribute\n",
1046         (int)imvID, (int)connectionID);
1047
1048     return (*setAttributePtr)(
1049             imvID,
1050             connectionID,
1051             attributeID,
1052             bufferLength,
1053             buffer);
1054 }
1055
1056
1057 /* Platform-Specific IMV Functions */
1058
1059 /**
1060  * TNC_IMV_ProvideBindFunction
1061  */
1062 TNC_IMV_API TNC_Result TNC_IMV_ProvideBindFunction(
1063     /*in*/  TNC_IMVID imvID,
1064     /*in*/  TNC_TNCS_BindFunctionPointer bindFunction) {
1065     DEBUG("TNC_IMV_ProvideBindFunction\n");
1066
1067     if (!initialized) {
1068         ERROR("Not initialized");
1069         return TNC_RESULT_NOT_INITIALIZED;
1070     }
1071
1072     if (imvID != imv_id) {
1073         ERROR("Bad id");
1074         return TNC_RESULT_INVALID_PARAMETER;
1075     }
1076
1077     if (bindFunction) {
1078         // Look for required functions in the parent TMCC
1079         if ((*bindFunction)(imvID, "TNC_TNCS_ReportMessageTypes",
1080                             (void**)&reportMessageTypesPtr) !=
1081                 TNC_RESULT_SUCCESS) {
1082             ERROR("TBD");
1083             return TNC_RESULT_FATAL;
1084         }
1085         if ((*bindFunction)(imvID, "TNC_TNCS_RequestHandshakeRetry",
1086                             (void**)&requestHandshakeRetryPtr) !=
1087                 TNC_RESULT_SUCCESS) {
1088             ERROR("TBD");
1089             return TNC_RESULT_FATAL;
1090         }
1091         if ((*bindFunction)(imvID, "TNC_TNCS_ProvideRecommendation",
1092                             (void**)&provideRecommendationPtr) !=
1093                 TNC_RESULT_SUCCESS) {
1094             ERROR("TBD");
1095             return TNC_RESULT_FATAL;
1096         }
1097         if ((*bindFunction)(imvID, "TNC_TNCS_SendMessage",
1098                             (void**)&sendMessagePtr) !=
1099                 TNC_RESULT_SUCCESS) {
1100             ERROR("TBD");
1101             return TNC_RESULT_FATAL;
1102         }
1103         if ((*bindFunction)(imvID, "TNC_TNCS_GetAttribute",
1104                             (void**)&getAttributePtr) !=
1105                 TNC_RESULT_SUCCESS) {
1106             // TODO(munetoh) optional
1107             ERROR("TBD");
1108             return TNC_RESULT_FATAL;
1109         }
1110         if ((*bindFunction)(imvID, "TNC_TNCS_SetAttribute",
1111                             (void**)&setAttributePtr) !=
1112                 TNC_RESULT_SUCCESS) {
1113             // TODO(munetoh) optional
1114             ERROR("TBD");
1115             return TNC_RESULT_FATAL;
1116         }
1117     }
1118
1119     if (reportMessageTypes(
1120                 imvID, messageTypes,
1121                 sizeof(messageTypes) / sizeof(TNC_MessageType)) ==
1122             TNC_RESULT_SUCCESS) {
1123         return TNC_RESULT_SUCCESS;
1124     } else {
1125         ERROR("TBD");
1126         return TNC_RESULT_FATAL;
1127     }
1128 }