3 * Copyright (c) 2020-2021 Project CHIP Authors
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * This file implements the CHIP Secure Session object.
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>
37 constexpr size_t kAESCCMIVLen = 12;
38 constexpr size_t kMaxAADLen = 128;
42 using namespace Crypto;
44 SecureSession::SecureSession() : mKeyAvailable(false) {}
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)
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);
57 ReturnErrorOnFailure(HKDF_SHA256(secret, secret_length, salt, salt_length, info, info_length, mKey, sizeof(mKey)));
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)
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);
73 P256ECDHDerivedSecret secret;
74 ReturnErrorOnFailure(local_keypair.ECDH_derive_secret(remote_public_key, secret));
76 return InitFromSecret(secret, secret.Length(), salt, salt_length, info, info_length);
79 void SecureSession::Reset()
81 mKeyAvailable = false;
82 memset(mKey, 0, sizeof(mKey));
85 CHIP_ERROR SecureSession::GetIV(const PacketHeader & header, uint8_t * iv, size_t len)
88 VerifyOrReturnError(len == kAESCCMIVLen, CHIP_ERROR_INVALID_ARGUMENT);
90 Encoding::LittleEndian::BufferWriter bbuf(iv, len);
92 bbuf.Put64(header.GetSourceNodeId().ValueOr(0));
93 bbuf.Put32(header.GetMessageId());
95 return bbuf.Fit() ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
98 CHIP_ERROR SecureSession::GetAdditionalAuthData(const PacketHeader & header, uint8_t * aad, uint16_t & len)
100 VerifyOrReturnError(len >= header.EncodeSizeBytes(), CHIP_ERROR_INVALID_ARGUMENT);
102 // Use unencrypted part of header as AAD. This will help
103 // integrity protect the whole message
104 uint16_t actualEncodedHeaderSize;
106 ReturnErrorOnFailure(header.Encode(aad, len, &actualEncodedHeaderSize));
107 VerifyOrReturnError(len >= actualEncodedHeaderSize, CHIP_ERROR_INVALID_ARGUMENT);
109 len = actualEncodedHeaderSize;
111 return CHIP_NO_ERROR;
114 CHIP_ERROR SecureSession::Encrypt(const uint8_t * input, size_t input_length, uint8_t * output, PacketHeader & header,
115 MessageAuthenticationCode & mac) const
118 constexpr Header::EncryptionType encType = Header::EncryptionType::kAESCCMTagLen16;
120 const size_t taglen = MessageAuthenticationCode::TagLenForEncryptionType(encType);
121 assert(taglen <= kMaxTagLen);
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);
128 uint8_t AAD[kMaxAADLen];
129 uint8_t IV[kAESCCMIVLen];
130 uint16_t aadLen = sizeof(AAD);
131 uint8_t tag[kMaxTagLen];
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));
138 mac.SetTag(&header, encType, tag, taglen);
140 return CHIP_NO_ERROR;
143 CHIP_ERROR SecureSession::Decrypt(const uint8_t * input, size_t input_length, uint8_t * output, const PacketHeader & header,
144 const MessageAuthenticationCode & mac) const
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);
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);
157 ReturnErrorOnFailure(GetIV(header, IV, sizeof(IV)));
158 ReturnErrorOnFailure(GetAdditionalAuthData(header, AAD, aadLen));
160 return AES_CCM_decrypt(input, input_length, AAD, aadLen, tag, taglen, mKey, sizeof(mKey), IV, sizeof(IV), output);