encode.c
来自「一个类似windows」· C语言 代码 · 共 1,906 行 · 第 1/5 页
C
1,906 行
/*
* Copyright 2005 Juan Lang
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* This file implements ASN.1 DER encoding and decoding of a limited set of
* types. It isn't a full ASN.1 implementation. Microsoft implements BER
* encoding of many of the basic types in msasn1.dll, but that interface is
* undocumented, so I implement them here.
*
* References:
* "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
* (available online, look for a PDF copy as the HTML versions tend to have
* translation errors.)
*
* RFC3280, http://www.faqs.org/rfcs/rfc3280.html
*
* MSDN, especially:
* http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
*/
#include "config.h"
#include "wine/port.h"
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#define NONAMELESSUNION
#include "windef.h"
#include "winbase.h"
#include "excpt.h"
#include "wincrypt.h"
#include "winreg.h"
#include "snmp.h"
#include "wine/debug.h"
#include "wine/exception.h"
#include "crypt32_private.h"
/* This is a bit arbitrary, but to set some limit: */
#define MAX_ENCODED_LEN 0x02000000
/* a few asn.1 tags we need */
#define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
#define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
#define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
#define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
#define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
#define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
#define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
#define ASN_FLAGS_MASK 0xe0
#define ASN_TYPE_MASK 0x1f
WINE_DEFAULT_DEBUG_CHANNEL(crypt);
struct GenericArray
{
DWORD cItems;
BYTE *rgItems;
};
typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
BYTE *, DWORD *);
typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
DWORD, DWORD, void *, DWORD *);
typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
/* Prototypes for built-in encoders/decoders. They follow the Ex style
* prototypes. The dwCertEncodingType and lpszStructType are ignored by the
* built-in functions, but the parameters are retained to simplify
* CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
* external DLLs that follow these signatures.
*/
static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
* time, doesn't do memory allocation, and doesn't do exception handling.
* (This isn't intended to be the externally-called one.)
*/
static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
/* Assumes algo->Parameters.pbData is set ahead of time. Internal func. */
static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Internal function */
static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
* member has been initialized, doesn't do exception handling, and doesn't do
* memory allocation.
*/
static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
* member has been initialized, doesn't do exception handling, and doesn't do
* memory allocation.
*/
static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
/* Like CRYPT_AsnDecodeInteger, but unsigned. */
static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
void *pvStructInfo, DWORD *pcbStructInfo);
BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
{
static HCRYPTOIDFUNCSET set = NULL;
BOOL ret = FALSE;
HCRYPTOIDFUNCADDR hFunc;
CryptEncodeObjectFunc pCryptEncodeObject;
TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
pcbEncoded);
if (!pbEncoded && !pcbEncoded)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Try registered DLL first.. */
if (!set)
set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
(void **)&pCryptEncodeObject, &hFunc);
if (pCryptEncodeObject)
{
ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
pvStructInfo, pbEncoded, pcbEncoded);
CryptFreeOIDFunctionAddress(hFunc, 0);
}
else
{
/* If not, use CryptEncodeObjectEx */
ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
}
return ret;
}
/* Helper function to check *pcbEncoded, set it to the required size, and
* optionally to allocate memory. Assumes pbEncoded is not NULL.
* If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
* pointer to the newly allocated memory.
*/
static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
DWORD bytesNeeded)
{
BOOL ret = TRUE;
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
{
if (pEncodePara && pEncodePara->pfnAlloc)
*(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
else
*(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
if (!*(BYTE **)pbEncoded)
ret = FALSE;
else
*pcbEncoded = bytesNeeded;
}
else if (bytesNeeded > *pcbEncoded)
{
*pcbEncoded = bytesNeeded;
SetLastError(ERROR_MORE_DATA);
ret = FALSE;
}
return ret;
}
static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
{
DWORD bytesNeeded, significantBytes = 0;
if (len <= 0x7f)
bytesNeeded = 1;
else
{
DWORD temp;
for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
temp <<= 8, significantBytes--)
;
bytesNeeded = significantBytes + 1;
}
if (!pbEncoded)
{
*pcbEncoded = bytesNeeded;
return TRUE;
}
if (*pcbEncoded < bytesNeeded)
{
SetLastError(ERROR_MORE_DATA);
return FALSE;
}
if (len <= 0x7f)
*pbEncoded = (BYTE)len;
else
{
DWORD i;
*pbEncoded++ = significantBytes | 0x80;
for (i = 0; i < significantBytes; i++)
{
*(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
len >>= 8;
}
}
*pcbEncoded = bytesNeeded;
return TRUE;
}
struct AsnEncodeSequenceItem
{
const void *pvStructInfo;
CryptEncodeObjectExFunc encodeFunc;
DWORD size; /* used during encoding, not for your use */
};
static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret;
DWORD i, dataLen = 0;
TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
pbEncoded, *pcbEncoded);
for (i = 0, ret = TRUE; ret && i < cItem; i++)
{
ret = items[i].encodeFunc(dwCertEncodingType, NULL,
items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
NULL, &items[i].size);
/* Some functions propagate their errors through the size */
if (!ret)
*pcbEncoded = items[i].size;
dataLen += items[i].size;
}
if (ret)
{
DWORD lenBytes, bytesNeeded;
CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
bytesNeeded = 1 + lenBytes + dataLen;
if (!pbEncoded)
*pcbEncoded = bytesNeeded;
else
{
if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
pcbEncoded, bytesNeeded)))
{
if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
pbEncoded = *(BYTE **)pbEncoded;
*pbEncoded++ = ASN_SEQUENCE;
CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
pbEncoded += lenBytes;
for (i = 0; ret && i < cItem; i++)
{
ret = items[i].encodeFunc(dwCertEncodingType, NULL,
items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
NULL, pbEncoded, &items[i].size);
/* Some functions propagate their errors through the size */
if (!ret)
*pcbEncoded = items[i].size;
pbEncoded += items[i].size;
}
}
}
}
TRACE("returning %d (%08lx)\n", ret, GetLastError());
return ret;
}
struct AsnConstructedItem
{
BYTE tag;
const void *pvStructInfo;
CryptEncodeObjectExFunc encodeFunc;
};
static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
{
BOOL ret;
const struct AsnConstructedItem *item =
(const struct AsnConstructedItem *)pvStructInfo;
DWORD len;
if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
{
DWORD dataLen, bytesNeeded;
CRYPT_EncodeLen(len, NULL, &dataLen);
bytesNeeded = 1 + dataLen + len;
if (!pbEncoded)
*pcbEncoded = bytesNeeded;
else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
pbEncoded, pcbEncoded, bytesNeeded)))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?