Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
4d7e1e4b
Commit
4d7e1e4b
authored
Jun 13, 2005
by
Juan Lang
Committed by
Alexandre Julliard
Jun 13, 2005
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
- encode/decode X509_NAMEs for simple string encodings, with tests
- more tests and some fixes to other types
parent
112df735
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1292 additions
and
120 deletions
+1292
-120
encode.c
dlls/crypt32/encode.c
+934
-58
encode.c
dlls/crypt32/tests/encode.c
+358
-62
No files found.
dlls/crypt32/encode.c
View file @
4d7e1e4b
...
...
@@ -18,6 +18,7 @@
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "wincrypt.h"
...
...
@@ -26,8 +27,12 @@
#include "wine/debug.h"
/* a few asn.1 tags we need */
#define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
#define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
#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)
WINE_DEFAULT_DEBUG_CHANNEL
(
crypt
);
...
...
@@ -336,6 +341,8 @@ static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
*
(
BYTE
**
)
pbEncoded
=
LocalAlloc
(
0
,
bytesNeeded
);
if
(
!*
(
BYTE
**
)
pbEncoded
)
ret
=
FALSE
;
else
*
pcbEncoded
=
bytesNeeded
;
}
else
if
(
bytesNeeded
>
*
pcbEncoded
)
{
...
...
@@ -346,6 +353,358 @@ static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnEncodeOid
(
DWORD
dwCertEncodingType
,
LPCSTR
pszObjId
,
BYTE
*
pbEncoded
,
DWORD
*
pcbEncoded
)
{
DWORD
bytesNeeded
=
2
;
BOOL
ret
=
TRUE
;
int
firstPos
=
0
;
BYTE
firstByte
=
0
;
if
(
pszObjId
)
{
const
char
*
ptr
;
int
val1
,
val2
;
if
(
sscanf
(
pszObjId
,
"%d.%d.%n"
,
&
val1
,
&
val2
,
&
firstPos
)
!=
2
)
{
SetLastError
(
CRYPT_E_ASN1_ERROR
);
return
FALSE
;
}
bytesNeeded
++
;
firstByte
=
val1
*
40
+
val2
;
ptr
=
pszObjId
+
firstPos
;
while
(
ret
&&
*
ptr
)
{
int
pos
;
/* note I assume each component is at most 32-bits long in base 2 */
if
(
sscanf
(
ptr
,
"%d%n"
,
&
val1
,
&
pos
)
==
1
)
{
if
(
val1
>=
0x10000000
)
bytesNeeded
+=
5
;
else
if
(
val1
>=
0x200000
)
bytesNeeded
+=
4
;
else
if
(
val1
>=
0x4000
)
bytesNeeded
+=
3
;
else
if
(
val1
>=
0x80
)
bytesNeeded
+=
2
;
else
bytesNeeded
+=
1
;
ptr
+=
pos
;
if
(
*
ptr
==
'.'
)
ptr
++
;
}
else
{
SetLastError
(
CRYPT_E_ASN1_ERROR
);
return
FALSE
;
}
}
}
if
(
pbEncoded
)
{
if
(
*
pbEncoded
<
bytesNeeded
)
{
SetLastError
(
ERROR_MORE_DATA
);
ret
=
FALSE
;
}
else
{
*
pbEncoded
++
=
ASN_OBJECTIDENTIFIER
;
*
pbEncoded
++
=
bytesNeeded
-
2
;
if
(
pszObjId
)
{
const
char
*
ptr
;
int
val
,
pos
;
*
pbEncoded
++
=
firstByte
;
ptr
=
pszObjId
+
firstPos
;
while
(
ret
&&
*
ptr
)
{
sscanf
(
ptr
,
"%d%n"
,
&
val
,
&
pos
);
{
unsigned
char
outBytes
[
5
];
int
numBytes
,
i
;
if
(
val
>=
0x10000000
)
numBytes
=
5
;
else
if
(
val
>=
0x200000
)
numBytes
=
4
;
else
if
(
val
>=
0x4000
)
numBytes
=
3
;
else
if
(
val
>=
0x80
)
numBytes
=
2
;
else
numBytes
=
1
;
for
(
i
=
numBytes
;
i
>
0
;
i
--
)
{
outBytes
[
i
-
1
]
=
val
&
0x7f
;
val
>>=
7
;
}
for
(
i
=
0
;
i
<
numBytes
-
1
;
i
++
)
*
pbEncoded
++
=
outBytes
[
i
]
|
0x80
;
*
pbEncoded
++
=
outBytes
[
i
];
ptr
+=
pos
;
if
(
*
ptr
==
'.'
)
ptr
++
;
}
}
}
}
}
*
pcbEncoded
=
bytesNeeded
;
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnEncodeNameValue
(
DWORD
dwCertEncodingType
,
CERT_NAME_VALUE
*
value
,
BYTE
*
pbEncoded
,
DWORD
*
pcbEncoded
)
{
BYTE
tag
;
DWORD
bytesNeeded
;
BOOL
ret
=
TRUE
;
switch
(
value
->
dwValueType
)
{
case
CERT_RDN_NUMERIC_STRING
:
tag
=
ASN_NUMERICSTRING
;
bytesNeeded
=
2
+
value
->
Value
.
cbData
;
break
;
case
CERT_RDN_PRINTABLE_STRING
:
tag
=
ASN_PRINTABLESTRING
;
bytesNeeded
=
2
+
value
->
Value
.
cbData
;
break
;
case
CERT_RDN_IA5_STRING
:
tag
=
ASN_IA5STRING
;
bytesNeeded
=
2
+
value
->
Value
.
cbData
;
break
;
case
CERT_RDN_ANY_TYPE
:
/* explicitly disallowed */
SetLastError
(
HRESULT_FROM_WIN32
(
ERROR_INVALID_PARAMETER
));
return
FALSE
;
default:
FIXME
(
"String type %ld unimplemented
\n
"
,
value
->
dwValueType
);
return
FALSE
;
}
if
(
pbEncoded
)
{
if
(
*
pcbEncoded
<
bytesNeeded
)
{
SetLastError
(
ERROR_MORE_DATA
);
ret
=
FALSE
;
}
else
{
*
pbEncoded
++
=
tag
;
*
pbEncoded
++
=
bytesNeeded
-
2
;
switch
(
value
->
dwValueType
)
{
case
CERT_RDN_NUMERIC_STRING
:
case
CERT_RDN_PRINTABLE_STRING
:
case
CERT_RDN_IA5_STRING
:
memcpy
(
pbEncoded
,
value
->
Value
.
pbData
,
value
->
Value
.
cbData
);
}
}
}
*
pcbEncoded
=
bytesNeeded
;
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnEncodeRdnAttr
(
DWORD
dwCertEncodingType
,
CERT_RDN_ATTR
*
attr
,
BYTE
*
pbEncoded
,
DWORD
*
pcbEncoded
)
{
DWORD
bytesNeeded
,
size
;
BOOL
ret
;
bytesNeeded
=
2
;
/* tag and len */
ret
=
CRYPT_AsnEncodeOid
(
dwCertEncodingType
,
attr
->
pszObjId
,
NULL
,
&
size
);
if
(
ret
)
{
bytesNeeded
+=
size
;
/* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
* with dwValueType, so "cast" it to get its encoded size
*/
ret
=
CRYPT_AsnEncodeNameValue
(
dwCertEncodingType
,
(
CERT_NAME_VALUE
*
)
&
attr
->
dwValueType
,
NULL
,
&
size
);
if
(
ret
)
{
bytesNeeded
+=
size
;
if
(
pbEncoded
)
{
if
(
*
pcbEncoded
<
bytesNeeded
)
{
SetLastError
(
ERROR_MORE_DATA
);
ret
=
FALSE
;
}
else
{
*
pbEncoded
++
=
ASN_CONSTRUCTOR
|
ASN_SEQUENCE
;
*
pbEncoded
++
=
bytesNeeded
-
2
;
size
=
bytesNeeded
-
2
;
ret
=
CRYPT_AsnEncodeOid
(
dwCertEncodingType
,
attr
->
pszObjId
,
pbEncoded
,
&
size
);
if
(
ret
)
{
pbEncoded
+=
size
;
size
=
bytesNeeded
-
2
-
size
;
ret
=
CRYPT_AsnEncodeNameValue
(
dwCertEncodingType
,
(
CERT_NAME_VALUE
*
)
&
attr
->
dwValueType
,
pbEncoded
,
&
size
);
}
}
}
*
pcbEncoded
=
bytesNeeded
;
}
}
return
ret
;
}
static
int
BLOBComp
(
const
void
*
l
,
const
void
*
r
)
{
CRYPT_DER_BLOB
*
a
=
(
CRYPT_DER_BLOB
*
)
l
,
*
b
=
(
CRYPT_DER_BLOB
*
)
r
;
int
ret
;
if
(
!
(
ret
=
memcmp
(
a
->
pbData
,
b
->
pbData
,
min
(
a
->
cbData
,
b
->
cbData
))))
ret
=
a
->
cbData
-
b
->
cbData
;
return
ret
;
}
/* This encodes as a SET OF, which in DER must be lexicographically sorted.
*/
static
BOOL
WINAPI
CRYPT_AsnEncodeRdn
(
DWORD
dwCertEncodingType
,
CERT_RDN
*
rdn
,
BYTE
*
pbEncoded
,
DWORD
*
pcbEncoded
)
{
DWORD
bytesNeeded
,
i
;
BOOL
ret
;
CRYPT_DER_BLOB
*
blobs
=
NULL
;
ret
=
TRUE
;
if
(
rdn
->
cRDNAttr
)
{
if
(
!
rdn
->
rgRDNAttr
)
{
SetLastError
(
STATUS_ACCESS_VIOLATION
);
ret
=
FALSE
;
}
else
{
blobs
=
HeapAlloc
(
GetProcessHeap
(),
HEAP_ZERO_MEMORY
,
rdn
->
cRDNAttr
*
sizeof
(
CRYPT_DER_BLOB
));
if
(
!
blobs
)
ret
=
FALSE
;
}
}
bytesNeeded
=
2
;
/* tag and len */
for
(
i
=
0
;
ret
&&
i
<
rdn
->
cRDNAttr
;
i
++
)
{
ret
=
CRYPT_AsnEncodeRdnAttr
(
dwCertEncodingType
,
&
rdn
->
rgRDNAttr
[
i
],
NULL
,
&
blobs
[
i
].
cbData
);
if
(
ret
)
bytesNeeded
+=
blobs
[
i
].
cbData
;
}
if
(
ret
)
{
if
(
pbEncoded
)
{
if
(
*
pcbEncoded
<
bytesNeeded
)
{
SetLastError
(
ERROR_MORE_DATA
);
ret
=
FALSE
;
}
else
{
for
(
i
=
0
;
ret
&&
i
<
rdn
->
cRDNAttr
;
i
++
)
{
blobs
[
i
].
pbData
=
HeapAlloc
(
GetProcessHeap
(),
0
,
blobs
[
i
].
cbData
);
if
(
!
blobs
[
i
].
pbData
)
ret
=
FALSE
;
else
ret
=
CRYPT_AsnEncodeRdnAttr
(
dwCertEncodingType
,
&
rdn
->
rgRDNAttr
[
i
],
blobs
[
i
].
pbData
,
&
blobs
[
i
].
cbData
);
}
if
(
ret
)
{
qsort
(
blobs
,
rdn
->
cRDNAttr
,
sizeof
(
CRYPT_DER_BLOB
),
BLOBComp
);
*
pbEncoded
++
=
ASN_CONSTRUCTOR
|
ASN_SETOF
;
*
pbEncoded
++
=
(
BYTE
)
bytesNeeded
-
2
;
for
(
i
=
0
;
ret
&&
i
<
rdn
->
cRDNAttr
;
i
++
)
{
memcpy
(
pbEncoded
,
blobs
[
i
].
pbData
,
blobs
[
i
].
cbData
);
pbEncoded
+=
blobs
[
i
].
cbData
;
}
}
}
}
*
pcbEncoded
=
bytesNeeded
;
}
if
(
blobs
)
{
for
(
i
=
0
;
i
<
rdn
->
cRDNAttr
;
i
++
)
HeapFree
(
GetProcessHeap
(),
0
,
blobs
[
i
].
pbData
);
HeapFree
(
GetProcessHeap
(),
0
,
blobs
);
}
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnEncodeName
(
DWORD
dwCertEncodingType
,
LPCSTR
lpszStructType
,
const
void
*
pvStructInfo
,
DWORD
dwFlags
,
PCRYPT_ENCODE_PARA
pEncodePara
,
BYTE
*
pbEncoded
,
DWORD
*
pcbEncoded
)
{
CERT_NAME_INFO
*
info
=
(
CERT_NAME_INFO
*
)
pvStructInfo
;
DWORD
bytesNeeded
,
size
,
i
;
BOOL
ret
;
if
(
!
pvStructInfo
)
{
SetLastError
(
STATUS_ACCESS_VIOLATION
);
return
FALSE
;
}
if
(
info
->
cRDN
&&
!
info
->
rgRDN
)
{
SetLastError
(
STATUS_ACCESS_VIOLATION
);
return
FALSE
;
}
TRACE
(
"encoding name with %ld RDNs
\n
"
,
info
->
cRDN
);
bytesNeeded
=
2
;
/* tag and len */
ret
=
TRUE
;
for
(
i
=
0
;
ret
&&
i
<
info
->
cRDN
;
i
++
)
{
ret
=
CRYPT_AsnEncodeRdn
(
dwCertEncodingType
,
&
info
->
rgRDN
[
i
],
NULL
,
&
size
);
if
(
ret
)
bytesNeeded
+=
size
;
}
if
(
ret
)
{
if
(
!
pbEncoded
)
{
*
pcbEncoded
=
bytesNeeded
;
return
TRUE
;
}
if
(
!
CRYPT_EncodeEnsureSpace
(
dwFlags
,
pEncodePara
,
pbEncoded
,
pcbEncoded
,
bytesNeeded
))
return
FALSE
;
if
(
dwFlags
&
CRYPT_ENCODE_ALLOC_FLAG
)
pbEncoded
=
*
(
BYTE
**
)
pbEncoded
;
*
pbEncoded
++
=
ASN_CONSTRUCTOR
|
ASN_SEQUENCE
;
*
pbEncoded
++
=
(
BYTE
)
bytesNeeded
-
2
;
for
(
i
=
0
;
ret
&&
i
<
info
->
cRDN
;
i
++
)
{
size
=
bytesNeeded
;
ret
=
CRYPT_AsnEncodeRdn
(
dwCertEncodingType
,
&
info
->
rgRDN
[
i
],
pbEncoded
,
&
size
);
if
(
ret
)
{
pbEncoded
+=
size
;
bytesNeeded
-=
size
;
}
}
}
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnEncodeInt
(
DWORD
dwCertEncodingType
,
LPCSTR
lpszStructType
,
const
void
*
pvStructInfo
,
DWORD
dwFlags
,
PCRYPT_ENCODE_PARA
pEncodePara
,
BYTE
*
pbEncoded
,
DWORD
*
pcbEncoded
)
...
...
@@ -356,7 +715,7 @@ static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
if
(
!
pvStructInfo
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
SetLastError
(
STATUS_ACCESS_VIOLATION
);
return
FALSE
;
}
...
...
@@ -425,7 +784,7 @@ static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
if
(
!
pvStructInfo
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
SetLastError
(
STATUS_ACCESS_VIOLATION
);
return
FALSE
;
}
/* Sanity check the year, this is a two-digit year format */
...
...
@@ -469,7 +828,7 @@ static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
if
(
!
pvStructInfo
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
SetLastError
(
STATUS_ACCESS_VIOLATION
);
return
FALSE
;
}
if
(
!
pbEncoded
)
...
...
@@ -502,7 +861,7 @@ static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
if
(
!
pvStructInfo
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
SetLastError
(
STATUS_ACCESS_VIOLATION
);
return
FALSE
;
}
/* Check the year, if it's in the UTCTime range call that encode func */
...
...
@@ -551,6 +910,9 @@ BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
{
switch
(
LOWORD
(
lpszStructType
))
{
case
(
WORD
)
X509_NAME
:
encodeFunc
=
CRYPT_AsnEncodeName
;
break
;
case
(
WORD
)
X509_INTEGER
:
encodeFunc
=
CRYPT_AsnEncodeInt
;
break
;
...
...
@@ -639,6 +1001,8 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
*
(
BYTE
**
)
pvStructInfo
=
LocalAlloc
(
0
,
bytesNeeded
);
if
(
!*
(
BYTE
**
)
pvStructInfo
)
ret
=
FALSE
;
else
*
pcbStructInfo
=
bytesNeeded
;
}
else
if
(
*
pcbStructInfo
<
bytesNeeded
)
{
...
...
@@ -649,6 +1013,468 @@ static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
return
ret
;
}
/* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
static
BOOL
WINAPI
CRYPT_AsnDecodeOid
(
DWORD
dwCertEncodingType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
LPSTR
pszObjId
,
DWORD
*
pcbObjId
)
{
BOOL
ret
=
TRUE
;
DWORD
bytesNeeded
;
/* cbEncoded is an upper bound on the number of bytes, not the actual
* count: check the count for sanity.
*/
if
(
cbEncoded
<=
1
||
pbEncoded
[
1
]
>
cbEncoded
-
2
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
if
(
pbEncoded
[
0
]
!=
ASN_OBJECTIDENTIFIER
)
{
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
if
(
pbEncoded
[
1
])
{
/* The largest possible string for the first two components is 2.175
* (= 2 * 40 + 175 = 255), so this is big enough.
*/
char
firstTwo
[
6
];
const
BYTE
*
ptr
;
snprintf
(
firstTwo
,
sizeof
(
firstTwo
),
"%d.%d"
,
pbEncoded
[
2
]
/
40
,
pbEncoded
[
2
]
-
(
pbEncoded
[
2
]
/
40
)
*
40
);
bytesNeeded
=
strlen
(
firstTwo
)
+
1
;
for
(
ptr
=
pbEncoded
+
3
;
ret
&&
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
];
)
{
/* large enough for ".4000000" */
char
str
[
9
];
int
val
=
0
;
while
(
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
]
&&
(
*
ptr
&
0x80
))
{
val
<<=
7
;
val
|=
*
ptr
&
0x7f
;
ptr
++
;
}
if
(
ptr
-
pbEncoded
-
2
>=
pbEncoded
[
1
]
||
(
*
ptr
&
0x80
))
{
SetLastError
(
CRYPT_E_ASN1_CORRUPT
);
ret
=
FALSE
;
}
else
{
val
<<=
7
;
val
|=
*
ptr
++
;
snprintf
(
str
,
sizeof
(
str
),
".%d"
,
val
);
bytesNeeded
+=
strlen
(
str
);
}
}
if
(
!
pszObjId
)
*
pcbObjId
=
bytesNeeded
;
else
if
(
*
pcbObjId
<
bytesNeeded
)
{
*
pcbObjId
=
bytesNeeded
;
SetLastError
(
ERROR_MORE_DATA
);
ret
=
FALSE
;
}
else
{
sprintf
(
pszObjId
,
"%d.%d"
,
pbEncoded
[
2
]
/
40
,
pbEncoded
[
2
]
-
(
pbEncoded
[
2
]
/
40
)
*
40
);
pszObjId
+=
strlen
(
pszObjId
);
for
(
ptr
=
pbEncoded
+
3
;
ret
&&
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
];
)
{
int
val
=
0
;
while
(
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
]
&&
(
*
ptr
&
0x80
))
{
val
<<=
7
;
val
|=
*
ptr
&
0x7f
;
ptr
++
;
}
val
<<=
7
;
val
|=
*
ptr
++
;
sprintf
(
pszObjId
,
".%d"
,
val
);
pszObjId
+=
strlen
(
pszObjId
);
}
}
}
else
bytesNeeded
=
0
;
*
pcbObjId
=
bytesNeeded
;
return
ret
;
}
/* Warning: this assumes the address of value->Value.pbData is already set, in
* order to avoid overwriting memory. (In some cases, it may change it, if it
* doesn't copy anything to memory.) Be sure to set it correctly!
*/
static
BOOL
WINAPI
CRYPT_AsnDecodeNameValue
(
DWORD
dwCertEncodingType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
CERT_NAME_VALUE
*
value
,
DWORD
*
pcbValue
)
{
DWORD
bytesNeeded
;
BOOL
ret
=
TRUE
;
/* cbEncoded is an upper bound on the number of bytes, not the actual
* count: check the count for sanity.
*/
if
(
cbEncoded
<=
1
||
pbEncoded
[
1
]
>
cbEncoded
-
2
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
switch
(
pbEncoded
[
0
])
{
case
ASN_NUMERICSTRING
:
case
ASN_PRINTABLESTRING
:
case
ASN_IA5STRING
:
break
;
default:
FIXME
(
"Unimplemented string type %02x
\n
"
,
pbEncoded
[
0
]);
SetLastError
(
OSS_UNIMPLEMENTED
);
return
FALSE
;
}
bytesNeeded
=
sizeof
(
CERT_NAME_VALUE
);
if
(
pbEncoded
[
1
])
{
switch
(
pbEncoded
[
0
])
{
case
ASN_NUMERICSTRING
:
case
ASN_PRINTABLESTRING
:
case
ASN_IA5STRING
:
if
(
!
(
dwFlags
&
CRYPT_DECODE_NOCOPY_FLAG
))
bytesNeeded
+=
pbEncoded
[
1
];
break
;
}
}
if
(
!
value
)
{
*
pcbValue
=
bytesNeeded
;
return
TRUE
;
}
if
(
*
pcbValue
<
bytesNeeded
)
{
*
pcbValue
=
bytesNeeded
;
SetLastError
(
ERROR_MORE_DATA
);
return
FALSE
;
}
*
pcbValue
=
bytesNeeded
;
switch
(
pbEncoded
[
0
])
{
case
ASN_NUMERICSTRING
:
value
->
dwValueType
=
CERT_RDN_NUMERIC_STRING
;
break
;
case
ASN_PRINTABLESTRING
:
value
->
dwValueType
=
CERT_RDN_PRINTABLE_STRING
;
break
;
case
ASN_IA5STRING
:
value
->
dwValueType
=
CERT_RDN_IA5_STRING
;
break
;
}
if
(
pbEncoded
[
1
])
{
switch
(
pbEncoded
[
0
])
{
case
ASN_NUMERICSTRING
:
case
ASN_PRINTABLESTRING
:
case
ASN_IA5STRING
:
value
->
Value
.
cbData
=
pbEncoded
[
1
];
if
(
dwFlags
&
CRYPT_DECODE_NOCOPY_FLAG
)
value
->
Value
.
pbData
=
(
BYTE
*
)
pbEncoded
+
2
;
else
{
if
(
!
value
->
Value
.
pbData
)
{
SetLastError
(
CRYPT_E_ASN1_INTERNAL
);
ret
=
FALSE
;
}
else
memcpy
(
value
->
Value
.
pbData
,
pbEncoded
+
2
,
pbEncoded
[
1
]);
}
break
;
}
}
else
{
value
->
Value
.
cbData
=
0
;
value
->
Value
.
pbData
=
NULL
;
}
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeRdnAttr
(
DWORD
dwCertEncodingType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
CERT_RDN_ATTR
*
attr
,
DWORD
*
pcbAttr
)
{
BOOL
ret
=
TRUE
;
DWORD
bytesNeeded
,
size
;
/* cbEncoded is an upper bound on the number of bytes, not the actual
* count: check the count for sanity. It must be at least 6, two for the
* tag and length for the RDN_ATTR, two for the OID, and two for the string.
*/
if
(
cbEncoded
<
6
||
pbEncoded
[
1
]
<
4
||
pbEncoded
[
1
]
>
cbEncoded
-
2
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
if
(
pbEncoded
[
0
]
!=
(
ASN_CONSTRUCTOR
|
ASN_SEQUENCE
))
{
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
bytesNeeded
=
sizeof
(
CERT_RDN_ATTR
);
ret
=
CRYPT_AsnDecodeOid
(
dwCertEncodingType
,
pbEncoded
+
2
,
cbEncoded
-
2
,
dwFlags
,
NULL
,
&
size
);
if
(
ret
)
{
/* ugly: need to know the size of the next element of the sequence,
* so get it directly
*/
BYTE
objIdLen
=
pbEncoded
[
3
];
bytesNeeded
+=
size
;
/* hack: like encoding, this takes advantage of the fact that the rest
* of the structure is identical to a CERT_NAME_VALUE.
*/
ret
=
CRYPT_AsnDecodeNameValue
(
dwCertEncodingType
,
pbEncoded
+
4
+
objIdLen
,
cbEncoded
-
4
-
objIdLen
,
dwFlags
,
NULL
,
&
size
);
if
(
ret
)
{
bytesNeeded
+=
size
;
if
(
!
attr
)
*
pcbAttr
=
bytesNeeded
;
else
if
(
*
pcbAttr
<
bytesNeeded
)
{
*
pcbAttr
=
bytesNeeded
;
SetLastError
(
ERROR_MORE_DATA
);
ret
=
FALSE
;
}
else
{
BYTE
*
originalData
=
attr
->
Value
.
pbData
;
*
pcbAttr
=
bytesNeeded
;
/* strange: decode the value first, because it has a counted
* size, and we can store the OID after it. Keep track of the
* original data pointer, we'll need to know whether it was
* changed.
*/
size
=
bytesNeeded
;
ret
=
CRYPT_AsnDecodeNameValue
(
dwCertEncodingType
,
pbEncoded
+
4
+
objIdLen
,
cbEncoded
-
4
-
objIdLen
,
dwFlags
,
(
CERT_NAME_VALUE
*
)
&
attr
->
dwValueType
,
&
size
);
if
(
ret
)
{
if
(
objIdLen
)
{
/* if the data were copied to the original location,
* the OID goes after. Otherwise it goes in the
* spot originally reserved for the data.
*/
if
(
attr
->
Value
.
pbData
==
originalData
)
attr
->
pszObjId
=
(
LPSTR
)(
attr
->
Value
.
pbData
+
attr
->
Value
.
cbData
);
else
attr
->
pszObjId
=
originalData
;
size
=
bytesNeeded
-
size
;
ret
=
CRYPT_AsnDecodeOid
(
dwCertEncodingType
,
pbEncoded
+
2
,
cbEncoded
-
2
,
dwFlags
,
attr
->
pszObjId
,
&
size
);
}
else
attr
->
pszObjId
=
NULL
;
}
}
}
}
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeRdn
(
DWORD
dwCertEncodingType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
CERT_RDN
*
rdn
,
DWORD
*
pcbRdn
)
{
BOOL
ret
=
TRUE
;
DWORD
bytesNeeded
,
cRDNAttr
=
0
;
/* cbEncoded is an upper bound on the number of bytes, not the actual
* count: check the count for sanity.
*/
if
(
cbEncoded
<=
1
||
pbEncoded
[
1
]
>
cbEncoded
-
2
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
if
(
pbEncoded
[
0
]
!=
(
ASN_CONSTRUCTOR
|
ASN_SETOF
))
{
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
bytesNeeded
=
sizeof
(
CERT_RDN
);
if
(
pbEncoded
[
1
])
{
const
BYTE
*
ptr
;
DWORD
size
;
for
(
ptr
=
pbEncoded
+
2
;
ret
&&
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
];
)
{
ret
=
CRYPT_AsnDecodeRdnAttr
(
dwCertEncodingType
,
ptr
,
cbEncoded
-
(
ptr
-
pbEncoded
),
dwFlags
,
NULL
,
&
size
);
if
(
ret
)
{
cRDNAttr
++
;
bytesNeeded
+=
size
;
ptr
+=
ptr
[
1
]
+
2
;
}
}
}
if
(
ret
)
{
if
(
!
rdn
)
{
*
pcbRdn
=
bytesNeeded
;
return
TRUE
;
}
if
(
*
pcbRdn
<
bytesNeeded
)
{
*
pcbRdn
=
bytesNeeded
;
SetLastError
(
ERROR_MORE_DATA
);
return
FALSE
;
}
*
pcbRdn
=
bytesNeeded
;
rdn
->
cRDNAttr
=
cRDNAttr
;
if
(
rdn
->
cRDNAttr
==
0
)
rdn
->
rgRDNAttr
=
NULL
;
else
{
DWORD
size
,
i
;
BYTE
*
nextData
;
const
BYTE
*
ptr
;
rdn
->
rgRDNAttr
=
(
CERT_RDN_ATTR
*
)((
BYTE
*
)
rdn
+
sizeof
(
CERT_RDN
));
nextData
=
(
BYTE
*
)
rdn
->
rgRDNAttr
+
rdn
->
cRDNAttr
*
sizeof
(
CERT_RDN_ATTR
);
for
(
i
=
0
,
ptr
=
pbEncoded
+
2
;
ret
&&
i
<
cRDNAttr
&&
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
];
i
++
)
{
rdn
->
rgRDNAttr
[
i
].
Value
.
pbData
=
nextData
;
size
=
bytesNeeded
;
ret
=
CRYPT_AsnDecodeRdnAttr
(
dwCertEncodingType
,
ptr
,
cbEncoded
-
(
ptr
-
pbEncoded
),
dwFlags
,
&
rdn
->
rgRDNAttr
[
i
],
&
size
);
if
(
ret
)
{
bytesNeeded
-=
size
;
/* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
* have been copied.
*/
if
(
rdn
->
rgRDNAttr
[
i
].
Value
.
pbData
==
nextData
)
nextData
+=
rdn
->
rgRDNAttr
[
i
].
Value
.
cbData
;
/* Ugly: the OID, if copied, is stored in memory after the
* value, so increment by its string length if it's set and
* points here.
*/
if
((
const
BYTE
*
)
rdn
->
rgRDNAttr
[
i
].
pszObjId
==
nextData
)
nextData
+=
strlen
(
rdn
->
rgRDNAttr
[
i
].
pszObjId
)
+
1
;
ptr
+=
ptr
[
1
]
+
2
;
}
}
}
}
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeName
(
DWORD
dwCertEncodingType
,
LPCSTR
lpszStructType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
PCRYPT_DECODE_PARA
pDecodePara
,
void
*
pvStructInfo
,
DWORD
*
pcbStructInfo
)
{
BOOL
ret
=
TRUE
;
DWORD
bytesNeeded
,
cRDN
=
0
;
if
(
!
pbEncoded
||
!
cbEncoded
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
return
FALSE
;
}
if
(
pbEncoded
[
0
]
!=
(
ASN_CONSTRUCTOR
|
ASN_SEQUENCEOF
))
{
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
if
(
cbEncoded
<=
1
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
bytesNeeded
=
sizeof
(
CERT_NAME_INFO
);
if
(
pbEncoded
[
1
])
{
const
BYTE
*
ptr
;
DWORD
size
;
for
(
ptr
=
pbEncoded
+
2
;
ret
&&
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
];
)
{
ret
=
CRYPT_AsnDecodeRdn
(
dwCertEncodingType
,
ptr
,
cbEncoded
-
(
ptr
-
pbEncoded
),
dwFlags
,
NULL
,
&
size
);
if
(
ret
)
{
cRDN
++
;
bytesNeeded
+=
size
;
ptr
+=
ptr
[
1
]
+
2
;
}
}
}
if
(
ret
)
{
CERT_NAME_INFO
*
info
;
if
(
!
pvStructInfo
)
{
*
pcbStructInfo
=
bytesNeeded
;
return
TRUE
;
}
if
(
!
CRYPT_DecodeEnsureSpace
(
dwFlags
,
pDecodePara
,
pvStructInfo
,
pcbStructInfo
,
bytesNeeded
))
return
FALSE
;
if
(
dwFlags
&
CRYPT_DECODE_ALLOC_FLAG
)
pvStructInfo
=
*
(
BYTE
**
)
pvStructInfo
;
info
=
(
CERT_NAME_INFO
*
)
pvStructInfo
;
info
->
cRDN
=
cRDN
;
if
(
info
->
cRDN
==
0
)
info
->
rgRDN
=
NULL
;
else
{
DWORD
size
,
i
;
BYTE
*
nextData
;
const
BYTE
*
ptr
;
info
->
rgRDN
=
(
CERT_RDN
*
)((
BYTE
*
)
pvStructInfo
+
sizeof
(
CERT_NAME_INFO
));
nextData
=
(
BYTE
*
)
info
->
rgRDN
+
info
->
cRDN
*
sizeof
(
CERT_RDN
);
for
(
i
=
0
,
ptr
=
pbEncoded
+
2
;
ret
&&
i
<
cRDN
&&
ptr
-
pbEncoded
-
2
<
pbEncoded
[
1
];
i
++
)
{
info
->
rgRDN
[
i
].
rgRDNAttr
=
(
CERT_RDN_ATTR
*
)
nextData
;
size
=
bytesNeeded
;
ret
=
CRYPT_AsnDecodeRdn
(
dwCertEncodingType
,
ptr
,
cbEncoded
-
(
ptr
-
pbEncoded
),
dwFlags
,
&
info
->
rgRDN
[
i
],
&
size
);
if
(
ret
)
{
nextData
+=
size
;
bytesNeeded
-=
size
;
ptr
+=
ptr
[
1
]
+
2
;
}
}
}
}
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeInt
(
DWORD
dwCertEncodingType
,
LPCSTR
lpszStructType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
PCRYPT_DECODE_PARA
pDecodePara
,
void
*
pvStructInfo
,
DWORD
*
pcbStructInfo
)
...
...
@@ -657,7 +1483,7 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
if
(
!
pbEncoded
||
!
cbEncoded
)
{
SetLastError
(
ERROR_INVALID_PARAMETER
);
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
if
(
!
pvStructInfo
)
...
...
@@ -670,6 +1496,11 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
if
(
cbEncoded
<=
1
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
if
(
pbEncoded
[
1
]
==
0
)
{
SetLastError
(
CRYPT_E_ASN1_CORRUPT
);
...
...
@@ -719,12 +1550,68 @@ static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
} \
} while (0)
static
BOOL
CRYPT_AsnDecodeTimeZone
(
const
BYTE
*
pbEncoded
,
DWORD
len
,
SYSTEMTIME
*
sysTime
)
{
BOOL
ret
=
TRUE
;
if
(
len
>=
3
&&
(
*
pbEncoded
==
'+'
||
*
pbEncoded
==
'-'
))
{
WORD
hours
,
minutes
=
0
;
BYTE
sign
=
*
pbEncoded
++
;
len
--
;
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
2
,
hours
);
if
(
hours
>=
24
)
{
SetLastError
(
CRYPT_E_ASN1_CORRUPT
);
ret
=
FALSE
;
goto
end
;
}
if
(
len
>=
2
)
{
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
2
,
minutes
);
if
(
minutes
>=
60
)
{
SetLastError
(
CRYPT_E_ASN1_CORRUPT
);
ret
=
FALSE
;
goto
end
;
}
}
if
(
sign
==
'+'
)
{
sysTime
->
wHour
+=
hours
;
sysTime
->
wMinute
+=
minutes
;
}
else
{
if
(
hours
>
sysTime
->
wHour
)
{
sysTime
->
wDay
--
;
sysTime
->
wHour
=
24
-
(
hours
-
sysTime
->
wHour
);
}
else
sysTime
->
wHour
-=
hours
;
if
(
minutes
>
sysTime
->
wMinute
)
{
sysTime
->
wHour
--
;
sysTime
->
wMinute
=
60
-
(
minutes
-
sysTime
->
wMinute
);
}
else
sysTime
->
wMinute
-=
minutes
;
}
}
end:
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeUtcTime
(
DWORD
dwCertEncodingType
,
LPCSTR
lpszStructType
,
const
BYTE
*
pbEncoded
,
DWORD
cbEncoded
,
DWORD
dwFlags
,
PCRYPT_DECODE_PARA
pDecodePara
,
void
*
pvStructInfo
,
DWORD
*
pcbStructInfo
)
{
SYSTEMTIME
sysTime
=
{
0
};
BYTE
len
;
BOOL
ret
=
TRUE
;
if
(
!
pbEncoded
||
!
cbEncoded
)
{
...
...
@@ -741,6 +1628,11 @@ static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
if
(
cbEncoded
<=
1
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
len
=
pbEncoded
[
1
];
/* FIXME: magic # */
if
(
len
<
10
)
...
...
@@ -764,19 +1656,22 @@ static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
2
,
sysTime
.
wSecond
);
else
if
(
isdigit
(
*
pbEncoded
))
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
1
,
sysTime
.
wSecond
);
if
(
len
>
0
)
ret
=
CRYPT_AsnDecodeTimeZone
(
pbEncoded
,
len
,
&
sysTime
);
}
if
(
ret
)
{
if
(
!
CRYPT_DecodeEnsureSpace
(
dwFlags
,
pDecodePara
,
pvStructInfo
,
pcbStructInfo
,
sizeof
(
FILETIME
)))
ret
=
FALSE
;
else
{
/* FIXME: get timezone, for now assuming UTC (no adjustment) */
if
(
dwFlags
&
CRYPT_DECODE_ALLOC_FLAG
)
pvStructInfo
=
*
(
BYTE
**
)
pvStructInfo
;
*
pcbStructInfo
=
sizeof
(
FILETIME
);
ret
=
SystemTimeToFileTime
(
&
sysTime
,
(
FILETIME
*
)
pvStructInfo
);
}
}
if
(
!
CRYPT_DecodeEnsureSpace
(
dwFlags
,
pDecodePara
,
pvStructInfo
,
pcbStructInfo
,
sizeof
(
FILETIME
)))
return
FALSE
;
if
(
dwFlags
&
CRYPT_DECODE_ALLOC_FLAG
)
pvStructInfo
=
*
(
BYTE
**
)
pvStructInfo
;
*
pcbStructInfo
=
sizeof
(
FILETIME
);
return
SystemTimeToFileTime
(
&
sysTime
,
(
FILETIME
*
)
pvStructInfo
);
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeGeneralizedTime
(
DWORD
dwCertEncodingType
,
...
...
@@ -785,6 +1680,7 @@ static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
{
SYSTEMTIME
sysTime
=
{
0
};
BYTE
len
;
BOOL
ret
=
TRUE
;
if
(
!
pbEncoded
||
!
cbEncoded
)
{
...
...
@@ -801,6 +1697,11 @@ static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
SetLastError
(
CRYPT_E_ASN1_BADTAG
);
return
FALSE
;
}
if
(
cbEncoded
<=
1
)
{
SetLastError
(
CRYPT_E_ASN1_EOD
);
return
FALSE
;
}
len
=
pbEncoded
[
1
];
/* FIXME: magic # */
if
(
len
<
10
)
...
...
@@ -828,50 +1729,22 @@ static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
digits
,
sysTime
.
wMilliseconds
);
}
if
(
len
>=
5
&&
(
*
pbEncoded
==
'+'
||
*
pbEncoded
==
'-'
))
ret
=
CRYPT_AsnDecodeTimeZone
(
pbEncoded
,
len
,
&
sysTime
);
}
if
(
ret
)
{
if
(
!
CRYPT_DecodeEnsureSpace
(
dwFlags
,
pDecodePara
,
pvStructInfo
,
pcbStructInfo
,
sizeof
(
FILETIME
)))
ret
=
FALSE
;
else
{
WORD
hours
,
minutes
;
BYTE
sign
=
*
pbEncoded
++
;
len
--
;
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
2
,
hours
);
if
(
hours
>=
24
)
return
CRYPT_E_ASN1_CORRUPT
;
CRYPT_TIME_GET_DIGITS
(
pbEncoded
,
len
,
2
,
minutes
);
if
(
minutes
>=
60
)
return
CRYPT_E_ASN1_CORRUPT
;
if
(
sign
==
'+'
)
{
sysTime
.
wHour
+=
hours
;
sysTime
.
wMinute
+=
minutes
;
}
else
{
if
(
hours
>
sysTime
.
wHour
)
{
sysTime
.
wDay
--
;
sysTime
.
wHour
=
24
-
(
hours
-
sysTime
.
wHour
);
}
else
sysTime
.
wHour
-=
hours
;
if
(
minutes
>
sysTime
.
wMinute
)
{
sysTime
.
wHour
--
;
sysTime
.
wMinute
=
60
-
(
minutes
-
sysTime
.
wMinute
);
}
else
sysTime
.
wMinute
-=
minutes
;
}
if
(
dwFlags
&
CRYPT_DECODE_ALLOC_FLAG
)
pvStructInfo
=
*
(
BYTE
**
)
pvStructInfo
;
*
pcbStructInfo
=
sizeof
(
FILETIME
);
ret
=
SystemTimeToFileTime
(
&
sysTime
,
(
FILETIME
*
)
pvStructInfo
);
}
}
if
(
!
CRYPT_DecodeEnsureSpace
(
dwFlags
,
pDecodePara
,
pvStructInfo
,
pcbStructInfo
,
sizeof
(
FILETIME
)))
return
FALSE
;
if
(
dwFlags
&
CRYPT_DECODE_ALLOC_FLAG
)
pvStructInfo
=
*
(
BYTE
**
)
pvStructInfo
;
*
pcbStructInfo
=
sizeof
(
FILETIME
);
return
SystemTimeToFileTime
(
&
sysTime
,
(
FILETIME
*
)
pvStructInfo
);
return
ret
;
}
static
BOOL
WINAPI
CRYPT_AsnDecodeChoiceOfTime
(
DWORD
dwCertEncodingType
,
...
...
@@ -940,6 +1813,9 @@ BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
{
switch
(
LOWORD
(
lpszStructType
))
{
case
(
WORD
)
X509_NAME
:
decodeFunc
=
CRYPT_AsnDecodeName
;
break
;
case
(
WORD
)
X509_INTEGER
:
decodeFunc
=
CRYPT_AsnDecodeInt
;
break
;
...
...
dlls/crypt32/tests/encode.c
View file @
4d7e1e4b
...
...
@@ -42,7 +42,7 @@ static const struct encodedInt ints[] = {
{
0xbaddf00d
,
{
2
,
4
,
0xba
,
0xdd
,
0xf0
,
0x0d
}
},
};
static
void
test_encodeint
(
void
)
static
void
test_encodeint
(
DWORD
dwEncoding
)
{
DWORD
bufSize
=
0
;
int
i
;
...
...
@@ -60,33 +60,35 @@ static void test_encodeint(void)
/* check with NULL integer buffer. Windows XP incorrectly returns an
* NTSTATUS.
*/
ret
=
CryptEncodeObjectEx
(
X509_ASN_ENCODING
,
X509_INTEGER
,
NULL
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
!
ret
&&
(
GetLastError
()
==
ERROR_INVALID_PARAMETER
||
GetLastError
()
==
STATUS_ACCESS_VIOLATION
),
"Unexpected error code %ld
\n
"
,
GetLastError
());
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
NULL
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
!
ret
&&
GetLastError
()
==
STATUS_ACCESS_VIOLATION
,
"Expected STATUS_ACCESS_VIOLATION, got %08lx
\n
"
,
GetLastError
());
for
(
i
=
0
;
i
<
sizeof
(
ints
)
/
sizeof
(
ints
[
0
]);
i
++
)
{
BYTE
*
buf
=
NULL
;
ret
=
CryptEncodeObjectEx
(
X509_ASN_ENCODING
|
PKCS_7_ASN_ENCODING
,
X509_INTEGER
,
&
ints
[
i
].
val
,
0
,
NULL
,
NULL
,
&
bufSize
);
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
&
ints
[
i
].
val
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
ret
,
"Expected success, got %ld
\n
"
,
GetLastError
());
ret
=
CryptEncodeObjectEx
(
X509_ASN_ENCODING
|
PKCS_7_ASN_ENCODING
,
X509_INTEGER
,
&
ints
[
i
].
val
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
&
ints
[
i
].
val
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
ret
,
"CryptEncodeObjectEx failed: %ld
\n
"
,
GetLastError
());
ok
(
buf
[
0
]
==
2
,
"Got unexpected type %d for integer (expected 2)
\n
"
,
buf
[
0
]);
ok
(
!
memcmp
(
buf
+
1
,
ints
[
i
].
encoded
+
1
,
ints
[
i
].
encoded
[
1
]
+
1
),
"Encoded value of 0x%08x didn't match expected
\n
"
,
ints
[
i
].
val
);
LocalFree
(
buf
);
if
(
buf
)
{
ok
(
buf
[
0
]
==
2
,
"Got unexpected type %d for integer (expected 2)
\n
"
,
buf
[
0
]);
ok
(
!
memcmp
(
buf
+
1
,
ints
[
i
].
encoded
+
1
,
ints
[
i
].
encoded
[
1
]
+
1
),
"Encoded value of 0x%08x didn't match expected
\n
"
,
ints
[
i
].
val
);
LocalFree
(
buf
);
}
}
}
static
void
test_decodeint
(
void
)
static
void
test_decodeint
(
DWORD
dwEncoding
)
{
static
const
char
bigInt
[]
=
{
2
,
5
,
0xff
,
0xfe
,
0xff
,
0xfe
,
0xff
};
static
const
char
testStr
[]
=
{
16
,
4
,
't'
,
'e'
,
's'
,
't'
};
static
const
char
testStr
[]
=
{
0x
16
,
4
,
't'
,
'e'
,
's'
,
't'
};
BYTE
*
buf
=
NULL
;
DWORD
bufSize
=
0
;
int
i
;
...
...
@@ -101,36 +103,33 @@ static void test_decodeint(void)
ints
[
0
].
encoded
[
1
]
+
2
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
!
ret
&&
GetLastError
()
==
ERROR_FILE_NOT_FOUND
,
"Expected ERROR_FILE_NOT_FOUND, got %ld
\n
"
,
GetLastError
());
/* check with NULL integer buffer. Windows XP returns an apparently random
* error code (0x01c567df).
*/
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
,
X509_INTEGER
,
NULL
,
0
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
!
ret
,
"Expected failure, got success
\n
"
);
/* check with NULL integer buffer */
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
NULL
,
0
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
!
ret
&&
GetLastError
()
==
CRYPT_E_ASN1_EOD
,
"Expected CRYPT_E_ASN1_EOD, got %08lx
\n
"
,
GetLastError
());
/* check with a valid, but too large, integer */
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
|
PKCS_7_ASN_ENCODING
,
X509_INTEGER
,
bigInt
,
bigInt
[
1
]
+
2
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
bigInt
,
bigInt
[
1
]
+
2
,
CRYPT_DECODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
!
ret
&&
GetLastError
()
==
CRYPT_E_ASN1_LARGE
,
"Expected CRYPT_E_ASN1_LARGE, got %ld
\n
"
,
GetLastError
());
/* check with a DER-encoded string */
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
|
PKCS_7_ASN_ENCODING
,
X509_INTEGER
,
testStr
,
testStr
[
1
]
+
2
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
testStr
,
testStr
[
1
]
+
2
,
CRYPT_DECODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
!
ret
&&
GetLastError
()
==
CRYPT_E_ASN1_BADTAG
,
"Expected CRYPT_E_ASN1_BADTAG, got %ld
\n
"
,
GetLastError
());
for
(
i
=
0
;
i
<
sizeof
(
ints
)
/
sizeof
(
ints
[
0
]);
i
++
)
{
/* When the output buffer is NULL, this always succeeds */
SetLastError
(
0xdeadbeef
);
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
,
X509_INTEGER
,
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
(
BYTE
*
)
&
ints
[
i
].
encoded
,
ints
[
i
].
encoded
[
1
]
+
2
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
ret
&&
GetLastError
()
==
NOERROR
,
"Expected success and NOERROR, got %ld
\n
"
,
GetLastError
());
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
|
PKCS_7_ASN_ENCODING
,
X509_INTEGER
,
(
BYTE
*
)
&
ints
[
i
].
encoded
,
ints
[
i
].
encoded
[
1
]
+
2
,
CRYPT_
EN
CODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_INTEGER
,
(
BYTE
*
)
&
ints
[
i
].
encoded
,
ints
[
i
].
encoded
[
1
]
+
2
,
CRYPT_
DE
CODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
ret
,
"CryptDecodeObjectEx failed: %ld
\n
"
,
GetLastError
());
ok
(
bufSize
==
sizeof
(
int
),
"Expected size %d, got %ld
\n
"
,
sizeof
(
int
),
bufSize
);
...
...
@@ -150,7 +149,7 @@ struct encodedFiletime
BYTE
*
encodedTime
;
};
static
void
testTimeEncoding
(
LPCSTR
encoding
,
static
void
testTimeEncoding
(
DWORD
dwEncoding
,
LPCSTR
structType
,
const
struct
encodedFiletime
*
time
)
{
FILETIME
ft
=
{
0
};
...
...
@@ -160,15 +159,12 @@ static void testTimeEncoding(LPCSTR encoding,
ret
=
SystemTimeToFileTime
(
&
time
->
sysTime
,
&
ft
);
ok
(
ret
,
"SystemTimeToFileTime failed: %ld
\n
"
,
GetLastError
());
/* No test case, but both X509_ASN_ENCODING and PKCS_7_ASN_ENCODING have
* the same effect for time encodings.
*/
ret
=
CryptEncodeObjectEx
(
X509_ASN_ENCODING
,
encoding
,
&
ft
,
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
structType
,
&
ft
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
/* years other than 1950-2050 are not allowed for encodings other than
* X509_CHOICE_OF_TIME.
*/
if
(
encoding
==
X509_CHOICE_OF_TIME
||
if
(
structType
==
X509_CHOICE_OF_TIME
||
(
time
->
sysTime
.
wYear
>=
1950
&&
time
->
sysTime
.
wYear
<=
2050
))
{
ok
(
ret
,
"CryptEncodeObjectEx failed: %ld (0x%08lx)
\n
"
,
GetLastError
(),
...
...
@@ -191,7 +187,7 @@ static void testTimeEncoding(LPCSTR encoding,
"Expected CRYPT_E_BAD_ENCODE, got 0x%08lx
\n
"
,
GetLastError
());
}
static
void
testTimeDecoding
(
LPCSTR
encoding
,
static
void
testTimeDecoding
(
DWORD
dwEncoding
,
LPCSTR
structType
,
const
struct
encodedFiletime
*
time
)
{
FILETIME
ft1
=
{
0
},
ft2
=
{
0
};
...
...
@@ -200,15 +196,12 @@ static void testTimeDecoding(LPCSTR encoding,
ret
=
SystemTimeToFileTime
(
&
time
->
sysTime
,
&
ft1
);
ok
(
ret
,
"SystemTimeToFileTime failed: %ld
\n
"
,
GetLastError
());
/* No test case, but both X509_ASN_ENCODING and PKCS_7_ASN_ENCODING have
* the same effect for time encodings.
*/
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
,
encoding
,
time
->
encodedTime
,
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
structType
,
time
->
encodedTime
,
time
->
encodedTime
[
1
]
+
2
,
0
,
NULL
,
&
ft2
,
&
size
);
/* years other than 1950-2050 are not allowed for encodings other than
* X509_CHOICE_OF_TIME.
*/
if
(
encoding
==
X509_CHOICE_OF_TIME
||
if
(
structType
==
X509_CHOICE_OF_TIME
||
(
time
->
sysTime
.
wYear
>=
1950
&&
time
->
sysTime
.
wYear
<=
2050
))
{
ok
(
ret
,
"CryptDecodeObjectEx failed: %ld (0x%08lx)
\n
"
,
GetLastError
(),
...
...
@@ -227,19 +220,19 @@ static const struct encodedFiletime times[] = {
{
{
2145
,
6
,
1
,
6
,
16
,
10
,
0
,
0
},
"
\x18
"
"
\x0f
"
"21450606161000Z"
},
};
static
void
test_encodeFiletime
(
void
)
static
void
test_encodeFiletime
(
DWORD
dwEncoding
)
{
DWORD
i
;
for
(
i
=
0
;
i
<
sizeof
(
times
)
/
sizeof
(
times
[
0
]);
i
++
)
{
testTimeEncoding
(
X509_CHOICE_OF_TIME
,
&
times
[
i
]);
testTimeEncoding
(
PKCS_UTC_TIME
,
&
times
[
i
]);
testTimeEncoding
(
szOID_RSA_signingTime
,
&
times
[
i
]);
testTimeEncoding
(
dwEncoding
,
X509_CHOICE_OF_TIME
,
&
times
[
i
]);
testTimeEncoding
(
dwEncoding
,
PKCS_UTC_TIME
,
&
times
[
i
]);
testTimeEncoding
(
dwEncoding
,
szOID_RSA_signingTime
,
&
times
[
i
]);
}
}
static
void
test_decodeFiletime
(
void
)
static
void
test_decodeFiletime
(
DWORD
dwEncoding
)
{
static
const
struct
encodedFiletime
otherTimes
[]
=
{
{
{
1945
,
6
,
1
,
6
,
16
,
10
,
0
,
0
},
"
\x18
"
"
\x13
"
"19450606161000.000Z"
},
...
...
@@ -249,6 +242,11 @@ static void test_decodeFiletime(void)
{
{
1945
,
6
,
1
,
6
,
14
,
55
,
0
,
0
},
"
\x18
"
"
\x13
"
"19450606161000-0115"
},
{
{
2145
,
6
,
1
,
6
,
16
,
0
,
0
,
0
},
"
\x18
"
"
\x0a
"
"2145060616"
},
{
{
2045
,
6
,
1
,
6
,
16
,
10
,
0
,
0
},
"
\x17
"
"
\x0a
"
"4506061610"
},
{
{
2045
,
6
,
1
,
6
,
16
,
10
,
0
,
0
},
"
\x17
"
"
\x0b
"
"4506061610Z"
},
{
{
2045
,
6
,
1
,
6
,
17
,
10
,
0
,
0
},
"
\x17
"
"
\x0d
"
"4506061610+01"
},
{
{
2045
,
6
,
1
,
6
,
15
,
10
,
0
,
0
},
"
\x17
"
"
\x0d
"
"4506061610-01"
},
{
{
2045
,
6
,
1
,
6
,
17
,
10
,
0
,
0
},
"
\x17
"
"
\x0f
"
"4506061610+0100"
},
{
{
2045
,
6
,
1
,
6
,
15
,
10
,
0
,
0
},
"
\x17
"
"
\x0f
"
"4506061610-0100"
},
};
/* An oddball case that succeeds in Windows, but doesn't seem correct
{ { 2145, 6, 1, 2, 11, 31, 0, 0 }, "\x18" "\x13" "21450606161000-9999" },
...
...
@@ -270,33 +268,322 @@ static void test_decodeFiletime(void)
ret
=
SystemTimeToFileTime
(
&
times
[
0
].
sysTime
,
&
ft1
);
ok
(
ret
,
"SystemTimeToFileTime failed: %ld
\n
"
,
GetLastError
());
size
=
1
;
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
,
X509_CHOICE_OF_TIME
,
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_CHOICE_OF_TIME
,
times
[
0
].
encodedTime
,
times
[
0
].
encodedTime
[
1
]
+
2
,
0
,
NULL
,
&
ft2
,
&
size
);
ok
(
!
ret
&&
GetLastError
()
==
ERROR_MORE_DATA
,
"Expected ERROR_MORE_DATA, got %ld
\n
"
,
GetLastError
());
/* Normal tests */
for
(
i
=
0
;
i
<
sizeof
(
times
)
/
sizeof
(
times
[
0
]);
i
++
)
{
testTimeDecoding
(
X509_CHOICE_OF_TIME
,
&
times
[
i
]);
testTimeDecoding
(
PKCS_UTC_TIME
,
&
times
[
i
]);
testTimeDecoding
(
szOID_RSA_signingTime
,
&
times
[
i
]);
testTimeDecoding
(
dwEncoding
,
X509_CHOICE_OF_TIME
,
&
times
[
i
]);
testTimeDecoding
(
dwEncoding
,
PKCS_UTC_TIME
,
&
times
[
i
]);
testTimeDecoding
(
dwEncoding
,
szOID_RSA_signingTime
,
&
times
[
i
]);
}
for
(
i
=
0
;
i
<
sizeof
(
otherTimes
)
/
sizeof
(
otherTimes
[
0
]);
i
++
)
{
testTimeDecoding
(
X509_CHOICE_OF_TIME
,
&
otherTimes
[
i
]);
testTimeDecoding
(
PKCS_UTC_TIME
,
&
otherTimes
[
i
]);
testTimeDecoding
(
szOID_RSA_signingTime
,
&
otherTimes
[
i
]);
testTimeDecoding
(
dwEncoding
,
X509_CHOICE_OF_TIME
,
&
otherTimes
[
i
]);
testTimeDecoding
(
dwEncoding
,
PKCS_UTC_TIME
,
&
otherTimes
[
i
]);
testTimeDecoding
(
dwEncoding
,
szOID_RSA_signingTime
,
&
otherTimes
[
i
]);
}
for
(
i
=
0
;
i
<
sizeof
(
bogusTimes
)
/
sizeof
(
bogusTimes
[
0
]);
i
++
)
{
size
=
sizeof
(
ft1
);
ret
=
CryptDecodeObjectEx
(
X509_ASN_ENCODING
,
X509_CHOICE_OF_TIME
,
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_CHOICE_OF_TIME
,
bogusTimes
[
i
],
bogusTimes
[
i
][
1
]
+
2
,
0
,
NULL
,
&
ft1
,
&
size
);
ok
(
!
ret
&&
GetLastError
()
==
CRYPT_E_ASN1_CORRUPT
,
"Expected CRYPT_E_ASN1_CORRUPT, got %08lx
\n
"
,
GetLastError
());
}
}
struct
EncodedName
{
CERT_RDN_ATTR
attr
;
BYTE
*
encoded
;
};
static
const
char
commonName
[]
=
"Juan Lang"
;
static
const
char
surName
[]
=
"Lang"
;
static
const
char
bogusIA5
[]
=
"
\x80
"
;
static
const
char
bogusPrintable
[]
=
"~"
;
static
const
char
bogusNumeric
[]
=
"A"
;
static
const
struct
EncodedName
names
[]
=
{
{
{
szOID_COMMON_NAME
,
CERT_RDN_PRINTABLE_STRING
,
{
sizeof
(
commonName
),
(
BYTE
*
)
commonName
}
},
"
\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x13\x0a
Juan Lang"
},
{
{
szOID_COMMON_NAME
,
CERT_RDN_IA5_STRING
,
{
sizeof
(
commonName
),
(
BYTE
*
)
commonName
}
},
"
\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x16\x0a
Juan Lang"
},
{
{
szOID_SUR_NAME
,
CERT_RDN_IA5_STRING
,
{
sizeof
(
surName
),
(
BYTE
*
)
surName
}
},
"
\x30\x10\x31\x0e\x30\x0c\x06\x03\x55\x04\x04\x16\x05
Lang"
},
{
{
NULL
,
CERT_RDN_PRINTABLE_STRING
,
{
sizeof
(
commonName
),
(
BYTE
*
)
commonName
}
},
"
\x30\x12\x31\x10\x30\x0e\x06\x00\x13\x0a
Juan Lang"
},
/* The following test isn't a very good one, because it doesn't encode any
* Japanese characters. I'm leaving it out for now.
{ { szOID_COMMON_NAME, CERT_RDN_T61_STRING,
{ sizeof(commonName), (BYTE *)commonName } },
"\x30\x15\x31\x13\x30\x11\x06\x03\x55\x04\x03\x14\x0aJuan Lang" },
*/
/* The following tests succeed under Windows, but really should fail,
* they contain characters that are illegal for the encoding. I'm
* including them to justify my lazy encoding.
*/
{
{
szOID_COMMON_NAME
,
CERT_RDN_IA5_STRING
,
{
sizeof
(
bogusIA5
),
(
BYTE
*
)
bogusIA5
}
},
"
\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x16\x02\x80
"
},
{
{
szOID_COMMON_NAME
,
CERT_RDN_PRINTABLE_STRING
,
{
sizeof
(
bogusPrintable
),
(
BYTE
*
)
bogusPrintable
}
},
"
\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x13\x02\x7e
"
},
{
{
szOID_COMMON_NAME
,
CERT_RDN_NUMERIC_STRING
,
{
sizeof
(
bogusNumeric
),
(
BYTE
*
)
bogusNumeric
}
},
"
\x30\x0d\x31\x0b\x30\x09\x06\x03\x55\x04\x03\x12\x02\x41
"
},
};
static
const
BYTE
emptyName
[]
=
{
0x30
,
0
};
static
const
BYTE
emptyRDNs
[]
=
{
0x30
,
0x02
,
0x31
,
0
};
static
const
BYTE
twoRDNs
[]
=
"
\x30\x23\x31\x21\x30\x0c\x06\x03\x55\x04\x04
"
"
\x13\x05\x4c\x61\x6e\x67\x00\x30\x11\x06\x03\x55\x04\x03
"
"
\x13\x0a\x4a\x75\x61\x6e\x20\x4c\x61\x6e\x67
"
;
static
void
test_encodeName
(
DWORD
dwEncoding
)
{
CERT_RDN_ATTR
attrs
[
2
];
CERT_RDN
rdn
;
CERT_NAME_INFO
info
;
BYTE
*
buf
=
NULL
;
DWORD
size
=
0
,
i
;
BOOL
ret
;
/* Test with NULL pvStructInfo */
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
NULL
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
!
ret
&&
GetLastError
()
==
STATUS_ACCESS_VIOLATION
,
"Expected STATUS_ACCESS_VIOLATION, got %08lx
\n
"
,
GetLastError
());
/* Test with empty CERT_NAME_INFO */
info
.
cRDN
=
0
;
info
.
rgRDN
=
NULL
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
ret
,
"CryptEncodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
if
(
buf
)
{
ok
(
!
memcmp
(
buf
,
emptyName
,
sizeof
(
emptyName
)),
"Got unexpected encoding for empty name
\n
"
);
LocalFree
(
buf
);
}
/* Test with bogus CERT_RDN */
info
.
cRDN
=
1
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
!
ret
&&
GetLastError
()
==
STATUS_ACCESS_VIOLATION
,
"Expected STATUS_ACCESS_VIOLATION, got %08lx
\n
"
,
GetLastError
());
/* Test with empty CERT_RDN */
rdn
.
cRDNAttr
=
0
;
rdn
.
rgRDNAttr
=
NULL
;
info
.
cRDN
=
1
;
info
.
rgRDN
=
&
rdn
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
ret
,
"CryptEncodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
if
(
buf
)
{
ok
(
!
memcmp
(
buf
,
emptyRDNs
,
sizeof
(
emptyRDNs
)),
"Got unexpected encoding for empty RDN array
\n
"
);
LocalFree
(
buf
);
}
/* Test with bogus attr array */
rdn
.
cRDNAttr
=
1
;
rdn
.
rgRDNAttr
=
NULL
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
!
ret
&&
GetLastError
()
==
STATUS_ACCESS_VIOLATION
,
"Expected STATUS_ACCESS_VIOLATION, got %08lx
\n
"
,
GetLastError
());
/* oddly, a bogus OID is accepted by Windows XP; not testing.
attrs[0].pszObjId = "bogus";
attrs[0].dwValueType = CERT_RDN_PRINTABLE_STRING;
attrs[0].Value.cbData = sizeof(commonName);
attrs[0].Value.pbData = (BYTE *)commonName;
rdn.cRDNAttr = 1;
rdn.rgRDNAttr = attrs;
ret = CryptEncodeObjectEx(dwEncoding, X509_NAME, &info,
CRYPT_ENCODE_ALLOC_FLAG, NULL, (BYTE *)&buf, &size);
ok(!ret, "Expected failure, got success\n");
*/
/* Check with two CERT_RDN_ATTRs. Note DER encoding forces the order of
* the encoded attributes to be swapped.
*/
attrs
[
0
].
pszObjId
=
szOID_COMMON_NAME
;
attrs
[
0
].
dwValueType
=
CERT_RDN_PRINTABLE_STRING
;
attrs
[
0
].
Value
.
cbData
=
sizeof
(
commonName
);
attrs
[
0
].
Value
.
pbData
=
(
BYTE
*
)
commonName
;
attrs
[
1
].
pszObjId
=
szOID_SUR_NAME
;
attrs
[
1
].
dwValueType
=
CERT_RDN_PRINTABLE_STRING
;
attrs
[
1
].
Value
.
cbData
=
sizeof
(
surName
);
attrs
[
1
].
Value
.
pbData
=
(
BYTE
*
)
surName
;
rdn
.
cRDNAttr
=
2
;
rdn
.
rgRDNAttr
=
attrs
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
ret
,
"CryptEncodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
if
(
buf
)
{
ok
(
!
memcmp
(
buf
,
twoRDNs
,
sizeof
(
twoRDNs
)),
"Got unexpected encoding for two RDN array
\n
"
);
LocalFree
(
buf
);
}
/* CERT_RDN_ANY_TYPE is too vague for X509_NAMEs, check the return */
rdn
.
cRDNAttr
=
1
;
attrs
[
0
].
dwValueType
=
CERT_RDN_ANY_TYPE
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
!
ret
&&
GetLastError
()
==
HRESULT_FROM_WIN32
(
ERROR_INVALID_PARAMETER
),
"Expected ERROR_INVALID_PARAMETER, got %08lx
\n
"
,
GetLastError
());
for
(
i
=
0
;
i
<
sizeof
(
names
)
/
sizeof
(
names
[
0
]);
i
++
)
{
rdn
.
cRDNAttr
=
1
;
rdn
.
rgRDNAttr
=
(
CERT_RDN_ATTR
*
)
&
names
[
i
].
attr
;
ret
=
CryptEncodeObjectEx
(
dwEncoding
,
X509_NAME
,
&
info
,
CRYPT_ENCODE_ALLOC_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
size
);
ok
(
ret
,
"CryptEncodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
if
(
buf
)
{
ok
(
size
==
names
[
i
].
encoded
[
1
]
+
2
,
"Expected size %d, got %ld
\n
"
,
names
[
i
].
encoded
[
1
]
+
2
,
size
);
ok
(
!
memcmp
(
buf
,
names
[
i
].
encoded
,
names
[
i
].
encoded
[
1
]
+
2
),
"Got unexpected encoding
\n
"
);
LocalFree
(
buf
);
}
}
}
static
void
compareNames
(
const
CERT_NAME_INFO
*
expected
,
const
CERT_NAME_INFO
*
got
)
{
ok
(
got
->
cRDN
==
expected
->
cRDN
,
"Expected %ld RDNs, got %ld
\n
"
,
expected
->
cRDN
,
got
->
cRDN
);
if
(
expected
->
cRDN
)
{
ok
(
got
->
rgRDN
[
0
].
cRDNAttr
==
expected
->
rgRDN
[
0
].
cRDNAttr
,
"Expected %ld RDN attrs, got %ld
\n
"
,
expected
->
rgRDN
[
0
].
cRDNAttr
,
got
->
rgRDN
[
0
].
cRDNAttr
);
if
(
expected
->
rgRDN
[
0
].
cRDNAttr
)
{
if
(
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
&&
strlen
(
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
))
{
ok
(
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
!=
NULL
,
"Expected OID %s, got NULL
\n
"
,
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
);
if
(
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
)
ok
(
!
strcmp
(
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
,
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
),
"Got unexpected OID %s, expected %s
\n
"
,
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
,
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
pszObjId
);
}
ok
(
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
cbData
==
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
cbData
,
"Unexpected data size, got %ld, expected %ld
\n
"
,
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
cbData
,
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
cbData
);
if
(
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
pbData
)
ok
(
!
memcmp
(
got
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
pbData
,
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
pbData
,
expected
->
rgRDN
[
0
].
rgRDNAttr
[
0
].
Value
.
cbData
),
"Unexpected value
\n
"
);
}
}
}
static
void
test_decodeName
(
DWORD
dwEncoding
)
{
int
i
;
BYTE
*
buf
=
NULL
;
DWORD
bufSize
=
0
;
BOOL
ret
;
CERT_RDN
rdn
;
CERT_NAME_INFO
info
=
{
1
,
&
rdn
};
for
(
i
=
0
;
i
<
sizeof
(
names
)
/
sizeof
(
names
[
0
]);
i
++
)
{
/* When the output buffer is NULL, this always succeeds */
SetLastError
(
0xdeadbeef
);
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_NAME
,
names
[
i
].
encoded
,
names
[
i
].
encoded
[
1
]
+
2
,
0
,
NULL
,
NULL
,
&
bufSize
);
ok
(
ret
&&
GetLastError
()
==
NOERROR
,
"Expected success and NOERROR, got %08lx
\n
"
,
GetLastError
());
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_NAME
,
names
[
i
].
encoded
,
names
[
i
].
encoded
[
1
]
+
2
,
CRYPT_DECODE_ALLOC_FLAG
|
CRYPT_DECODE_SHARE_OID_STRING_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
ret
,
"CryptDecodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
rdn
.
cRDNAttr
=
1
;
rdn
.
rgRDNAttr
=
(
CERT_RDN_ATTR
*
)
&
names
[
i
].
attr
;
if
(
buf
)
{
compareNames
((
CERT_NAME_INFO
*
)
buf
,
&
info
);
LocalFree
(
buf
);
}
}
/* test empty name */
bufSize
=
0
;
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_NAME
,
emptyName
,
emptyName
[
1
]
+
2
,
CRYPT_DECODE_ALLOC_FLAG
|
CRYPT_DECODE_SHARE_OID_STRING_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
ret
,
"CryptDecodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
/* Interestingly, in Windows, if cRDN is 0, rgRGN may not be NULL. My
* decoder works the same way, so only test the count.
*/
if
(
buf
)
{
ok
(
bufSize
==
sizeof
(
CERT_NAME_INFO
),
"Expected bufSize %d, got %ld
\n
"
,
sizeof
(
CERT_NAME_INFO
),
bufSize
);
ok
(((
CERT_NAME_INFO
*
)
buf
)
->
cRDN
==
0
,
"Expected 0 RDNs in empty info, got %ld
\n
"
,
((
CERT_NAME_INFO
*
)
buf
)
->
cRDN
);
LocalFree
(
buf
);
}
/* test empty RDN */
bufSize
=
0
;
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_NAME
,
emptyRDNs
,
emptyRDNs
[
1
]
+
2
,
CRYPT_DECODE_ALLOC_FLAG
|
CRYPT_DECODE_SHARE_OID_STRING_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
ret
,
"CryptDecodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
if
(
buf
)
{
CERT_NAME_INFO
*
info
=
(
CERT_NAME_INFO
*
)
buf
;
ok
(
bufSize
==
sizeof
(
CERT_NAME_INFO
)
+
sizeof
(
CERT_RDN
)
&&
info
->
cRDN
==
1
&&
info
->
rgRDN
&&
info
->
rgRDN
[
0
].
cRDNAttr
==
0
,
"Got unexpected value for empty RDN
\n
"
);
LocalFree
(
buf
);
}
/* test two RDN attrs */
bufSize
=
0
;
ret
=
CryptDecodeObjectEx
(
dwEncoding
,
X509_NAME
,
twoRDNs
,
twoRDNs
[
1
]
+
2
,
CRYPT_DECODE_ALLOC_FLAG
|
CRYPT_DECODE_SHARE_OID_STRING_FLAG
,
NULL
,
(
BYTE
*
)
&
buf
,
&
bufSize
);
ok
(
ret
,
"CryptDecodeObjectEx failed: %08lx
\n
"
,
GetLastError
());
if
(
buf
)
{
CERT_RDN_ATTR
attrs
[]
=
{
{
szOID_SUR_NAME
,
CERT_RDN_PRINTABLE_STRING
,
{
sizeof
(
surName
),
(
BYTE
*
)
surName
}
},
{
szOID_COMMON_NAME
,
CERT_RDN_PRINTABLE_STRING
,
{
sizeof
(
commonName
),
(
BYTE
*
)
commonName
}
},
};
rdn
.
cRDNAttr
=
sizeof
(
attrs
)
/
sizeof
(
attrs
[
0
]);
rdn
.
rgRDNAttr
=
attrs
;
compareNames
((
CERT_NAME_INFO
*
)
buf
,
&
info
);
LocalFree
(
buf
);
}
}
static
void
test_registerOIDFunction
(
void
)
{
static
const
WCHAR
bogusDll
[]
=
{
'b'
,
'o'
,
'g'
,
'u'
,
's'
,
'.'
,
'd'
,
'l'
,
'l'
,
0
};
...
...
@@ -353,9 +640,18 @@ static void test_registerOIDFunction(void)
START_TEST
(
encode
)
{
test_encodeint
();
test_decodeint
();
test_encodeFiletime
();
test_decodeFiletime
();
static
const
DWORD
encodings
[]
=
{
X509_ASN_ENCODING
,
PKCS_7_ASN_ENCODING
,
X509_ASN_ENCODING
|
PKCS_7_ASN_ENCODING
};
DWORD
i
;
for
(
i
=
0
;
i
<
sizeof
(
encodings
)
/
sizeof
(
encodings
[
0
]);
i
++
)
{
test_encodeint
(
encodings
[
i
]);
test_decodeint
(
encodings
[
i
]);
test_encodeFiletime
(
encodings
[
i
]);
test_decodeFiletime
(
encodings
[
i
]);
test_encodeName
(
encodings
[
i
]);
test_decodeName
(
encodings
[
i
]);
}
test_registerOIDFunction
();
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment