OSDN Git Service

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