Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / transport / SecureSession.cpp
1 /*
2  *
3  *    Copyright (c) 2020-2021 Project CHIP Authors
4  *    All rights reserved.
5  *
6  *    Licensed under the Apache License, Version 2.0 (the "License");
7  *    you may not use this file except in compliance with the License.
8  *    You may obtain a copy of the License at
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *    Unless required by applicable law or agreed to in writing, software
13  *    distributed under the License is distributed on an "AS IS" BASIS,
14  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *    See the License for the specific language governing permissions and
16  *    limitations under the License.
17  */
18
19 /**
20  *    @file
21  *      This file implements the CHIP Secure Session object.
22  *
23  */
24
25 #include <core/CHIPEncoding.h>
26 #include <support/BufferWriter.h>
27 #include <support/CodeUtils.h>
28 #include <transport/SecureSession.h>
29 #include <transport/raw/MessageHeader.h>
30
31 #include <string.h>
32
33 namespace chip {
34
35 namespace {
36
37 constexpr size_t kAESCCMIVLen = 12;
38 constexpr size_t kMaxAADLen   = 128;
39
40 } // namespace
41
42 using namespace Crypto;
43
44 SecureSession::SecureSession() : mKeyAvailable(false) {}
45
46 CHIP_ERROR SecureSession::InitFromSecret(const uint8_t * secret, const size_t secret_length, const uint8_t * salt,
47                                          const size_t salt_length, const uint8_t * info, const size_t info_length)
48 {
49
50     VerifyOrReturnError(mKeyAvailable == false, CHIP_ERROR_INCORRECT_STATE);
51     VerifyOrReturnError(secret != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
52     VerifyOrReturnError(secret_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
53     VerifyOrReturnError((salt_length == 0) || (salt != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
54     VerifyOrReturnError(info_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
55     VerifyOrReturnError(info != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
56
57     ReturnErrorOnFailure(HKDF_SHA256(secret, secret_length, salt, salt_length, info, info_length, mKey, sizeof(mKey)));
58
59     mKeyAvailable = true;
60
61     return CHIP_NO_ERROR;
62 }
63
64 CHIP_ERROR SecureSession::Init(const Crypto::P256Keypair & local_keypair, const Crypto::P256PublicKey & remote_public_key,
65                                const uint8_t * salt, const size_t salt_length, const uint8_t * info, const size_t info_length)
66 {
67
68     VerifyOrReturnError(mKeyAvailable == false, CHIP_ERROR_INCORRECT_STATE);
69     VerifyOrReturnError((salt_length == 0) || (salt != nullptr), CHIP_ERROR_INVALID_ARGUMENT);
70     VerifyOrReturnError(info_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
71     VerifyOrReturnError(info != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
72
73     P256ECDHDerivedSecret secret;
74     ReturnErrorOnFailure(local_keypair.ECDH_derive_secret(remote_public_key, secret));
75
76     return InitFromSecret(secret, secret.Length(), salt, salt_length, info, info_length);
77 }
78
79 void SecureSession::Reset()
80 {
81     mKeyAvailable = false;
82     memset(mKey, 0, sizeof(mKey));
83 }
84
85 CHIP_ERROR SecureSession::GetIV(const PacketHeader & header, uint8_t * iv, size_t len)
86 {
87
88     VerifyOrReturnError(len == kAESCCMIVLen, CHIP_ERROR_INVALID_ARGUMENT);
89
90     Encoding::LittleEndian::BufferWriter bbuf(iv, len);
91
92     bbuf.Put64(header.GetSourceNodeId().ValueOr(0));
93     bbuf.Put32(header.GetMessageId());
94
95     return bbuf.Fit() ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
96 }
97
98 CHIP_ERROR SecureSession::GetAdditionalAuthData(const PacketHeader & header, uint8_t * aad, uint16_t & len)
99 {
100     VerifyOrReturnError(len >= header.EncodeSizeBytes(), CHIP_ERROR_INVALID_ARGUMENT);
101
102     // Use unencrypted part of header as AAD. This will help
103     // integrity protect the whole message
104     uint16_t actualEncodedHeaderSize;
105
106     ReturnErrorOnFailure(header.Encode(aad, len, &actualEncodedHeaderSize));
107     VerifyOrReturnError(len >= actualEncodedHeaderSize, CHIP_ERROR_INVALID_ARGUMENT);
108
109     len = actualEncodedHeaderSize;
110
111     return CHIP_NO_ERROR;
112 }
113
114 CHIP_ERROR SecureSession::Encrypt(const uint8_t * input, size_t input_length, uint8_t * output, PacketHeader & header,
115                                   MessageAuthenticationCode & mac) const
116 {
117
118     constexpr Header::EncryptionType encType = Header::EncryptionType::kAESCCMTagLen16;
119
120     const size_t taglen = MessageAuthenticationCode::TagLenForEncryptionType(encType);
121     assert(taglen <= kMaxTagLen);
122
123     VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY);
124     VerifyOrReturnError(input != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
125     VerifyOrReturnError(input_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
126     VerifyOrReturnError(output != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
127
128     uint8_t AAD[kMaxAADLen];
129     uint8_t IV[kAESCCMIVLen];
130     uint16_t aadLen = sizeof(AAD);
131     uint8_t tag[kMaxTagLen];
132
133     ReturnErrorOnFailure(GetIV(header, IV, sizeof(IV)));
134     ReturnErrorOnFailure(GetAdditionalAuthData(header, AAD, aadLen));
135     ReturnErrorOnFailure(
136         AES_CCM_encrypt(input, input_length, AAD, aadLen, mKey, sizeof(mKey), IV, sizeof(IV), output, tag, taglen));
137
138     mac.SetTag(&header, encType, tag, taglen);
139
140     return CHIP_NO_ERROR;
141 }
142
143 CHIP_ERROR SecureSession::Decrypt(const uint8_t * input, size_t input_length, uint8_t * output, const PacketHeader & header,
144                                   const MessageAuthenticationCode & mac) const
145 {
146     const size_t taglen = MessageAuthenticationCode::TagLenForEncryptionType(header.GetEncryptionType());
147     const uint8_t * tag = mac.GetTag();
148     uint8_t IV[kAESCCMIVLen];
149     uint8_t AAD[kMaxAADLen];
150     uint16_t aadLen = sizeof(AAD);
151
152     VerifyOrReturnError(mKeyAvailable, CHIP_ERROR_INVALID_USE_OF_SESSION_KEY);
153     VerifyOrReturnError(input != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
154     VerifyOrReturnError(input_length > 0, CHIP_ERROR_INVALID_ARGUMENT);
155     VerifyOrReturnError(output != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
156
157     ReturnErrorOnFailure(GetIV(header, IV, sizeof(IV)));
158     ReturnErrorOnFailure(GetAdditionalAuthData(header, AAD, aadLen));
159
160     return AES_CCM_decrypt(input, input_length, AAD, aadLen, tag, taglen, mKey, sizeof(mKey), IV, sizeof(IV), output);
161 }
162
163 } // namespace chip