mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
winpr: add some ASN1 parsing functions
This patch implements ASN1 parsing in WinPR, as we need it in SSPI packages.
This commit is contained in:
@@ -46,7 +46,7 @@
|
||||
#define ER_TAG_INTEGER 0x02
|
||||
#define ER_TAG_BIT_STRING 0x03
|
||||
#define ER_TAG_OCTET_STRING 0x04
|
||||
#define ER_TAG_OBJECT_IDENFIER 0x06
|
||||
#define ER_TAG_OBJECT_IDENTIFIER 0x06
|
||||
#define ER_TAG_ENUMERATED 0x0A
|
||||
#define ER_TAG_SEQUENCE 0x10
|
||||
#define ER_TAG_SEQUENCE_OF 0x10
|
||||
|
||||
188
winpr/include/winpr/asn1.h
Normal file
188
winpr/include/winpr/asn1.h
Normal file
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* ASN1 encoder / decoder
|
||||
*
|
||||
* Copyright 2022 David Fort <contact@hardening-consulting.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_ASN1_H_
|
||||
#define WINPR_ASN1_H_
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#define ER_TAG_MASK 0x1F
|
||||
|
||||
enum
|
||||
{
|
||||
ER_TAG_BOOLEAN = 0x01,
|
||||
ER_TAG_INTEGER = 0x02,
|
||||
ER_TAG_BIT_STRING = 0x03,
|
||||
ER_TAG_OCTET_STRING = 0x04,
|
||||
ER_TAG_NULL = 0x05,
|
||||
ER_TAG_OBJECT_IDENTIFIER = 0x06,
|
||||
ER_TAG_ENUMERATED = 0x0A,
|
||||
ER_TAG_UTF8STRING = 0x0C,
|
||||
ER_TAG_PRINTABLE_STRING = 0x13,
|
||||
ER_TAG_IA5STRING = 0x16,
|
||||
ER_TAG_UTCTIME = 0x17,
|
||||
ER_TAG_GENERAL_STRING = 0x1B,
|
||||
ER_TAG_GENERALIZED_TIME = 0x18,
|
||||
|
||||
ER_TAG_APP = 0x60,
|
||||
ER_TAG_SEQUENCE = 0x30,
|
||||
ER_TAG_SEQUENCE_OF = 0x30,
|
||||
ER_TAG_SET = 0x31,
|
||||
ER_TAG_SET_OF = 0x31,
|
||||
|
||||
ER_TAG_CONTEXTUAL = 0xA0
|
||||
};
|
||||
|
||||
/** @brief rules for encoding */
|
||||
typedef enum
|
||||
{
|
||||
WINPR_ASN1_BER,
|
||||
WINPR_ASN1_DER
|
||||
} WinPrAsn1EncodingRule;
|
||||
|
||||
typedef struct WinPrAsn1Encoder WinPrAsn1Encoder;
|
||||
|
||||
struct WinPrAsn1Decoder
|
||||
{
|
||||
WinPrAsn1EncodingRule encoding;
|
||||
wStream source;
|
||||
};
|
||||
|
||||
typedef struct WinPrAsn1Decoder WinPrAsn1Decoder;
|
||||
|
||||
typedef BYTE WinPrAsn1_tag;
|
||||
typedef BYTE WinPrAsn1_tagId;
|
||||
typedef BOOL WinPrAsn1_BOOL;
|
||||
typedef INT32 WinPrAsn1_INTEGER;
|
||||
typedef char* WinPrAsn1_STRING;
|
||||
typedef char* WinPrAsn1_IA5STRING;
|
||||
typedef struct
|
||||
{
|
||||
size_t len;
|
||||
BYTE* data;
|
||||
} WinPrAsn1_MemoryChunk;
|
||||
|
||||
typedef WinPrAsn1_MemoryChunk WinPrAsn1_OID;
|
||||
typedef WinPrAsn1_MemoryChunk WinPrAsn1_OctetString;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT16 year;
|
||||
UINT8 month;
|
||||
UINT8 day;
|
||||
UINT8 hour;
|
||||
UINT8 minute;
|
||||
UINT8 second;
|
||||
char tz;
|
||||
} WinPrAsn1_UTCTIME;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif /* __cplusplus */
|
||||
|
||||
WINPR_API void WinPrAsn1FreeOID(WinPrAsn1_OID* poid);
|
||||
WINPR_API void WinPrAsn1FreeOctetString(WinPrAsn1_OctetString* octets);
|
||||
|
||||
/* decoder functions */
|
||||
|
||||
WINPR_API void WinPrAsn1Decoder_Init(WinPrAsn1Decoder* dec, WinPrAsn1EncodingRule encoding,
|
||||
wStream* source);
|
||||
|
||||
WINPR_API BOOL WinPrAsn1DecPeekTag(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag);
|
||||
WINPR_API size_t WinPrAsn1DecReadTagAndLen(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
|
||||
size_t* len);
|
||||
WINPR_API size_t WinPrAsn1DecPeekTagAndLen(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
|
||||
size_t* len);
|
||||
WINPR_API size_t WinPrAsn1DecReadTagLenValue(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
|
||||
size_t* len, WinPrAsn1Decoder* value);
|
||||
WINPR_API size_t WinPrAsn1DecReadBoolean(WinPrAsn1Decoder* dec, WinPrAsn1_BOOL* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadInteger(WinPrAsn1Decoder* dec, WinPrAsn1_INTEGER* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadOID(WinPrAsn1Decoder* dec, WinPrAsn1_OID* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadOctetString(WinPrAsn1Decoder* dec,
|
||||
WinPrAsn1_OctetString* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadIA5String(WinPrAsn1Decoder* dec, WinPrAsn1_IA5STRING* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadUtcTime(WinPrAsn1Decoder* dec, WinPrAsn1_UTCTIME* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadNull(WinPrAsn1Decoder* dec);
|
||||
|
||||
WINPR_API size_t WinPrAsn1DecReadApp(WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
|
||||
WinPrAsn1Decoder* setDec);
|
||||
WINPR_API size_t WinPrAsn1DecReadSequence(WinPrAsn1Decoder* dec, WinPrAsn1Decoder* seqDec);
|
||||
WINPR_API size_t WinPrAsn1DecReadSet(WinPrAsn1Decoder* dec, WinPrAsn1Decoder* setDec);
|
||||
|
||||
WINPR_API size_t WinPrAsn1DecReadContextualTag(WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
|
||||
WinPrAsn1Decoder* ctxtDec);
|
||||
WINPR_API size_t WinPrAsn1DecPeekContextualTag(WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
|
||||
WinPrAsn1Decoder* ctxtDec);
|
||||
|
||||
WINPR_API size_t WinPrAsn1DecReadContextualBool(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
|
||||
BOOL* error, WinPrAsn1_BOOL* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadContextualInteger(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
|
||||
BOOL* error, WinPrAsn1_INTEGER* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadContextualOID(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
|
||||
BOOL* error, WinPrAsn1_OID* target);
|
||||
WINPR_API size_t WinPrAsn1DecReadContextualSequence(WinPrAsn1Decoder* dec,
|
||||
WinPrAsn1_tagId tagId, BOOL* error,
|
||||
WinPrAsn1Decoder* target);
|
||||
|
||||
/* encoder functions */
|
||||
|
||||
WINPR_API WinPrAsn1Encoder* WinPrAsn1Encoder_New(WinPrAsn1EncodingRule encoding);
|
||||
WINPR_API void WinPrAsn1Encoder_Reset(WinPrAsn1Encoder* enc);
|
||||
|
||||
WINPR_API BOOL WinPrAsn1EncAppContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId);
|
||||
WINPR_API BOOL WinPrAsn1EncSeqContainer(WinPrAsn1Encoder* enc);
|
||||
WINPR_API BOOL WinPrAsn1EncContextualSeqContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId);
|
||||
WINPR_API BOOL WinPrAsn1EncSetContainer(WinPrAsn1Encoder* enc);
|
||||
WINPR_API BOOL WinPrAsn1EncContextualSetContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId);
|
||||
WINPR_API BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId);
|
||||
WINPR_API size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc);
|
||||
|
||||
WINPR_API size_t WinPrAsn1EncInteger(WinPrAsn1Encoder* enc, WinPrAsn1_INTEGER integer);
|
||||
WINPR_API size_t WinPrAsn1EncContextualInteger(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
|
||||
WinPrAsn1_INTEGER integer);
|
||||
WINPR_API size_t WinPrAsn1EncBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_BOOL b);
|
||||
WINPR_API size_t WinPrAsn1EncContextualBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
|
||||
WinPrAsn1_BOOL b);
|
||||
WINPR_API size_t WinPrAsn1EncOID(WinPrAsn1Encoder* enc, const WinPrAsn1_OID* oid);
|
||||
WINPR_API size_t WinPrAsn1EncContextualOID(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
|
||||
const WinPrAsn1_OID* oid);
|
||||
WINPR_API size_t WinPrAsn1EncOctetString(WinPrAsn1Encoder* enc,
|
||||
const WinPrAsn1_OctetString* oid);
|
||||
WINPR_API size_t WinPrAsn1EncContextualOctetString(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
|
||||
const WinPrAsn1_OctetString* oid);
|
||||
WINPR_API size_t WinPrAsn1EncIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_IA5STRING ia5);
|
||||
WINPR_API size_t WinPrAsn1EncContextualIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
|
||||
WinPrAsn1_IA5STRING ia5);
|
||||
WINPR_API size_t WinPrAsn1EncUtcTime(WinPrAsn1Encoder* enc, const WinPrAsn1_UTCTIME* utc);
|
||||
WINPR_API size_t WinPrAsn1EncContextualUtcTime(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
|
||||
const WinPrAsn1_UTCTIME* utc);
|
||||
|
||||
WINPR_API BOOL WinPrAsn1EncStreamSize(WinPrAsn1Encoder* enc, size_t* s);
|
||||
WINPR_API BOOL WinPrAsn1EncToStream(WinPrAsn1Encoder* enc, wStream* s);
|
||||
|
||||
WINPR_API void WinPrAsn1Encoder_Free(WinPrAsn1Encoder** penc);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* WINPR_ASN1_H_ */
|
||||
@@ -287,6 +287,15 @@ extern "C"
|
||||
*_s->pointer++ = (_v)&0xFF;
|
||||
}
|
||||
|
||||
static INLINE void Stream_Write_UINT24_BE(wStream* _s, UINT32 _v)
|
||||
{
|
||||
WINPR_ASSERT(_s);
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 3);
|
||||
*_s->pointer++ = ((_v) >> 16) & 0xFF;
|
||||
*_s->pointer++ = ((_v) >> 8) & 0xFF;
|
||||
*_s->pointer++ = (_v)&0xFF;
|
||||
}
|
||||
|
||||
static INLINE void Stream_Write_INT32(wStream* _s, INT32 _v)
|
||||
{
|
||||
WINPR_ASSERT(_s);
|
||||
|
||||
@@ -87,6 +87,9 @@ set(WLOG_SRCS
|
||||
${JOURNALD_SRCS}
|
||||
)
|
||||
|
||||
set(ASN1_SRCS
|
||||
asn1/asn1.c
|
||||
)
|
||||
|
||||
set(SRCS
|
||||
ini.c
|
||||
@@ -141,7 +144,9 @@ endif()
|
||||
winpr_module_add(${SRCS}
|
||||
${COLLECTIONS_SRCS}
|
||||
${LODEPNG_SRCS}
|
||||
${WLOG_SRCS})
|
||||
${WLOG_SRCS}
|
||||
${ASN1_SRCS}
|
||||
)
|
||||
|
||||
winpr_include_directory_add(
|
||||
"lodepng"
|
||||
|
||||
1297
winpr/libwinpr/utils/asn1/asn1.c
Normal file
1297
winpr/libwinpr/utils/asn1/asn1.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,7 @@ set(${MODULE_PREFIX}_TESTS
|
||||
TestLinkedList.c
|
||||
TestListDictionary.c
|
||||
TestCmdLine.c
|
||||
TestASN1.c
|
||||
TestWLog.c
|
||||
TestWLogCallback.c
|
||||
TestHashTable.c
|
||||
|
||||
275
winpr/libwinpr/utils/test/TestASN1.c
Normal file
275
winpr/libwinpr/utils/test/TestASN1.c
Normal file
@@ -0,0 +1,275 @@
|
||||
#include <winpr/asn1.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
const BYTE boolContent[] = { 0x01, 0x01, 0xFF };
|
||||
const BYTE badBoolContent[] = { 0x01, 0x04, 0xFF };
|
||||
|
||||
const BYTE integerContent[] = { 0x02, 0x01, 0x02 };
|
||||
const BYTE badIntegerContent[] = { 0x02, 0x04, 0x02 };
|
||||
|
||||
const BYTE seqContent[] = { 0x30, 0x22, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x1B, 0x44,
|
||||
0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, 0x20, 0x53, 0x69, 0x67,
|
||||
0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x54, 0x72, 0x75,
|
||||
0x73, 0x74, 0x20, 0x43, 0x6F, 0x2E, 0x31 };
|
||||
|
||||
const BYTE contextualInteger[] = { 0xA0, 0x03, 0x02, 0x01, 0x02 };
|
||||
|
||||
const BYTE oidContent[] = { 0x06, 0x03, 0x55, 0x04, 0x0A };
|
||||
const BYTE badOidContent[] = { 0x06, 0x89, 0x55, 0x04, 0x0A };
|
||||
const BYTE oidValue[] = { 0x55, 0x04, 0x0A };
|
||||
|
||||
const BYTE ia5stringContent[] = { 0x16, 0x22, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F,
|
||||
0x63, 0x70, 0x73, 0x2E, 0x72, 0x6F, 0x6F, 0x74, 0x2D,
|
||||
0x78, 0x31, 0x2E, 0x6C, 0x65, 0x74, 0x73, 0x65, 0x6E,
|
||||
0x63, 0x72, 0x79, 0x70, 0x74, 0x2E, 0x6F, 0x72, 0x67 };
|
||||
|
||||
const BYTE utctimeContent[] = { 0x17, 0x0D, 0x32, 0x31, 0x30, 0x33, 0x31, 0x37,
|
||||
0x31, 0x36, 0x34, 0x30, 0x34, 0x36, 0x5A };
|
||||
|
||||
int TestASN1Read(int argc, char* argv[])
|
||||
{
|
||||
WinPrAsn1Decoder decoder, seqDecoder;
|
||||
wStream staticS;
|
||||
WinPrAsn1_BOOL boolV;
|
||||
WinPrAsn1_INTEGER integerV;
|
||||
WinPrAsn1_OID oidV;
|
||||
WinPrAsn1_IA5STRING ia5stringV;
|
||||
WinPrAsn1_UTCTIME utctimeV;
|
||||
WinPrAsn1_tag tag;
|
||||
size_t len;
|
||||
BOOL error;
|
||||
|
||||
/* ============== Test INTEGERs ================ */
|
||||
Stream_StaticConstInit(&staticS, integerContent, sizeof(integerContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadInteger(&decoder, &integerV))
|
||||
return -1;
|
||||
|
||||
Stream_StaticConstInit(&staticS, badIntegerContent, sizeof(badIntegerContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadInteger(&decoder, &integerV))
|
||||
return -1;
|
||||
|
||||
/* ================ Test BOOL ================*/
|
||||
Stream_StaticConstInit(&staticS, boolContent, sizeof(boolContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadBoolean(&decoder, &boolV))
|
||||
return -10;
|
||||
|
||||
Stream_StaticConstInit(&staticS, badBoolContent, sizeof(badBoolContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadBoolean(&decoder, &boolV))
|
||||
return -11;
|
||||
|
||||
/* ================ Test OID ================*/
|
||||
Stream_StaticConstInit(&staticS, oidContent, sizeof(oidContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadOID(&decoder, &oidV) || oidV.len != 3 ||
|
||||
memcmp(oidV.data, oidValue, oidV.len))
|
||||
return -15;
|
||||
WinPrAsn1FreeOID(&oidV);
|
||||
|
||||
Stream_StaticConstInit(&staticS, badOidContent, sizeof(badOidContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadOID(&decoder, &oidV))
|
||||
return -15;
|
||||
WinPrAsn1FreeOID(&oidV);
|
||||
|
||||
Stream_StaticConstInit(&staticS, ia5stringContent, sizeof(ia5stringContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadIA5String(&decoder, &ia5stringV) ||
|
||||
strcmp(ia5stringV, "http://cps.root-x1.letsencrypt.org"))
|
||||
return -16;
|
||||
free(ia5stringV);
|
||||
|
||||
/* ================ Test utc time ================*/
|
||||
Stream_StaticConstInit(&staticS, utctimeContent, sizeof(utctimeContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadUtcTime(&decoder, &utctimeV) || utctimeV.year != 2021 ||
|
||||
utctimeV.month != 3 || utctimeV.day != 17 || utctimeV.minute != 40 || utctimeV.tz != 'Z')
|
||||
return -17;
|
||||
|
||||
/* ================ Test sequence ================*/
|
||||
Stream_StaticConstInit(&staticS, seqContent, sizeof(seqContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadSequence(&decoder, &seqDecoder))
|
||||
return -20;
|
||||
|
||||
Stream_StaticConstInit(&staticS, seqContent, sizeof(seqContent));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadTagLenValue(&decoder, &tag, &len, &seqDecoder))
|
||||
return -21;
|
||||
|
||||
if (tag != ER_TAG_SEQUENCE)
|
||||
return -22;
|
||||
|
||||
if (!WinPrAsn1DecPeekTag(&seqDecoder, &tag) || tag != ER_TAG_OBJECT_IDENTIFIER)
|
||||
return -23;
|
||||
|
||||
/* ================ Test contextual ================*/
|
||||
Stream_StaticConstInit(&staticS, contextualInteger, sizeof(contextualInteger));
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (!WinPrAsn1DecReadContextualInteger(&decoder, 0, &error, &integerV))
|
||||
return -25;
|
||||
|
||||
/* test reading a contextual integer that is not there (index 1).
|
||||
* that should not touch the decoder read head and we shall be able to extract contextual tag 0
|
||||
* after that
|
||||
*/
|
||||
WinPrAsn1Decoder_Init(&decoder, WINPR_ASN1_DER, &staticS);
|
||||
if (WinPrAsn1DecReadContextualInteger(&decoder, 1, &error, &integerV) || error)
|
||||
return -26;
|
||||
|
||||
if (!WinPrAsn1DecReadContextualInteger(&decoder, 0, &error, &integerV))
|
||||
return -27;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const BYTE oid1_val[] = { 1 };
|
||||
static const WinPrAsn1_OID oid1 = { sizeof(oid1_val), (BYTE*)oid1_val };
|
||||
static BYTE oid2_val[] = { 2, 2 };
|
||||
static WinPrAsn1_OID oid2 = { sizeof(oid2_val), oid2_val };
|
||||
static BYTE oid3_val[] = { 3, 3, 3 };
|
||||
static WinPrAsn1_OID oid3 = { sizeof(oid3_val), oid3_val };
|
||||
static BYTE oid4_val[] = { 4, 4, 4, 4 };
|
||||
static WinPrAsn1_OID oid4 = { sizeof(oid4_val), oid4_val };
|
||||
|
||||
int TestASN1Write(int argc, char* argv[])
|
||||
{
|
||||
wStream* s = NULL;
|
||||
size_t expectedOuputSz;
|
||||
int retCode = 100;
|
||||
WinPrAsn1_UTCTIME utcTime;
|
||||
WinPrAsn1_IA5STRING ia5string;
|
||||
WinPrAsn1Encoder* enc = WinPrAsn1Encoder_New(WINPR_ASN1_DER);
|
||||
if (!enc)
|
||||
goto out;
|
||||
|
||||
/* Let's encode something like:
|
||||
* APP(3)
|
||||
* SEQ2
|
||||
* OID1
|
||||
* OID2
|
||||
* SEQ3
|
||||
* OID3
|
||||
* OID4
|
||||
*
|
||||
* [5] integer(200)
|
||||
* [6] SEQ (empty)
|
||||
* [7] UTC time (2016-03-17 16:40:41 UTC)
|
||||
* [8] IA5String(test)
|
||||
*/
|
||||
|
||||
/* APP(3) */
|
||||
retCode = 101;
|
||||
if (!WinPrAsn1EncAppContainer(enc, 3))
|
||||
goto out;
|
||||
|
||||
/* SEQ2 */
|
||||
retCode = 102;
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
retCode = 103;
|
||||
if (WinPrAsn1EncOID(enc, &oid1) != 3)
|
||||
goto out;
|
||||
|
||||
retCode = 104;
|
||||
if (WinPrAsn1EncOID(enc, &oid2) != 4)
|
||||
goto out;
|
||||
|
||||
retCode = 105;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 9)
|
||||
goto out;
|
||||
|
||||
/* SEQ3 */
|
||||
retCode = 110;
|
||||
if (!WinPrAsn1EncSeqContainer(enc))
|
||||
goto out;
|
||||
|
||||
retCode = 111;
|
||||
if (WinPrAsn1EncOID(enc, &oid3) != 5)
|
||||
goto out;
|
||||
|
||||
retCode = 112;
|
||||
if (WinPrAsn1EncOID(enc, &oid4) != 6)
|
||||
goto out;
|
||||
|
||||
retCode = 113;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 13)
|
||||
goto out;
|
||||
|
||||
/* [5] integer(200) */
|
||||
retCode = 114;
|
||||
if (WinPrAsn1EncContextualInteger(enc, 5, 200) != 6)
|
||||
goto out;
|
||||
|
||||
/* [6] SEQ (empty) */
|
||||
retCode = 115;
|
||||
if (!WinPrAsn1EncContextualSeqContainer(enc, 6))
|
||||
goto out;
|
||||
|
||||
retCode = 116;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 4)
|
||||
goto out;
|
||||
|
||||
/* [7] UTC time (2016-03-17 16:40:41 UTC) */
|
||||
retCode = 117;
|
||||
utcTime.year = 2016;
|
||||
utcTime.month = 3;
|
||||
utcTime.day = 17;
|
||||
utcTime.hour = 16;
|
||||
utcTime.minute = 40;
|
||||
utcTime.second = 41;
|
||||
utcTime.tz = 'Z';
|
||||
if (WinPrAsn1EncContextualUtcTime(enc, 7, &utcTime) != 17)
|
||||
goto out;
|
||||
|
||||
/* [8] IA5String(test) */
|
||||
retCode = 118;
|
||||
ia5string = "test";
|
||||
if (!WinPrAsn1EncContextualContainer(enc, 8))
|
||||
goto out;
|
||||
|
||||
retCode = 119;
|
||||
if (WinPrAsn1EncIA5String(enc, ia5string) != 6)
|
||||
goto out;
|
||||
|
||||
retCode = 120;
|
||||
if (WinPrAsn1EncEndContainer(enc) != 8)
|
||||
goto out;
|
||||
|
||||
/* close APP */
|
||||
expectedOuputSz = 24 + 6 + 4 + 17 + 8;
|
||||
retCode = 200;
|
||||
if (WinPrAsn1EncEndContainer(enc) != expectedOuputSz)
|
||||
goto out;
|
||||
|
||||
/* let's output the result */
|
||||
retCode = 201;
|
||||
s = Stream_New(NULL, 1024);
|
||||
if (!s)
|
||||
goto out;
|
||||
|
||||
retCode = 202;
|
||||
if (!WinPrAsn1EncToStream(enc, s) || Stream_GetPosition(s) != expectedOuputSz)
|
||||
goto out;
|
||||
retCode = 0;
|
||||
|
||||
/*winpr_HexDump("", WLOG_ERROR, Stream_Buffer(s), Stream_GetPosition(s));*/
|
||||
out:
|
||||
if (s)
|
||||
Stream_Free(s, TRUE);
|
||||
WinPrAsn1Encoder_Free(&enc);
|
||||
return retCode;
|
||||
}
|
||||
|
||||
int TestASN1(int argc, char* argv[])
|
||||
{
|
||||
int ret = TestASN1Read(argc, argv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return TestASN1Write(argc, argv);
|
||||
}
|
||||
Reference in New Issue
Block a user