summaryrefslogtreecommitdiff
path: root/SmartDeviceLink/private/SDLSecurityQueryPayload.m
blob: 744e1770adc362b47b1302cbd075bcd69b1959fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//
//  SDLSecurityQueryPayload.m
//  SmartDeviceLink
//
//  Created by Frank Elias on 7/28/21.
//  Copyright © 2021 smartdevicelink. All rights reserved.
//

#import "SDLSecurityQueryPayload.h"

#import "SDLLogMacros.h"

const NSUInteger SECURITY_QUERY_HEADER_SIZE = 12;

NS_ASSUME_NONNULL_BEGIN

@implementation SDLSecurityQueryPayload

- (nullable instancetype)initWithData:(NSData *)data {
    if (data == nil || data.length < SECURITY_QUERY_HEADER_SIZE) {
        SDLLogE(@"Security Payload error: not enough data to form Security Query header. Data length: %lu", (unsigned long)data.length);
        return nil;
    }

    self = [super init];
    if (!self) { return nil; }

    @try {
        // Setup our pointers for data access
        Byte *bytePointer = (UInt8 *)data.bytes;
        UInt32 *ui32Pointer = (UInt32 *)data.bytes;

        // Extract the parts
        UInt8 queryType = bytePointer[0];

        self.queryType = queryType;

        // Extract the 24 bit query ID in the last 24 bits of the first 32 bits.
        UInt32 queryID = ui32Pointer[0];
        queryID = CFSwapInt32BigToHost(queryID) & 0x00FFFFFF;
        self.queryID = queryID;

        // Extract the 32 bit sequence number from the data after the first 32 bits.
        UInt32 sequenceNumber = ui32Pointer[1];
        sequenceNumber = CFSwapInt32BigToHost(sequenceNumber);
        self.sequenceNumber = sequenceNumber;

        // Extract the 32 bit json data size from the data after the first 64 bits
        UInt32 jsonDataSize = ui32Pointer[2];
        jsonDataSize = CFSwapInt32BigToHost(jsonDataSize);

        // Extract the JSON data after the header (96 bits) based on the JSON data size
        NSData *jsonData = nil;
        NSUInteger offsetOfJSONData = SECURITY_QUERY_HEADER_SIZE;
        if (jsonDataSize > 0 && jsonDataSize <= (data.length - SECURITY_QUERY_HEADER_SIZE)) {
            jsonData = [data subdataWithRange:NSMakeRange(offsetOfJSONData, jsonDataSize)];
        }
        self.jsonData = jsonData;

        // Extract the binary data after the header (96 bits) and the JSON data to the end
        NSData *binaryData = nil;
        NSUInteger offsetOfBinaryData = SECURITY_QUERY_HEADER_SIZE + jsonDataSize;
        NSUInteger binaryDataSize = data.length - jsonDataSize - SECURITY_QUERY_HEADER_SIZE;
        if (binaryDataSize > 0) {
            binaryData = [data subdataWithRange:NSMakeRange(offsetOfBinaryData, binaryDataSize)];
        }
        self.binaryData = binaryData;

    } @catch (NSException *e) {
        SDLLogE(@"SDLSecurityQueryPayload init error: %@", e);
        return nil;
    }

    return self;
}

- (instancetype)initWithQueryType:(SDLSecurityQueryType)queryType queryID:(SDLSecurityQueryId)queryID sequenceNumber:(UInt32)sequenceNumber jsonData:(nullable NSData *)jsonData binaryData:(nullable NSData *)binaryData {
    self = [super init];
    if (!self) { return nil; }

    _queryType = queryType;
    _queryID = queryID;
    _sequenceNumber = sequenceNumber;
    _jsonData = jsonData;
    _binaryData = binaryData;

    return self;
}

+ (nullable id)securityPayloadWithData:(NSData *)data {
    return [[SDLSecurityQueryPayload alloc] initWithData:data];
}

- (NSData *)convertToData {
    // From the properties, create a data buffer
    // Query Type - first 8 bits
    // Query ID - next 24 bits
    // Sequence Number - next 32 bits
    // JSON size - next 32 bits
    UInt8 headerBuffer[SECURITY_QUERY_HEADER_SIZE];
    *(UInt32 *)&headerBuffer[0] = CFSwapInt32HostToBig(self.queryID);
    *(UInt32 *)&headerBuffer[4] = CFSwapInt32HostToBig(self.sequenceNumber);
    *(UInt32 *)&headerBuffer[8] = CFSwapInt32HostToBig((UInt32)self.jsonData.length);
    headerBuffer[0] &= 0xFF;
    headerBuffer[0] |= self.queryType;

    // Serialize the header. Append the json data, then the binary data
    NSUInteger jsonDataSize = self.jsonData.length;
    NSUInteger binaryDataSize = self.binaryData.length;
    NSUInteger size = SECURITY_QUERY_HEADER_SIZE + jsonDataSize + binaryDataSize;
    NSMutableData *dataOut = [NSMutableData dataWithCapacity:size];
    [dataOut appendBytes:&headerBuffer length:12];
    [dataOut appendData:self.jsonData];
    [dataOut appendData:self.binaryData];

    return dataOut;
}

- (NSString *)description {
    return [NSString stringWithFormat:@"Security Query Header: %@, %@, sequenceNumber: %lu, json size: %lu bytes, binary size: %lu bytes", [self descriptionForQueryID], [self descriptionForQueryType], (unsigned long)self.sequenceNumber, (unsigned long)self.jsonData.length, (unsigned long)self.binaryData.length];
}

- (NSString *)descriptionForQueryID {
    NSString *queryIdDescription;
    switch (self.queryID) {
        case SDLSecurityQueryIdSendHandshake:
            queryIdDescription = @"Send Handshake Data";
            break;
        case SDLSecurityQueryIdSendInternalError:
            queryIdDescription = @"Send Internal Error";
            break;
        case SDLSecurityQueryIdInvalid:
            queryIdDescription = @"Invalid Query ID";
            break;
        default:
            queryIdDescription = @"Unknown Query ID";
            break;
    }
    return [NSString stringWithFormat:@"queryID: %lu - %@", (unsigned long)self.queryID, queryIdDescription];
}

- (NSString *)descriptionForQueryType {
    NSString *queryTypeDescription;
    switch (self.queryType) {
        case SDLSecurityQueryTypeRequest:
            queryTypeDescription = @"Request";
            break;
        case SDLSecurityQueryTypeResponse:
            queryTypeDescription = @"Response";
            break;
        case SDLSecurityQueryTypeNotification:
            queryTypeDescription = @"Notification";
            break;
        case SDLSecurityQueryTypeInvalid:
            queryTypeDescription = @"Invalid Query Type";
            break;
        default:
            queryTypeDescription = @"Unknown Query Type";
            break;
    }
    return [NSString stringWithFormat:@"queryType: %lu - %@", (unsigned long)self.queryType, queryTypeDescription];
}

@end

NS_ASSUME_NONNULL_END