#include "tpm.h" #include "facilities.h" #include "edm.h" #include #include #include #include #include #include #include #include #include #include #include static char* tts(int type) { static char* stype[] = {"null", "entry", "exit", "single"}; if (type < 1 || type > 3) return stype[0]; else return stype[type]; } int tpm_is_inside_zone(tolling_info_t* ti) { int rv = 0; double point[2]; int16_t heading; itss_space_lock(); itss_space_get(); point[0] = epv.space.data.latitude.value/1.0e7; point[1] = epv.space.data.longitude.value/1.0e7; heading = epv.space.data.heading.value; itss_space_unlock(); if (it2s_geodesy_inside_polygon(point[0], point[1], ti->zone.polygon, ti->zone.polygon_len)) { uint16_t da = abs((int16_t)heading - (int16_t)ti->asn->angle); if (da <= 900 || da >= 2700) { return 1; } } return 0; } int tpm_should_retransmit() { tolling_t* tolling = &facilities.tolling; uint64_t now = itss_ts_get(TIME_MICROSECONDS); if (tolling->station.obu.rt_on) { if (now > tolling->station.obu.rt_init + TOLLING_RT_TIMEOUT_MS*1000ULL) { tolling->station.obu.rt_on = false; return 0; } if (now > tolling->station.obu.rt_t_trigger + TOLLING_RT_PERIOD_MS*1000ULL) { return 1; } } return 0; } int tpm_pay(tolling_info_t* info, void** security_socket, uint8_t* neighbour, uint8_t* dst_addr) { int rv = 0; tolling_t* tolling = (tolling_t*) &facilities.tolling; const size_t buf_len = INDICATION_BUFFER_SIZE; uint8_t tpm_uper[buf_len]; uint8_t buf1[buf_len], buf2[buf_len]; if (!tolling->enabled) { log_debug("[tolling] tolling is disabled"); return rv; } EI1_TPM_t* tpm = NULL; EIS_NetworkingRequest_t* nr = NULL; EIS_SecurityRequest_t* sreq = NULL; EIS_SecurityReply_t* srep = NULL; EIS_FacilitiesIndication_t* fi = NULL; pthread_mutex_lock(&tolling->lock); tolling->station.obu.t_init = itss_ts_get(TIME_MICROSECONDS); tolling->station.obu.active = true; tolling->station.obu.nonce = rand() + 1; log_info("[tolling] issuing toll %s.request | client: %lld nonce: %lld", tts(info->asn->tollType), tolling->station.obu.client_id, tolling->station.obu.nonce); // TPM tpm = calloc(1, sizeof(EI1_TPM_t)); tpm->header.messageID = 117; tpm->header.protocolVersion = 0; pthread_mutex_lock(&facilities.id.lock); tpm->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); tpm->tpm = calloc(1, sizeof(EI1_TollingPaymentMessage_t)); // timestamp asn_ulong2INTEGER(&tpm->tpm->timestamp, itss_time_get()); // stationType tpm->tpm->stationType = facilities.station_type; // referencePosition itss_space_lock(); itss_space_get(); tpm->tpm->referencePosition.altitude.altitudeValue = epv.space.data.altitude.value; tpm->tpm->referencePosition.altitude.altitudeConfidence = epv.space.data.altitude.confidence; tpm->tpm->referencePosition.latitude = epv.space.data.latitude.value; tpm->tpm->referencePosition.longitude = epv.space.data.longitude.value; uint16_t lat_conf = epv.space.data.latitude.confidence; uint16_t lon_conf = epv.space.data.longitude.confidence; itss_space_unlock(); if (lat_conf > lon_conf) { tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 0; } else { tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 900; } tpm->tpm->tollingType = calloc(1, sizeof(EI1_TollingType_t)); EI1_TollingType_t* type = tpm->tpm->tollingType; switch (info->asn->tollType) { case EI1_TollType_entry: if (tolling->station.obu.toll_type != -1 && !tolling->station.obu.rt_on) { log_error("[tolling] trying to issue entry.request but current tolling state is %s - resetting", tts(tolling->station.obu.toll_type)); tolling->station.obu.toll_type = -1; tolling->station.obu.active = false; ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tolling->station.obu.entry_proof); tolling->station.obu.entry_proof = NULL; } type->present = EI1_TollingType_PR_entry; type->choice.entry.present = EI1_TollingEntry_PR_request; type->choice.entry.choice.request.clientId = tolling->station.obu.client_id; type->choice.entry.choice.request.infoId = info->asn->id; type->choice.entry.choice.request.transactionNonce = tolling->station.obu.nonce; break; case EI1_TollType_exit: type->present = EI1_TollingType_PR_exit; type->choice.exit = calloc(1, sizeof(EI1_TollingExit_t)); type->choice.exit->present = EI1_TollingExit_PR_request; type->choice.exit->choice.request = calloc(1, sizeof(EI1_TollingExitRequest_t)); type->choice.exit->choice.request->clientId = tolling->station.obu.client_id; type->choice.exit->choice.request->infoId = info->asn->id; type->choice.exit->choice.request->transactionNonce = tolling->station.obu.nonce; if (tolling->station.obu.toll_type != EI1_TollingType_PR_entry && !tolling->station.obu.rt_on) { log_error("[tolling] trying to issue exit.request but current tolling state is %s - will not provide entry proof", tts(tolling->station.obu.toll_type)); } else { uint8_t b_tep[1024]; asn_enc_rval_t e_tep = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tolling->station.obu.entry_proof, b_tep, 1024); if (e_tep.encoded == -1) { log_error("[tolling] error encoding TPM entry proof (%s)", e_tep.failed_type->name); ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tolling->station.obu.entry_proof); tolling->station.obu.entry_proof = NULL; rv = 1; goto cleanup; } uper_decode_complete(NULL, &asn_DEF_EI1_TPM, (void**) &type->choice.exit->choice.request->entryProof, b_tep, (e_tep.encoded+7)/8); } break; case EI1_TollType_single: if (tolling->station.obu.toll_type != -1 && !tolling->station.obu.rt_on) { log_error("[tolling] trying to issue single.request but current tolling state is %s", tts(tolling->station.obu.toll_type)); rv = 1; goto cleanup; } type->present = EI1_TollingType_PR_single; type->choice.single.present = EI1_TollingSingle_PR_request; type->choice.single.choice.request.clientId = tolling->station.obu.client_id; type->choice.single.choice.request.infoId = info->asn->id; type->choice.single.choice.request.transactionNonce = tolling->station.obu.nonce; break; } tolling->station.obu.toll_type = info->asn->tollType; // Encode TollingPaymentMessage asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm->tpm, buf1, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name); rv = 1; goto cleanup; } if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) { // Sign sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_sign; sreq->choice.sign.data.size = enc.encoded; sreq->choice.sign.data.buf = malloc(enc.encoded); memcpy(sreq->choice.sign.data.buf, buf1, enc.encoded); buf2[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf2+1, INDICATION_BUFFER_SIZE-1); log_debug("->[security] SecurityRequest.sign (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf2, enc.encoded+1); int32_t rl = itss_0recv_rt(security_socket, buf1, buf_len, buf2, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.sign (%dB)", rl); if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf1, rl).code) { log_error("SecurityReply.sign decode failure"); rv = 1; goto cleanup; } if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) { log_error("SecurityReply.sign rejected"); rv = 1; goto cleanup; } tpm->tpmSignature = calloc(1, sizeof(EI1_TpmSignature_t)); tpm->tpmSignature->r.size = srep->data->choice.sign.r.size; tpm->tpmSignature->r.buf = malloc(srep->data->choice.sign.r.size); memcpy(tpm->tpmSignature->r.buf, srep->data->choice.sign.r.buf, srep->data->choice.sign.r.size); tpm->tpmSignature->s.size = srep->data->choice.sign.s.size; tpm->tpmSignature->s.buf = malloc(srep->data->choice.sign.s.size); memcpy(tpm->tpmSignature->s.buf, srep->data->choice.sign.s.buf, srep->data->choice.sign.s.size); tpm->tpmSignature->signer.size = srep->data->choice.sign.signer.size; tpm->tpmSignature->signer.buf = malloc(srep->data->choice.sign.signer.size); memcpy(tpm->tpmSignature->signer.buf, srep->data->choice.sign.signer.buf, srep->data->choice.sign.signer.size); tpm->tpmSignature->type = srep->data->choice.sign.type; } // Encode TPM enc = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tpm, tpm_uper, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TPM.request (%s)", enc.failed_type->name); rv = 1; goto cleanup; } size_t tpm_uper_len = (enc.encoded + 7) / 8; if (facilities.edm.enabled) { edm_encap(tpm_uper, (uint16_t*)&tpm_uper_len, buf_len, 7011); } // [transport] request (TR) nr = calloc(1, sizeof(EIS_NetworkingRequest_t)); nr->present = EIS_NetworkingRequest_PR_packet; EIS_NetworkingPacketRequest_t* npr = &nr->choice.packet; uint64_t id = 0; switch (facilities.tolling.protocol.p) { case TOLLING_PROTOCOL_GN_SPKI: case TOLLING_PROTOCOL_GN_DPKI: npr->transport.present = EIS_NetworkingPacketRequestTP_PR_btp; npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn; npr->network.choice.gn.securityProfile.encrypt = true; npr->network.choice.gn.securityProfile.sign = true; if(neighbour){ npr->network.choice.gn.securityNeighbour = calloc(1, sizeof(OCTET_STRING_t)); npr->network.choice.gn.securityNeighbour->size = 8; npr->network.choice.gn.securityNeighbour->buf = malloc(8); memcpy(npr->network.choice.gn.securityNeighbour->buf, neighbour, 8); } npr->data.size = tpm_uper_len; npr->data.buf = malloc(tpm_uper_len); memcpy(npr->data.buf, tpm_uper, tpm_uper_len); npr->id = itss_id(npr->data.buf, npr->data.size); id = npr->id; npr->transport.choice.btp.destinationPort = 7011; npr->transport.choice.btp.btpType = EIS_BTPType_btpB; npr->network.choice.gn.destinationAddress.buf = malloc(6); for (int i = 0; i < 6; ++i) { npr->network.choice.gn.destinationAddress.buf[i] = 0xff; } npr->network.choice.gn.destinationAddress.size = 6; npr->network.choice.gn.trafficClass = 2; npr->network.choice.gn.packetTransportType = EIS_PacketTransportType_shb; break; case TOLLING_PROTOCOL_TLS: case TOLLING_PROTOCOL_TLS_GN: case TOLLING_PROTOCOL_TLS_SHS: sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_tlsSend; sreq->choice.tlsSend.data.buf = malloc(tpm_uper_len); sreq->choice.tlsSend.data.size = tpm_uper_len; memcpy(sreq->choice.tlsSend.data.buf, tpm_uper, tpm_uper_len); tlsc_t* tlsc = tolling_tlsc_get(dst_addr, 7011); if (tlsc) { id = tlsc->id; } else { tlsc = tolling_tlsc_new(dst_addr, 7011); id = tlsc->id; } ++tlsc->nmsg; sreq->choice.tlsSend.connId = id; buf1[0] = ITSS_FACILITIES; asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); log_debug("[tolling]-> SecurityRequest.tlsSend ->[security] | size:%ldB", enc.encoded); itss_0send(*security_socket, buf1, enc.encoded+1); int rc = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); if (rc == -1) { log_error("[tolling]-> SecurityRequest.tlsSend ->[security] "); rv = 1; goto cleanup; } log_debug("[tolling]<- SecurityReply.tlsSend <-[security] | size:%dB", rc); EIS_SecurityReply_t* srep = NULL; asn_dec_rval_t dec = oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, buf_len); if (dec.code || srep->returnCode != EIS_SecurityReplyReturnCode_accepted || !srep->data || srep->data->present != EIS_SecurityReplyData_PR_tlsSend) { log_error("[tolling]<- SecurityReply.tlsSend rejected"); rv = 1; goto cleanup; } // TR TCP npr->transport.present = EIS_NetworkingPacketRequestTP_PR_tcp; npr->id = id; npr->transport.choice.tcp.destinationAddress = calloc(1, sizeof(OCTET_STRING_t)); npr->transport.choice.tcp.destinationAddress->buf = malloc(16); npr->transport.choice.tcp.destinationAddress->size = 16; memcpy(npr->transport.choice.tcp.destinationAddress->buf, dst_addr, 16); npr->transport.choice.tcp.destinationPort = 7011; npr->transport.choice.tcp.sourcePort = 7011; npr->data.buf = malloc(srep->data->choice.tlsSend.data.size); npr->data.size = srep->data->choice.tlsSend.data.size; memcpy(npr->data.buf, srep->data->choice.tlsSend.data.buf, srep->data->choice.tlsSend.data.size); if (tolling->protocol.p == TOLLING_PROTOCOL_TLS_GN || tolling->protocol.p == TOLLING_PROTOCOL_TLS_SHS) { npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn6a; npr->network.choice.gn6a.gn.packetTransportType = EIS_PacketTransportType_shb; npr->network.choice.gn6a.gn.destinationAddress.buf = calloc(1, 6); npr->network.choice.gn6a.gn.destinationAddress.size = 6; npr->network.choice.gn6a.gn.securityProfile.encrypt = false; npr->network.choice.gn6a.gn.securityProfile.sign = true; npr->network.choice.gn6a.ip.destinationAddress.buf = malloc(16); npr->network.choice.gn6a.ip.destinationAddress.size = 16; memcpy(npr->network.choice.gn6a.ip.destinationAddress.buf, dst_addr, 16); } else { npr->network.present = EIS_NetworkingPacketRequestNW_PR_ip; npr->network.choice.ip.destinationAddress.buf = malloc(16); npr->network.choice.ip.destinationAddress.size = 16; memcpy(npr->network.choice.ip.destinationAddress.buf, dst_addr, 16); } break; } // encode TR buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, nr, buf1+1, buf_len-1); if (enc.encoded == -1) { log_error("[tolling] error encoding TR TPM.request (%s)", enc.failed_type->name); rv = 1; goto cleanup; } itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id, (tolling->protocol.p == TOLLING_PROTOCOL_GN_SPKI || tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) ? "NR.packet.btp" : "NR.packet.tcp")); // Retransmission uint64_t now = itss_ts_get(TIME_MICROSECONDS); if (!tolling->station.obu.rt_on) { tolling->station.obu.rt_init = now; tolling->station.obu.rt_on = true; } tolling->station.obu.rt_t_trigger = now; // Logging if (facilities.logging.dbms) { pthread_mutex_lock(&facilities.id.lock); uint32_t station_id = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); itss_db_add(facilities.logging.dbms, station_id, id, true, 117, NULL, tpm_uper, tpm_uper_len); } // send to [applications] fi = calloc(1, sizeof(EIS_FacilitiesIndication_t)); fi->present = EIS_FacilitiesIndication_PR_message; fi->choice.message.id = id; fi->choice.message.itsMessageType = 7011; fi->choice.message.data.size = tpm_uper_len; fi->choice.message.data.buf = malloc(tpm_uper_len); memcpy(fi->choice.message.data.buf, tpm_uper, tpm_uper_len); enc = oer_encode_to_buffer(&asn_DEF_EIS_FacilitiesIndication, NULL, fi, buf1+1, buf_len-1); if (enc.encoded == -1) { log_error("[tolling] error encoding FI TPM.request (%s)", enc.failed_type->name); rv = 1; goto cleanup; } itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_APPLICATIONS, id, "FI.message (TPM.request)")); if (facilities.logging.recorder) { uint16_t buffer_len = INDICATION_BUFFER_SIZE; uint8_t buffer[buffer_len]; int e = itss_management_record_packet_sdu( buffer, buffer_len, tpm_uper, tpm_uper_len, id, itss_time_get(), ITSS_FACILITIES, true); if (e != -1) { itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buffer, e, ITSS_MANAGEMENT, id, "MReq.packet.set")); } } cleanup: pthread_mutex_unlock(&tolling->lock); ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tpm); ASN_STRUCT_FREE(asn_DEF_EIS_NetworkingRequest, nr); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep); ASN_STRUCT_FREE(asn_DEF_EIS_FacilitiesIndication, fi); return rv; } static int rsu_handle_recv(EI1_TPM_t* tpm_rx, void** security_socket, uint8_t* neighbour, uint8_t* src_addr) { int rv = 0; if (!tpm_rx->tpm->tollingType) { log_error("[tolling] received TPM does not have a type"); return 1; } EI1_TollingType_t* type_rx = tpm_rx->tpm->tollingType; uint64_t client_id, nonce, info_id; const uint32_t buf_len = 1800; uint8_t buf1[buf_len], buf2[buf_len]; uint8_t tpm_uper[buf_len]; EIS_SecurityRequest_t* sreq = NULL; EIS_SecurityReply_t* srep = NULL; tolling_t* tolling = &facilities.tolling; switch (type_rx->present) { case EI1_TollingType_PR_entry: if (type_rx->choice.entry.present != EI1_TollingEntry_PR_request) { log_error("[tolling] received TPM.entry is not request"); return 1; } client_id = type_rx->choice.entry.choice.request.clientId; nonce = type_rx->choice.entry.choice.request.transactionNonce; info_id = type_rx->choice.entry.choice.request.infoId; break; case EI1_TollingType_PR_exit: if (!type_rx->choice.exit || type_rx->choice.exit->present != EI1_TollingExit_PR_request || !type_rx->choice.exit->choice.request ) { log_error("[tolling] received TPM.exit is not request"); return 1; } if (tolling->protocol.p != TOLLING_PROTOCOL_GN_DPKI) { log_warn("[tolling] cannot cryptographically verify entryProof in mode different than GN-DPKI"); client_id = type_rx->choice.exit->choice.request->clientId; nonce = type_rx->choice.exit->choice.request->transactionNonce; info_id = type_rx->choice.exit->choice.request->infoId; } else { client_id = type_rx->choice.exit->choice.request->clientId; nonce = type_rx->choice.exit->choice.request->transactionNonce; info_id = type_rx->choice.exit->choice.request->infoId; if (!type_rx->choice.exit->choice.request->entryProof) { log_error("[tolling] received TPM.exit.request does not contain entry proof"); return 1; } EI1_TPM_t* ep = (EI1_TPM_t*) type_rx->choice.exit->choice.request->entryProof; if (!ep->tpmSignature) { log_error("[tolling] received TPM.exit.request.entryProof does not contain signature");; return 1; } // Encode TollingPaymentMessage asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, ep->tpm, buf1, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name); rv = 1; goto cleanup; } // Verify sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_verify; // message sreq->choice.verify.message.size = enc.encoded; sreq->choice.verify.message.buf = malloc(enc.encoded); memcpy(sreq->choice.verify.message.buf, buf1, enc.encoded); // r sreq->choice.verify.r.size = ep->tpmSignature->r.size; sreq->choice.verify.r.buf = malloc(ep->tpmSignature->r.size); memcpy(sreq->choice.verify.r.buf, ep->tpmSignature->r.buf, ep->tpmSignature->r.size); // s sreq->choice.verify.s.size = ep->tpmSignature->s.size; sreq->choice.verify.s.buf = malloc(ep->tpmSignature->s.size); memcpy(sreq->choice.verify.s.buf, ep->tpmSignature->s.buf, ep->tpmSignature->s.size); // signer sreq->choice.verify.signer.size = ep->tpmSignature->signer.size; sreq->choice.verify.signer.buf = malloc(ep->tpmSignature->signer.size); memcpy(sreq->choice.verify.signer.buf, ep->tpmSignature->signer.buf, ep->tpmSignature->signer.size); // signature type sreq->choice.verify.type = ep->tpmSignature->type; buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); log_debug("->[security] SecurityRequest.verify (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf1, enc.encoded+1); int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.verify (%dB)", rl); if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rl).code) { log_error("SecurityReply.verify decode failure"); rv = 1; goto cleanup; } if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) { log_error("SecurityReply.verify rejected"); rv = 1; goto cleanup; } if (srep->data->choice.verify.report != EIS_SecurityVerifyConfirmCode_success) { log_debug("entry proof signature verify failed"); rv = 1; goto cleanup; } ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep); sreq = NULL; srep = NULL; } break; case EI1_TollingType_PR_single: if (type_rx->choice.single.present != EI1_TollingSingle_PR_request) { log_error("[tolling] received TPM.single is not request"); return 1; } client_id = type_rx->choice.single.choice.request.clientId; nonce = type_rx->choice.single.choice.request.transactionNonce; info_id = type_rx->choice.single.choice.request.infoId; break; default: log_error("[tolling] received TPM has unrecognized type"); return 1; } switch (tolling->protocol.p) { case TOLLING_PROTOCOL_GN_SPKI: case TOLLING_PROTOCOL_GN_DPKI: log_info("[tolling] received toll %s.request | client: %lld (certificate id: 0x%02x%02x%02x) nonce: %lld", tts(type_rx->present), client_id, neighbour ? neighbour[5] : 0, neighbour ? neighbour[6] : 0, neighbour ? neighbour[7] : 0, nonce ); break; case TOLLING_PROTOCOL_TLS: case TOLLING_PROTOCOL_TLS_GN: case TOLLING_PROTOCOL_TLS_SHS: log_info("[tolling] received toll %s.request | client: %lld nonce: %lld", tts(type_rx->present), client_id, nonce ); break; } int known_id = 0; for (int i = 0; i < facilities.tolling.infos.length; i++) { if (info_id != facilities.tolling.infos.z[i]->asn->id) { known_id = 1; } } if (!known_id) { log_warn("[tolling] received TPM has unkown info_id"); return 1; } asn_enc_rval_t enc; EIS_NetworkingRequest_t* nr = NULL; EIS_FacilitiesIndication_t* fi = NULL; EI1_TPM_t* tpm = NULL; if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) { if (!tpm_rx->tpmSignature) { log_error("[tolling] in simple mode but TPM without signature received"); rv = 1; goto cleanup; } // Encode TollingPaymentMessage enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm_rx->tpm, buf1, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name); rv = 1; goto cleanup; } // Verify sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_verify; // message sreq->choice.verify.message.size = enc.encoded; sreq->choice.verify.message.buf = malloc(enc.encoded); memcpy(sreq->choice.verify.message.buf, buf1, enc.encoded); // r sreq->choice.verify.r.size = tpm_rx->tpmSignature->r.size; sreq->choice.verify.r.buf = malloc(tpm_rx->tpmSignature->r.size); memcpy(sreq->choice.verify.r.buf, tpm_rx->tpmSignature->r.buf, tpm_rx->tpmSignature->r.size); // s sreq->choice.verify.s.size = tpm_rx->tpmSignature->s.size; sreq->choice.verify.s.buf = malloc(tpm_rx->tpmSignature->s.size); memcpy(sreq->choice.verify.s.buf, tpm_rx->tpmSignature->s.buf, tpm_rx->tpmSignature->s.size); // signer sreq->choice.verify.signer.size = tpm_rx->tpmSignature->signer.size; sreq->choice.verify.signer.buf = malloc(tpm_rx->tpmSignature->signer.size); memcpy(sreq->choice.verify.signer.buf, tpm_rx->tpmSignature->signer.buf, tpm_rx->tpmSignature->signer.size); // signature type sreq->choice.verify.type = tpm_rx->tpmSignature->type; buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); log_debug("->[security] SecurityRequest.verify (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf1, enc.encoded+1); int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.verify (%dB)", rl); if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rl).code) { log_error("SecurityReply.verify decode failure"); rv = 1; goto cleanup; } if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) { log_error("SecurityReply.verify rejected"); rv = 1; goto cleanup; } if (srep->data->choice.verify.report != EIS_SecurityVerifyConfirmCode_success) { log_debug("signature verify failed"); rv = 1; goto cleanup; } ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep); sreq = NULL; srep = NULL; } // TPM tpm = calloc(1, sizeof(EI1_TPM_t)); tpm->header.messageID = 117; tpm->header.protocolVersion = 0; pthread_mutex_lock(&facilities.id.lock); tpm->header.stationID = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); tpm->tpm = calloc(1, sizeof(EI1_TollingPaymentMessage_t)); // timestamp asn_ulong2INTEGER(&tpm->tpm->timestamp, itss_time_get()); // stationType tpm->tpm->stationType = facilities.station_type; // referencePosition itss_space_lock(); itss_space_get(); tpm->tpm->referencePosition.altitude.altitudeValue = epv.space.data.altitude.value; tpm->tpm->referencePosition.altitude.altitudeConfidence = epv.space.data.altitude.confidence; tpm->tpm->referencePosition.latitude = epv.space.data.latitude.value; tpm->tpm->referencePosition.longitude = epv.space.data.longitude.value; uint16_t lat_conf = epv.space.data.latitude.confidence; uint16_t lon_conf = epv.space.data.longitude.confidence; itss_space_unlock(); if (lat_conf > lon_conf) { tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 0; } else { tpm->tpm->referencePosition.positionConfidenceEllipse.semiMinorConfidence = lon_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorConfidence = lat_conf; tpm->tpm->referencePosition.positionConfidenceEllipse.semiMajorOrientation = 900; } // Client management for (int i = 0 ; i < tolling->station.rsu.clients_len; ++i) { if (itss_time_get() > tolling->station.rsu.clients[i]->ts + TOLLING_CLIENT_LIFETIME_MS) { free(tolling->station.rsu.clients[i]); tolling->station.rsu.clients[i] = NULL; for (int j = i; j < tolling->station.rsu.clients_len-1; ++j) { tolling->station.rsu.clients[j] = tolling->station.rsu.clients[j+1]; } --tolling->station.rsu.clients_len; } } // Find client toll_client_t* client = NULL; for (int i = 0; i < tolling->station.rsu.clients_len; ++i) { if (tolling->station.rsu.clients[i]->id == client_id) { client = tolling->station.rsu.clients[i]; } } // Create client if (!client) { if (tolling->station.rsu.clients_len-1 >= TOLLING_MAX_CLIENTS) { log_error("[tolling] max clients reached"); rv = 1; goto cleanup; } tolling->station.rsu.clients[tolling->station.rsu.clients_len] = malloc(sizeof(toll_client_t)); client = tolling->station.rsu.clients[tolling->station.rsu.clients_len]; client->id = client_id; client->station_id = tpm_rx->header.stationID; client->ts = itss_time_get(); client->accepted = -1; } uint8_t confirmation_code = EI1_TollingConfirmationCode_rejected; if (itss_time_get() > client->ts + TOLLING_PAYMENT_MIN_PERIOD_MS || client->accepted == -1) { confirmation_code = EI1_TollingConfirmationCode_accepted; client->accepted = true; } else if (client->accepted && itss_time_get() < client->ts + TOLLING_PAYMENT_MIN_PERIOD_MS) { confirmation_code = EI1_TollingConfirmationCode_alreadyAccepted; } tpm->tpm->tollingType = calloc(1, sizeof(EI1_TollingType_t)); switch (tpm_rx->tpm->tollingType->present) { case EI1_TollingType_PR_entry: tpm->tpm->tollingType->present = EI1_TollingType_PR_entry; tpm->tpm->tollingType->choice.entry.present = EI1_TollingEntry_PR_reply; tpm->tpm->tollingType->choice.entry.choice.reply.clientId = client_id; tpm->tpm->tollingType->choice.entry.choice.reply.infoId = info_id; tpm->tpm->tollingType->choice.entry.choice.reply.transactionNonce = nonce; tpm->tpm->tollingType->choice.entry.choice.reply.confirmationCode = confirmation_code; break; case EI1_TollingType_PR_exit: tpm->tpm->tollingType->present = EI1_TollingType_PR_exit; tpm->tpm->tollingType->choice.exit = calloc(1, sizeof(EI1_TollingExit_t)); tpm->tpm->tollingType->choice.exit->present = EI1_TollingExit_PR_reply; tpm->tpm->tollingType->choice.exit->choice.reply.clientId = client_id; tpm->tpm->tollingType->choice.exit->choice.reply.infoId = info_id; tpm->tpm->tollingType->choice.exit->choice.reply.transactionNonce = nonce; tpm->tpm->tollingType->choice.exit->choice.reply.confirmationCode = confirmation_code; break; case EI1_TollingType_PR_single: tpm->tpm->tollingType->present = EI1_TollingType_PR_single; tpm->tpm->tollingType->choice.single.present = EI1_TollingSingle_PR_reply; tpm->tpm->tollingType->choice.single.choice.reply.clientId = client_id; tpm->tpm->tollingType->choice.single.choice.reply.infoId = info_id; tpm->tpm->tollingType->choice.single.choice.reply.transactionNonce = nonce; tpm->tpm->tollingType->choice.single.choice.reply.confirmationCode = confirmation_code; break; default: break; } // TODO check clientId // Encode TollingPaymentMessage enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm->tpm, buf1, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name); rv = 1; goto cleanup; } if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) { // Sign sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_sign; sreq->choice.sign.data.size = enc.encoded; sreq->choice.sign.data.buf = malloc(enc.encoded); memcpy(sreq->choice.sign.data.buf, buf1, enc.encoded); buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); if (enc.encoded == -1) { log_error("[tolling] error encoding SecurityRequest (%s)", enc.failed_type->name); rv = 1; goto cleanup; } log_debug("->[security] SecurityRequest.sign (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf1, enc.encoded+1); int rc = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.sign (%dB)", rc); if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rc).code) { log_error("SecurityReply.sign decode failure"); rv = 1; goto cleanup; } if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) { log_error("SecurityReply.sign rejected"); rv = 1; goto cleanup; } tpm->tpmSignature = calloc(1, sizeof(EI1_TpmSignature_t)); tpm->tpmSignature->r.size = srep->data->choice.sign.r.size; tpm->tpmSignature->r.buf = malloc(srep->data->choice.sign.r.size); memcpy(tpm->tpmSignature->r.buf, srep->data->choice.sign.r.buf, srep->data->choice.sign.r.size); tpm->tpmSignature->s.size = srep->data->choice.sign.s.size; tpm->tpmSignature->s.buf = malloc(srep->data->choice.sign.s.size); memcpy(tpm->tpmSignature->s.buf, srep->data->choice.sign.s.buf, srep->data->choice.sign.s.size); tpm->tpmSignature->signer.size = srep->data->choice.sign.signer.size; tpm->tpmSignature->signer.buf = malloc(srep->data->choice.sign.signer.size); memcpy(tpm->tpmSignature->signer.buf, srep->data->choice.sign.signer.buf, srep->data->choice.sign.signer.size); tpm->tpmSignature->type = srep->data->choice.sign.type; ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep); sreq = NULL; srep = NULL; } // encode TPM enc = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tpm, tpm_uper, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TPM.reply (%s)", enc.failed_type->name); rv = 1; goto cleanup; } size_t tpm_uper_len = (enc.encoded + 7) / 8; if (facilities.edm.enabled) { edm_encap(tpm_uper, (uint16_t*)&tpm_uper_len, buf_len, 7011); } uint64_t id = 0; nr = calloc(1, sizeof(EIS_NetworkingRequest_t)); nr->present = EIS_NetworkingRequest_PR_packet; EIS_NetworkingPacketRequest_t* npr = &nr->choice.packet; // [transport] request (TR) switch (tolling->protocol.p) { case TOLLING_PROTOCOL_GN_SPKI: case TOLLING_PROTOCOL_GN_DPKI: npr->transport.present = EIS_NetworkingPacketRequestTP_PR_btp; npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn; npr->network.choice.gn.securityProfile.encrypt = true; npr->network.choice.gn.securityProfile.sign = true; if(neighbour){ npr->network.choice.gn.securityNeighbour = calloc(1, sizeof(OCTET_STRING_t)); npr->network.choice.gn.securityNeighbour->size = 8; npr->network.choice.gn.securityNeighbour->buf = malloc(8); memcpy(npr->network.choice.gn.securityNeighbour->buf, neighbour, 8); } npr->data.size = tpm_uper_len; npr->data.buf = malloc(tpm_uper_len); memcpy(npr->data.buf, tpm_uper, tpm_uper_len); npr->id = itss_id(npr->data.buf, npr->data.size); id = npr->id; npr->transport.choice.btp.destinationPort = 7011; npr->transport.choice.btp.btpType = EIS_BTPType_btpB; npr->network.choice.gn.destinationAddress.buf = malloc(6); for (int i = 0; i < 6; ++i) { npr->network.choice.gn.destinationAddress.buf[i] = 0xff; } npr->network.choice.gn.destinationAddress.size = 6; npr->network.choice.gn.trafficClass = 2; npr->network.choice.gn.packetTransportType = EIS_PacketTransportType_shb; if (neighbour) { /* neighbour ID for [security] encryption */ npr->network.choice.gn.securityNeighbour = calloc(1, sizeof(OCTET_STRING_t)); npr->network.choice.gn.securityNeighbour->size = 8; npr->network.choice.gn.securityNeighbour->buf = malloc(8); memcpy(npr->network.choice.gn.securityNeighbour->buf, neighbour, 8); } break; case TOLLING_PROTOCOL_TLS: case TOLLING_PROTOCOL_TLS_GN: case TOLLING_PROTOCOL_TLS_SHS: sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_tlsSend; sreq->choice.tlsSend.data.buf = malloc(tpm_uper_len); sreq->choice.tlsSend.data.size = tpm_uper_len; memcpy(sreq->choice.tlsSend.data.buf, tpm_uper, tpm_uper_len); tlsc_t* tlsc = tolling_tlsc_get(src_addr, 7011); if (tlsc) { id = tlsc->id; } else { tlsc = tolling_tlsc_new(src_addr, 7011); id = tlsc->id; } ++tlsc->nmsg; sreq->choice.tlsSend.connId = id; buf1[0] = ITSS_FACILITIES; asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); log_debug("[tolling]-> SecurityRequest.tlsSend ->[security] | size:%ldB", enc.encoded); itss_0send(*security_socket, buf1, enc.encoded+1); int rc = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); if (rc == -1) { log_error("[tolling]-> SecurityRequest.tlsSend ->[security] "); rv = 1; goto cleanup; } log_debug("[tolling]<- SecurityReply.tlsSend <-[security] | size:%dB", rc); asn_dec_rval_t dec = oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rc); if (dec.code || srep->returnCode != EIS_SecurityReplyReturnCode_accepted || !srep->data || srep->data->present != EIS_SecurityReplyData_PR_tlsSend) { log_error("[tolling]<- SecurityReply.tlsSend rejected"); rv = 1; goto cleanup; } // TR TCP npr->transport.present = EIS_NetworkingPacketRequestTP_PR_tcp; npr->id = id; npr->transport.choice.tcp.destinationAddress = calloc(1, sizeof(OCTET_STRING_t)); npr->transport.choice.tcp.destinationAddress->buf = malloc(16); npr->transport.choice.tcp.destinationAddress->size = 16; memcpy(npr->transport.choice.tcp.destinationAddress->buf,src_addr, 16); npr->transport.choice.tcp.destinationPort = 7011; npr->transport.choice.tcp.sourcePort = 7011; npr->data.buf = malloc(srep->data->choice.tlsSend.data.size); npr->data.size = srep->data->choice.tlsSend.data.size; memcpy(npr->data.buf, srep->data->choice.tlsSend.data.buf, srep->data->choice.tlsSend.data.size); if (tolling->protocol.p == TOLLING_PROTOCOL_TLS_GN) { npr->network.present = EIS_NetworkingPacketRequestNW_PR_gn6a; npr->network.choice.gn6a.gn.packetTransportType = EIS_PacketTransportType_shb; npr->network.choice.gn6a.gn.destinationAddress.buf = calloc(1, 6); npr->network.choice.gn6a.gn.destinationAddress.size = 6; npr->network.choice.gn6a.gn.securityProfile.encrypt = false; npr->network.choice.gn6a.gn.securityProfile.sign = true; npr->network.choice.gn6a.ip.destinationAddress.buf = malloc(16); npr->network.choice.gn6a.ip.destinationAddress.size = 16; memcpy(npr->network.choice.gn6a.ip.destinationAddress.buf, src_addr, 16); } else { npr->network.present = EIS_NetworkingPacketRequestNW_PR_ip; npr->network.choice.ip.destinationAddress.buf = malloc(16); npr->network.choice.ip.destinationAddress.size = 16; memcpy(npr->network.choice.ip.destinationAddress.buf, src_addr, 16); } break; } // encode TR buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, nr, buf1+1, buf_len-1); if (enc.encoded == -1) { log_error("[tolling] error encoding TR TPM.reply (%s)", enc.failed_type->name); rv = 1; goto cleanup; } itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id, (tolling->protocol.p == TOLLING_PROTOCOL_GN_SPKI || tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) ? "NR.packet.btp" : "NR.packet.tcp")); // Logging if (facilities.logging.dbms) { pthread_mutex_lock(&facilities.id.lock); uint32_t station_id = facilities.id.station_id; pthread_mutex_unlock(&facilities.id.lock); itss_db_add(facilities.logging.dbms, station_id, id, true, 117, NULL, tpm_uper, tpm_uper_len); } // send to [applications] fi = calloc(1, sizeof(EIS_FacilitiesIndication_t)); fi->present = EIS_FacilitiesIndication_PR_message; fi->choice.message.id = id; fi->choice.message.itsMessageType = 7011; fi->choice.message.data.size = tpm_uper_len; fi->choice.message.data.buf = malloc(tpm_uper_len); memcpy(fi->choice.message.data.buf, tpm_uper, tpm_uper_len); enc = oer_encode_to_buffer(&asn_DEF_EIS_FacilitiesIndication, NULL, fi, buf1+1, buf_len-1); if (enc.encoded == -1) { log_error("[tolling] error encoding FI TPM.reply (%s)", enc.failed_type->name); rv = 1; goto cleanup; } itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_APPLICATIONS, id, "FI.message (TPM.reply)")); if (facilities.logging.recorder) { uint16_t buffer_len = INDICATION_BUFFER_SIZE; uint8_t buffer[buffer_len]; int e = itss_management_record_packet_sdu( buffer, buffer_len, tpm_uper, tpm_uper_len, id, itss_time_get(), ITSS_FACILITIES, true); if (e != -1) { itss_queue_send(facilities.tx_queue, itss_queue_packet_new(buffer, e, ITSS_MANAGEMENT, id, "MReq.packet.set")); } } cleanup: ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tpm); ASN_STRUCT_FREE(asn_DEF_EIS_NetworkingRequest, nr); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep); ASN_STRUCT_FREE(asn_DEF_EIS_FacilitiesIndication, fi); return rv; } static int veh_handle_recv(tolling_t* tolling, EI1_TPM_t* tpm_rx, void** security_socket, itss_queue_t* tx_queue, uint8_t* neighbour, uint8_t* src_addr) { int rv = 0; if (!tpm_rx->tpm->tollingType) { log_error("[tolling] received TPM does not have a type"); return 1; } EI1_TollingType_t* type_rx = tpm_rx->tpm->tollingType; uint64_t client_id, nonce, info_id; int confirmation_code; EIS_SecurityRequest_t* sreq = NULL; EIS_SecurityReply_t* srep = NULL; EIS_NetworkingRequest_t* tr = NULL; const uint16_t buf_len = INDICATION_BUFFER_SIZE; uint8_t buf1[buf_len], buf2[buf_len]; switch (type_rx->present) { case EI1_TollingType_PR_entry: if (type_rx->choice.entry.present != EI1_TollingEntry_PR_reply) { log_error("[tolling] received TPM.entry is not reply"); return 1; } if (tolling->station.obu.toll_type != EI1_TollingType_PR_entry) { log_error("[tolling] received TPM toll (%d) is not expected toll type (%d)", EI1_TollingType_PR_entry, tolling->station.obu.toll_type); } client_id = type_rx->choice.entry.choice.reply.clientId; nonce = type_rx->choice.entry.choice.reply.transactionNonce; info_id = type_rx->choice.entry.choice.reply.infoId; confirmation_code = type_rx->choice.entry.choice.reply.confirmationCode; uint8_t b_tep[INDICATION_BUFFER_SIZE]; asn_enc_rval_t e_tep = uper_encode_to_buffer(&asn_DEF_EI1_TPM, NULL, tpm_rx, b_tep, INDICATION_BUFFER_SIZE); if (e_tep.encoded == -1) { log_error("[tolling] error encoding received TPM as entry proof"); return 1; } uper_decode_complete(NULL, &asn_DEF_EI1_TPM, (void**) &tolling->station.obu.entry_proof, b_tep, (e_tep.encoded+7)/8); break; case EI1_TollingType_PR_exit: if (!type_rx->choice.exit || type_rx->choice.exit->present != EI1_TollingExit_PR_reply ) { log_error("[tolling] received TPM.exit is not reply"); return 1; } if (tolling->station.obu.toll_type != EI1_TollingType_PR_exit) { log_error("[tolling] received TPM toll (%d) is not expected toll type (%d)", EI1_TollingType_PR_exit, tolling->station.obu.toll_type); return 1; } client_id = type_rx->choice.exit->choice.reply.clientId; nonce = type_rx->choice.exit->choice.reply.transactionNonce; info_id = type_rx->choice.exit->choice.reply.infoId; confirmation_code = type_rx->choice.exit->choice.reply.confirmationCode; break; case EI1_TollingType_PR_single: if (type_rx->choice.single.present != EI1_TollingSingle_PR_reply) { log_error("[tolling] received TPM.single is not reply"); return 1; } if (tolling->station.obu.toll_type != EI1_TollingType_PR_single) { log_error("[tolling] received TPM type (%d) is not expected toll type (%d)", EI1_TollingType_PR_single, tolling->station.obu.toll_type); } client_id = type_rx->choice.single.choice.reply.clientId; nonce = type_rx->choice.single.choice.reply.transactionNonce; info_id = type_rx->choice.single.choice.reply.infoId; confirmation_code = type_rx->choice.single.choice.reply.confirmationCode; break; default: log_error("[tolling] received TPM has unrecognized type"); return 1; } if (client_id != tolling->station.obu.client_id) { log_debug("[tolling]<- received TPM.reply clientId different from ego"); return 1; } if (nonce != tolling->station.obu.nonce) { log_error("[tolling]<- received TPM.reply nonce different from sent request"); return 1; } // Encode TollingPaymentMessage asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EI1_TollingPaymentMessage, NULL, tpm_rx->tpm, buf1, buf_len); if (enc.encoded == -1) { log_error("[tolling] error encoding TollingPaymentMessage (%s)", enc.failed_type->name); rv = 1; goto cleanup; } bool accepted = true; if (tolling->protocol.p == TOLLING_PROTOCOL_GN_DPKI) { // Verify sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_verify; // message sreq->choice.verify.message.size = enc.encoded; sreq->choice.verify.message.buf = malloc(enc.encoded); memcpy(sreq->choice.verify.message.buf, buf1, enc.encoded); // r sreq->choice.verify.r.size = tpm_rx->tpmSignature->r.size; sreq->choice.verify.r.buf = malloc(tpm_rx->tpmSignature->r.size); memcpy(sreq->choice.verify.r.buf, tpm_rx->tpmSignature->r.buf, tpm_rx->tpmSignature->r.size); // s sreq->choice.verify.s.size = tpm_rx->tpmSignature->s.size; sreq->choice.verify.s.buf = malloc(tpm_rx->tpmSignature->s.size); memcpy(sreq->choice.verify.s.buf, tpm_rx->tpmSignature->s.buf, tpm_rx->tpmSignature->s.size); // signer sreq->choice.verify.signer.size = tpm_rx->tpmSignature->signer.size; sreq->choice.verify.signer.buf = malloc(tpm_rx->tpmSignature->signer.size); memcpy(sreq->choice.verify.signer.buf, tpm_rx->tpmSignature->signer.buf, tpm_rx->tpmSignature->signer.size); // signature type sreq->choice.verify.type = tpm_rx->tpmSignature->type; buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, INDICATION_BUFFER_SIZE-1); log_debug("->[security] SecurityRequest.verify (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf1, enc.encoded+1); int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.verify (%dB)", rl); if (oer_decode(NULL, &asn_DEF_EIS_SecurityReply, (void**) &srep, buf2, rl).code) { log_error("SecurityReply.verify decode failure"); rv = 1; goto cleanup; } if (srep->returnCode == EIS_SecurityReplyReturnCode_rejected) { log_error("SecurityReply.verify rejected"); rv = 1; goto cleanup; } if (srep->data->choice.verify.report != EIS_SecurityVerifyConfirmCode_success) { log_debug("signature verify failed"); rv = 1; goto cleanup; } accepted = confirmation_code == EI1_TollingConfirmationCode_accepted || confirmation_code == EI1_TollingConfirmationCode_alreadyAccepted; } switch (type_rx->present) { case EI1_TollingType_PR_entry: log_info("[tolling] received entry.reply | client: %lld nonce: %lld accepted: %s", tolling->station.obu.client_id, tolling->station.obu.nonce, accepted ? "yes" : "no"); break; case EI1_TollingType_PR_exit: log_info("[tolling] received exit.reply | client: %lld nonce: %lld accepted: %s", tolling->station.obu.client_id, tolling->station.obu.nonce, accepted ? "yes" : "no"); tolling->station.obu.toll_type = -1; tolling->station.obu.active = false; ASN_STRUCT_FREE(asn_DEF_EI1_TPM, tolling->station.obu.entry_proof); tolling->station.obu.entry_proof = NULL; break; case EI1_TollingType_PR_single: log_info("[tolling] received single.reply | client: %lld nonce: %lld accepted: %s", tolling->station.obu.client_id, tolling->station.obu.nonce, accepted ? "yes" : "no"); tolling->station.obu.toll_type = -1; tolling->station.obu.active = false; break; default: break; } // Close TCP & TLS conn if (tolling->protocol.p == TOLLING_PROTOCOL_TLS || tolling->protocol.p == TOLLING_PROTOCOL_TLS_GN || tolling->protocol.p == TOLLING_PROTOCOL_TLS_SHS) { tlsc_t* tlsc = tolling_tlsc_get(src_addr, 7011); if (tlsc) { sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_tlsClose; sreq->choice.tlsClose.connId = tlsc->id; buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); log_debug("->[security] SecurityRequest.tlsClose (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf1, enc.encoded+1); int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.tlsClose (%dB)", rl); uint32_t id = rand(); tr = calloc(1, sizeof(EIS_NetworkingRequest_t)); tr->present = EIS_NetworkingRequest_PR_data; tr->choice.data.present = EIS_NetworkingDataRequest_PR_tcp; tr->choice.data.choice.tcp.present = EIS_TCPDataRequest_PR_connCloseReq; tr->choice.data.choice.tcp.choice.connCloseReq.closeByPeer = false; tr->choice.data.choice.tcp.choice.connCloseReq.destinationPort = 7011; tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.size = 16; tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf = malloc(16); memcpy(tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf, src_addr, 16); tr->choice.data.choice.tcp.choice.connCloseReq.id = id; buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, tr, buf1+1, buf_len-1); itss_queue_send(tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id, "NR.data.tcp.connClose")); free(tlsc); for (int i = 0; i < tolling->protocol.c.tls.n_tlsc; ++i) { if (tlsc == tolling->protocol.c.tls.tls_conns[i]) { for (int j = i; j < tolling->protocol.c.tls.n_tlsc-1; ++j) { tolling->protocol.c.tls.tls_conns[j] = tolling->protocol.c.tls.tls_conns[j+1]; } --tolling->protocol.c.tls.n_tlsc; break; } } } else { log_debug("[tolling] unable to close TLS connection, not found"); } } cleanup: ASN_STRUCT_FREE(asn_DEF_EIS_SecurityRequest, sreq); ASN_STRUCT_FREE(asn_DEF_EIS_SecurityReply, srep); return rv; } int tpm_recv(EI1_TPM_t* tpm_rx, void** security_socket, uint8_t* neighbour, uint8_t* src_addr) { tolling_t* tolling = &facilities.tolling; if (!tolling->enabled) { log_debug("[tolling] tolling is disabled"); return 0; } if (!tpm_rx->tpm) { log_error("[tolling] received TPM does not have substructure TollingPaymentMessage"); return 1; } if (!tpm_rx->tpm->tollingType) { log_error("[tolling] received TPM does not have a type"); return 1; } pthread_mutex_lock(&tolling->lock); switch (tpm_rx->tpm->tollingType->present) { // Entry case EI1_TollingType_PR_entry: switch (tpm_rx->tpm->tollingType->choice.entry.present) { case EI1_TollingSingle_PR_request: if (facilities.station_type != 15) { log_debug("[tolling] received TPM.entry.request, ignoring"); goto cleanup; } rsu_handle_recv(tpm_rx, security_socket, neighbour, src_addr); break; case EI1_TollingSingle_PR_reply: if (facilities.station_type == 15) { log_debug("[tolling] received TPM.entry.reply, ignoring"); goto cleanup; } if (!veh_handle_recv(tolling, tpm_rx, security_socket, facilities.tx_queue, neighbour, src_addr)) { itss_time_lock(); log_info("[tolling] entry.reply took %lld us", itss_ts_get(TIME_MICROSECONDS) - tolling->station.obu.t_init); itss_time_unlock(); tolling->station.obu.rt_on = false; } break; default: break; } break; // Exit case EI1_TollingType_PR_exit: if (!tpm_rx->tpm->tollingType->choice.exit) { return 1; } switch (tpm_rx->tpm->tollingType->choice.exit->present) { case EI1_TollingSingle_PR_request: if (facilities.station_type != 15) { log_debug("[tolling] received TPM.exit.request, ignoring"); goto cleanup; } rsu_handle_recv(tpm_rx, security_socket, neighbour, src_addr); break; case EI1_TollingSingle_PR_reply: if (facilities.station_type == 15) { log_debug("[tolling] received TPM.exit.reply, ignoring"); goto cleanup; } if (!veh_handle_recv(tolling, tpm_rx, security_socket, facilities.tx_queue, neighbour, src_addr)) { itss_time_lock(); log_info("[tolling] exit.reply took %lld us", itss_ts_get(TIME_MICROSECONDS) - tolling->station.obu.t_init); itss_time_unlock(); tolling->station.obu.rt_on = false; } break; default: break; } break; // Single case EI1_TollingType_PR_single: switch (tpm_rx->tpm->tollingType->choice.single.present) { case EI1_TollingSingle_PR_request: if (facilities.station_type != 15) { log_debug("[tolling] received TPM.single.request, ignoring"); goto cleanup; } rsu_handle_recv(tpm_rx, security_socket, neighbour, src_addr); break; case EI1_TollingSingle_PR_reply: if (facilities.station_type == 15) { log_debug("[tolling] received TPM.single.reply, ignoring"); goto cleanup; } if (!veh_handle_recv(tolling, tpm_rx, security_socket, facilities.tx_queue, neighbour, src_addr)) { itss_time_lock(); log_info("[tolling] single.reply took %lld us", itss_ts_get(TIME_MICROSECONDS) - tolling->station.obu.t_init); itss_time_unlock(); tolling->station.obu.rt_on = false; } break; default: break; } break; default: break; } cleanup: pthread_mutex_unlock(&tolling->lock); return 0; } int tolling_init(uint8_t station_type) { tolling_t* tolling = &facilities.tolling; pthread_mutex_init(&tolling->lock, NULL); switch (station_type) { case 15: for (int i = 0; i < TOLLING_MAX_CLIENTS; ++i) { tolling->station.rsu.clients[i] = NULL; } break; default: tolling->station.obu.toll_type = -1; break; } return 0; } tolling_info_t* tolling_info_new(EI1_TollingPaymentInfo_t* tpi) { tolling_info_t* ti = calloc(1, sizeof(tolling_info_t)); ti->timestamp = itss_time_get(); ti->asn = tpi; ti->zone.polygon_len = tpi->zone.list.count; ti->zone.polygon = malloc(tpi->zone.list.count * sizeof(double[2])); for (int i = 0; i < tpi->zone.list.count; ++i) { ti->zone.polygon[i][0] = tpi->zone.list.array[i]->latitude / 1.0e7; ti->zone.polygon[i][1] = tpi->zone.list.array[i]->longitude / 1.0e7; } return ti; } void tolling_info_free(tolling_info_t* ti) { ASN_STRUCT_FREE(asn_DEF_EI1_TollingPaymentInfo, ti->asn); free(ti->zone.polygon); free(ti); } tlsc_t* tolling_tlsc_new(uint8_t ipv6[16], uint16_t port) { tolling_t* tolling = &facilities.tolling; log_debug("[tolling] new tlsc, nconns=%d", tolling->protocol.c.tls.n_tlsc); if (tolling->protocol.c.tls.n_tlsc >= TOLLING_MAX_CONNS - 1) { return NULL; } tolling->protocol.c.tls.tls_conns[tolling->protocol.c.tls.n_tlsc] = calloc(1, sizeof(tlsc_t)); tlsc_t* tlsc = tolling->protocol.c.tls.tls_conns[tolling->protocol.c.tls.n_tlsc]; memcpy(tlsc->ipv6, ipv6, 16); tlsc->port = port; tlsc->id = rand(); tlsc->ts = itss_time_get(); tlsc->nmsg = 0; tlsc->state = 0; ++tolling->protocol.c.tls.n_tlsc; return tlsc; } tlsc_t* tolling_tlsc_get(uint8_t ipv6[16], uint16_t port) { tolling_t* tolling = &facilities.tolling; log_debug("[tolling] new get , nconns=%d", tolling->protocol.c.tls.n_tlsc); tlsc_t* tlsc = NULL; for (int i = 0; i < tolling->protocol.c.tls.n_tlsc; ++i) { if (!memcmp(tolling->protocol.c.tls.tls_conns[i]->ipv6, ipv6, 16) && tolling->protocol.c.tls.tls_conns[i]->port == port) { tlsc = tolling->protocol.c.tls.tls_conns[i]; tlsc->ts = itss_time_get(); break; } } return tlsc; } void tolling_tlsc_mgmt(itss_queue_t* tx_queue, void** security_socket) { tolling_t* tolling = &facilities.tolling; pthread_mutex_lock(&tolling->lock); uint64_t now = itss_time_get(); for (int i = 0; i < tolling->protocol.c.tls.n_tlsc; ++i) { tlsc_t* tlsc = tolling->protocol.c.tls.tls_conns[i]; if (tlsc->ts + TOLLING_CONN_TIMEOUT_MS < now) { EIS_SecurityRequest_t* sreq = NULL; EIS_NetworkingRequest_t* tr = NULL; const uint32_t buf_len = 1024; uint8_t buf1[buf_len], buf2[buf_len]; log_debug("[tolling] closing TCP/TLS connection"); sreq = calloc(1, sizeof(EIS_SecurityRequest_t)); sreq->present = EIS_SecurityRequest_PR_tlsClose; sreq->choice.tlsClose.connId = tlsc->id; buf1[0] = ITSS_FACILITIES; asn_enc_rval_t enc = oer_encode_to_buffer(&asn_DEF_EIS_SecurityRequest, NULL, sreq, buf1+1, buf_len-1); log_debug("->[security] SecurityRequest.tlsClose (%ldB)", enc.encoded+1); itss_0send(*security_socket, buf1, enc.encoded+1); int32_t rl = itss_0recv_rt(security_socket, buf2, buf_len, buf1, enc.encoded+1, 1000); log_debug("<-[security] SecurityReply.tlsClose (%dB)", rl); uint64_t id = rand() + 1; tr = calloc(1, sizeof(EIS_NetworkingRequest_t)); tr->present = EIS_NetworkingRequest_PR_data; tr->choice.data.present = EIS_NetworkingDataRequest_PR_tcp; tr->choice.data.choice.tcp.present = EIS_TCPDataRequest_PR_connCloseReq; tr->choice.data.choice.tcp.choice.connCloseReq.closeByPeer = false; tr->choice.data.choice.tcp.choice.connCloseReq.destinationPort = 7011; tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.size = 16; tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf = malloc(16); memcpy(tr->choice.data.choice.tcp.choice.connCloseReq.destinationAddress.buf, tlsc->ipv6, 16); tr->choice.data.choice.tcp.choice.connCloseReq.id = id; buf1[0] = ITSS_FACILITIES; enc = oer_encode_to_buffer(&asn_DEF_EIS_NetworkingRequest, NULL, tr, buf1+1, buf_len-1); itss_queue_send(tx_queue, itss_queue_packet_new(buf1, enc.encoded+1, ITSS_NETWORKING, id, "NR.data.tcp.connClose")); free(tlsc); for (int j = i; j < tolling->protocol.c.tls.n_tlsc-1; ++j) { tolling->protocol.c.tls.tls_conns[j] = tolling->protocol.c.tls.tls_conns[j+1]; } --tolling->protocol.c.tls.n_tlsc; --i; } } pthread_mutex_unlock(&tolling->lock); }