in HAP/HAPIPAccessoryServer.c [2227:2503]
static void handle_secure_message(HAPIPSessionDescriptor* session) {
HAPPrecondition(session);
HAPPrecondition(session->server);
HAPAccessoryServer* server = (HAPAccessoryServer*) session->server;
HAPPrecondition(server->primaryAccessory);
HAPPrecondition(session->securitySession.type == kHAPIPSecuritySessionType_HAP);
HAPPrecondition(session->securitySession.isOpen);
HAPPrecondition(session->securitySession.isSecured || kHAPIPAccessoryServer_SessionSecurityDisabled);
HAPPrecondition(session->inboundBuffer.data);
HAPPrecondition(session->inboundBuffer.position <= session->inboundBuffer.limit);
HAPPrecondition(session->inboundBuffer.limit <= session->inboundBuffer.capacity);
HAPPrecondition(session->httpReaderPosition <= session->inboundBuffer.position);
HAPError err;
// Validate request.
// Requests use the HAP PDU format.
// See HomeKit Accessory Protocol Specification R14
// Section 7.3.3 HAP PDU Format
if (session->httpContentType != kHAPIPAccessoryServerContentType_Application_OctetStream) {
HAPLog(&logObject, "Received unexpected Content-Type in /secure-message request.");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_BadRequest);
return;
}
if (!session->httpContentLength.isDefined) {
HAPLog(&logObject, "Received malformed /secure-message request (no content length).");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_BadRequest);
return;
}
HAPAssert(session->httpContentLength.value <= session->inboundBuffer.position - session->httpReaderPosition);
uint8_t* requestBytes = (uint8_t*) &session->inboundBuffer.data[session->httpReaderPosition];
size_t numRequestBytes = session->httpContentLength.value;
if (numRequestBytes < 5) {
HAPLog(&logObject, "Received too short /secure-message request.");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_BadRequest);
return;
}
if (requestBytes[0] != ((0 << 7) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0))) {
HAPLog(&logObject, "Received malformed /secure-message request (control field: 0x%02x).", requestBytes[0]);
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_BadRequest);
return;
}
uint8_t opcode = requestBytes[1];
uint8_t tid = (uint8_t) requestBytes[2];
uint16_t iid = HAPReadLittleUInt16(&requestBytes[3]);
HAPTLVReaderRef requestBodyReader;
if (numRequestBytes <= 5) {
HAPAssert(numRequestBytes == 5);
HAPTLVReaderCreate(&requestBodyReader, NULL, 0);
} else {
if (numRequestBytes < 7) {
HAPLog(&logObject, "Received malformed /secure-message request (malformed body length).");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_BadRequest);
return;
}
uint16_t numRequestBodyBytes = HAPReadLittleUInt16(&requestBytes[5]);
if (numRequestBytes - 7 != numRequestBodyBytes) {
HAPLog(&logObject, "Received malformed /secure-message request (incorrect body length).");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_BadRequest);
return;
}
HAPTLVReaderCreate(&requestBodyReader, &requestBytes[7], numRequestBodyBytes);
}
// Response variables.
HAPBLEPDUStatus status;
void* _Nullable responseBodyBytes = NULL;
size_t numResponseBodyBytes = 0;
// Validate opcode.
if (!HAPPDUIsValidOpcode(opcode)) {
// If an accessory receives a HAP PDU with an opcode that it does not support it shall reject the PDU and
// respond with a status code Unsupported PDU in its HAP response.
// See HomeKit Accessory Protocol Specification R14
// Section 7.3.3.2 HAP Request Format
HAPLogAccessory(
&logObject,
server->primaryAccessory,
"Rejected /secure-message request with unsupported opcode: 0x%02x.",
opcode);
status = kHAPBLEPDUStatus_UnsupportedPDU;
goto SendResponse;
}
// Validate iid.
// For IP accessories instance ID in the request shall be set to 0.
// See HomeKit Accessory Protocol Specification R14
// Section 5.15 Software Authentication Procedure
if (iid) {
HAPLogAccessory(
&logObject,
server->primaryAccessory,
"Request's IID [00000000%08X] does not match the addressed IID.",
iid);
status = kHAPBLEPDUStatus_InvalidInstanceID;
goto SendResponse;
}
#define DestroyRequestBodyAndCreateResponseBodyWriter(responseWriter) \
do { \
size_t numBytes = server->ip.storage->scratchBuffer.numBytes; \
if (numBytes > UINT16_MAX) { \
/* Maximum for HAP-BLE PDU. */ \
numBytes = UINT16_MAX; \
} \
HAPTLVWriterCreate(responseWriter, server->ip.storage->scratchBuffer.bytes, numBytes); \
} while (0)
// Handle request.
HAPAssert(sizeof opcode == sizeof(HAPPDUOpcode));
switch ((HAPPDUOpcode) opcode) {
case kHAPPDUOpcode_ServiceSignatureRead:
case kHAPPDUOpcode_CharacteristicSignatureRead:
case kHAPPDUOpcode_CharacteristicConfiguration:
case kHAPPDUOpcode_ProtocolConfiguration:
case kHAPPDUOpcode_CharacteristicTimedWrite:
case kHAPPDUOpcode_CharacteristicExecuteWrite:
case kHAPPDUOpcode_CharacteristicWrite:
case kHAPPDUOpcode_CharacteristicRead: {
HAPLogAccessory(
&logObject,
server->primaryAccessory,
"Rejected /secure-message request with opcode that is not supported by IP: 0x%02x.",
opcode);
status = kHAPBLEPDUStatus_UnsupportedPDU;
}
goto SendResponse;
case kHAPPDUOpcode_Token: {
// See HomeKit Accessory Protocol Specification R14
// Section 5.15.1 HAP-Token-Request
HAPAssert(!iid);
HAPAssert(session->securitySession.isSecured || kHAPIPAccessoryServer_SessionSecurityDisabled);
// HAP-Token-Request ok.
HAPTLVWriterRef writer;
DestroyRequestBodyAndCreateResponseBodyWriter(&writer);
// Serialize HAP-Token-Response.
err = HAPMFiTokenAuthGetTokenResponse(
HAPNonnull(session->server),
&session->securitySession._.hap,
HAPNonnull(server->primaryAccessory),
&writer);
if (err) {
HAPAssert(err == kHAPError_Unknown || err == kHAPError_InvalidState || err == kHAPError_OutOfResources);
HAPLogAccessory(
&logObject,
server->primaryAccessory,
"Rejected token request: Request handling failed with error %u.",
err);
status = kHAPBLEPDUStatus_InvalidRequest;
goto SendResponse;
}
HAPTLVWriterGetBuffer(&writer, &responseBodyBytes, &numResponseBodyBytes);
status = kHAPBLEPDUStatus_Success;
}
goto SendResponse;
case kHAPPDUOpcode_TokenUpdate: {
// See HomeKit Accessory Protocol Specification R14
// Section 5.15.3 HAP-Token-Update-Request
HAPAssert(!iid);
HAPAssert(session->securitySession.isSecured || kHAPIPAccessoryServer_SessionSecurityDisabled);
// Handle HAP-Token-Update-Request.
err = HAPMFiTokenAuthHandleTokenUpdateRequest(
HAPNonnull(session->server),
&session->securitySession._.hap,
HAPNonnull(server->primaryAccessory),
&requestBodyReader);
if (err) {
HAPAssert(err == kHAPError_Unknown || err == kHAPError_InvalidData);
HAPLogAccessory(
&logObject,
server->primaryAccessory,
"Rejected token update request: Request handling failed with error %u.",
err);
status = kHAPBLEPDUStatus_InvalidRequest;
goto SendResponse;
}
// Send HAP-Token-Update-Response.
status = kHAPBLEPDUStatus_Success;
}
goto SendResponse;
case kHAPPDUOpcode_Info: {
// See HomeKit Accessory Protocol Specification R14
// Section 5.15.5 HAP-Info-Request
HAPAssert(!iid);
HAPAssert(session->securitySession.isSecured || kHAPIPAccessoryServer_SessionSecurityDisabled);
// HAP-Info-Request ok.
HAPTLVWriterRef writer;
DestroyRequestBodyAndCreateResponseBodyWriter(&writer);
// Serialize HAP-Info-Response.
err = HAPAccessoryGetInfoResponse(
HAPNonnull(session->server),
&session->securitySession._.hap,
HAPNonnull(server->primaryAccessory),
&writer);
if (err) {
HAPAssert(err == kHAPError_Unknown || err == kHAPError_OutOfResources);
HAPLogAccessory(
&logObject,
server->primaryAccessory,
"Rejected info request: Request handling failed with error %u.",
err);
status = kHAPBLEPDUStatus_InvalidRequest;
goto SendResponse;
}
HAPTLVWriterGetBuffer(&writer, &responseBodyBytes, &numResponseBodyBytes);
status = kHAPBLEPDUStatus_Success;
}
goto SendResponse;
}
#undef DestroyRequestBodyAndCreateResponseBodyWriter
HAPFatalError();
SendResponse : {
// Serialize response.
// Responses use the HAP PDU format.
// See HomeKit Accessory Protocol Specification R14
// Section 7.3.3 HAP PDU Format
size_t mark = session->outboundBuffer.position;
size_t numResponseBytes = 3;
if (responseBodyBytes) {
numResponseBytes += 2;
numResponseBytes += numResponseBodyBytes;
}
HAP_DIAGNOSTIC_IGNORED_ICCARM(Pa084)
if (numResponseBytes > UINT32_MAX) {
HAPLog(&logObject, "/secure-message response: Content length exceeds UINT32_MAX.");
session->outboundBuffer.position = mark;
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_OutOfResources);
return;
}
HAP_DIAGNOSTIC_RESTORE_ICCARM(Pa084)
const char* contentType = "application/octet-stream";
err = HAPIPByteBufferAppendStringWithFormat(
&session->outboundBuffer,
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Content-Length: %lu\r\n\r\n",
contentType,
(unsigned long) numResponseBytes);
if (err) {
HAPAssert(err == kHAPError_OutOfResources);
session->outboundBuffer.position = mark;
HAPLog(&logObject, "/secure-message response: Invalid configuration (outbound buffer too small for headers).");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_InternalServerError);
return;
}
if (numResponseBytes > session->outboundBuffer.limit - session->outboundBuffer.position) {
HAPAssert(err == kHAPError_OutOfResources);
session->outboundBuffer.position = mark;
HAPLog(&logObject, "/secure-message response: Invalid configuration (outbound buffer too small for body).");
write_msg(&session->outboundBuffer, kHAPIPAccessoryServerResponse_InternalServerError);
return;
}
session->outboundBuffer.data[session->outboundBuffer.position++] =
(0 << 7) | (0 << 4) | (0 << 3) | (0 << 2) | (1 << 1) | (0 << 0);
session->outboundBuffer.data[session->outboundBuffer.position++] = (char) tid;
session->outboundBuffer.data[session->outboundBuffer.position++] = (char) status;
if (responseBodyBytes) {
HAPWriteLittleUInt16(&session->outboundBuffer.data[session->outboundBuffer.position], numResponseBodyBytes);
session->outboundBuffer.position += 2;
HAPRawBufferCopyBytes(
&session->outboundBuffer.data[session->outboundBuffer.position],
HAPNonnullVoid(responseBodyBytes),
numResponseBodyBytes);
session->outboundBuffer.position += numResponseBodyBytes;
}
HAPAssert(session->outboundBuffer.limit >= session->outboundBuffer.position);
}
}