Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qasn1element.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4
5#include "qasn1element_p.h"
6
7#include <QtCore/qdatastream.h>
8#include <QtCore/qdatetime.h>
9#include <QtCore/qtimezone.h>
10#include <QtCore/qlist.h>
11#include <QDebug>
12#include <private/qtools_p.h>
13
14#include <limits>
15
17
18using namespace QtMiscUtils;
19
20typedef QMap<QByteArray, QByteArray> OidNameMap;
22{
23 OidNameMap oids;
24 // used by unit tests
25 oids.insert(oids.cend(), QByteArrayLiteral("0.9.2342.19200300.100.1.5"), QByteArrayLiteral("favouriteDrink"));
26 oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.113549.1.9.1"), QByteArrayLiteral("emailAddress"));
27 oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.1.1"), QByteArrayLiteral("authorityInfoAccess"));
28 oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.1"), QByteArrayLiteral("OCSP"));
29 oids.insert(oids.cend(), QByteArrayLiteral("1.3.6.1.5.5.7.48.2"), QByteArrayLiteral("caIssuers"));
30 oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.14"), QByteArrayLiteral("subjectKeyIdentifier"));
31 oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.15"), QByteArrayLiteral("keyUsage"));
32 oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.17"), QByteArrayLiteral("subjectAltName"));
33 oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.19"), QByteArrayLiteral("basicConstraints"));
34 oids.insert(oids.cend(), QByteArrayLiteral("2.5.29.35"), QByteArrayLiteral("authorityKeyIdentifier"));
35 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.10"), QByteArrayLiteral("O"));
36 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.11"), QByteArrayLiteral("OU"));
37 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.12"), QByteArrayLiteral("title"));
38 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.13"), QByteArrayLiteral("description"));
39 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.17"), QByteArrayLiteral("postalCode"));
40 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.3"), QByteArrayLiteral("CN"));
41 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.4"), QByteArrayLiteral("SN"));
42 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.41"), QByteArrayLiteral("name"));
43 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.42"), QByteArrayLiteral("GN"));
44 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.43"), QByteArrayLiteral("initials"));
45 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.46"), QByteArrayLiteral("dnQualifier"));
46 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.5"), QByteArrayLiteral("serialNumber"));
47 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.6"), QByteArrayLiteral("C"));
48 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.7"), QByteArrayLiteral("L"));
49 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.8"), QByteArrayLiteral("ST"));
50 oids.insert(oids.cend(), QByteArrayLiteral("2.5.4.9"), QByteArrayLiteral("street"));
51 return oids;
52}
54
56 : mType(type)
57 , mValue(value)
58{
59}
60
62{
63 // type
64 quint8 tmpType;
65 stream >> tmpType;
66 if (!tmpType)
67 return false;
68
69 // length
70 quint64 length = 0;
72 stream >> first;
73 if (first & 0x80) {
74 // long form
75 const quint8 bytes = (first & 0x7f);
76 if (bytes > 7)
77 return false;
78
79 quint8 b;
80 for (int i = 0; i < bytes; i++) {
81 stream >> b;
82 length = (length << 8) | b;
83 }
84 } else {
85 // short form
86 length = (first & 0x7f);
87 }
88
89 if (length > quint64(std::numeric_limits<int>::max()))
90 return false;
91
92 // read value in blocks to avoid being fooled by incorrect length
93 const int BUFFERSIZE = 4 * 1024;
94 QByteArray tmpValue;
95 int remainingLength = length;
96 while (remainingLength) {
97 char readBuffer[BUFFERSIZE];
98 const int bytesToRead = qMin(remainingLength, BUFFERSIZE);
99 const int count = stream.readRawData(readBuffer, bytesToRead);
100 if (count != int(bytesToRead))
101 return false;
102 tmpValue.append(readBuffer, bytesToRead);
103 remainingLength -= bytesToRead;
104 }
105
106 mType = tmpType;
107 mValue.swap(tmpValue);
108 return true;
109}
110
112{
114 return read(stream);
115}
116
118{
119 // type
120 stream << mType;
121
122 // length
123 qint64 length = mValue.size();
124 if (length >= 128) {
125 // long form
126 quint8 encodedLength = 0x80;
128 while (length) {
129 ba.prepend(quint8((length & 0xff)));
130 length >>= 8;
131 encodedLength += 1;
132 }
133 stream << encodedLength;
134 stream.writeRawData(ba.data(), ba.size());
135 } else {
136 // short form
137 stream << quint8(length);
138 }
139
140 // value
141 stream.writeRawData(mValue.data(), mValue.size());
142}
143
145{
147 QByteArray(1, val ? 0xff : 0x00));
148}
149
151{
153 while (val > 127) {
154 elem.mValue.prepend(val & 0xff);
155 val >>= 8;
156 }
157 elem.mValue.prepend(val & 0x7f);
158 return elem;
159}
160
161QAsn1Element QAsn1Element::fromVector(const QList<QAsn1Element> &items)
162{
163 QAsn1Element seq;
164 seq.mType = SequenceType;
166 for (auto it = items.cbegin(), end = items.cend(); it != end; ++it)
167 it->write(stream);
168 return seq;
169}
170
172{
173 QAsn1Element elem;
174 elem.mType = ObjectIdentifierType;
175 const QList<QByteArray> bits = id.split('.');
176 Q_ASSERT(bits.size() > 2);
177 elem.mValue += quint8((bits[0].toUInt() * 40 + bits[1].toUInt()));
178 for (int i = 2; i < bits.size(); ++i) {
179 char buffer[std::numeric_limits<unsigned int>::digits / 7 + 2];
180 char *pBuffer = buffer + sizeof(buffer);
181 *--pBuffer = '\0';
182 unsigned int node = bits[i].toUInt();
183 *--pBuffer = quint8((node & 0x7f));
184 node >>= 7;
185 while (node) {
186 *--pBuffer = quint8(((node & 0x7f) | 0x80));
187 node >>= 7;
188 }
189 elem.mValue += pBuffer;
190 }
191 return elem;
192}
193
194bool QAsn1Element::toBool(bool *ok) const
195{
196 if (*this == fromBool(true)) {
197 if (ok)
198 *ok = true;
199 return true;
200 } else if (*this == fromBool(false)) {
201 if (ok)
202 *ok = true;
203 return false;
204 } else {
205 if (ok)
206 *ok = false;
207 return false;
208 }
209}
210
212{
214
215 if (mValue.size() != 13 && mValue.size() != 15)
216 return result;
217
218 // QDateTime::fromString is lenient and accepts +- signs in front
219 // of the year; but ASN.1 doesn't allow them.
220 if (!isAsciiDigit(mValue[0]))
221 return result;
222
223 // Timezone must be present, and UTC
224 if (mValue.back() != 'Z')
225 return result;
226
227 if (mType == UtcTimeType && mValue.size() == 13) {
228 // RFC 2459:
229 // Where YY is greater than or equal to 50, the year shall be
230 // interpreted as 19YY; and
231 //
232 // Where YY is less than 50, the year shall be interpreted as 20YY.
233 //
234 // so use 1950 as base year.
235 constexpr int rfc2459CenturyStart = 1950;
236 const QLatin1StringView inputView(mValue);
237 QDate date = QDate::fromString(inputView.first(6), u"yyMMdd", rfc2459CenturyStart);
238 if (!date.isValid())
239 return result;
240
241 Q_ASSERT(date.year() >= rfc2459CenturyStart);
242 Q_ASSERT(date.year() < 100 + rfc2459CenturyStart);
243
244 QTime time = QTime::fromString(inputView.sliced(6, 6), u"HHmmss");
245 if (!time.isValid())
246 return result;
248 } else if (mType == GeneralizedTimeType && mValue.size() == 15) {
249 result = QDateTime::fromString(QString::fromLatin1(mValue), u"yyyyMMddHHmmsst");
250 }
251
252 return result;
253}
254
255QMultiMap<QByteArray, QString> QAsn1Element::toInfo() const
256{
257 QMultiMap<QByteArray, QString> info;
258 QAsn1Element elem;
259 QDataStream issuerStream(mValue);
260 while (elem.read(issuerStream) && elem.mType == QAsn1Element::SetType) {
261 QAsn1Element issuerElem;
262 QDataStream setStream(elem.mValue);
263 if (issuerElem.read(setStream) && issuerElem.mType == QAsn1Element::SequenceType) {
264 const auto elems = issuerElem.toList();
265 if (elems.size() == 2) {
266 const QByteArray key = elems.front().toObjectName();
267 if (!key.isEmpty())
268 info.insert(key, elems.back().toString());
269 }
270 }
271 }
272 return info;
273}
274
276{
277 if (mType != QAsn1Element::IntegerType || mValue.isEmpty()) {
278 if (ok)
279 *ok = false;
280 return 0;
281 }
282
283 // NOTE: - negative numbers are not handled
284 // - greater sizes would overflow
285 if (mValue.at(0) & 0x80 || mValue.size() > 8) {
286 if (ok)
287 *ok = false;
288 return 0;
289 }
290
291 qint64 value = mValue.at(0) & 0x7f;
292 for (int i = 1; i < mValue.size(); ++i)
293 value = (value << 8) | quint8(mValue.at(i));
294
295 if (ok)
296 *ok = true;
297 return value;
298}
299
300QList<QAsn1Element> QAsn1Element::toList() const
301{
302 QList<QAsn1Element> items;
303 if (mType == SequenceType) {
304 QAsn1Element elem;
305 QDataStream stream(mValue);
306 while (elem.read(stream))
307 items << elem;
308 }
309 return items;
310}
311
313{
315 if (mType == ObjectIdentifierType && !mValue.isEmpty()) {
316 quint8 b = mValue.at(0);
317 key += QByteArray::number(b / 40) + '.' + QByteArray::number (b % 40);
318 unsigned int val = 0;
319 for (int i = 1; i < mValue.size(); ++i) {
320 b = mValue.at(i);
321 val = (val << 7) | (b & 0x7f);
322 if (!(b & 0x80)) {
323 key += '.' + QByteArray::number(val);
324 val = 0;
325 }
326 }
327 }
328 return key;
329}
330
332{
334 return oidNameMap->value(key, key);
335}
336
338{
339 // Detect embedded NULs and reject
340 if (qstrlen(mValue) < uint(mValue.size()))
341 return QString();
342
343 if (mType == PrintableStringType || mType == TeletexStringType
344 || mType == Rfc822NameType || mType == DnsNameType
346 return QString::fromLatin1(mValue, mValue.size());
347 if (mType == Utf8StringType)
348 return QString::fromUtf8(mValue, mValue.size());
349
350 return QString();
351}
352
@ UniformResourceIdentifierType
QByteArray toObjectName() const
QMultiMap< QByteArray, QString > toInfo() const
QDateTime toDateTime() const
bool read(QDataStream &data)
qint64 toInteger(bool *ok=nullptr) const
static QAsn1Element fromVector(const QList< QAsn1Element > &items)
static QAsn1Element fromObjectId(const QByteArray &id)
void write(QDataStream &data) const
static QAsn1Element fromInteger(unsigned int val)
QAsn1Element(quint8 type=0, const QByteArray &value=QByteArray())
QString toString() const
QByteArray toObjectId() const
bool toBool(bool *ok=nullptr) const
static QAsn1Element fromBool(bool val)
QList< QAsn1Element > toList() const
QByteArray value() const
\inmodule QtCore
Definition qbytearray.h:57
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
Definition qbytearray.h:611
QByteArray & prepend(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:280
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
char front() const
Definition qbytearray.h:134
char at(qsizetype i) const
Returns the byte at index position i in the byte array.
Definition qbytearray.h:600
void swap(QByteArray &other) noexcept
Definition qbytearray.h:104
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:107
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
char back() const
Definition qbytearray.h:136
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore\reentrant
Definition qdatetime.h:283
\inmodule QtCore \reentrant
Definition qdatetime.h:29
constexpr bool isValid() const
Returns true if this date is valid; otherwise returns false.
Definition qdatetime.h:71
int year() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
constexpr QLatin1Char first() const
constexpr QLatin1StringView sliced(qsizetype pos) const
const_iterator cend() const noexcept
Definition qlist.h:631
const_iterator cbegin() const noexcept
Definition qlist.h:630
iterator insert(const Key &key, const T &value)
Definition qmap.h:688
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
\inmodule QtCore \reentrant
Definition qdatetime.h:215
bool isValid() const
Returns true if the time is valid; otherwise returns false.
QDate date
[1]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
constexpr bool isAsciiDigit(char32_t c) noexcept
Definition qtools_p.h:67
QMap< QByteArray, QByteArray > OidNameMap
static OidNameMap createOidMap()
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
size_t qstrlen(const char *str)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_GLOBAL_STATIC_WITH_ARGS(TYPE, NAME, ARGS)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
GLboolean GLboolean GLboolean b
GLuint64 key
GLuint GLuint end
GLenum GLuint GLenum GLsizei length
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum type
GLint first
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
GLuint64EXT * result
[6]
GLbitfield GLuint readBuffer
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
long long qint64
Definition qtypes.h:60
unsigned char quint8
Definition qtypes.h:46
QByteArray ba
[0]
QList< QTreeWidgetItem * > items
QHostInfo info
[0]