Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
lecmaccalculator.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:uses-kernel-cryptography
5
6#include "bluez/bluez_data_p.h"
7
8#include <QtCore/qbytearray.h>
9#include <QtCore/qloggingcategory.h>
10#include <QtCore/private/qcore_unix_p.h>
11
12#include <cstring>
13#include <sys/socket.h>
14#include <sys/types.h>
15#include <unistd.h>
16
17#ifdef CONFIG_LINUX_CRYPTO_API
18#include <linux/if_alg.h>
19#endif
20
21QT_BEGIN_NAMESPACE
22
23Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
24
25LeCmacCalculator::LeCmacCalculator()
26{
27#ifdef CONFIG_LINUX_CRYPTO_API
28 m_baseSocket = socket(AF_ALG, SOCK_SEQPACKET, 0);
29 if (m_baseSocket == -1) {
30 qCWarning(QT_BT_BLUEZ) << "failed to create first level crypto socket:"
31 << strerror(errno);
32 return;
33 }
34 sockaddr_alg sa;
35 using namespace std;
36 memset(&sa, 0, sizeof sa);
37 sa.salg_family = AF_ALG;
38 strcpy(reinterpret_cast<char *>(sa.salg_type), "hash");
39 strcpy(reinterpret_cast<char *>(sa.salg_name), "cmac(aes)");
40 if (::bind(m_baseSocket, reinterpret_cast<sockaddr *>(&sa), sizeof sa) == -1) {
41 qCWarning(QT_BT_BLUEZ) << "bind() failed for crypto socket:" << strerror(errno);
42 return;
43 }
44#else // CONFIG_LINUX_CRYPTO_API
45 qCWarning(QT_BT_BLUEZ) << "Linux crypto API not present, CMAC verification will fail.";
46#endif
47}
48
49LeCmacCalculator::~LeCmacCalculator()
50{
51 if (m_baseSocket != -1)
52 close(m_baseSocket);
53}
54
55QByteArray LeCmacCalculator::createFullMessage(const QByteArray &message, quint32 signCounter)
56{
57 // Spec v4.2, Vol 3, Part H, 2.4.5
58 QByteArray fullMessage = message;
59 fullMessage.resize(fullMessage.size() + sizeof signCounter);
60 putBtData(signCounter, fullMessage.data() + message.size());
61 return fullMessage;
62}
63
64quint64 LeCmacCalculator::calculateMac(const QByteArray &message, QUuid::Id128Bytes csrk) const
65{
66#ifdef CONFIG_LINUX_CRYPTO_API
67 if (m_baseSocket == -1)
68 return false;
69 QUuid::Id128Bytes csrkMsb;
70 std::reverse_copy(std::begin(csrk.data), std::end(csrk.data), std::begin(csrkMsb.data));
71 if (setsockopt(m_baseSocket, 279 /* SOL_ALG */, ALG_SET_KEY, csrkMsb.data, sizeof csrkMsb) == -1) {
72 qCWarning(QT_BT_BLUEZ) << "setsockopt() failed for crypto socket:" << strerror(errno);
73 return 0;
74 }
75
76 class SocketWrapper
77 {
78 public:
79 SocketWrapper(int socket) : m_socket(socket) {}
80 ~SocketWrapper() {
81 if (m_socket != -1)
82 close(m_socket);
83 }
84
85 int value() const { return m_socket; }
86 private:
87 int m_socket;
88 };
89 SocketWrapper cryptoSocket(accept(m_baseSocket, nullptr, nullptr));
90 if (cryptoSocket.value() == -1) {
91 qCWarning(QT_BT_BLUEZ) << "accept() failed for crypto socket:" << strerror(errno);
92 return 0;
93 }
94
95 QByteArray messageSwapped(message.size(), Qt::Uninitialized);
96 std::reverse_copy(message.begin(), message.end(), messageSwapped.begin());
97 qint64 totalBytesWritten = 0;
98 do {
99 const qint64 bytesWritten = qt_safe_write(cryptoSocket.value(),
100 messageSwapped.constData() + totalBytesWritten,
101 messageSwapped.size() - totalBytesWritten);
102 if (bytesWritten == -1) {
103 qCWarning(QT_BT_BLUEZ) << "writing to crypto socket failed:" << strerror(errno);
104 return 0;
105 }
106 totalBytesWritten += bytesWritten;
107 } while (totalBytesWritten < messageSwapped.size());
108 quint64 mac;
109 quint8 * const macPtr = reinterpret_cast<quint8 *>(&mac);
110 qint64 totalBytesRead = 0;
111 do {
112 const qint64 bytesRead = qt_safe_read(cryptoSocket.value(), macPtr + totalBytesRead,
113 sizeof mac - totalBytesRead);
114 if (bytesRead == -1) {
115 qCWarning(QT_BT_BLUEZ) << "reading from crypto socket failed:" << strerror(errno);
116 return 0;
117 }
118 totalBytesRead += bytesRead;
119 } while (totalBytesRead < qint64(sizeof mac));
120 return qFromBigEndian(mac);
121#else // CONFIG_LINUX_CRYPTO_API
122 Q_UNUSED(message);
123 Q_UNUSED(csrk);
124 qCWarning(QT_BT_BLUEZ) << "CMAC calculation failed due to missing Linux crypto API.";
125 return 0;
126#endif
127}
128
129bool LeCmacCalculator::verify(const QByteArray &message, QUuid::Id128Bytes csrk,
130 quint64 expectedMac) const
131{
132#ifdef CONFIG_LINUX_CRYPTO_API
133 const quint64 actualMac = calculateMac(message, csrk);
134 if (actualMac != expectedMac) {
135 qCWarning(QT_BT_BLUEZ) << "signature verification failed: mac mismatch";
136 return false;
137 }
138 return true;
139#else // CONFIG_LINUX_CRYPTO_API
140 Q_UNUSED(message);
141 Q_UNUSED(csrk);
142 Q_UNUSED(expectedMac);
143 qCWarning(QT_BT_BLUEZ) << "CMAC verification failed due to missing Linux crypto API.";
144 return false;
145#endif
146}
147
148QT_END_NAMESPACE