Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
62
third_party/FreeRDP/libfreerdp/crypto/CMakeLists.txt
vendored
Normal file
62
third_party/FreeRDP/libfreerdp/crypto/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
# FreeRDP: A Remote Desktop Protocol Implementation
|
||||
# libfreerdp-crypto cmake build script
|
||||
#
|
||||
# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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.
|
||||
|
||||
set(MODULE_NAME "freerdp-crypto")
|
||||
set(MODULE_PREFIX "FREERDP_CRYPTO")
|
||||
|
||||
freerdp_module_add(
|
||||
ber.c
|
||||
per.c
|
||||
base64.c
|
||||
x509_utils.c
|
||||
x509_utils.h
|
||||
cert_common.h
|
||||
cert_common.c
|
||||
privatekey.c
|
||||
privatekey.h
|
||||
certificate.c
|
||||
certificate.h
|
||||
certificate_data.c
|
||||
certificate_store.c
|
||||
crypto.c
|
||||
tls.c
|
||||
tls.h
|
||||
opensslcompat.c
|
||||
)
|
||||
|
||||
if(NOT WITHOUT_FREERDP_3x_DEPRECATED)
|
||||
freerdp_module_add(er.c der.c)
|
||||
endif()
|
||||
|
||||
freerdp_include_directory_add(${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
freerdp_library_add(${OPENSSL_LIBRARIES})
|
||||
freerdp_pc_add_requires_private("libssl")
|
||||
|
||||
if(MBEDTLS_FOUND)
|
||||
freerdp_include_directory_add(${MBEDTLS_INCLUDE_DIR})
|
||||
freerdp_library_add(${MBEDTLS_LIBRARIES})
|
||||
freerdp_pc_add_requires_private("mbedtls")
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
freerdp_library_add(ws2_32)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
555
third_party/FreeRDP/libfreerdp/crypto/base64.c
vendored
Normal file
555
third_party/FreeRDP/libfreerdp/crypto/base64.c
vendored
Normal file
@@ -0,0 +1,555 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Base64 Encoding & Decoding
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
static const BYTE enc_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const BYTE enc_base64url[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
static const signed char dec_base64url[] = {
|
||||
-1, /* 0 000 00 00000000 NUL � Null character */
|
||||
-1, /* 1 001 01 00000001 SOH  Start of Heading */
|
||||
-1, /* 2 002 02 00000010 STX  Start of Text */
|
||||
-1, /* 3 003 03 00000011 ETX  End of Text */
|
||||
-1, /* 4 004 04 00000100 EOT  End of Transmission */
|
||||
-1, /* 5 005 05 00000101 ENQ  Enquiry */
|
||||
-1, /* 6 006 06 00000110 ACK  Acknowledge */
|
||||
-1, /* 7 007 07 00000111 BEL  Bell, Alert */
|
||||
-1, /* 8 010 08 00001000 BS  Backspace */
|
||||
-1, /* 9 011 09 00001001 HT 	 Horizontal Tab */
|
||||
-1, /* 10 012 0A 00001010 LF Line Feed */
|
||||
-1, /* 11 013 0B 00001011 VT  Vertical Tabulation */
|
||||
-1, /* 12 014 0C 00001100 FF  Form Feed */
|
||||
-1, /* 13 015 0D 00001101 CR Carriage Return */
|
||||
-1, /* 14 016 0E 00001110 SO  Shift Out */
|
||||
-1, /* 15 017 0F 00001111 SI  Shift In */
|
||||
-1, /* 16 020 10 00010000 DLE  Data Link Escape */
|
||||
-1, /* 17 021 11 00010001 DC1  Device Control One (XON) */
|
||||
-1, /* 18 022 12 00010010 DC2  Device Control Two */
|
||||
-1, /* 19 023 13 00010011 DC3  Device Control Three (XOFF) */
|
||||
-1, /* 20 024 14 00010100 DC4  Device Control Four */
|
||||
-1, /* 21 025 15 00010101 NAK  Negative Acknowledge */
|
||||
-1, /* 22 026 16 00010110 SYN  Synchronous Idle */
|
||||
-1, /* 23 027 17 00010111 ETB  End of Transmission Block */
|
||||
-1, /* 24 030 18 00011000 CAN  Cancel */
|
||||
-1, /* 25 031 19 00011001 EM  End of medium */
|
||||
-1, /* 26 032 1A 00011010 SUB  Substitute */
|
||||
-1, /* 27 033 1B 00011011 ESC  Escape */
|
||||
-1, /* 28 034 1C 00011100 FS  File Separator */
|
||||
-1, /* 29 035 1D 00011101 GS  Group Separator */
|
||||
-1, /* 30 036 1E 00011110 RS  Record Separator */
|
||||
-1, /* 31 037 1F 00011111 US  Unit Separator */
|
||||
-1, /* 32 040 20 00100000 SP   Space */
|
||||
-1, /* 33 041 21 00100001 ! ! ! Exclamation mark */
|
||||
-1, /* 34 042 22 00100010 " " " Double quotes (or speech marks) */
|
||||
-1, /* 35 043 23 00100011 # # # Number sign */
|
||||
-1, /* 36 044 24 00100100 $ $ $ Dollar */
|
||||
-1, /* 37 045 25 00100101 % % % Per cent sign */
|
||||
-1, /* 38 046 26 00100110 & & & Ampersand */
|
||||
-1, /* 39 047 27 00100111 ' ' ' Single quote */
|
||||
-1, /* 40 050 28 00101000 ( ( &lparen; Open parenthesis (or open
|
||||
* bracket)
|
||||
*/
|
||||
-1, /* 41 051 29 00101001 ) ) &rparen; Close parenthesis (or close
|
||||
* bracket)
|
||||
*/
|
||||
-1, /* 42 052 2A 00101010 * * * Asterisk */
|
||||
-1, /* 43 053 2B 00101011 + + + Plus */
|
||||
-1, /* 44 054 2C 00101100 , , , Comma */
|
||||
62, /* 45 055 2D 00101101 - - Hyphen-minus */
|
||||
-1, /* 46 056 2E 00101110 . . . Period, dot or full stop */
|
||||
-1, /* 47 057 2F 00101111 / / / Slash or divide */
|
||||
52, /* 48 060 30 00110000 0 0 Zero */
|
||||
53, /* 49 061 31 00110001 1 1 One */
|
||||
54, /* 50 062 32 00110010 2 2 Two */
|
||||
55, /* 51 063 33 00110011 3 3 Three */
|
||||
56, /* 52 064 34 00110100 4 4 Four */
|
||||
57, /* 53 065 35 00110101 5 5 Five */
|
||||
58, /* 54 066 36 00110110 6 6 Six */
|
||||
59, /* 55 067 37 00110111 7 7 Seven */
|
||||
60, /* 56 070 38 00111000 8 8 Eight */
|
||||
61, /* 57 071 39 00111001 9 9 Nine */
|
||||
-1, /* 58 072 3A 00111010 : : : Colon */
|
||||
-1, /* 59 073 3B 00111011 ; ; ; Semicolon */
|
||||
-1, /* 60 074 3C 00111100 < < < Less than (or open angled bracket)
|
||||
*/
|
||||
-1, /* 61 075 3D 00111101 = = = Equals */
|
||||
-1, /* 62 076 3E 00111110 > > > Greater than (or close angled
|
||||
* bracket)
|
||||
*/
|
||||
-1, /* 63 077 3F 00111111 ? ? ? Question mark */
|
||||
-1, /* 64 100 40 01000000 @ @ @ At sign */
|
||||
0, /* 65 101 41 01000001 A A Uppercase A */
|
||||
1, /* 66 102 42 01000010 B B Uppercase B */
|
||||
2, /* 67 103 43 01000011 C C Uppercase C */
|
||||
3, /* 68 104 44 01000100 D D Uppercase D */
|
||||
4, /* 69 105 45 01000101 E E Uppercase E */
|
||||
5, /* 70 106 46 01000110 F F Uppercase F */
|
||||
6, /* 71 107 47 01000111 G G Uppercase G */
|
||||
7, /* 72 110 48 01001000 H H Uppercase H */
|
||||
8, /* 73 111 49 01001001 I I Uppercase I */
|
||||
9, /* 74 112 4A 01001010 J J Uppercase J */
|
||||
10, /* 75 113 4B 01001011 K K Uppercase K */
|
||||
11, /* 76 114 4C 01001100 L L Uppercase L */
|
||||
12, /* 77 115 4D 01001101 M M Uppercase M */
|
||||
13, /* 78 116 4E 01001110 N N Uppercase N */
|
||||
14, /* 79 117 4F 01001111 O O Uppercase O */
|
||||
15, /* 80 120 50 01010000 P P Uppercase P */
|
||||
16, /* 81 121 51 01010001 Q Q Uppercase Q */
|
||||
17, /* 82 122 52 01010010 R R Uppercase R */
|
||||
18, /* 83 123 53 01010011 S S Uppercase S */
|
||||
19, /* 84 124 54 01010100 T T Uppercase T */
|
||||
20, /* 85 125 55 01010101 U U Uppercase U */
|
||||
21, /* 86 126 56 01010110 V V Uppercase V */
|
||||
22, /* 87 127 57 01010111 W W Uppercase W */
|
||||
23, /* 88 130 58 01011000 X X Uppercase X */
|
||||
24, /* 89 131 59 01011001 Y Y Uppercase Y */
|
||||
25, /* 90 132 5A 01011010 Z Z Uppercase Z */
|
||||
-1, /* 91 133 5B 01011011 [ [ [ Opening bracket */
|
||||
-1, /* 92 134 5C 01011100 \ \ \ Backslash */
|
||||
-1, /* 93 135 5D 01011101 ] ] ] Closing bracket */
|
||||
-1, /* 94 136 5E 01011110 ^ ^ ^ Caret - circumflex */
|
||||
63, /* 95 137 5F 01011111 _ _ _ Underscore */
|
||||
-1, /* 96 140 60 01100000 ` ` ` Grave accent */
|
||||
26, /* 97 141 61 01100001 a a Lowercase a */
|
||||
27, /* 98 142 62 01100010 b b Lowercase b */
|
||||
28, /* 99 143 63 01100011 c c Lowercase c */
|
||||
29, /* 100 144 64 01100100 d d Lowercase d */
|
||||
30, /* 101 145 65 01100101 e e Lowercase e */
|
||||
31, /* 102 146 66 01100110 f f Lowercase f */
|
||||
32, /* 103 147 67 01100111 g g Lowercase g */
|
||||
33, /* 104 150 68 01101000 h h Lowercase h */
|
||||
34, /* 105 151 69 01101001 i i Lowercase i */
|
||||
35, /* 106 152 6A 01101010 j j Lowercase j */
|
||||
36, /* 107 153 6B 01101011 k k Lowercase k */
|
||||
37, /* 108 154 6C 01101100 l l Lowercase l */
|
||||
38, /* 109 155 6D 01101101 m m Lowercase m */
|
||||
39, /* 110 156 6E 01101110 n n Lowercase n */
|
||||
40, /* 111 157 6F 01101111 o o Lowercase o */
|
||||
41, /* 112 160 70 01110000 p p Lowercase p */
|
||||
42, /* 113 161 71 01110001 q q Lowercase q */
|
||||
43, /* 114 162 72 01110010 r r Lowercase r */
|
||||
44, /* 115 163 73 01110011 s s Lowercase s */
|
||||
45, /* 116 164 74 01110100 t t Lowercase t */
|
||||
46, /* 117 165 75 01110101 u u Lowercase u */
|
||||
47, /* 118 166 76 01110110 v v Lowercase v */
|
||||
48, /* 119 167 77 01110111 w w Lowercase w */
|
||||
49, /* 120 170 78 01111000 x x Lowercase x */
|
||||
50, /* 121 171 79 01111001 y y Lowercase y */
|
||||
51, /* 122 172 7A 01111010 z z Lowercase z */
|
||||
-1, /* 123 173 7B 01111011 { { { Opening brace */
|
||||
-1, /* 124 174 7C 01111100 | | | Vertical bar */
|
||||
-1, /* 125 175 7D 01111101 } } } Closing brace */
|
||||
-1, /* 126 176 7E 01111110 ~ ~ ˜ Equivalency sign - tilde */
|
||||
-1, /* 127 177 7F 01111111 DEL  Delete */
|
||||
};
|
||||
static const signed char dec_base64[] = {
|
||||
-1, /* 0 000 00 00000000 NUL � Null character */
|
||||
-1, /* 1 001 01 00000001 SOH  Start of Heading */
|
||||
-1, /* 2 002 02 00000010 STX  Start of Text */
|
||||
-1, /* 3 003 03 00000011 ETX  End of Text */
|
||||
-1, /* 4 004 04 00000100 EOT  End of Transmission */
|
||||
-1, /* 5 005 05 00000101 ENQ  Enquiry */
|
||||
-1, /* 6 006 06 00000110 ACK  Acknowledge */
|
||||
-1, /* 7 007 07 00000111 BEL  Bell, Alert */
|
||||
-1, /* 8 010 08 00001000 BS  Backspace */
|
||||
-1, /* 9 011 09 00001001 HT 	 Horizontal Tab */
|
||||
-1, /* 10 012 0A 00001010 LF Line Feed */
|
||||
-1, /* 11 013 0B 00001011 VT  Vertical Tabulation */
|
||||
-1, /* 12 014 0C 00001100 FF  Form Feed */
|
||||
-1, /* 13 015 0D 00001101 CR Carriage Return */
|
||||
-1, /* 14 016 0E 00001110 SO  Shift Out */
|
||||
-1, /* 15 017 0F 00001111 SI  Shift In */
|
||||
-1, /* 16 020 10 00010000 DLE  Data Link Escape */
|
||||
-1, /* 17 021 11 00010001 DC1  Device Control One (XON) */
|
||||
-1, /* 18 022 12 00010010 DC2  Device Control Two */
|
||||
-1, /* 19 023 13 00010011 DC3  Device Control Three (XOFF) */
|
||||
-1, /* 20 024 14 00010100 DC4  Device Control Four */
|
||||
-1, /* 21 025 15 00010101 NAK  Negative Acknowledge */
|
||||
-1, /* 22 026 16 00010110 SYN  Synchronous Idle */
|
||||
-1, /* 23 027 17 00010111 ETB  End of Transmission Block */
|
||||
-1, /* 24 030 18 00011000 CAN  Cancel */
|
||||
-1, /* 25 031 19 00011001 EM  End of medium */
|
||||
-1, /* 26 032 1A 00011010 SUB  Substitute */
|
||||
-1, /* 27 033 1B 00011011 ESC  Escape */
|
||||
-1, /* 28 034 1C 00011100 FS  File Separator */
|
||||
-1, /* 29 035 1D 00011101 GS  Group Separator */
|
||||
-1, /* 30 036 1E 00011110 RS  Record Separator */
|
||||
-1, /* 31 037 1F 00011111 US  Unit Separator */
|
||||
-1, /* 32 040 20 00100000 SP   Space */
|
||||
-1, /* 33 041 21 00100001 ! ! ! Exclamation mark */
|
||||
-1, /* 34 042 22 00100010 " " " Double quotes (or speech marks) */
|
||||
-1, /* 35 043 23 00100011 # # # Number sign */
|
||||
-1, /* 36 044 24 00100100 $ $ $ Dollar */
|
||||
-1, /* 37 045 25 00100101 % % % Per cent sign */
|
||||
-1, /* 38 046 26 00100110 & & & Ampersand */
|
||||
-1, /* 39 047 27 00100111 ' ' ' Single quote */
|
||||
-1, /* 40 050 28 00101000 ( ( &lparen; Open parenthesis (or open
|
||||
* bracket)
|
||||
*/
|
||||
-1, /* 41 051 29 00101001 ) ) &rparen; Close parenthesis (or close
|
||||
* bracket)
|
||||
*/
|
||||
-1, /* 42 052 2A 00101010 * * * Asterisk */
|
||||
62, /* 43 053 2B 00101011 + + + Plus */
|
||||
-1, /* 44 054 2C 00101100 , , , Comma */
|
||||
-1, /* 45 055 2D 00101101 - - Hyphen-minus */
|
||||
-1, /* 46 056 2E 00101110 . . . Period, dot or full stop */
|
||||
63, /* 47 057 2F 00101111 / / / Slash or divide */
|
||||
52, /* 48 060 30 00110000 0 0 Zero */
|
||||
53, /* 49 061 31 00110001 1 1 One */
|
||||
54, /* 50 062 32 00110010 2 2 Two */
|
||||
55, /* 51 063 33 00110011 3 3 Three */
|
||||
56, /* 52 064 34 00110100 4 4 Four */
|
||||
57, /* 53 065 35 00110101 5 5 Five */
|
||||
58, /* 54 066 36 00110110 6 6 Six */
|
||||
59, /* 55 067 37 00110111 7 7 Seven */
|
||||
60, /* 56 070 38 00111000 8 8 Eight */
|
||||
61, /* 57 071 39 00111001 9 9 Nine */
|
||||
-1, /* 58 072 3A 00111010 : : : Colon */
|
||||
-1, /* 59 073 3B 00111011 ; ; ; Semicolon */
|
||||
-1, /* 60 074 3C 00111100 < < < Less than (or open angled bracket)
|
||||
*/
|
||||
-1, /* 61 075 3D 00111101 = = = Equals */
|
||||
-1, /* 62 076 3E 00111110 > > > Greater than (or close angled
|
||||
* bracket)
|
||||
*/
|
||||
-1, /* 63 077 3F 00111111 ? ? ? Question mark */
|
||||
-1, /* 64 100 40 01000000 @ @ @ At sign */
|
||||
0, /* 65 101 41 01000001 A A Uppercase A */
|
||||
1, /* 66 102 42 01000010 B B Uppercase B */
|
||||
2, /* 67 103 43 01000011 C C Uppercase C */
|
||||
3, /* 68 104 44 01000100 D D Uppercase D */
|
||||
4, /* 69 105 45 01000101 E E Uppercase E */
|
||||
5, /* 70 106 46 01000110 F F Uppercase F */
|
||||
6, /* 71 107 47 01000111 G G Uppercase G */
|
||||
7, /* 72 110 48 01001000 H H Uppercase H */
|
||||
8, /* 73 111 49 01001001 I I Uppercase I */
|
||||
9, /* 74 112 4A 01001010 J J Uppercase J */
|
||||
10, /* 75 113 4B 01001011 K K Uppercase K */
|
||||
11, /* 76 114 4C 01001100 L L Uppercase L */
|
||||
12, /* 77 115 4D 01001101 M M Uppercase M */
|
||||
13, /* 78 116 4E 01001110 N N Uppercase N */
|
||||
14, /* 79 117 4F 01001111 O O Uppercase O */
|
||||
15, /* 80 120 50 01010000 P P Uppercase P */
|
||||
16, /* 81 121 51 01010001 Q Q Uppercase Q */
|
||||
17, /* 82 122 52 01010010 R R Uppercase R */
|
||||
18, /* 83 123 53 01010011 S S Uppercase S */
|
||||
19, /* 84 124 54 01010100 T T Uppercase T */
|
||||
20, /* 85 125 55 01010101 U U Uppercase U */
|
||||
21, /* 86 126 56 01010110 V V Uppercase V */
|
||||
22, /* 87 127 57 01010111 W W Uppercase W */
|
||||
23, /* 88 130 58 01011000 X X Uppercase X */
|
||||
24, /* 89 131 59 01011001 Y Y Uppercase Y */
|
||||
25, /* 90 132 5A 01011010 Z Z Uppercase Z */
|
||||
-1, /* 91 133 5B 01011011 [ [ [ Opening bracket */
|
||||
-1, /* 92 134 5C 01011100 \ \ \ Backslash */
|
||||
-1, /* 93 135 5D 01011101 ] ] ] Closing bracket */
|
||||
-1, /* 94 136 5E 01011110 ^ ^ ^ Caret - circumflex */
|
||||
-1, /* 95 137 5F 01011111 _ _ _ Underscore */
|
||||
-1, /* 96 140 60 01100000 ` ` ` Grave accent */
|
||||
26, /* 97 141 61 01100001 a a Lowercase a */
|
||||
27, /* 98 142 62 01100010 b b Lowercase b */
|
||||
28, /* 99 143 63 01100011 c c Lowercase c */
|
||||
29, /* 100 144 64 01100100 d d Lowercase d */
|
||||
30, /* 101 145 65 01100101 e e Lowercase e */
|
||||
31, /* 102 146 66 01100110 f f Lowercase f */
|
||||
32, /* 103 147 67 01100111 g g Lowercase g */
|
||||
33, /* 104 150 68 01101000 h h Lowercase h */
|
||||
34, /* 105 151 69 01101001 i i Lowercase i */
|
||||
35, /* 106 152 6A 01101010 j j Lowercase j */
|
||||
36, /* 107 153 6B 01101011 k k Lowercase k */
|
||||
37, /* 108 154 6C 01101100 l l Lowercase l */
|
||||
38, /* 109 155 6D 01101101 m m Lowercase m */
|
||||
39, /* 110 156 6E 01101110 n n Lowercase n */
|
||||
40, /* 111 157 6F 01101111 o o Lowercase o */
|
||||
41, /* 112 160 70 01110000 p p Lowercase p */
|
||||
42, /* 113 161 71 01110001 q q Lowercase q */
|
||||
43, /* 114 162 72 01110010 r r Lowercase r */
|
||||
44, /* 115 163 73 01110011 s s Lowercase s */
|
||||
45, /* 116 164 74 01110100 t t Lowercase t */
|
||||
46, /* 117 165 75 01110101 u u Lowercase u */
|
||||
47, /* 118 166 76 01110110 v v Lowercase v */
|
||||
48, /* 119 167 77 01110111 w w Lowercase w */
|
||||
49, /* 120 170 78 01111000 x x Lowercase x */
|
||||
50, /* 121 171 79 01111001 y y Lowercase y */
|
||||
51, /* 122 172 7A 01111010 z z Lowercase z */
|
||||
-1, /* 123 173 7B 01111011 { { { Opening brace */
|
||||
-1, /* 124 174 7C 01111100 | | | Vertical bar */
|
||||
-1, /* 125 175 7D 01111101 } } } Closing brace */
|
||||
-1, /* 126 176 7E 01111110 ~ ~ ˜ Equivalency sign - tilde */
|
||||
-1, /* 127 177 7F 01111111 DEL  Delete */
|
||||
};
|
||||
|
||||
static inline char* base64_encode_ex(const BYTE* WINPR_RESTRICT alphabet,
|
||||
WINPR_ATTR_UNUSED size_t alphabetCount,
|
||||
const BYTE* WINPR_RESTRICT data, size_t length, BOOL pad,
|
||||
BOOL crLf, size_t lineSize)
|
||||
{
|
||||
size_t blocks = 0;
|
||||
size_t outLen = (length + 3) * 4 / 3;
|
||||
size_t extra = 0;
|
||||
if (crLf)
|
||||
{
|
||||
size_t nCrLf = (outLen + lineSize - 1) / lineSize;
|
||||
extra = nCrLf * 2ull;
|
||||
}
|
||||
size_t outCounter = 0;
|
||||
|
||||
const BYTE* q = data;
|
||||
BYTE* p = malloc(outLen + extra + 1ull);
|
||||
if (!p)
|
||||
return nullptr;
|
||||
|
||||
char* ret = (char*)p;
|
||||
|
||||
/* b1, b2, b3 are input bytes
|
||||
*
|
||||
* 0 1 2
|
||||
* 012345678901234567890123
|
||||
* | b1 | b2 | b3 |
|
||||
*
|
||||
* [ c1 ] [ c3 ]
|
||||
* [ c2 ] [ c4 ]
|
||||
*
|
||||
* c1, c2, c3, c4 are output chars in base64
|
||||
*/
|
||||
|
||||
/* first treat complete blocks */
|
||||
blocks = length - (length % 3);
|
||||
for (size_t i = 0; i < blocks; i += 3, q += 3)
|
||||
{
|
||||
const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8) + q[2];
|
||||
const unsigned idx0 = (c & 0x00FC0000) >> 18;
|
||||
const unsigned idx1 = (c & 0x0003F000) >> 12;
|
||||
const unsigned idx2 = (c & 0x00000FC0) >> 6;
|
||||
const unsigned idx3 = c & 0x0000003F;
|
||||
|
||||
WINPR_ASSERT(idx0 < alphabetCount);
|
||||
WINPR_ASSERT(idx1 < alphabetCount);
|
||||
WINPR_ASSERT(idx2 < alphabetCount);
|
||||
WINPR_ASSERT(idx3 < alphabetCount);
|
||||
|
||||
*p++ = alphabet[idx0];
|
||||
*p++ = alphabet[idx1];
|
||||
*p++ = alphabet[idx2];
|
||||
*p++ = alphabet[idx3];
|
||||
|
||||
outCounter += 4;
|
||||
if (crLf && (outCounter % lineSize == 0))
|
||||
{
|
||||
*p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
}
|
||||
|
||||
/* then remainder */
|
||||
switch (length % 3)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
const unsigned c = ((unsigned)q[0] << 16);
|
||||
const unsigned idx0 = (c & 0x00FC0000) >> 18;
|
||||
const unsigned idx1 = (c & 0x0003F000) >> 12;
|
||||
|
||||
WINPR_ASSERT(idx0 < alphabetCount);
|
||||
WINPR_ASSERT(idx1 < alphabetCount);
|
||||
|
||||
*p++ = alphabet[idx0];
|
||||
*p++ = alphabet[idx1];
|
||||
if (pad)
|
||||
{
|
||||
*p++ = '=';
|
||||
*p++ = '=';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8);
|
||||
const unsigned idx0 = (c & 0x00FC0000) >> 18;
|
||||
const unsigned idx1 = (c & 0x0003F000) >> 12;
|
||||
const unsigned idx2 = (c & 0x00000FC0) >> 6;
|
||||
|
||||
WINPR_ASSERT(idx0 < alphabetCount);
|
||||
WINPR_ASSERT(idx1 < alphabetCount);
|
||||
WINPR_ASSERT(idx2 < alphabetCount);
|
||||
|
||||
*p++ = alphabet[idx0];
|
||||
*p++ = alphabet[idx1];
|
||||
*p++ = alphabet[idx2];
|
||||
if (pad)
|
||||
*p++ = '=';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (crLf && length % 3)
|
||||
{
|
||||
*p++ = '\r';
|
||||
*p++ = '\n';
|
||||
}
|
||||
*p = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char* base64_encode(const BYTE* WINPR_RESTRICT alphabet, size_t alphabetCount,
|
||||
const BYTE* WINPR_RESTRICT data, size_t length, BOOL pad)
|
||||
{
|
||||
return base64_encode_ex(alphabet, alphabetCount, data, length, pad, FALSE, 64);
|
||||
}
|
||||
|
||||
static inline int base64_decode_char(const signed char* WINPR_RESTRICT alphabet,
|
||||
size_t alphabetCount, char c)
|
||||
{
|
||||
/* ensure char is signed for this check */
|
||||
const int ic = (int)c;
|
||||
if ((ic <= 0) || ((size_t)ic >= alphabetCount))
|
||||
return -1;
|
||||
|
||||
return alphabet[(size_t)c];
|
||||
}
|
||||
|
||||
static inline void* base64_decode(const signed char* WINPR_RESTRICT alphabet, size_t alphabetCount,
|
||||
const char* WINPR_RESTRICT s, size_t length,
|
||||
size_t* WINPR_RESTRICT data_len, BOOL pad)
|
||||
{
|
||||
int n[4] = WINPR_C_ARRAY_INIT;
|
||||
BYTE* data = nullptr;
|
||||
const size_t remainder = length % 4;
|
||||
|
||||
if ((pad && remainder > 0) || (remainder == 1))
|
||||
return nullptr;
|
||||
|
||||
if (!pad && remainder)
|
||||
length += 4 - remainder;
|
||||
|
||||
BYTE* q = data = (BYTE*)malloc(length / 4 * 3 + 1);
|
||||
if (!q)
|
||||
return nullptr;
|
||||
|
||||
/* first treat complete blocks */
|
||||
const size_t nBlocks = (length / 4);
|
||||
size_t outputLen = 0;
|
||||
|
||||
if (nBlocks < 1)
|
||||
{
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nBlocks - 1; i++, q += 3)
|
||||
{
|
||||
n[0] = base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
n[1] = base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
n[2] = base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
n[3] = base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
|
||||
if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1))
|
||||
goto out_free;
|
||||
|
||||
q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
|
||||
q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
|
||||
q[2] = (BYTE)(((n[2] & 3) << 6) + n[3]);
|
||||
outputLen += 3;
|
||||
}
|
||||
|
||||
/* treat last block */
|
||||
n[0] = base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
n[1] = base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
if ((n[0] == -1) || (n[1] == -1))
|
||||
goto out_free;
|
||||
|
||||
n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++);
|
||||
|
||||
q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
|
||||
if (n[2] == -1)
|
||||
{
|
||||
/* XX== */
|
||||
outputLen += 1;
|
||||
if (n[3] != -1)
|
||||
goto out_free;
|
||||
|
||||
q[1] = (BYTE)((n[1] & 15) << 4);
|
||||
}
|
||||
else if (n[3] == -1)
|
||||
{
|
||||
/* yyy= */
|
||||
outputLen += 2;
|
||||
q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
|
||||
q[2] = (BYTE)((n[2] & 3) << 6);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXXX */
|
||||
outputLen += 3;
|
||||
q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4));
|
||||
q[1] = (BYTE)(((n[1] & 15) << 4) + (n[2] >> 2));
|
||||
q[2] = (BYTE)(((n[2] & 3) << 6) + n[3]);
|
||||
}
|
||||
|
||||
if (data_len)
|
||||
*data_len = outputLen;
|
||||
data[outputLen] = '\0';
|
||||
|
||||
return data;
|
||||
out_free:
|
||||
free(data);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* crypto_base64_encode_ex(const BYTE* WINPR_RESTRICT data, size_t length, BOOL withCrLf)
|
||||
{
|
||||
return base64_encode_ex(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, withCrLf, 64);
|
||||
}
|
||||
|
||||
char* crypto_base64_encode(const BYTE* WINPR_RESTRICT data, size_t length)
|
||||
{
|
||||
return base64_encode(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE);
|
||||
}
|
||||
|
||||
void crypto_base64_decode(const char* WINPR_RESTRICT enc_data, size_t length,
|
||||
BYTE** WINPR_RESTRICT dec_data, size_t* WINPR_RESTRICT res_length)
|
||||
{
|
||||
*dec_data =
|
||||
base64_decode(dec_base64, ARRAYSIZE(dec_base64), enc_data, length, res_length, TRUE);
|
||||
}
|
||||
|
||||
char* crypto_base64url_encode(const BYTE* WINPR_RESTRICT data, size_t length)
|
||||
{
|
||||
return base64_encode(enc_base64url, ARRAYSIZE(enc_base64url), data, length, FALSE);
|
||||
}
|
||||
|
||||
void crypto_base64url_decode(const char* WINPR_RESTRICT enc_data, size_t length,
|
||||
BYTE** WINPR_RESTRICT dec_data, size_t* WINPR_RESTRICT res_length)
|
||||
{
|
||||
*dec_data =
|
||||
base64_decode(dec_base64url, ARRAYSIZE(dec_base64url), enc_data, length, res_length, FALSE);
|
||||
}
|
||||
745
third_party/FreeRDP/libfreerdp/crypto/ber.c
vendored
Normal file
745
third_party/FreeRDP/libfreerdp/crypto/ber.c
vendored
Normal file
@@ -0,0 +1,745 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* ASN.1 Basic Encoding Rules (BER)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/crypto/ber.h>
|
||||
|
||||
#define TAG FREERDP_TAG("crypto")
|
||||
|
||||
BOOL ber_read_length(wStream* s, size_t* length)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(length);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte & 0x80)
|
||||
{
|
||||
byte &= ~(0x80);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, byte))
|
||||
return FALSE;
|
||||
|
||||
if (byte == 1)
|
||||
Stream_Read_UINT8(s, *length);
|
||||
else if (byte == 2)
|
||||
Stream_Read_UINT16_BE(s, *length);
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "ber: unexpected byte 0x%02" PRIx8 ", expected [1,2]", byte);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = byte;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write BER length.
|
||||
* @param s stream
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
size_t ber_write_length(wStream* s, size_t length)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (length > 0xFF)
|
||||
{
|
||||
WINPR_ASSERT(length <= UINT16_MAX);
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 3);
|
||||
Stream_Write_UINT8(s, 0x80 ^ 2);
|
||||
Stream_Write_UINT16_BE(s, (UINT16)length);
|
||||
return 3;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(length <= UINT8_MAX);
|
||||
if (length > 0x7F)
|
||||
{
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
|
||||
Stream_Write_UINT8(s, 0x80 ^ 1);
|
||||
Stream_Write_UINT8(s, (UINT8)length);
|
||||
return 2;
|
||||
}
|
||||
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
|
||||
Stream_Write_UINT8(s, (UINT8)length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t _ber_sizeof_length(size_t length)
|
||||
{
|
||||
if (length > 0xFF)
|
||||
return 3;
|
||||
|
||||
if (length > 0x7F)
|
||||
return 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read BER Universal tag.
|
||||
*
|
||||
* @param s The stream to read from
|
||||
* @param tag BER universally-defined tag
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise
|
||||
*/
|
||||
|
||||
BOOL ber_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
const BYTE expect = (BER_CLASS_UNIV | BER_PC(pc) | (BER_TAG_MASK & tag));
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != expect)
|
||||
{
|
||||
WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write BER Universal tag.
|
||||
* @param s stream
|
||||
* @param tag BER universally-defined tag
|
||||
* @param pc primitive (FALSE) or constructed (TRUE)
|
||||
*/
|
||||
|
||||
size_t ber_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read BER Application tag.
|
||||
* @param s stream
|
||||
* @param tag BER application-defined tag
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
BOOL ber_read_application_tag(wStream* s, BYTE tag, size_t* length)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(length);
|
||||
|
||||
if (tag > 30)
|
||||
{
|
||||
const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != expect)
|
||||
{
|
||||
WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != tag)
|
||||
{
|
||||
WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, tag);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ber_read_length(s, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
const BYTE expect = ((BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != expect)
|
||||
{
|
||||
WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ber_read_length(s, length);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write BER Application tag.
|
||||
* @param s stream
|
||||
* @param tag BER application-defined tag
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
void ber_write_application_tag(wStream* s, BYTE tag, size_t length)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (tag > 30)
|
||||
{
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 2);
|
||||
Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | BER_TAG_MASK);
|
||||
Stream_Write_UINT8(s, tag);
|
||||
ber_write_length(s, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
|
||||
Stream_Write_UINT8(s, (BER_CLASS_APPL | BER_CONSTRUCT) | (BER_TAG_MASK & tag));
|
||||
ber_write_length(s, length);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL ber_read_contextual_tag(wStream* s, BYTE tag, size_t* length, BOOL pc)
|
||||
{
|
||||
const BYTE expect = ((BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
||||
BYTE byte = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(length);
|
||||
|
||||
if (Stream_GetRemainingLength(s) < 1)
|
||||
{
|
||||
WLog_VRB(TAG, "short data, got %" PRIuz ", expected %u", Stream_GetRemainingLength(s), 1u);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != expect)
|
||||
{
|
||||
WLog_VRB(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
|
||||
Stream_Rewind(s, 1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ber_read_length(s, length);
|
||||
}
|
||||
|
||||
size_t ber_write_contextual_tag(wStream* s, BYTE tag, size_t length, BOOL pc)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= 1);
|
||||
Stream_Write_UINT8(s, (BER_CLASS_CTXT | BER_PC(pc)) | (BER_TAG_MASK & tag));
|
||||
return 1 + ber_write_length(s, length);
|
||||
}
|
||||
|
||||
size_t ber_sizeof_contextual_tag(size_t length)
|
||||
{
|
||||
return 1 + _ber_sizeof_length(length);
|
||||
}
|
||||
|
||||
BOOL ber_read_sequence_tag(wStream* s, size_t* length)
|
||||
{
|
||||
const BYTE expect = ((BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_SEQUENCE_OF));
|
||||
BYTE byte = 0;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != expect)
|
||||
{
|
||||
WLog_WARN(TAG, "invalid tag, got 0x%02" PRIx8 ", expected 0x%02" PRIx8, byte, expect);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return ber_read_length(s, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write BER SEQUENCE tag.
|
||||
* @param s stream
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
size_t ber_write_sequence_tag(wStream* s, size_t length)
|
||||
{
|
||||
Stream_Write_UINT8(s, (BER_CLASS_UNIV | BER_CONSTRUCT) | (BER_TAG_MASK & BER_TAG_SEQUENCE));
|
||||
return 1 + ber_write_length(s, length);
|
||||
}
|
||||
|
||||
size_t ber_sizeof_sequence(size_t length)
|
||||
{
|
||||
return 1 + _ber_sizeof_length(length) + length;
|
||||
}
|
||||
|
||||
size_t ber_sizeof_sequence_tag(size_t length)
|
||||
{
|
||||
return 1 + _ber_sizeof_length(length);
|
||||
}
|
||||
|
||||
BOOL ber_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
WINPR_ASSERT(enumerated);
|
||||
|
||||
if (!ber_read_universal_tag(s, BER_TAG_ENUMERATED, FALSE) || !ber_read_length(s, &length))
|
||||
return FALSE;
|
||||
|
||||
if (length != 1)
|
||||
{
|
||||
WLog_WARN(TAG, "short data, got %" PRIuz ", expected %u", length, 1u);
|
||||
return FALSE;
|
||||
}
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, *enumerated);
|
||||
|
||||
/* check that enumerated value falls within expected range */
|
||||
if (*enumerated + 1 > count)
|
||||
{
|
||||
WLog_WARN(TAG, "invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void ber_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
|
||||
{
|
||||
ber_write_universal_tag(s, BER_TAG_ENUMERATED, FALSE);
|
||||
ber_write_length(s, 1);
|
||||
Stream_Write_UINT8(s, enumerated);
|
||||
}
|
||||
|
||||
BOOL ber_read_bit_string(wStream* s, size_t* length, BYTE* padding)
|
||||
{
|
||||
if (!ber_read_universal_tag(s, BER_TAG_BIT_STRING, FALSE) || !ber_read_length(s, length))
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, *padding);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a BER OCTET_STRING
|
||||
* @param s stream
|
||||
* @param oct_str octet string
|
||||
* @param length string length
|
||||
*/
|
||||
|
||||
size_t ber_write_octet_string(wStream* s, const BYTE* oct_str, size_t length)
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
WINPR_ASSERT(oct_str || (length == 0));
|
||||
size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
||||
size += ber_write_length(s, length);
|
||||
Stream_Write(s, oct_str, length);
|
||||
size += length;
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t ber_write_contextual_octet_string(wStream* s, BYTE tag, const BYTE* oct_str, size_t length)
|
||||
{
|
||||
size_t inner = ber_sizeof_octet_string(length);
|
||||
size_t ret = 0;
|
||||
size_t r = 0;
|
||||
|
||||
ret = ber_write_contextual_tag(s, tag, inner, TRUE);
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
r = ber_write_octet_string(s, oct_str, length);
|
||||
if (!r)
|
||||
return 0;
|
||||
return ret + r;
|
||||
}
|
||||
|
||||
size_t ber_write_char_to_unicode_octet_string(wStream* s, const char* str)
|
||||
{
|
||||
WINPR_ASSERT(str);
|
||||
size_t size = 0;
|
||||
size_t length = strlen(str) + 1;
|
||||
size += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
||||
size += ber_write_length(s, length * sizeof(WCHAR));
|
||||
|
||||
if (Stream_Write_UTF16_String_From_UTF8(s, length, str, length, TRUE) < 0)
|
||||
return 0;
|
||||
return size + length * sizeof(WCHAR);
|
||||
}
|
||||
|
||||
size_t ber_write_contextual_unicode_octet_string(wStream* s, BYTE tag, LPWSTR str)
|
||||
{
|
||||
WINPR_ASSERT(str);
|
||||
size_t len = _wcslen(str) * sizeof(WCHAR);
|
||||
size_t inner_len = ber_sizeof_octet_string(len);
|
||||
size_t ret = 0;
|
||||
|
||||
ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
|
||||
return ret + ber_write_octet_string(s, (const BYTE*)str, len);
|
||||
}
|
||||
|
||||
size_t ber_write_contextual_char_to_unicode_octet_string(wStream* s, BYTE tag, const char* str)
|
||||
{
|
||||
size_t ret = 0;
|
||||
size_t len = strlen(str);
|
||||
size_t inner_len = ber_sizeof_octet_string(len * 2);
|
||||
|
||||
WINPR_ASSERT(Stream_GetRemainingCapacity(s) < ber_sizeof_contextual_tag(inner_len) + inner_len);
|
||||
|
||||
ret = ber_write_contextual_tag(s, tag, inner_len, TRUE);
|
||||
ret += ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE);
|
||||
ret += ber_write_length(s, len * sizeof(WCHAR));
|
||||
|
||||
if (Stream_Write_UTF16_String_From_UTF8(s, len, str, len, TRUE) < 0)
|
||||
return 0;
|
||||
|
||||
return ret + len;
|
||||
}
|
||||
|
||||
BOOL ber_read_unicode_octet_string(wStream* s, LPWSTR* str)
|
||||
{
|
||||
LPWSTR ret = nullptr;
|
||||
size_t length = 0;
|
||||
|
||||
if (!ber_read_octet_string_tag(s, &length))
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
ret = calloc(1, length + 2);
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
memcpy(ret, Stream_ConstPointer(s), length);
|
||||
ret[length / 2] = 0;
|
||||
Stream_Seek(s, length);
|
||||
*str = ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ber_read_char_from_unicode_octet_string(wStream* s, char** str)
|
||||
{
|
||||
size_t length = 0;
|
||||
char* ptr = nullptr;
|
||||
|
||||
*str = nullptr;
|
||||
if (!ber_read_octet_string_tag(s, &length))
|
||||
return FALSE;
|
||||
|
||||
ptr = Stream_Read_UTF16_String_As_UTF8(s, length / sizeof(WCHAR), nullptr);
|
||||
if (!ptr)
|
||||
return FALSE;
|
||||
*str = ptr;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL ber_read_octet_string_tag(wStream* s, size_t* length)
|
||||
{
|
||||
return ber_read_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) && ber_read_length(s, length);
|
||||
}
|
||||
|
||||
BOOL ber_read_octet_string(wStream* s, BYTE** content, size_t* length)
|
||||
{
|
||||
BYTE* ret = nullptr;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
WINPR_ASSERT(content);
|
||||
WINPR_ASSERT(length);
|
||||
|
||||
if (!ber_read_octet_string_tag(s, length))
|
||||
return FALSE;
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, *length))
|
||||
return FALSE;
|
||||
|
||||
ret = malloc(*length);
|
||||
if (!ret)
|
||||
return FALSE;
|
||||
|
||||
Stream_Read(s, ret, *length);
|
||||
*content = ret;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
size_t ber_write_octet_string_tag(wStream* s, size_t length)
|
||||
{
|
||||
if (ber_write_universal_tag(s, BER_TAG_OCTET_STRING, FALSE) == 0)
|
||||
return 0;
|
||||
if (ber_write_length(s, length) == 0)
|
||||
return 0;
|
||||
return 1 + _ber_sizeof_length(length);
|
||||
}
|
||||
|
||||
size_t ber_sizeof_octet_string(size_t length)
|
||||
{
|
||||
return 1 + _ber_sizeof_length(length) + length;
|
||||
}
|
||||
|
||||
size_t ber_sizeof_contextual_octet_string(size_t length)
|
||||
{
|
||||
size_t ret = ber_sizeof_octet_string(length);
|
||||
return ber_sizeof_contextual_tag(ret) + ret;
|
||||
}
|
||||
|
||||
/** \brief Read a BER BOOLEAN
|
||||
*
|
||||
* @param s The stream to read from.
|
||||
* @param value A pointer to the value read, must not be nullptr
|
||||
*
|
||||
* \return \b TRUE for success, \b FALSE for any failure
|
||||
*/
|
||||
|
||||
BOOL ber_read_BOOL(wStream* s, BOOL* value)
|
||||
{
|
||||
size_t length = 0;
|
||||
BYTE v = 0;
|
||||
|
||||
WINPR_ASSERT(value);
|
||||
if (!ber_read_universal_tag(s, BER_TAG_BOOLEAN, FALSE) || !ber_read_length(s, &length))
|
||||
return FALSE;
|
||||
|
||||
if (length != 1)
|
||||
{
|
||||
WLog_WARN(TAG, "short data, got %" PRIuz ", expected %u", length, 1u);
|
||||
return FALSE;
|
||||
}
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, v);
|
||||
*value = (v != 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a BER BOOLEAN
|
||||
*
|
||||
* @param s A pointer to the stream to write to
|
||||
* @param value The value to write
|
||||
*/
|
||||
|
||||
void ber_write_BOOL(wStream* s, BOOL value)
|
||||
{
|
||||
ber_write_universal_tag(s, BER_TAG_BOOLEAN, FALSE);
|
||||
ber_write_length(s, 1);
|
||||
Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
|
||||
}
|
||||
|
||||
BOOL ber_read_integer(wStream* s, UINT32* value)
|
||||
{
|
||||
size_t length = 0;
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (!ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE))
|
||||
return FALSE;
|
||||
if (!ber_read_length(s, &length))
|
||||
return FALSE;
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
if (value == nullptr)
|
||||
{
|
||||
// even if we don't care the integer value, check the announced size
|
||||
return Stream_SafeSeek(s, length);
|
||||
}
|
||||
|
||||
if (length == 1)
|
||||
{
|
||||
Stream_Read_UINT8(s, *value);
|
||||
}
|
||||
else if (length == 2)
|
||||
{
|
||||
Stream_Read_UINT16_BE(s, *value);
|
||||
}
|
||||
else if (length == 3)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
Stream_Read_UINT8(s, byte);
|
||||
Stream_Read_UINT16_BE(s, *value);
|
||||
*value += (byte << 16) & 0xFF0000;
|
||||
}
|
||||
else if (length == 4)
|
||||
{
|
||||
Stream_Read_UINT32_BE(s, *value);
|
||||
}
|
||||
else if (length == 8)
|
||||
{
|
||||
WLog_ERR(TAG, "should implement reading an 8 bytes integer");
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "should implement reading an integer with length=%" PRIuz, length);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a BER INTEGER
|
||||
*
|
||||
* @param s A pointer to the stream to write to
|
||||
* @param value The value to write
|
||||
*
|
||||
* @return The size in bytes that were written
|
||||
*/
|
||||
|
||||
size_t ber_write_integer(wStream* s, UINT32 value)
|
||||
{
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
if (value < 0x80)
|
||||
{
|
||||
if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
|
||||
return 0;
|
||||
if (ber_write_length(s, 1) == 0)
|
||||
return 0;
|
||||
|
||||
Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value));
|
||||
return 3;
|
||||
}
|
||||
else if (value < 0x8000)
|
||||
{
|
||||
if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
|
||||
return 0;
|
||||
if (ber_write_length(s, 2) == 0)
|
||||
return 0;
|
||||
|
||||
Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
|
||||
return 4;
|
||||
}
|
||||
else if (value < 0x800000)
|
||||
{
|
||||
if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
|
||||
return 0;
|
||||
if (ber_write_length(s, 3) == 0)
|
||||
return 0;
|
||||
|
||||
Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, value >> 16));
|
||||
Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, value));
|
||||
return 5;
|
||||
}
|
||||
else if (value < 0x80000000)
|
||||
{
|
||||
if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
|
||||
return 0;
|
||||
if (ber_write_length(s, 4) == 0)
|
||||
return 0;
|
||||
|
||||
Stream_Write_UINT32_BE(s, value);
|
||||
return 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* treat as signed integer i.e. NT/HRESULT error codes */
|
||||
if (ber_write_universal_tag(s, BER_TAG_INTEGER, FALSE) == 0)
|
||||
return 0;
|
||||
if (ber_write_length(s, 4) == 0)
|
||||
return 0;
|
||||
|
||||
Stream_Write_UINT32_BE(s, value);
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ber_write_contextual_integer(wStream* s, BYTE tag, UINT32 value)
|
||||
{
|
||||
size_t len = ber_sizeof_integer(value);
|
||||
|
||||
WINPR_ASSERT(s);
|
||||
|
||||
WINPR_ASSERT(Stream_EnsureRemainingCapacity(s, len + 5));
|
||||
|
||||
len += ber_write_contextual_tag(s, tag, len, TRUE);
|
||||
if (ber_write_integer(s, value) == 0)
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t ber_sizeof_integer(UINT32 value)
|
||||
{
|
||||
if (value < 0x80)
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
else if (value < 0x8000)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
else if (value < 0x800000)
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
else if (value < 0x80000000)
|
||||
{
|
||||
return 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* treat as signed integer i.e. NT/HRESULT error codes */
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
size_t ber_sizeof_contextual_integer(UINT32 value)
|
||||
{
|
||||
size_t intSize = ber_sizeof_integer(value);
|
||||
return ber_sizeof_contextual_tag(intSize) + intSize;
|
||||
}
|
||||
|
||||
BOOL ber_read_integer_length(wStream* s, size_t* length)
|
||||
{
|
||||
return ber_read_universal_tag(s, BER_TAG_INTEGER, FALSE) && ber_read_length(s, length);
|
||||
}
|
||||
245
third_party/FreeRDP/libfreerdp/crypto/cert_common.c
vendored
Normal file
245
third_party/FreeRDP/libfreerdp/crypto/cert_common.c
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Certificate Handling
|
||||
*
|
||||
* Copyright 2011 Jiten Pathy
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include "cert_common.h"
|
||||
#include "crypto.h"
|
||||
#include "opensslcompat.h"
|
||||
|
||||
#define TAG FREERDP_TAG("core")
|
||||
|
||||
static BOOL cert_info_allocate(rdpCertInfo* info, size_t size);
|
||||
|
||||
BOOL read_bignum(BYTE** dst, DWORD* length, const BIGNUM* num, BOOL alloc)
|
||||
{
|
||||
WINPR_ASSERT(dst);
|
||||
WINPR_ASSERT(length);
|
||||
WINPR_ASSERT(num);
|
||||
|
||||
if (alloc)
|
||||
{
|
||||
free(*dst);
|
||||
*dst = nullptr;
|
||||
*length = 0;
|
||||
}
|
||||
|
||||
const int len = BN_num_bytes(num);
|
||||
if (len < 0)
|
||||
return FALSE;
|
||||
|
||||
if (!alloc)
|
||||
{
|
||||
if (*length < (UINT32)len)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
if (alloc)
|
||||
{
|
||||
*dst = malloc((size_t)len);
|
||||
if (!*dst)
|
||||
return FALSE;
|
||||
}
|
||||
BN_bn2bin(num, *dst);
|
||||
crypto_reverse(*dst, (size_t)len);
|
||||
*length = (UINT32)len;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL cert_info_create(rdpCertInfo* dst, const BIGNUM* rsa, const BIGNUM* rsa_e)
|
||||
{
|
||||
const rdpCertInfo empty = WINPR_C_ARRAY_INIT;
|
||||
|
||||
WINPR_ASSERT(dst);
|
||||
WINPR_ASSERT(rsa);
|
||||
|
||||
*dst = empty;
|
||||
|
||||
if (!read_bignum(&dst->Modulus, &dst->ModulusLength, rsa, TRUE))
|
||||
goto fail;
|
||||
|
||||
{
|
||||
DWORD len = sizeof(dst->exponent);
|
||||
BYTE* ptr = &dst->exponent[0];
|
||||
if (!read_bignum(&ptr, &len, rsa_e, FALSE))
|
||||
goto fail;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
fail:
|
||||
cert_info_free(dst);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src)
|
||||
{
|
||||
WINPR_ASSERT(dst);
|
||||
WINPR_ASSERT(src);
|
||||
|
||||
*dst = *src;
|
||||
|
||||
dst->Modulus = nullptr;
|
||||
dst->ModulusLength = 0;
|
||||
if (src->ModulusLength > 0)
|
||||
{
|
||||
dst->Modulus = malloc(src->ModulusLength);
|
||||
if (!dst->Modulus)
|
||||
return FALSE;
|
||||
memcpy(dst->Modulus, src->Modulus, src->ModulusLength);
|
||||
dst->ModulusLength = src->ModulusLength;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void cert_info_free(rdpCertInfo* info)
|
||||
{
|
||||
WINPR_ASSERT(info);
|
||||
free(info->Modulus);
|
||||
info->ModulusLength = 0;
|
||||
info->Modulus = nullptr;
|
||||
}
|
||||
|
||||
BOOL cert_info_allocate(rdpCertInfo* info, size_t size)
|
||||
{
|
||||
WINPR_ASSERT(info);
|
||||
cert_info_free(info);
|
||||
|
||||
info->Modulus = (BYTE*)malloc(size);
|
||||
|
||||
if (!info->Modulus && (size > 0))
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to allocate info->Modulus of size %" PRIuz, size);
|
||||
return FALSE;
|
||||
}
|
||||
info->ModulusLength = (UINT32)size;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
|
||||
return FALSE;
|
||||
if (size > UINT32_MAX)
|
||||
{
|
||||
WLog_ERR(TAG, "modulus size %" PRIuz " exceeds limit of %" PRIu32, size, UINT32_MAX);
|
||||
return FALSE;
|
||||
}
|
||||
if (!cert_info_allocate(info, size))
|
||||
return FALSE;
|
||||
Stream_Read(s, info->Modulus, info->ModulusLength);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, size))
|
||||
return FALSE;
|
||||
if (size > 4)
|
||||
{
|
||||
WLog_ERR(TAG, "exponent size %" PRIuz " exceeds limit of %" PRIu32, size, 4u);
|
||||
return FALSE;
|
||||
}
|
||||
if (!info->Modulus || (info->ModulusLength == 0))
|
||||
{
|
||||
WLog_ERR(TAG, "invalid modulus=%p [%" PRIu32 "]",
|
||||
WINPR_CXX_COMPAT_CAST(const void*, info->Modulus), info->ModulusLength);
|
||||
return FALSE;
|
||||
}
|
||||
Stream_Read(s, &info->exponent[4 - size], size);
|
||||
crypto_reverse(info->Modulus, info->ModulusLength);
|
||||
crypto_reverse(info->exponent, 4);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
X509* x509_from_rsa(const RSA* rsa)
|
||||
{
|
||||
EVP_PKEY* pubkey = nullptr;
|
||||
X509* x509 = nullptr;
|
||||
BIO* bio = BIO_new(
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
BIO_s_mem()
|
||||
#else
|
||||
BIO_s_secmem()
|
||||
#endif
|
||||
);
|
||||
if (!bio)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new() failed");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const int rc = PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa);
|
||||
if (rc != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "PEM_write_bio_RSA_PUBKEY(bio, (RSA*)rsa) failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pubkey = PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr);
|
||||
if (!pubkey)
|
||||
{
|
||||
WLog_ERR(TAG, "PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr) failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
x509 = X509_new();
|
||||
if (!x509)
|
||||
{
|
||||
WLog_ERR(TAG, "X509_new() failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const int res = X509_set_pubkey(x509, pubkey);
|
||||
if (res != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "X509_set_pubkey(x509, pubkey) failed");
|
||||
X509_free(x509);
|
||||
x509 = nullptr;
|
||||
goto fail;
|
||||
}
|
||||
fail:
|
||||
BIO_free_all(bio);
|
||||
EVP_PKEY_free(pubkey);
|
||||
return x509;
|
||||
}
|
||||
#endif
|
||||
64
third_party/FreeRDP/libfreerdp/crypto/cert_common.h
vendored
Normal file
64
third_party/FreeRDP/libfreerdp/crypto/cert_common.h
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Certificate and private key helpers
|
||||
*
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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 FREERDP_LIB_CORE_CERT_COMMON_H
|
||||
#define FREERDP_LIB_CORE_CERT_COMMON_H
|
||||
|
||||
#include <freerdp/crypto/ber.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
#include <freerdp/settings.h>
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/api.h>
|
||||
|
||||
#include "opensslcompat.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL cert_info_create(rdpCertInfo* dst, const BIGNUM* rsa, const BIGNUM* rsa_e);
|
||||
|
||||
FREERDP_LOCAL void cert_info_free(rdpCertInfo* info);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL cert_info_clone(rdpCertInfo* dst, const rdpCertInfo* src);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL cert_info_read_modulus(rdpCertInfo* info, size_t size, wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL cert_info_read_exponent(rdpCertInfo* info, size_t size, wStream* s);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL read_bignum(BYTE** dst, DWORD* length, const BIGNUM* num, BOOL alloc);
|
||||
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL X509* x509_from_rsa(const RSA* rsa);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CORE_CERT_COMMON_H */
|
||||
1948
third_party/FreeRDP/libfreerdp/crypto/certificate.c
vendored
Normal file
1948
third_party/FreeRDP/libfreerdp/crypto/certificate.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
80
third_party/FreeRDP/libfreerdp/crypto/certificate.h
vendored
Normal file
80
third_party/FreeRDP/libfreerdp/crypto/certificate.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Certificate Handling
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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 FREERDP_LIB_CORE_CERTIFICATE_H
|
||||
#define FREERDP_LIB_CORE_CERTIFICATE_H
|
||||
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
#include <freerdp/crypto/certificate.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
/* Certificate Version */
|
||||
#define CERT_CHAIN_VERSION_1 0x00000001
|
||||
#define CERT_CHAIN_VERSION_2 0x00000002
|
||||
#define CERT_CHAIN_VERSION_MASK 0x7FFFFFFF
|
||||
#define CERT_PERMANENTLY_ISSUED 0x00000000
|
||||
#define CERT_TEMPORARILY_ISSUED 0x80000000
|
||||
|
||||
#define SIGNATURE_ALG_RSA 0x00000001
|
||||
#define KEY_EXCHANGE_ALG_RSA 0x00000001
|
||||
|
||||
#define BB_RSA_KEY_BLOB 6
|
||||
#define BB_RSA_SIGNATURE_BLOB 8
|
||||
|
||||
WINPR_ATTR_MALLOC(freerdp_certificate_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpCertificate* freerdp_certificate_new_from_x509(const X509* xcert,
|
||||
const STACK_OF(X509) * chain);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL freerdp_certificate_read_server_cert(rdpCertificate* certificate,
|
||||
const BYTE* server_cert, size_t length);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL SSIZE_T freerdp_certificate_write_server_cert(const rdpCertificate* certificate,
|
||||
UINT32 dwVersion, wStream* s);
|
||||
|
||||
WINPR_ATTR_MALLOC(freerdp_certificate_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpCertificate* freerdp_certificate_clone(const rdpCertificate* certificate);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL const rdpCertInfo* freerdp_certificate_get_info(const rdpCertificate* certificate);
|
||||
|
||||
/** \brief returns a pointer to a X509 structure.
|
||||
* Call X509_free when done.
|
||||
*/
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL X509* freerdp_certificate_get_x509(rdpCertificate* certificate);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL size_t freerdp_certificate_get_chain_len(rdpCertificate* certificate);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL X509* freerdp_certificate_get_chain_at(rdpCertificate* certificate, size_t offset);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL freerdp_certificate_publickey_encrypt(const rdpCertificate* cert,
|
||||
const BYTE* input, size_t cbInput,
|
||||
BYTE** poutput, size_t* pcbOutput);
|
||||
|
||||
#endif /* FREERDP_LIB_CORE_CERTIFICATE_H */
|
||||
311
third_party/FreeRDP/libfreerdp/crypto/certificate_data.c
vendored
Normal file
311
third_party/FreeRDP/libfreerdp/crypto/certificate_data.c
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Certificate Handling
|
||||
*
|
||||
* Copyright 2011 Jiten Pathy
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/path.h>
|
||||
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
#include <freerdp/crypto/certificate_data.h>
|
||||
|
||||
#include "certificate.h"
|
||||
#include <freerdp/log.h>
|
||||
#define TAG FREERDP_TAG("crypto.certificate_data")
|
||||
|
||||
struct rdp_certificate_data
|
||||
{
|
||||
char* hostname;
|
||||
UINT16 port;
|
||||
rdpCertificate* cert;
|
||||
|
||||
char cached_hash[MAX_PATH + 10];
|
||||
char* cached_subject;
|
||||
char* cached_issuer;
|
||||
char* cached_fingerprint;
|
||||
char* cached_pem;
|
||||
char* cached_pem_chain;
|
||||
};
|
||||
|
||||
/* ensure our hostnames (and therefore filenames) always use the same capitalization.
|
||||
* the user might have input random case, but we always need to have a sane
|
||||
* baseline to compare against. */
|
||||
static char* ensure_lowercase(char* str, size_t length)
|
||||
{
|
||||
const size_t len = strnlen(str, length);
|
||||
for (size_t x = 0; x < len; x++)
|
||||
str[x] = (char)tolower(str[x]);
|
||||
return str;
|
||||
}
|
||||
|
||||
static char* ensure_valid_charset(char* str, size_t length)
|
||||
{
|
||||
const size_t len = strnlen(str, length);
|
||||
for (size_t x = 0; x < len; x++)
|
||||
{
|
||||
char cur = str[x];
|
||||
switch (cur)
|
||||
{
|
||||
case ':':
|
||||
str[x] = '.';
|
||||
break;
|
||||
case '/':
|
||||
case '\\':
|
||||
str[x] = '_';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static const char* freerdp_certificate_data_hash_(const char* hostname, UINT16 port, char* name,
|
||||
size_t length)
|
||||
{
|
||||
(void)_snprintf(name, length, "%s_%" PRIu16 ".pem", hostname, port);
|
||||
return ensure_lowercase(ensure_valid_charset(name, length), length);
|
||||
}
|
||||
|
||||
static BOOL freerdp_certificate_data_load_cache(rdpCertificateData* data)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(data);
|
||||
|
||||
freerdp_certificate_data_hash_(data->hostname, data->port, data->cached_hash,
|
||||
sizeof(data->cached_hash) - 1);
|
||||
const size_t len = strnlen(data->cached_hash, sizeof(data->cached_hash));
|
||||
if ((len == 0) || (len >= sizeof(data->cached_hash)))
|
||||
goto fail;
|
||||
|
||||
data->cached_subject = freerdp_certificate_get_subject(data->cert);
|
||||
if (!data->cached_subject)
|
||||
data->cached_subject = calloc(1, 1);
|
||||
|
||||
{
|
||||
size_t pemlen = 0;
|
||||
data->cached_pem = freerdp_certificate_get_pem_ex(data->cert, &pemlen, FALSE);
|
||||
}
|
||||
if (!data->cached_pem)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
size_t pemchainlen = 0;
|
||||
data->cached_pem_chain = freerdp_certificate_get_pem_ex(data->cert, &pemchainlen, TRUE);
|
||||
if (!data->cached_pem_chain)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
data->cached_fingerprint = freerdp_certificate_get_fingerprint(data->cert);
|
||||
if (!data->cached_fingerprint)
|
||||
goto fail;
|
||||
|
||||
data->cached_issuer = freerdp_certificate_get_issuer(data->cert);
|
||||
if (!data->cached_issuer)
|
||||
data->cached_issuer = calloc(1, 1);
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static rdpCertificateData* freerdp_certificate_data_new_nocopy(const char* hostname, UINT16 port,
|
||||
rdpCertificate* xcert)
|
||||
{
|
||||
rdpCertificateData* certdata = nullptr;
|
||||
|
||||
if (!hostname || !xcert)
|
||||
goto fail;
|
||||
if (strnlen(hostname, MAX_PATH) >= MAX_PATH)
|
||||
{
|
||||
WLog_ERR(TAG, "hostname exceeds length limits");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
certdata = (rdpCertificateData*)calloc(1, sizeof(rdpCertificateData));
|
||||
|
||||
if (!certdata)
|
||||
goto fail;
|
||||
|
||||
certdata->port = port;
|
||||
certdata->hostname = _strdup(hostname);
|
||||
if (!certdata->hostname)
|
||||
goto fail;
|
||||
ensure_lowercase(certdata->hostname, strlen(certdata->hostname));
|
||||
|
||||
certdata->cert = xcert;
|
||||
if (!freerdp_certificate_data_load_cache(certdata))
|
||||
{
|
||||
certdata->cert = nullptr;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return certdata;
|
||||
fail:
|
||||
freerdp_certificate_data_free(certdata);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rdpCertificateData* freerdp_certificate_data_new(const char* hostname, UINT16 port,
|
||||
const rdpCertificate* xcert)
|
||||
{
|
||||
rdpCertificate* copy = freerdp_certificate_clone(xcert);
|
||||
rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, copy);
|
||||
if (!data)
|
||||
freerdp_certificate_free(copy);
|
||||
return data;
|
||||
}
|
||||
|
||||
rdpCertificateData* freerdp_certificate_data_new_from_pem(const char* hostname, UINT16 port,
|
||||
const char* pem, size_t length)
|
||||
{
|
||||
if (!pem || (length == 0))
|
||||
return nullptr;
|
||||
|
||||
rdpCertificate* cert = freerdp_certificate_new_from_pem(pem);
|
||||
rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
|
||||
if (!data)
|
||||
freerdp_certificate_free(cert);
|
||||
return data;
|
||||
}
|
||||
|
||||
rdpCertificateData* freerdp_certificate_data_new_from_file(const char* hostname, UINT16 port,
|
||||
const char* file)
|
||||
{
|
||||
if (!file)
|
||||
return nullptr;
|
||||
|
||||
rdpCertificate* cert = freerdp_certificate_new_from_file(file);
|
||||
rdpCertificateData* data = freerdp_certificate_data_new_nocopy(hostname, port, cert);
|
||||
if (!data)
|
||||
freerdp_certificate_free(cert);
|
||||
return data;
|
||||
}
|
||||
|
||||
void freerdp_certificate_data_free(rdpCertificateData* data)
|
||||
{
|
||||
if (data == nullptr)
|
||||
return;
|
||||
|
||||
free(data->hostname);
|
||||
freerdp_certificate_free(data->cert);
|
||||
free(data->cached_subject);
|
||||
free(data->cached_issuer);
|
||||
free(data->cached_fingerprint);
|
||||
free(data->cached_pem);
|
||||
free(data->cached_pem_chain);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_data_get_host(const rdpCertificateData* cert)
|
||||
{
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
return cert->hostname;
|
||||
}
|
||||
|
||||
UINT16 freerdp_certificate_data_get_port(const rdpCertificateData* cert)
|
||||
{
|
||||
if (!cert)
|
||||
return 0;
|
||||
return cert->port;
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_data_get_pem(const rdpCertificateData* cert)
|
||||
{
|
||||
return freerdp_certificate_data_get_pem_ex(cert, TRUE);
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_data_get_pem_ex(const rdpCertificateData* cert, BOOL withFullChain)
|
||||
{
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
if (withFullChain)
|
||||
return cert->cached_pem_chain;
|
||||
return cert->cached_pem;
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_data_get_subject(const rdpCertificateData* cert)
|
||||
{
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
|
||||
return cert->cached_subject;
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_data_get_issuer(const rdpCertificateData* cert)
|
||||
{
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
|
||||
return cert->cached_issuer;
|
||||
}
|
||||
const char* freerdp_certificate_data_get_fingerprint(const rdpCertificateData* cert)
|
||||
{
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
|
||||
return cert->cached_fingerprint;
|
||||
}
|
||||
|
||||
BOOL freerdp_certificate_data_equal(const rdpCertificateData* a, const rdpCertificateData* b)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(a);
|
||||
WINPR_ASSERT(b);
|
||||
|
||||
if (strcmp(a->hostname, b->hostname) != 0)
|
||||
return FALSE;
|
||||
if (a->port != b->port)
|
||||
return FALSE;
|
||||
|
||||
const char* pem1 = freerdp_certificate_data_get_fingerprint(a);
|
||||
const char* pem2 = freerdp_certificate_data_get_fingerprint(b);
|
||||
if (pem1 && pem2)
|
||||
rc = strcmp(pem1, pem2) == 0;
|
||||
else
|
||||
rc = pem1 == pem2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_data_get_hash(const rdpCertificateData* cert)
|
||||
{
|
||||
if (!cert)
|
||||
return nullptr;
|
||||
|
||||
return cert->cached_hash;
|
||||
}
|
||||
|
||||
char* freerdp_certificate_data_hash(const char* hostname, UINT16 port)
|
||||
{
|
||||
char name[MAX_PATH + 10] = WINPR_C_ARRAY_INIT;
|
||||
freerdp_certificate_data_hash_(hostname, port, name, sizeof(name));
|
||||
return strndup(name, sizeof(name));
|
||||
}
|
||||
206
third_party/FreeRDP/libfreerdp/crypto/certificate_store.c
vendored
Normal file
206
third_party/FreeRDP/libfreerdp/crypto/certificate_store.c
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Certificate Handling
|
||||
*
|
||||
* Copyright 2011 Jiten Pathy
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <winpr/crypto.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/path.h>
|
||||
|
||||
#include <freerdp/settings.h>
|
||||
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
#include <freerdp/crypto/certificate_store.h>
|
||||
#include <freerdp/log.h>
|
||||
|
||||
struct rdp_certificate_store
|
||||
{
|
||||
char* certs_path;
|
||||
char* server_path;
|
||||
};
|
||||
|
||||
static const char certificate_store_dir[] = "certs";
|
||||
static const char certificate_server_dir[] = "server";
|
||||
|
||||
static char* freerdp_certificate_store_file_path(const rdpCertificateStore* store, const char* hash)
|
||||
{
|
||||
const char* hosts = freerdp_certificate_store_get_hosts_path(store);
|
||||
|
||||
if (!hosts || !hash)
|
||||
return nullptr;
|
||||
|
||||
return GetCombinedPath(hosts, hash);
|
||||
}
|
||||
|
||||
freerdp_certificate_store_result
|
||||
freerdp_certificate_store_contains_data(rdpCertificateStore* store, const rdpCertificateData* data)
|
||||
{
|
||||
freerdp_certificate_store_result rc = CERT_STORE_NOT_FOUND;
|
||||
const char* host = freerdp_certificate_data_get_host(data);
|
||||
const UINT16 port = freerdp_certificate_data_get_port(data);
|
||||
|
||||
rdpCertificateData* loaded = freerdp_certificate_store_load_data(store, host, port);
|
||||
if (!loaded)
|
||||
goto fail;
|
||||
|
||||
rc = freerdp_certificate_data_equal(data, loaded) ? CERT_STORE_MATCH : CERT_STORE_MISMATCH;
|
||||
|
||||
fail:
|
||||
freerdp_certificate_data_free(loaded);
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL freerdp_certificate_store_remove_data(rdpCertificateStore* store,
|
||||
const rdpCertificateData* data)
|
||||
{
|
||||
BOOL rc = TRUE;
|
||||
|
||||
WINPR_ASSERT(store);
|
||||
|
||||
const char* hash = freerdp_certificate_data_get_hash(data);
|
||||
if (!hash)
|
||||
return FALSE;
|
||||
char* path = freerdp_certificate_store_file_path(store, hash);
|
||||
|
||||
if (!path)
|
||||
return FALSE;
|
||||
|
||||
if (winpr_PathFileExists(path))
|
||||
rc = winpr_DeleteFile(path);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
BOOL freerdp_certificate_store_save_data(rdpCertificateStore* store, const rdpCertificateData* data)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
const char* base = freerdp_certificate_store_get_hosts_path(store);
|
||||
const char* hash = freerdp_certificate_data_get_hash(data);
|
||||
char* path = freerdp_certificate_store_file_path(store, hash);
|
||||
FILE* fp = nullptr;
|
||||
|
||||
if (!winpr_PathFileExists(base))
|
||||
{
|
||||
if (!winpr_PathMakePath(base, nullptr))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fp = winpr_fopen(path, "w");
|
||||
if (!fp)
|
||||
goto fail;
|
||||
|
||||
(void)fprintf(fp, "%s", freerdp_certificate_data_get_pem_ex(data, FALSE));
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (fp)
|
||||
(void)fclose(fp);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rdpCertificateData* freerdp_certificate_store_load_data(rdpCertificateStore* store,
|
||||
const char* host, UINT16 port)
|
||||
{
|
||||
char* path = nullptr;
|
||||
rdpCertificateData* data = nullptr;
|
||||
|
||||
WINPR_ASSERT(store);
|
||||
|
||||
path = freerdp_certificate_store_get_cert_path(store, host, port);
|
||||
if (!path)
|
||||
goto fail;
|
||||
|
||||
data = freerdp_certificate_data_new_from_file(host, port, path);
|
||||
|
||||
fail:
|
||||
free(path);
|
||||
return data;
|
||||
}
|
||||
|
||||
rdpCertificateStore* freerdp_certificate_store_new(const rdpSettings* settings)
|
||||
{
|
||||
rdpCertificateStore* store = (rdpCertificateStore*)calloc(1, sizeof(rdpCertificateStore));
|
||||
|
||||
if (!store)
|
||||
return nullptr;
|
||||
|
||||
const char* base = freerdp_settings_get_string(settings, FreeRDP_ConfigPath);
|
||||
if (!base)
|
||||
goto fail;
|
||||
|
||||
store->certs_path = GetCombinedPath(base, certificate_store_dir);
|
||||
store->server_path = GetCombinedPath(base, certificate_server_dir);
|
||||
if (!store->certs_path || !store->server_path)
|
||||
goto fail;
|
||||
|
||||
return store;
|
||||
|
||||
fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
freerdp_certificate_store_free(store);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void freerdp_certificate_store_free(rdpCertificateStore* store)
|
||||
{
|
||||
if (!store)
|
||||
return;
|
||||
|
||||
free(store->certs_path);
|
||||
free(store->server_path);
|
||||
free(store);
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_store_get_certs_path(const rdpCertificateStore* store)
|
||||
{
|
||||
WINPR_ASSERT(store);
|
||||
return store->certs_path;
|
||||
}
|
||||
|
||||
const char* freerdp_certificate_store_get_hosts_path(const rdpCertificateStore* store)
|
||||
{
|
||||
WINPR_ASSERT(store);
|
||||
return store->server_path;
|
||||
}
|
||||
|
||||
char* freerdp_certificate_store_get_cert_path(const rdpCertificateStore* store, const char* host,
|
||||
UINT16 port)
|
||||
{
|
||||
WINPR_ASSERT(store);
|
||||
|
||||
char* hash = freerdp_certificate_data_hash(host, port);
|
||||
if (!hash)
|
||||
return nullptr;
|
||||
char* path = freerdp_certificate_store_file_path(store, hash);
|
||||
free(hash);
|
||||
return path;
|
||||
}
|
||||
272
third_party/FreeRDP/libfreerdp/crypto/crypto.c
vendored
Normal file
272
third_party/FreeRDP/libfreerdp/crypto/crypto.c
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Cryptographic Abstraction Layer
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
#include "crypto.h"
|
||||
#include "privatekey.h"
|
||||
|
||||
#define TAG FREERDP_TAG("crypto")
|
||||
|
||||
static SSIZE_T crypto_rsa_common(const BYTE* input, size_t length, UINT32 key_length,
|
||||
const BYTE* modulus, const BYTE* exponent, size_t exponent_size,
|
||||
BYTE* output, size_t out_length)
|
||||
{
|
||||
BN_CTX* ctx = nullptr;
|
||||
int output_length = -1;
|
||||
BYTE* input_reverse = nullptr;
|
||||
BYTE* modulus_reverse = nullptr;
|
||||
BYTE* exponent_reverse = nullptr;
|
||||
BIGNUM* mod = nullptr;
|
||||
BIGNUM* exp = nullptr;
|
||||
BIGNUM* x = nullptr;
|
||||
BIGNUM* y = nullptr;
|
||||
size_t bufferSize = 0;
|
||||
|
||||
if (!input || !modulus || !exponent || !output)
|
||||
return -1;
|
||||
|
||||
if (exponent_size > INT_MAX / 2)
|
||||
return -1;
|
||||
|
||||
if (key_length >= INT_MAX / 2 - exponent_size)
|
||||
return -1;
|
||||
|
||||
bufferSize = 2ULL * key_length + exponent_size;
|
||||
if (length > bufferSize)
|
||||
bufferSize = length;
|
||||
|
||||
input_reverse = (BYTE*)calloc(bufferSize, 1);
|
||||
|
||||
if (!input_reverse)
|
||||
return -1;
|
||||
|
||||
modulus_reverse = input_reverse + key_length;
|
||||
exponent_reverse = modulus_reverse + key_length;
|
||||
memcpy(modulus_reverse, modulus, key_length);
|
||||
crypto_reverse(modulus_reverse, key_length);
|
||||
memcpy(exponent_reverse, exponent, exponent_size);
|
||||
crypto_reverse(exponent_reverse, exponent_size);
|
||||
memcpy(input_reverse, input, length);
|
||||
crypto_reverse(input_reverse, length);
|
||||
|
||||
if (!(ctx = BN_CTX_new()))
|
||||
goto fail;
|
||||
|
||||
if (!(mod = BN_new()))
|
||||
goto fail;
|
||||
|
||||
if (!(exp = BN_new()))
|
||||
goto fail;
|
||||
|
||||
if (!(x = BN_new()))
|
||||
goto fail;
|
||||
|
||||
if (!(y = BN_new()))
|
||||
goto fail;
|
||||
|
||||
if (!BN_bin2bn(modulus_reverse, (int)key_length, mod))
|
||||
goto fail;
|
||||
|
||||
if (!BN_bin2bn(exponent_reverse, (int)exponent_size, exp))
|
||||
goto fail;
|
||||
if (!BN_bin2bn(input_reverse, (int)length, x))
|
||||
goto fail;
|
||||
if (BN_mod_exp(y, x, exp, mod, ctx) != 1)
|
||||
goto fail;
|
||||
output_length = BN_bn2bin(y, output);
|
||||
if (output_length < 0)
|
||||
goto fail;
|
||||
if (WINPR_ASSERTING_INT_CAST(size_t, output_length) > out_length)
|
||||
goto fail;
|
||||
crypto_reverse(output, WINPR_ASSERTING_INT_CAST(size_t, output_length));
|
||||
|
||||
if ((size_t)output_length < key_length)
|
||||
{
|
||||
size_t diff = key_length - WINPR_ASSERTING_INT_CAST(size_t, output_length);
|
||||
if ((size_t)output_length + diff > out_length)
|
||||
diff = out_length - (size_t)output_length;
|
||||
memset(output + output_length, 0, diff);
|
||||
}
|
||||
|
||||
fail:
|
||||
BN_free(y);
|
||||
BN_clear_free(x);
|
||||
BN_free(exp);
|
||||
BN_free(mod);
|
||||
BN_CTX_free(ctx);
|
||||
free(input_reverse);
|
||||
return output_length;
|
||||
}
|
||||
|
||||
static SSIZE_T crypto_rsa_public(const BYTE* input, size_t length, const rdpCertInfo* cert,
|
||||
BYTE* output, size_t output_length)
|
||||
{
|
||||
WINPR_ASSERT(cert);
|
||||
return crypto_rsa_common(input, length, cert->ModulusLength, cert->Modulus, cert->exponent,
|
||||
sizeof(cert->exponent), output, output_length);
|
||||
}
|
||||
|
||||
static SSIZE_T crypto_rsa_private(const BYTE* input, size_t length, const rdpPrivateKey* key,
|
||||
BYTE* output, size_t output_length)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
const rdpCertInfo* info = freerdp_key_get_info(key);
|
||||
WINPR_ASSERT(info);
|
||||
|
||||
size_t PrivateExponentLength = 0;
|
||||
const BYTE* PrivateExponent = freerdp_key_get_exponent(key, &PrivateExponentLength);
|
||||
return crypto_rsa_common(input, length, info->ModulusLength, info->Modulus, PrivateExponent,
|
||||
PrivateExponentLength, output, output_length);
|
||||
}
|
||||
|
||||
SSIZE_T crypto_rsa_public_encrypt(const BYTE* input, size_t length, const rdpCertInfo* cert,
|
||||
BYTE* output, size_t output_length)
|
||||
{
|
||||
return crypto_rsa_public(input, length, cert, output, output_length);
|
||||
}
|
||||
|
||||
SSIZE_T crypto_rsa_public_decrypt(const BYTE* input, size_t length, const rdpCertInfo* cert,
|
||||
BYTE* output, size_t output_length)
|
||||
{
|
||||
return crypto_rsa_public(input, length, cert, output, output_length);
|
||||
}
|
||||
|
||||
SSIZE_T crypto_rsa_private_encrypt(const BYTE* input, size_t length, const rdpPrivateKey* key,
|
||||
BYTE* output, size_t output_length)
|
||||
{
|
||||
return crypto_rsa_private(input, length, key, output, output_length);
|
||||
}
|
||||
|
||||
SSIZE_T crypto_rsa_private_decrypt(const BYTE* input, size_t length, const rdpPrivateKey* key,
|
||||
BYTE* output, size_t output_length)
|
||||
{
|
||||
return crypto_rsa_private(input, length, key, output, output_length);
|
||||
}
|
||||
|
||||
void crypto_reverse(BYTE* data, size_t length)
|
||||
{
|
||||
if (length < 1)
|
||||
return;
|
||||
|
||||
for (size_t i = 0, j = length - 1; i < j; i++, j--)
|
||||
{
|
||||
const BYTE temp = data[i];
|
||||
data[i] = data[j];
|
||||
data[j] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
char* crypto_read_pem(const char* WINPR_RESTRICT filename, size_t* WINPR_RESTRICT plength)
|
||||
{
|
||||
char* pem = nullptr;
|
||||
FILE* fp = nullptr;
|
||||
|
||||
WINPR_ASSERT(filename);
|
||||
|
||||
if (plength)
|
||||
*plength = 0;
|
||||
|
||||
fp = winpr_fopen(filename, "r");
|
||||
if (!fp)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const int rs = _fseeki64(fp, 0, SEEK_END);
|
||||
if (rs < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
{
|
||||
const int64_t size = _ftelli64(fp);
|
||||
if (size < 0)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const int rc = _fseeki64(fp, 0, SEEK_SET);
|
||||
if (rc < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pem = calloc(WINPR_ASSERTING_INT_CAST(size_t, size) + 1, sizeof(char));
|
||||
if (!pem)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const size_t fr = fread(pem, (size_t)size, 1, fp);
|
||||
if (fr != 1)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (plength)
|
||||
*plength = strnlen(pem, WINPR_ASSERTING_INT_CAST(size_t, size));
|
||||
}
|
||||
(void)fclose(fp);
|
||||
return pem;
|
||||
|
||||
fail:
|
||||
{
|
||||
char buffer[8192] = WINPR_C_ARRAY_INIT;
|
||||
WLog_WARN(TAG, "Failed to read PEM from file '%s' [%s]", filename,
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
}
|
||||
if (fp)
|
||||
(void)fclose(fp);
|
||||
free(pem);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BOOL crypto_write_pem(const char* WINPR_RESTRICT filename, const char* WINPR_RESTRICT pem,
|
||||
size_t length)
|
||||
{
|
||||
WINPR_ASSERT(filename);
|
||||
WINPR_ASSERT(pem || (length == 0));
|
||||
|
||||
WINPR_ASSERT(filename);
|
||||
WINPR_ASSERT(pem);
|
||||
|
||||
const size_t size = strnlen(pem, length) + 1;
|
||||
size_t rc = 0;
|
||||
FILE* fp = winpr_fopen(filename, "w");
|
||||
if (!fp)
|
||||
goto fail;
|
||||
rc = fwrite(pem, 1, size, fp);
|
||||
(void)fclose(fp);
|
||||
fail:
|
||||
if (rc == 0)
|
||||
{
|
||||
char buffer[8192] = WINPR_C_ARRAY_INIT;
|
||||
WLog_WARN(TAG, "Failed to write PEM [%" PRIuz "] to file '%s' [%s]", length, filename,
|
||||
winpr_strerror(errno, buffer, sizeof(buffer)));
|
||||
}
|
||||
return rc == size;
|
||||
}
|
||||
62
third_party/FreeRDP/libfreerdp/crypto/crypto.h
vendored
Normal file
62
third_party/FreeRDP/libfreerdp/crypto/crypto.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Cryptographic Abstraction Layer
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.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 FREERDP_LIB_CRYPTO_H
|
||||
#define FREERDP_LIB_CRYPTO_H
|
||||
|
||||
/* OpenSSL includes windows.h */
|
||||
#include <winpr/windows.h>
|
||||
#include <winpr/custom-crypto.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/freerdp.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL SSIZE_T crypto_rsa_public_encrypt(const BYTE* input, size_t length,
|
||||
const rdpCertInfo* cert, BYTE* output,
|
||||
size_t output_length);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL SSIZE_T crypto_rsa_public_decrypt(const BYTE* input, size_t length,
|
||||
const rdpCertInfo* cert, BYTE* output,
|
||||
size_t output_length);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL SSIZE_T crypto_rsa_private_encrypt(const BYTE* input, size_t length,
|
||||
const rdpPrivateKey* key, BYTE* output,
|
||||
size_t output_length);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL SSIZE_T crypto_rsa_private_decrypt(const BYTE* input, size_t length,
|
||||
const rdpPrivateKey* key, BYTE* output,
|
||||
size_t output_length);
|
||||
|
||||
FREERDP_LOCAL void crypto_reverse(BYTE* data, size_t length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CRYPTO_H */
|
||||
106
third_party/FreeRDP/libfreerdp/crypto/der.c
vendored
Normal file
106
third_party/FreeRDP/libfreerdp/crypto/der.c
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* ASN.1 Basic Encoding Rules (DER)
|
||||
*
|
||||
* Copyright 2011 Samsung, Author Jiten Pathy
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include <freerdp/crypto/der.h>
|
||||
|
||||
int _der_skip_length(int length)
|
||||
{
|
||||
if (length > 0x7F && length <= 0xFF)
|
||||
return 2;
|
||||
else if (length > 0xFF)
|
||||
return 3;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int der_write_length(wStream* s, int length)
|
||||
{
|
||||
if (length > 0x7F && length <= 0xFF)
|
||||
{
|
||||
Stream_Write_UINT8(s, 0x81);
|
||||
Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, length));
|
||||
return 2;
|
||||
}
|
||||
else if (length > 0xFF)
|
||||
{
|
||||
Stream_Write_UINT8(s, 0x82);
|
||||
Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, length));
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, length));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int der_get_content_length(int length)
|
||||
{
|
||||
if (length > 0x81 && length <= 0x102)
|
||||
return length - 3;
|
||||
else if (length > 0x102)
|
||||
return length - 4;
|
||||
else
|
||||
return length - 2;
|
||||
}
|
||||
|
||||
int der_skip_contextual_tag(int length)
|
||||
{
|
||||
return _der_skip_length(length) + 1;
|
||||
}
|
||||
|
||||
int der_write_contextual_tag(wStream* s, BYTE tag, int length, BOOL pc)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_CTXT | ER_PC(pc)) | (ER_TAG_MASK & tag));
|
||||
return der_write_length(s, length) + 1;
|
||||
}
|
||||
|
||||
static void der_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_UNIV | ER_PC(pc)) | (ER_TAG_MASK & tag));
|
||||
}
|
||||
|
||||
int der_skip_octet_string(int length)
|
||||
{
|
||||
return 1 + _der_skip_length(length) + length;
|
||||
}
|
||||
|
||||
void der_write_octet_string(wStream* s, BYTE* oct_str, int length)
|
||||
{
|
||||
der_write_universal_tag(s, ER_TAG_OCTET_STRING, FALSE);
|
||||
der_write_length(s, length);
|
||||
Stream_Write(s, oct_str, WINPR_ASSERTING_INT_CAST(size_t, length));
|
||||
}
|
||||
|
||||
int der_skip_sequence_tag(int length)
|
||||
{
|
||||
return 1 + _der_skip_length(length);
|
||||
}
|
||||
|
||||
int der_write_sequence_tag(wStream* s, int length)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_UNIV | ER_CONSTRUCT) | (ER_TAG_MASK & ER_TAG_SEQUENCE));
|
||||
return der_write_length(s, length) + 1;
|
||||
}
|
||||
445
third_party/FreeRDP/libfreerdp/crypto/er.c
vendored
Normal file
445
third_party/FreeRDP/libfreerdp/crypto/er.c
vendored
Normal file
@@ -0,0 +1,445 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* ASN.1 Encoding Rules (BER/DER common functions)
|
||||
*
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Modified by Jiten Pathy
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
|
||||
#include <freerdp/crypto/er.h>
|
||||
#include <freerdp/crypto/ber.h>
|
||||
#include <freerdp/crypto/der.h>
|
||||
|
||||
void er_read_length(wStream* s, int* length)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (!length)
|
||||
return;
|
||||
|
||||
*length = 0;
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
if (byte & 0x80)
|
||||
{
|
||||
byte &= ~(0x80);
|
||||
|
||||
if (byte == 1)
|
||||
Stream_Read_UINT8(s, *length);
|
||||
if (byte == 2)
|
||||
Stream_Read_UINT16_BE(s, *length);
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = byte;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write er length.
|
||||
* @param s stream
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
int er_write_length(wStream* s, int length, BOOL flag)
|
||||
{
|
||||
WINPR_ASSERT(length >= 0);
|
||||
if (flag)
|
||||
return der_write_length(s, length);
|
||||
else
|
||||
return (int)ber_write_length(s, (size_t)length);
|
||||
}
|
||||
|
||||
int _er_skip_length(int length)
|
||||
{
|
||||
if (length > 0x7F)
|
||||
return 3;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int er_get_content_length(int length)
|
||||
{
|
||||
if (length - 1 > 0x7F)
|
||||
return length - 4;
|
||||
else
|
||||
return length - 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read er Universal tag.
|
||||
* @param s A pointer to the stream to write to
|
||||
* @param tag er universally-defined tag
|
||||
* @return \b TRUE for success
|
||||
*/
|
||||
|
||||
BOOL er_read_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
return (byte == (ER_CLASS_UNIV | ER_PC(pc) | (ER_TAG_MASK & tag)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write er Universal tag.
|
||||
* @param s stream
|
||||
* @param tag er universally-defined tag
|
||||
* @param pc primitive (FALSE) or constructed (TRUE)
|
||||
*/
|
||||
|
||||
void er_write_universal_tag(wStream* s, BYTE tag, BOOL pc)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_UNIV | ER_PC(pc)) | (ER_TAG_MASK & tag));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read er Application tag.
|
||||
* @param s stream
|
||||
* @param tag er application-defined tag
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
BOOL er_read_application_tag(wStream* s, BYTE tag, int* length)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
if (tag > 30)
|
||||
{
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != ((ER_CLASS_APPL | ER_CONSTRUCT) | ER_TAG_MASK))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != tag)
|
||||
return FALSE;
|
||||
|
||||
er_read_length(s, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != ((ER_CLASS_APPL | ER_CONSTRUCT) | (ER_TAG_MASK & tag)))
|
||||
return FALSE;
|
||||
|
||||
er_read_length(s, length);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write er Application tag.
|
||||
* @param s stream
|
||||
* @param tag er application-defined tag
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
void er_write_application_tag(wStream* s, BYTE tag, int length, BOOL flag)
|
||||
{
|
||||
if (tag > 30)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_APPL | ER_CONSTRUCT) | ER_TAG_MASK);
|
||||
Stream_Write_UINT8(s, tag);
|
||||
er_write_length(s, length, flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_APPL | ER_CONSTRUCT) | (ER_TAG_MASK & tag));
|
||||
er_write_length(s, length, flag);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL er_read_contextual_tag(wStream* s, BYTE tag, int* length, BOOL pc)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != ((ER_CLASS_CTXT | ER_PC(pc)) | (ER_TAG_MASK & tag)))
|
||||
{
|
||||
Stream_Rewind(s, 1);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
er_read_length(s, length);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int er_write_contextual_tag(wStream* s, BYTE tag, int length, BOOL pc, BOOL flag)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_CTXT | ER_PC(pc)) | (ER_TAG_MASK & tag));
|
||||
return er_write_length(s, length, flag) + 1;
|
||||
}
|
||||
|
||||
int er_skip_contextual_tag(int length)
|
||||
{
|
||||
return _er_skip_length(length) + 1;
|
||||
}
|
||||
|
||||
BOOL er_read_sequence_tag(wStream* s, int* length)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte != ((ER_CLASS_UNIV | ER_CONSTRUCT) | (ER_TAG_SEQUENCE_OF)))
|
||||
return FALSE;
|
||||
|
||||
er_read_length(s, length);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write er SEQUENCE tag.
|
||||
* @param s stream
|
||||
* @param length length
|
||||
*/
|
||||
|
||||
int er_write_sequence_tag(wStream* s, int length, BOOL flag)
|
||||
{
|
||||
Stream_Write_UINT8(s, (ER_CLASS_UNIV | ER_CONSTRUCT) | (ER_TAG_MASK & ER_TAG_SEQUENCE));
|
||||
return er_write_length(s, length, flag) + 1;
|
||||
}
|
||||
|
||||
int er_skip_sequence(int length)
|
||||
{
|
||||
return 1 + _er_skip_length(length) + length;
|
||||
}
|
||||
|
||||
int er_skip_sequence_tag(int length)
|
||||
{
|
||||
return 1 + _er_skip_length(length);
|
||||
}
|
||||
|
||||
BOOL er_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
|
||||
{
|
||||
int length = 0;
|
||||
|
||||
er_read_universal_tag(s, ER_TAG_ENUMERATED, FALSE);
|
||||
er_read_length(s, &length);
|
||||
|
||||
if (length == 1)
|
||||
Stream_Read_UINT8(s, *enumerated);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
/* check that enumerated value falls within expected range */
|
||||
if (*enumerated + 1 > count)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void er_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count, BOOL flag)
|
||||
{
|
||||
er_write_universal_tag(s, ER_TAG_ENUMERATED, FALSE);
|
||||
er_write_length(s, 1, flag);
|
||||
Stream_Write_UINT8(s, enumerated);
|
||||
}
|
||||
|
||||
BOOL er_read_bit_string(wStream* s, int* length, BYTE* padding)
|
||||
{
|
||||
er_read_universal_tag(s, ER_TAG_BIT_STRING, FALSE);
|
||||
er_read_length(s, length);
|
||||
Stream_Read_UINT8(s, *padding);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL er_write_bit_string_tag(wStream* s, UINT32 length, BYTE padding, BOOL flag)
|
||||
{
|
||||
er_write_universal_tag(s, ER_TAG_BIT_STRING, FALSE);
|
||||
er_write_length(s, WINPR_ASSERTING_INT_CAST(int, length), flag);
|
||||
Stream_Write_UINT8(s, padding);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL er_read_octet_string(wStream* s, int* length)
|
||||
{
|
||||
if (!er_read_universal_tag(s, ER_TAG_OCTET_STRING, FALSE))
|
||||
return FALSE;
|
||||
er_read_length(s, length);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a er OCTET_STRING
|
||||
* @param s stream
|
||||
* @param oct_str octet string
|
||||
* @param length string length
|
||||
*/
|
||||
|
||||
void er_write_octet_string(wStream* s, BYTE* oct_str, int length, BOOL flag)
|
||||
{
|
||||
er_write_universal_tag(s, ER_TAG_OCTET_STRING, FALSE);
|
||||
er_write_length(s, length, flag);
|
||||
Stream_Write(s, oct_str, WINPR_ASSERTING_INT_CAST(size_t, length));
|
||||
}
|
||||
|
||||
int er_write_octet_string_tag(wStream* s, int length, BOOL flag)
|
||||
{
|
||||
er_write_universal_tag(s, ER_TAG_OCTET_STRING, FALSE);
|
||||
er_write_length(s, length, flag);
|
||||
return 1 + _er_skip_length(length);
|
||||
}
|
||||
|
||||
int er_skip_octet_string(int length)
|
||||
{
|
||||
return 1 + _er_skip_length(length) + length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a er BOOLEAN
|
||||
* @param s A pointer to the stream to read from
|
||||
* @param value A pointer to read the data to
|
||||
*/
|
||||
|
||||
BOOL er_read_BOOL(wStream* s, BOOL* value)
|
||||
{
|
||||
int length = 0;
|
||||
BYTE v = 0;
|
||||
|
||||
if (!er_read_universal_tag(s, ER_TAG_BOOLEAN, FALSE))
|
||||
return FALSE;
|
||||
er_read_length(s, &length);
|
||||
if (length != 1)
|
||||
return FALSE;
|
||||
Stream_Read_UINT8(s, v);
|
||||
*value = v != 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a er BOOLEAN
|
||||
* @param s A pointer to the stream to write to
|
||||
* @param value The value to write
|
||||
*/
|
||||
|
||||
void er_write_BOOL(wStream* s, BOOL value)
|
||||
{
|
||||
er_write_universal_tag(s, ER_TAG_BOOLEAN, FALSE);
|
||||
er_write_length(s, 1, FALSE);
|
||||
Stream_Write_UINT8(s, (value == TRUE) ? 0xFF : 0);
|
||||
}
|
||||
|
||||
BOOL er_read_integer(wStream* s, UINT32* value)
|
||||
{
|
||||
int length = 0;
|
||||
|
||||
er_read_universal_tag(s, ER_TAG_INTEGER, FALSE);
|
||||
er_read_length(s, &length);
|
||||
|
||||
if (value == nullptr)
|
||||
{
|
||||
Stream_Seek(s, WINPR_ASSERTING_INT_CAST(size_t, length));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (length == 1)
|
||||
{
|
||||
Stream_Read_UINT8(s, *value);
|
||||
}
|
||||
else if (length == 2)
|
||||
{
|
||||
Stream_Read_UINT16_BE(s, *value);
|
||||
}
|
||||
else if (length == 3)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
Stream_Read_UINT8(s, byte);
|
||||
Stream_Read_UINT16_BE(s, *value);
|
||||
*value += (byte << 16) & 0xFF0000;
|
||||
}
|
||||
else if (length == 4)
|
||||
{
|
||||
Stream_Read_UINT32_BE(s, *value);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a er INTEGER
|
||||
* @param s A pointer to the stream to write to
|
||||
* @param value the value to write
|
||||
*/
|
||||
|
||||
int er_write_integer(wStream* s, INT32 value)
|
||||
{
|
||||
er_write_universal_tag(s, ER_TAG_INTEGER, FALSE);
|
||||
|
||||
if (value <= 127 && value >= -128)
|
||||
{
|
||||
er_write_length(s, 1, FALSE);
|
||||
Stream_Write_INT8(s, WINPR_ASSERTING_INT_CAST(INT8, value));
|
||||
return 2;
|
||||
}
|
||||
else if (value <= 32767 && value >= -32768)
|
||||
{
|
||||
er_write_length(s, 2, FALSE);
|
||||
Stream_Write_INT16_BE(s, WINPR_ASSERTING_INT_CAST(INT16, value));
|
||||
return 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
er_write_length(s, 4, FALSE);
|
||||
Stream_Write_INT32_BE(s, value);
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
int er_skip_integer(INT32 value)
|
||||
{
|
||||
if (value <= 127 && value >= -128)
|
||||
{
|
||||
return _er_skip_length(1) + 2;
|
||||
}
|
||||
else if (value <= 32767 && value >= -32768)
|
||||
{
|
||||
return _er_skip_length(2) + 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
return _er_skip_length(4) + 5;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL er_read_integer_length(wStream* s, int* length)
|
||||
{
|
||||
er_read_universal_tag(s, ER_TAG_INTEGER, FALSE);
|
||||
er_read_length(s, length);
|
||||
return TRUE;
|
||||
}
|
||||
45
third_party/FreeRDP/libfreerdp/crypto/opensslcompat.c
vendored
Normal file
45
third_party/FreeRDP/libfreerdp/crypto/opensslcompat.c
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* OpenSSL Compatibility
|
||||
*
|
||||
* Copyright (C) 2016 Norbert Federa <norbert.federa@thincast.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.
|
||||
*/
|
||||
|
||||
#include "opensslcompat.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
|
||||
BIO_METHOD* BIO_meth_new(int type, const char* name)
|
||||
{
|
||||
BIO_METHOD* m;
|
||||
if (!(m = calloc(1, sizeof(BIO_METHOD))))
|
||||
return nullptr;
|
||||
m->type = type;
|
||||
m->name = name;
|
||||
return m;
|
||||
}
|
||||
|
||||
void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d)
|
||||
{
|
||||
if (n != nullptr)
|
||||
*n = r->n;
|
||||
if (e != nullptr)
|
||||
*e = r->e;
|
||||
if (d != nullptr)
|
||||
*d = r->d;
|
||||
}
|
||||
|
||||
#endif /* OPENSSL < 1.1.0 || LIBRESSL */
|
||||
119
third_party/FreeRDP/libfreerdp/crypto/opensslcompat.h
vendored
Normal file
119
third_party/FreeRDP/libfreerdp/crypto/opensslcompat.h
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* OpenSSL Compatibility
|
||||
*
|
||||
* Copyright (C) 2016 Norbert Federa <norbert.federa@thincast.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 FREERDP_LIB_CRYPTO_OPENSSLCOMPAT_H
|
||||
#define FREERDP_LIB_CRYPTO_OPENSSLCOMPAT_H
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/assert.h>
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#ifdef WITH_OPENSSL
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
|
||||
(defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL)
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
|
||||
#define BIO_get_data(b) (b)->ptr
|
||||
#define BIO_set_data(b, v) (b)->ptr = v
|
||||
#define BIO_get_init(b) (b)->init
|
||||
#define BIO_set_init(b, v) (b)->init = v
|
||||
#define BIO_get_next(b, v) (b)->next_bio
|
||||
#define BIO_set_next(b, v) (b)->next_bio = v
|
||||
#define BIO_get_shutdown(b) (b)->shutdown
|
||||
#define BIO_set_shutdown(b, v) (b)->shutdown = v
|
||||
#define BIO_get_retry_reason(b) (b)->retry_reason
|
||||
#define BIO_set_retry_reason(b, v) (b)->retry_reason = v
|
||||
|
||||
#define BIO_meth_set_write(b, f) (b)->bwrite = (f)
|
||||
#define BIO_meth_set_read(b, f) (b)->bread = (f)
|
||||
#define BIO_meth_set_puts(b, f) (b)->bputs = (f)
|
||||
#define BIO_meth_set_gets(b, f) (b)->bgets = (f)
|
||||
#define BIO_meth_set_ctrl(b, f) (b)->ctrl = (f)
|
||||
#define BIO_meth_set_create(b, f) (b)->create = (f)
|
||||
#define BIO_meth_set_destroy(b, f) (b)->destroy = (f)
|
||||
#define BIO_meth_set_callback_ctrl(b, f) (b)->callback_ctrl = (f)
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL
|
||||
BIO_METHOD* BIO_meth_new(int type, const char* name);
|
||||
|
||||
FREERDP_LOCAL void RSA_get0_key(const RSA* r, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d);
|
||||
|
||||
#endif /* OPENSSL < 1.1.0 || LIBRESSL */
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
||||
/* Drop in replacement for older OpenSSL and LibRESSL */
|
||||
#if defined(LIBRESSL_VERSION_NUMBER) || \
|
||||
(defined(OPENSSL_VERSION_NUMBER) && (OPENSSL_VERSION_NUMBER < 0x1010000fL))
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
static inline STACK_OF(X509) * sk_X509_deep_copy(const STACK_OF(X509) * sk,
|
||||
X509* (*copyfunc)(const X509*),
|
||||
void (*freefunc)(X509*))
|
||||
{
|
||||
WINPR_ASSERT(copyfunc);
|
||||
WINPR_ASSERT(freefunc);
|
||||
|
||||
STACK_OF(X509)* stack = sk_X509_new_null();
|
||||
if (!stack)
|
||||
return nullptr;
|
||||
|
||||
if (sk)
|
||||
{
|
||||
for (int i = 0; i < sk_X509_num(sk); i++)
|
||||
{
|
||||
X509* cert = sk_X509_value(sk, i);
|
||||
X509* copy = copyfunc(cert);
|
||||
if (!copy)
|
||||
goto fail;
|
||||
const int rc = sk_X509_push(stack, copy);
|
||||
if (rc <= 0)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return stack;
|
||||
|
||||
fail:
|
||||
sk_X509_pop_free(stack, freefunc);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* OpenSSL API is not const consistent.
|
||||
* While the TYPE_dup function take non const arguments
|
||||
* the TYPE_sk versions require the arguments to be const...
|
||||
*/
|
||||
WINPR_ATTR_NODISCARD
|
||||
static inline X509* X509_const_dup(const X509* x509)
|
||||
{
|
||||
X509* ptr = WINPR_CAST_CONST_PTR_AWAY(x509, X509*);
|
||||
return X509_dup(ptr);
|
||||
}
|
||||
#endif /* FREERDP_LIB_CRYPTO_OPENSSLCOMPAT_H */
|
||||
591
third_party/FreeRDP/libfreerdp/crypto/per.c
vendored
Normal file
591
third_party/FreeRDP/libfreerdp/crypto/per.c
vendored
Normal file
@@ -0,0 +1,591 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* ASN.1 Packed Encoding Rules (BER)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.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.
|
||||
*/
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/cast.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
#include <freerdp/crypto/per.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
#define TAG FREERDP_TAG("crypto.per")
|
||||
|
||||
/**
|
||||
* Read PER length.
|
||||
*
|
||||
* @param s stream to read from
|
||||
* @param length A pointer to return the length read, must not be nullptr
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_length(wStream* s, UINT16* length)
|
||||
{
|
||||
BYTE byte = 0;
|
||||
|
||||
WINPR_ASSERT(length);
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, byte);
|
||||
|
||||
if (byte & 0x80)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
byte &= ~(0x80);
|
||||
*length = WINPR_ASSERTING_INT_CAST(UINT16, byte << 8);
|
||||
Stream_Read_UINT8(s, byte);
|
||||
*length += byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
*length = byte;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER length.
|
||||
* @param s stream
|
||||
* @param length length
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_length(wStream* s, UINT16 length)
|
||||
{
|
||||
if (length > 0x7F)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 2))
|
||||
return FALSE;
|
||||
Stream_Write_UINT16_BE(s, (length | 0x8000));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 1))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, (UINT8)length);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER choice.
|
||||
* @param s stream
|
||||
* @param choice choice
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_choice(wStream* s, BYTE* choice)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, *choice);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER CHOICE.
|
||||
* @param s stream
|
||||
* @param choice index of chosen field
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_choice(wStream* s, BYTE choice)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 1))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, choice);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER selection.
|
||||
* @param s stream
|
||||
* @param selection selection
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_selection(wStream* s, BYTE* selection)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(selection);
|
||||
Stream_Read_UINT8(s, *selection);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER selection for OPTIONAL fields.
|
||||
* @param s stream
|
||||
* @param selection bit map of selected fields
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_selection(wStream* s, BYTE selection)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 1))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, selection);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER number of sets.
|
||||
* @param s stream
|
||||
* @param number number of sets
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_number_of_sets(wStream* s, BYTE* number)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(number);
|
||||
Stream_Read_UINT8(s, *number);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER number of sets for SET OF.
|
||||
*
|
||||
* @param s stream
|
||||
* @param number number of sets
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_number_of_sets(wStream* s, BYTE number)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 1))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, number);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER padding with zeros.
|
||||
*
|
||||
* @param s A stream to read from
|
||||
* @param length the data to write
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_padding(wStream* s, UINT16 length)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
Stream_Seek(s, length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER padding with zeros.
|
||||
* @param s A stream to write to
|
||||
* @param length the data to write
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_padding(wStream* s, UINT16 length)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, length))
|
||||
return FALSE;
|
||||
Stream_Zero(s, length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER INTEGER.
|
||||
* @param s stream
|
||||
* @param integer integer
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_integer(wStream* s, UINT32* integer)
|
||||
{
|
||||
UINT16 length = 0;
|
||||
|
||||
WINPR_ASSERT(integer);
|
||||
|
||||
if (!per_read_length(s, &length))
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
if (length == 0)
|
||||
*integer = 0;
|
||||
else if (length == 1)
|
||||
Stream_Read_UINT8(s, *integer);
|
||||
else if (length == 2)
|
||||
Stream_Read_UINT16_BE(s, *integer);
|
||||
else
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER INTEGER.
|
||||
* @param s stream
|
||||
* @param integer integer
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_integer(wStream* s, UINT32 integer)
|
||||
{
|
||||
if (integer <= UINT8_MAX)
|
||||
{
|
||||
if (!per_write_length(s, 1))
|
||||
return FALSE;
|
||||
if (!Stream_EnsureRemainingCapacity(s, 1))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(UINT8, integer));
|
||||
}
|
||||
else if (integer <= UINT16_MAX)
|
||||
{
|
||||
if (!per_write_length(s, 2))
|
||||
return FALSE;
|
||||
if (!Stream_EnsureRemainingCapacity(s, 2))
|
||||
return FALSE;
|
||||
Stream_Write_UINT16_BE(s, WINPR_ASSERTING_INT_CAST(UINT16, integer));
|
||||
}
|
||||
else if (integer <= UINT32_MAX)
|
||||
{
|
||||
if (!per_write_length(s, 4))
|
||||
return FALSE;
|
||||
if (!Stream_EnsureRemainingCapacity(s, 4))
|
||||
return FALSE;
|
||||
Stream_Write_UINT32_BE(s, integer);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER INTEGER (UINT16).
|
||||
*
|
||||
* @param s The stream to read from
|
||||
* @param integer The integer result variable pointer, must not be nullptr
|
||||
* @param min minimum value
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise
|
||||
*/
|
||||
|
||||
BOOL per_read_integer16(wStream* s, UINT16* integer, UINT16 min)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT16_BE(s, *integer);
|
||||
|
||||
if (*integer > UINT16_MAX - min)
|
||||
{
|
||||
WLog_WARN(TAG, "PER uint16 invalid value %" PRIu16 " > %d", *integer, UINT16_MAX - min);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*integer += min;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER INTEGER (UINT16).
|
||||
* @param s stream
|
||||
* @param integer integer
|
||||
* @param min minimum value
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_integer16(wStream* s, UINT16 integer, UINT16 min)
|
||||
{
|
||||
if (min > integer)
|
||||
return FALSE;
|
||||
if (!Stream_EnsureRemainingCapacity(s, 2))
|
||||
return FALSE;
|
||||
Stream_Write_UINT16_BE(s, integer - min);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER ENUMERATED.
|
||||
*
|
||||
* @param s The stream to read from
|
||||
* @param enumerated enumerated result variable, must not be nullptr
|
||||
* @param count enumeration count
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise
|
||||
*/
|
||||
|
||||
BOOL per_read_enumerated(wStream* s, BYTE* enumerated, BYTE count)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
|
||||
return FALSE;
|
||||
|
||||
WINPR_ASSERT(enumerated);
|
||||
Stream_Read_UINT8(s, *enumerated);
|
||||
|
||||
/* check that enumerated value falls within expected range */
|
||||
if (*enumerated + 1 > count)
|
||||
{
|
||||
WLog_WARN(TAG, "PER invalid data, expected %" PRIu8 " < %" PRIu8, *enumerated, count);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER ENUMERATED.
|
||||
*
|
||||
* @param s The stream to write to
|
||||
* @param enumerated enumerated
|
||||
* @param count enumeration count
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise
|
||||
*/
|
||||
|
||||
BOOL per_write_enumerated(wStream* s, BYTE enumerated, WINPR_ATTR_UNUSED BYTE count)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 1))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, enumerated);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL per_check_oid_and_log_mismatch(const BYTE* got, const BYTE* expect, size_t length)
|
||||
{
|
||||
if (memcmp(got, expect, length) == 0)
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
char* got_str = winpr_BinToHexString(got, length, TRUE);
|
||||
char* expect_str = winpr_BinToHexString(expect, length, TRUE);
|
||||
|
||||
WLog_WARN(TAG, "PER OID mismatch, got %s, expected %s", got_str, expect_str);
|
||||
free(got_str);
|
||||
free(expect_str);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER OBJECT_IDENTIFIER (OID).
|
||||
*
|
||||
* @param s The stream to read from
|
||||
* @param oid object identifier (OID)
|
||||
* @warning It works correctly only for limited set of OIDs.
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise
|
||||
*/
|
||||
|
||||
BOOL per_read_object_identifier(wStream* s, const BYTE oid[6])
|
||||
{
|
||||
BYTE t12 = 0;
|
||||
UINT16 length = 0;
|
||||
BYTE a_oid[6] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (!per_read_length(s, &length))
|
||||
return FALSE;
|
||||
|
||||
if (length != 5)
|
||||
{
|
||||
WLog_WARN(TAG, "PER length, got %" PRIu16 ", expected 5", length);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT8(s, t12); /* first two tuples */
|
||||
a_oid[0] = t12 / 40;
|
||||
a_oid[1] = t12 % 40;
|
||||
|
||||
Stream_Read_UINT8(s, a_oid[2]); /* tuple 3 */
|
||||
Stream_Read_UINT8(s, a_oid[3]); /* tuple 4 */
|
||||
Stream_Read_UINT8(s, a_oid[4]); /* tuple 5 */
|
||||
Stream_Read_UINT8(s, a_oid[5]); /* tuple 6 */
|
||||
|
||||
return per_check_oid_and_log_mismatch(a_oid, oid, sizeof(a_oid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER OBJECT_IDENTIFIER (OID)
|
||||
* @param s stream
|
||||
* @param oid object identifier (oid)
|
||||
* @warning It works correctly only for limited set of OIDs.
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_object_identifier(wStream* s, const BYTE oid[6])
|
||||
{
|
||||
BYTE t12 = oid[0] * 40 + oid[1];
|
||||
if (!Stream_EnsureRemainingCapacity(s, 6))
|
||||
return FALSE;
|
||||
Stream_Write_UINT8(s, 5); /* length */
|
||||
Stream_Write_UINT8(s, t12); /* first two tuples */
|
||||
Stream_Write_UINT8(s, oid[2]); /* tuple 3 */
|
||||
Stream_Write_UINT8(s, oid[3]); /* tuple 4 */
|
||||
Stream_Write_UINT8(s, oid[4]); /* tuple 5 */
|
||||
Stream_Write_UINT8(s, oid[5]); /* tuple 6 */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER OCTET_STRING.
|
||||
*
|
||||
* @param s The stream to read from
|
||||
* @param oct_str octet string
|
||||
* @param length string length
|
||||
* @param min minimum length
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
|
||||
{
|
||||
UINT16 mlength = 0;
|
||||
|
||||
if (!per_read_length(s, &mlength))
|
||||
return FALSE;
|
||||
|
||||
if (mlength + min != length)
|
||||
{
|
||||
WLog_ERR(TAG, "length mismatch: %d!= %" PRIu16, mlength + min, length);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
const BYTE* a_oct_str = Stream_ConstPointer(s);
|
||||
Stream_Seek(s, length);
|
||||
|
||||
return per_check_oid_and_log_mismatch(a_oct_str, oct_str, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER OCTET_STRING
|
||||
* @param s stream
|
||||
* @param oct_str octet string
|
||||
* @param length string length
|
||||
* @param min minimum string length
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_octet_string(wStream* s, const BYTE* oct_str, UINT16 length, UINT16 min)
|
||||
{
|
||||
UINT16 mlength = 0;
|
||||
|
||||
mlength = (length >= min) ? length - min : min;
|
||||
|
||||
if (!per_write_length(s, mlength))
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, length))
|
||||
return FALSE;
|
||||
for (UINT16 i = 0; i < length; i++)
|
||||
Stream_Write_UINT8(s, oct_str[i]);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read PER NumericString.
|
||||
* @param s stream
|
||||
* @param min minimum string length
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_read_numeric_string(wStream* s, UINT16 min)
|
||||
{
|
||||
size_t length = 0;
|
||||
UINT16 mlength = 0;
|
||||
|
||||
if (!per_read_length(s, &mlength))
|
||||
return FALSE;
|
||||
|
||||
length = (mlength + min + 1) / 2;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
|
||||
return FALSE;
|
||||
|
||||
Stream_Seek(s, length);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write PER NumericString.
|
||||
* @param s stream
|
||||
* @param num_str numeric string
|
||||
* @param length string length
|
||||
* @param min minimum string length
|
||||
*
|
||||
* @return \b TRUE for success, \b FALSE otherwise.
|
||||
*/
|
||||
|
||||
BOOL per_write_numeric_string(wStream* s, const BYTE* num_str, UINT16 length, UINT16 min)
|
||||
{
|
||||
WINPR_ASSERT(num_str || (length == 0));
|
||||
|
||||
const UINT16 mlength = (length >= min) ? length - min : min;
|
||||
|
||||
if (!per_write_length(s, mlength))
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_EnsureRemainingCapacity(s, length))
|
||||
return FALSE;
|
||||
for (UINT16 i = 0; i < length; i += 2)
|
||||
{
|
||||
BYTE c1 = num_str[i];
|
||||
BYTE c2 = ((i + 1) < length) ? num_str[i + 1] : 0x30;
|
||||
|
||||
if ((c1 < 0x30) || (c2 < 0x30))
|
||||
return FALSE;
|
||||
|
||||
c1 = (c1 - 0x30) % 10;
|
||||
c2 = (c2 - 0x30) % 10;
|
||||
const BYTE num = WINPR_ASSERTING_INT_CAST(BYTE, (c1 << 4) | c2);
|
||||
|
||||
Stream_Write_UINT8(s, num); /* string */
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
684
third_party/FreeRDP/libfreerdp/crypto/privatekey.c
vendored
Normal file
684
third_party/FreeRDP/libfreerdp/crypto/privatekey.c
vendored
Normal file
@@ -0,0 +1,684 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Private key Handling
|
||||
*
|
||||
* Copyright 2011 Jiten Pathy
|
||||
* Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/crypto.h>
|
||||
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "privatekey.h"
|
||||
#include "cert_common.h"
|
||||
|
||||
#include <freerdp/crypto/privatekey.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
|
||||
#include <openssl/core_names.h>
|
||||
#endif
|
||||
|
||||
#include "x509_utils.h"
|
||||
#include "crypto.h"
|
||||
#include "opensslcompat.h"
|
||||
|
||||
#define TAG FREERDP_TAG("crypto")
|
||||
|
||||
struct rdp_private_key
|
||||
{
|
||||
EVP_PKEY* evp;
|
||||
|
||||
rdpCertInfo cert;
|
||||
BYTE* PrivateExponent;
|
||||
DWORD PrivateExponentLength;
|
||||
};
|
||||
|
||||
/*
|
||||
* Terminal Services Signing Keys.
|
||||
* Yes, Terminal Services Private Key is publicly available.
|
||||
*/
|
||||
|
||||
static BYTE tssk_modulus[] = { 0x3d, 0x3a, 0x5e, 0xbd, 0x72, 0x43, 0x3e, 0xc9, 0x4d, 0xbb, 0xc1,
|
||||
0x1e, 0x4a, 0xba, 0x5f, 0xcb, 0x3e, 0x88, 0x20, 0x87, 0xef, 0xf5,
|
||||
0xc1, 0xe2, 0xd7, 0xb7, 0x6b, 0x9a, 0xf2, 0x52, 0x45, 0x95, 0xce,
|
||||
0x63, 0x65, 0x6b, 0x58, 0x3a, 0xfe, 0xef, 0x7c, 0xe7, 0xbf, 0xfe,
|
||||
0x3d, 0xf6, 0x5c, 0x7d, 0x6c, 0x5e, 0x06, 0x09, 0x1a, 0xf5, 0x61,
|
||||
0xbb, 0x20, 0x93, 0x09, 0x5f, 0x05, 0x6d, 0xea, 0x87 };
|
||||
|
||||
static BYTE tssk_privateExponent[] = {
|
||||
0x87, 0xa7, 0x19, 0x32, 0xda, 0x11, 0x87, 0x55, 0x58, 0x00, 0x16, 0x16, 0x25, 0x65, 0x68, 0xf8,
|
||||
0x24, 0x3e, 0xe6, 0xfa, 0xe9, 0x67, 0x49, 0x94, 0xcf, 0x92, 0xcc, 0x33, 0x99, 0xe8, 0x08, 0x60,
|
||||
0x17, 0x9a, 0x12, 0x9f, 0x24, 0xdd, 0xb1, 0x24, 0x99, 0xc7, 0x3a, 0xb8, 0x0a, 0x7b, 0x0d, 0xdd,
|
||||
0x35, 0x07, 0x79, 0x17, 0x0b, 0x51, 0x9b, 0xb3, 0xc7, 0x10, 0x01, 0x13, 0xe7, 0x3f, 0xf3, 0x5f
|
||||
};
|
||||
|
||||
static const rdpPrivateKey tssk = { .PrivateExponent = tssk_privateExponent,
|
||||
.PrivateExponentLength = sizeof(tssk_privateExponent),
|
||||
.cert = { .Modulus = tssk_modulus,
|
||||
.ModulusLength = sizeof(tssk_modulus) } };
|
||||
const rdpPrivateKey* priv_key_tssk = &tssk;
|
||||
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
static RSA* evp_pkey_to_rsa(const rdpPrivateKey* key)
|
||||
{
|
||||
if (!freerdp_key_is_rsa(key))
|
||||
{
|
||||
WLog_WARN(TAG, "Key is no RSA key");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RSA* rsa = nullptr;
|
||||
BIO* bio = BIO_new(
|
||||
#if defined(LIBRESSL_VERSION_NUMBER)
|
||||
BIO_s_mem()
|
||||
#else
|
||||
BIO_s_secmem()
|
||||
#endif
|
||||
);
|
||||
if (!bio)
|
||||
return nullptr;
|
||||
const int rc = PEM_write_bio_PrivateKey(bio, key->evp, nullptr, nullptr, 0, nullptr, nullptr);
|
||||
if (rc != 1)
|
||||
goto fail;
|
||||
rsa = PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr);
|
||||
fail:
|
||||
BIO_free_all(bio);
|
||||
return rsa;
|
||||
}
|
||||
#endif
|
||||
|
||||
static EVP_PKEY* evp_pkey_utils_from_pem(const char* data, size_t len, BOOL fromFile,
|
||||
const char* password)
|
||||
{
|
||||
EVP_PKEY* evp = nullptr;
|
||||
BIO* bio = nullptr;
|
||||
if (fromFile)
|
||||
bio = BIO_new_file(data, "rb");
|
||||
else
|
||||
{
|
||||
if (len > INT_MAX)
|
||||
return nullptr;
|
||||
bio = BIO_new_mem_buf(data, (int)len);
|
||||
}
|
||||
|
||||
if (!bio)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new failed for private key");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
evp =
|
||||
PEM_read_bio_PrivateKey(bio, nullptr, nullptr, WINPR_CAST_CONST_PTR_AWAY(password, void*));
|
||||
BIO_free_all(bio);
|
||||
if (!evp)
|
||||
WLog_ERR(TAG, "PEM_read_bio_PrivateKey returned nullptr [input length %" PRIuz "]", len);
|
||||
|
||||
return evp;
|
||||
}
|
||||
|
||||
static BOOL key_read_private(rdpPrivateKey* key)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(key);
|
||||
WINPR_ASSERT(key->evp);
|
||||
|
||||
/* The key is not an RSA key, that means we just return success. */
|
||||
if (!freerdp_key_is_rsa(key))
|
||||
return TRUE;
|
||||
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
RSA* rsa = evp_pkey_to_rsa(key);
|
||||
if (!rsa)
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "unable to load RSA key: %s.",
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch (RSA_check_key(rsa))
|
||||
{
|
||||
case 0:
|
||||
WLog_ERR(TAG, "invalid RSA key");
|
||||
goto fail;
|
||||
|
||||
case 1:
|
||||
/* Valid key. */
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
char ebuffer[256] = WINPR_C_ARRAY_INIT;
|
||||
WLog_ERR(TAG, "unexpected error when checking RSA key: %s.",
|
||||
winpr_strerror(errno, ebuffer, sizeof(ebuffer)));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
const BIGNUM* rsa_e = nullptr;
|
||||
const BIGNUM* rsa_n = nullptr;
|
||||
const BIGNUM* rsa_d = nullptr;
|
||||
|
||||
RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
|
||||
#else
|
||||
BIGNUM* rsa_e = nullptr;
|
||||
BIGNUM* rsa_n = nullptr;
|
||||
BIGNUM* rsa_d = nullptr;
|
||||
|
||||
if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_N, &rsa_n))
|
||||
goto fail;
|
||||
if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_E, &rsa_e))
|
||||
goto fail;
|
||||
if (!EVP_PKEY_get_bn_param(key->evp, OSSL_PKEY_PARAM_RSA_D, &rsa_d))
|
||||
goto fail;
|
||||
#endif
|
||||
if (BN_num_bytes(rsa_e) > 4)
|
||||
{
|
||||
WLog_ERR(TAG, "RSA public exponent too large");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!read_bignum(&key->PrivateExponent, &key->PrivateExponentLength, rsa_d, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!cert_info_create(&key->cert, rsa_n, rsa_e))
|
||||
goto fail;
|
||||
rc = TRUE;
|
||||
fail:
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
RSA_free(rsa);
|
||||
#else
|
||||
BN_free(rsa_d);
|
||||
BN_free(rsa_e);
|
||||
BN_free(rsa_n);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_pem(const char* pem)
|
||||
{
|
||||
return freerdp_key_new_from_pem_enc(pem, nullptr);
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_pem_enc(const char* pem, const char* password)
|
||||
{
|
||||
rdpPrivateKey* key = freerdp_key_new();
|
||||
if (!key || !pem)
|
||||
goto fail;
|
||||
key->evp = evp_pkey_utils_from_pem(pem, strlen(pem), FALSE, password);
|
||||
if (!key->evp)
|
||||
goto fail;
|
||||
if (!key_read_private(key))
|
||||
goto fail;
|
||||
return key;
|
||||
fail:
|
||||
freerdp_key_free(key);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_file(const char* keyfile)
|
||||
{
|
||||
return freerdp_key_new_from_file_enc(keyfile, nullptr);
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new_from_file_enc(const char* keyfile, const char* password)
|
||||
{
|
||||
rdpPrivateKey* key = freerdp_key_new();
|
||||
if (!key || !keyfile)
|
||||
goto fail;
|
||||
|
||||
key->evp = evp_pkey_utils_from_pem(keyfile, strlen(keyfile), TRUE, password);
|
||||
if (!key->evp)
|
||||
goto fail;
|
||||
if (!key_read_private(key))
|
||||
goto fail;
|
||||
return key;
|
||||
fail:
|
||||
freerdp_key_free(key);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_new(void)
|
||||
{
|
||||
return calloc(1, sizeof(rdpPrivateKey));
|
||||
}
|
||||
|
||||
rdpPrivateKey* freerdp_key_clone(const rdpPrivateKey* key)
|
||||
{
|
||||
if (!key)
|
||||
return nullptr;
|
||||
|
||||
rdpPrivateKey* _key = (rdpPrivateKey*)calloc(1, sizeof(rdpPrivateKey));
|
||||
|
||||
if (!_key)
|
||||
return nullptr;
|
||||
|
||||
if (key->evp)
|
||||
{
|
||||
_key->evp = key->evp;
|
||||
if (!_key->evp)
|
||||
goto out_fail;
|
||||
EVP_PKEY_up_ref(_key->evp);
|
||||
}
|
||||
|
||||
if (key->PrivateExponent)
|
||||
{
|
||||
_key->PrivateExponent = (BYTE*)malloc(key->PrivateExponentLength);
|
||||
|
||||
if (!_key->PrivateExponent)
|
||||
goto out_fail;
|
||||
|
||||
CopyMemory(_key->PrivateExponent, key->PrivateExponent, key->PrivateExponentLength);
|
||||
_key->PrivateExponentLength = key->PrivateExponentLength;
|
||||
}
|
||||
|
||||
if (!cert_info_clone(&_key->cert, &key->cert))
|
||||
goto out_fail;
|
||||
|
||||
return _key;
|
||||
out_fail:
|
||||
WINPR_PRAGMA_DIAG_PUSH
|
||||
WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
|
||||
freerdp_key_free(_key);
|
||||
WINPR_PRAGMA_DIAG_POP
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void freerdp_key_free(rdpPrivateKey* key)
|
||||
{
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
EVP_PKEY_free(key->evp);
|
||||
if (key->PrivateExponent)
|
||||
memset(key->PrivateExponent, 0, key->PrivateExponentLength);
|
||||
free(key->PrivateExponent);
|
||||
cert_info_free(&key->cert);
|
||||
free(key);
|
||||
}
|
||||
|
||||
const rdpCertInfo* freerdp_key_get_info(const rdpPrivateKey* key)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
if (!freerdp_key_is_rsa(key))
|
||||
return nullptr;
|
||||
return &key->cert;
|
||||
}
|
||||
|
||||
const BYTE* freerdp_key_get_exponent(const rdpPrivateKey* key, size_t* plength)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
if (!freerdp_key_is_rsa(key))
|
||||
{
|
||||
if (plength)
|
||||
*plength = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (plength)
|
||||
*plength = key->PrivateExponentLength;
|
||||
return key->PrivateExponent;
|
||||
}
|
||||
|
||||
EVP_PKEY* freerdp_key_get_evp_pkey(const rdpPrivateKey* key)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
|
||||
EVP_PKEY* evp = key->evp;
|
||||
WINPR_ASSERT(evp);
|
||||
EVP_PKEY_up_ref(evp);
|
||||
return evp;
|
||||
}
|
||||
|
||||
BOOL freerdp_key_is_rsa(const rdpPrivateKey* key)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
if (key == priv_key_tssk)
|
||||
return TRUE;
|
||||
|
||||
WINPR_ASSERT(key->evp);
|
||||
return (EVP_PKEY_id(key->evp) == EVP_PKEY_RSA);
|
||||
}
|
||||
|
||||
size_t freerdp_key_get_bits(const rdpPrivateKey* key)
|
||||
{
|
||||
int rc = -1;
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
RSA* rsa = evp_pkey_to_rsa(key);
|
||||
if (rsa)
|
||||
{
|
||||
rc = RSA_bits(rsa);
|
||||
RSA_free(rsa);
|
||||
}
|
||||
#else
|
||||
rc = EVP_PKEY_get_bits(key->evp);
|
||||
#endif
|
||||
|
||||
return WINPR_ASSERTING_INT_CAST(size_t, rc);
|
||||
}
|
||||
|
||||
BOOL freerdp_key_generate(rdpPrivateKey* key, const char* type, size_t count, ...)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
if (!type)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid argument type=%s", type);
|
||||
return FALSE;
|
||||
}
|
||||
if (strncmp("RSA", type, 4) != 0)
|
||||
{
|
||||
WLog_ERR(TAG, "Argument type=%s is currently not supported, aborting", type);
|
||||
return FALSE;
|
||||
}
|
||||
if (count != 1)
|
||||
{
|
||||
WLog_ERR(TAG, "Argument type=%s requires count=1, got %" PRIuz ", aborting", type, count);
|
||||
return FALSE;
|
||||
}
|
||||
va_list ap = WINPR_C_ARRAY_INIT;
|
||||
va_start(ap, count);
|
||||
const int key_length = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
|
||||
#if !defined(OPENSSL_VERSION_MAJOR) || (OPENSSL_VERSION_MAJOR < 3)
|
||||
RSA* rsa = nullptr;
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
|
||||
rsa = RSA_generate_key(key_length, RSA_F4, nullptr, nullptr);
|
||||
#else
|
||||
{
|
||||
BIGNUM* bn = BN_secure_new();
|
||||
|
||||
if (!bn)
|
||||
return FALSE;
|
||||
|
||||
rsa = RSA_new();
|
||||
|
||||
if (!rsa)
|
||||
{
|
||||
BN_clear_free(bn);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BN_set_word(bn, RSA_F4);
|
||||
const int res = RSA_generate_key_ex(rsa, key_length, bn, nullptr);
|
||||
BN_clear_free(bn);
|
||||
|
||||
if (res != 1)
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
EVP_PKEY_free(key->evp);
|
||||
key->evp = EVP_PKEY_new();
|
||||
|
||||
if (!EVP_PKEY_assign_RSA(key->evp, rsa))
|
||||
{
|
||||
EVP_PKEY_free(key->evp);
|
||||
key->evp = nullptr;
|
||||
RSA_free(rsa);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
#else
|
||||
EVP_PKEY_CTX* pctx = EVP_PKEY_CTX_new_from_name(nullptr, type, nullptr);
|
||||
if (!pctx)
|
||||
return FALSE;
|
||||
|
||||
if (EVP_PKEY_keygen_init(pctx) != 1)
|
||||
goto fail;
|
||||
|
||||
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, key_length) != 1)
|
||||
goto fail;
|
||||
|
||||
EVP_PKEY_free(key->evp);
|
||||
key->evp = nullptr;
|
||||
|
||||
if (EVP_PKEY_generate(pctx, &key->evp) != 1)
|
||||
goto fail;
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
BYTE* freerdp_key_get_param(const rdpPrivateKey* key, enum FREERDP_KEY_PARAM param, size_t* plength)
|
||||
{
|
||||
BYTE* buf = nullptr;
|
||||
|
||||
WINPR_ASSERT(key);
|
||||
WINPR_ASSERT(plength);
|
||||
|
||||
*plength = 0;
|
||||
|
||||
BIGNUM* bn = nullptr;
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
const char* pk = nullptr;
|
||||
switch (param)
|
||||
{
|
||||
case FREERDP_KEY_PARAM_RSA_D:
|
||||
pk = OSSL_PKEY_PARAM_RSA_D;
|
||||
break;
|
||||
case FREERDP_KEY_PARAM_RSA_E:
|
||||
pk = OSSL_PKEY_PARAM_RSA_E;
|
||||
break;
|
||||
case FREERDP_KEY_PARAM_RSA_N:
|
||||
pk = OSSL_PKEY_PARAM_RSA_N;
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!EVP_PKEY_get_bn_param(key->evp, pk, &bn))
|
||||
return nullptr;
|
||||
#else
|
||||
{
|
||||
const RSA* rsa = EVP_PKEY_get0_RSA(key->evp);
|
||||
if (!rsa)
|
||||
return nullptr;
|
||||
|
||||
const BIGNUM* cbn = nullptr;
|
||||
switch (param)
|
||||
{
|
||||
case FREERDP_KEY_PARAM_RSA_D:
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
|
||||
cbn = RSA_get0_d(rsa);
|
||||
#endif
|
||||
break;
|
||||
case FREERDP_KEY_PARAM_RSA_E:
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
|
||||
cbn = RSA_get0_e(rsa);
|
||||
#endif
|
||||
break;
|
||||
case FREERDP_KEY_PARAM_RSA_N:
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10101007L
|
||||
cbn = RSA_get0_n(rsa);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
if (!cbn)
|
||||
return nullptr;
|
||||
bn = BN_dup(cbn);
|
||||
if (!bn)
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
const int length = BN_num_bytes(bn);
|
||||
if (length < 0)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const size_t alloc_size = (size_t)length + 1ull;
|
||||
buf = calloc(alloc_size, sizeof(BYTE));
|
||||
}
|
||||
|
||||
if (!buf)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
const int bnlen = BN_bn2bin(bn, buf);
|
||||
if (bnlen != length)
|
||||
{
|
||||
free(buf);
|
||||
buf = nullptr;
|
||||
}
|
||||
else
|
||||
*plength = WINPR_ASSERTING_INT_CAST(size_t, length);
|
||||
}
|
||||
|
||||
fail:
|
||||
BN_free(bn);
|
||||
return buf;
|
||||
}
|
||||
|
||||
WINPR_DIGEST_CTX* freerdp_key_digest_sign(rdpPrivateKey* key, WINPR_MD_TYPE digest)
|
||||
{
|
||||
WINPR_DIGEST_CTX* md_ctx = winpr_Digest_New();
|
||||
if (!md_ctx)
|
||||
return nullptr;
|
||||
|
||||
if (!winpr_DigestSign_Init(md_ctx, digest, key->evp))
|
||||
{
|
||||
winpr_Digest_Free(md_ctx);
|
||||
return nullptr;
|
||||
}
|
||||
return md_ctx;
|
||||
}
|
||||
|
||||
static BOOL bio_read_pem(BIO* bio, char** ppem, size_t* plength)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
|
||||
WINPR_ASSERT(bio);
|
||||
WINPR_ASSERT(ppem);
|
||||
|
||||
const size_t blocksize = 2048;
|
||||
size_t offset = 0;
|
||||
size_t length = blocksize;
|
||||
char* pem = nullptr;
|
||||
|
||||
*ppem = nullptr;
|
||||
if (plength)
|
||||
*plength = 0;
|
||||
|
||||
while (offset < length)
|
||||
{
|
||||
char* tmp = realloc(pem, length + 1);
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
pem = tmp;
|
||||
|
||||
ERR_clear_error();
|
||||
|
||||
const int status = BIO_read(bio, &pem[offset], (int)(length - offset));
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "failed to read certificate");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
break;
|
||||
|
||||
offset += (size_t)status;
|
||||
if (length - offset > 0)
|
||||
break;
|
||||
length += blocksize;
|
||||
}
|
||||
|
||||
if (pem)
|
||||
{
|
||||
if (offset >= length)
|
||||
goto fail;
|
||||
pem[offset] = '\0';
|
||||
}
|
||||
*ppem = pem;
|
||||
if (plength)
|
||||
*plength = offset;
|
||||
rc = TRUE;
|
||||
fail:
|
||||
if (!rc)
|
||||
free(pem);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
char* freerdp_key_get_pem(const rdpPrivateKey* key, size_t* plen, const char* password)
|
||||
{
|
||||
WINPR_ASSERT(key);
|
||||
|
||||
if (!key->evp)
|
||||
return nullptr;
|
||||
|
||||
/**
|
||||
* Don't manage certificates internally, leave it up entirely to the external client
|
||||
* implementation
|
||||
*/
|
||||
BIO* bio = BIO_new(BIO_s_mem());
|
||||
|
||||
if (!bio)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new() failure");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char* pem = nullptr;
|
||||
|
||||
const EVP_CIPHER* enc = nullptr;
|
||||
if (password)
|
||||
enc = EVP_aes_256_xts();
|
||||
|
||||
const int status = PEM_write_bio_PrivateKey(bio, key->evp, enc, nullptr, 0, nullptr,
|
||||
WINPR_CAST_CONST_PTR_AWAY(password, void*));
|
||||
if (status < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "PEM_write_bio_PrivateKey failure: %d", status);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
(void)bio_read_pem(bio, &pem, plen);
|
||||
|
||||
fail:
|
||||
BIO_free_all(bio);
|
||||
return pem;
|
||||
}
|
||||
76
third_party/FreeRDP/libfreerdp/crypto/privatekey.h
vendored
Normal file
76
third_party/FreeRDP/libfreerdp/crypto/privatekey.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Private key Handling
|
||||
*
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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 FREERDP_LIB_CORE_PRIVATEKEY_H
|
||||
#define FREERDP_LIB_CORE_PRIVATEKEY_H
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
#include <freerdp/crypto/privatekey.h>
|
||||
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
enum FREERDP_KEY_PARAM
|
||||
{
|
||||
FREERDP_KEY_PARAM_RSA_D,
|
||||
FREERDP_KEY_PARAM_RSA_E,
|
||||
FREERDP_KEY_PARAM_RSA_N
|
||||
};
|
||||
|
||||
WINPR_ATTR_MALLOC(freerdp_key_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpPrivateKey* freerdp_key_clone(const rdpPrivateKey* key);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL const rdpCertInfo* freerdp_key_get_info(const rdpPrivateKey* key);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL const BYTE* freerdp_key_get_exponent(const rdpPrivateKey* key, size_t* plength);
|
||||
|
||||
/** \brief returns a pointer to a EVP_PKEY structure.
|
||||
* Call EVP_PKEY_free when done.
|
||||
*/
|
||||
WINPR_ATTR_MALLOC(EVP_PKEY_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL EVP_PKEY* freerdp_key_get_evp_pkey(const rdpPrivateKey* key);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BYTE* freerdp_key_get_param(const rdpPrivateKey* key,
|
||||
enum FREERDP_KEY_PARAM param, size_t* plength);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
WINPR_ATTR_MALLOC(winpr_Digest_Free, 1)
|
||||
FREERDP_LOCAL WINPR_DIGEST_CTX* freerdp_key_digest_sign(rdpPrivateKey* key,
|
||||
WINPR_MD_TYPE digest);
|
||||
|
||||
FREERDP_LOCAL extern const rdpPrivateKey* priv_key_tssk;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CORE_PRIVATEKEY_H */
|
||||
32
third_party/FreeRDP/libfreerdp/crypto/test/CMakeLists.txt
vendored
Normal file
32
third_party/FreeRDP/libfreerdp/crypto/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
set(MODULE_NAME "TestFreeRDPCrypto")
|
||||
set(MODULE_PREFIX "TEST_FREERDP_CRYPTO")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(TESTS TestKnownHosts.c TestBase64.c)
|
||||
|
||||
if(BUILD_TESTING_INTERNAL)
|
||||
list(APPEND TESTS Test_x509_utils.c)
|
||||
endif()
|
||||
|
||||
create_test_sourcelist(SRCS ${DRIVER} ${TESTS})
|
||||
|
||||
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
|
||||
|
||||
add_executable(${MODULE_NAME} ${SRCS})
|
||||
|
||||
set(TEST_PATH ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_compile_definitions(TEST_SOURCE_DIR="${TEST_PATH}")
|
||||
target_link_libraries(${MODULE_NAME} freerdp winpr ${OPENSSL_LIBRARIES})
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "FreeRDP/Test")
|
||||
178
third_party/FreeRDP/libfreerdp/crypto/test/TestBase64.c
vendored
Normal file
178
third_party/FreeRDP/libfreerdp/crypto/test/TestBase64.c
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2014 Thincast Technologies GmbH
|
||||
* Copyright 2014 Hardening <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.
|
||||
*/
|
||||
|
||||
#include <freerdp/crypto/crypto.h>
|
||||
|
||||
struct Encode64test
|
||||
{
|
||||
const char* input;
|
||||
size_t len;
|
||||
const char* output;
|
||||
};
|
||||
|
||||
static const struct Encode64test encodeTests_base64[] = {
|
||||
{ "\x00", 1, "AA==" },
|
||||
{ "\x00\x00", 2, "AAA=" },
|
||||
{ "\x00\x00\x00", 3, "AAAA" },
|
||||
{ "0123456", 7, "MDEyMzQ1Ng==" },
|
||||
{ "90123456", 8, "OTAxMjM0NTY=" },
|
||||
{ "890123456", 9, "ODkwMTIzNDU2" },
|
||||
{ "7890123456", 10, "Nzg5MDEyMzQ1Ng==" },
|
||||
|
||||
{ nullptr, -1, nullptr }, /* /!\ last one /!\ */
|
||||
};
|
||||
|
||||
static const struct Encode64test encodeTests_base64url[] = {
|
||||
{ "\x00", 1, "AA" },
|
||||
{ "\x00\x00", 2, "AAA" },
|
||||
{ "\x00\x00\x00", 3, "AAAA" },
|
||||
{ "01?34>6", 7, "MDE_MzQ-Ng" },
|
||||
{ "90123456", 8, "OTAxMjM0NTY" },
|
||||
{ "890123456", 9, "ODkwMTIzNDU2" },
|
||||
{ "78?01>3456", 10, "Nzg_MDE-MzQ1Ng" },
|
||||
|
||||
{ nullptr, -1, nullptr }, /* /!\ last one /!\ */
|
||||
};
|
||||
|
||||
int TestBase64(int argc, char* argv[])
|
||||
{
|
||||
int testNb = 0;
|
||||
size_t outLen = 0;
|
||||
BYTE* decoded = nullptr;
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
testNb++;
|
||||
(void)fprintf(stderr, "%d:encode base64...", testNb);
|
||||
|
||||
for (int i = 0; encodeTests_base64[i].input; i++)
|
||||
{
|
||||
char* encoded = crypto_base64_encode((const BYTE*)encodeTests_base64[i].input,
|
||||
encodeTests_base64[i].len);
|
||||
|
||||
if (strcmp(encodeTests_base64[i].output, encoded) != 0)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, error for string %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(encoded);
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
testNb++;
|
||||
(void)fprintf(stderr, "%d:encode base64url...", testNb);
|
||||
|
||||
for (int i = 0; encodeTests_base64url[i].input; i++)
|
||||
{
|
||||
char* encoded = crypto_base64url_encode((const BYTE*)encodeTests_base64url[i].input,
|
||||
encodeTests_base64url[i].len);
|
||||
|
||||
if (strcmp(encodeTests_base64url[i].output, encoded) != 0)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, error for string %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(encoded);
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
testNb++;
|
||||
(void)fprintf(stderr, "%d:decode base64...", testNb);
|
||||
|
||||
for (int i = 0; encodeTests_base64[i].input; i++)
|
||||
{
|
||||
crypto_base64_decode(encodeTests_base64[i].output, strlen(encodeTests_base64[i].output),
|
||||
&decoded, &outLen);
|
||||
|
||||
if (!decoded || (outLen != encodeTests_base64[i].len) ||
|
||||
memcmp(encodeTests_base64[i].input, decoded, outLen) != 0)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, error for string %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(decoded);
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
testNb++;
|
||||
(void)fprintf(stderr, "%d:decode base64url...", testNb);
|
||||
|
||||
for (int i = 0; encodeTests_base64url[i].input; i++)
|
||||
{
|
||||
crypto_base64url_decode(encodeTests_base64url[i].output,
|
||||
strlen(encodeTests_base64url[i].output), &decoded, &outLen);
|
||||
|
||||
if (!decoded || (outLen != encodeTests_base64url[i].len) ||
|
||||
memcmp(encodeTests_base64url[i].input, decoded, outLen) != 0)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, error for string %d\n", i);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(decoded);
|
||||
}
|
||||
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
testNb++;
|
||||
(void)fprintf(stderr, "%d:decode base64 errors...", testNb);
|
||||
crypto_base64_decode("000", 3, &decoded, &outLen);
|
||||
|
||||
if (decoded)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, badly padded string\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_base64_decode("0=00", 4, &decoded, &outLen);
|
||||
|
||||
if (decoded)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, = in a wrong place\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
crypto_base64_decode("00=0", 4, &decoded, &outLen);
|
||||
|
||||
if (decoded)
|
||||
{
|
||||
(void)fprintf(stderr, "ko, = in a wrong place\n");
|
||||
return -1;
|
||||
}
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
testNb++;
|
||||
|
||||
/* test the encode_ex version that will add \r\n */
|
||||
(void)fprintf(stderr, "%d:encode base64 with crLf...", testNb);
|
||||
const char* longStr = "01234567890123456789012345678901234567890123456789";
|
||||
const char* longStrExpected =
|
||||
"MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3\r\nODk=\r\n";
|
||||
|
||||
char* encoded = crypto_base64_encode_ex((const BYTE*)longStr, strlen(longStr), TRUE);
|
||||
if (!encoded || strcmp(encoded, longStrExpected) != 0)
|
||||
{
|
||||
(void)fprintf(stderr, "problem with encode with CRLF\n");
|
||||
return -1;
|
||||
}
|
||||
free(encoded);
|
||||
(void)fprintf(stderr, "ok\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
394
third_party/FreeRDP/libfreerdp/crypto/test/TestKnownHosts.c
vendored
Normal file
394
third_party/FreeRDP/libfreerdp/crypto/test/TestKnownHosts.c
vendored
Normal file
@@ -0,0 +1,394 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
*
|
||||
* Copyright 2015 Thincast Technologies GmbH
|
||||
* Copyright 2015 Armin Novak <armin.novak@thincast.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.
|
||||
*/
|
||||
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
|
||||
#include <freerdp/crypto/certificate_store.h>
|
||||
|
||||
/* Some certificates copied from /usr/share/ca-certificates */
|
||||
static const char pem1[] = "-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH\n"
|
||||
"MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
|
||||
"QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n"
|
||||
"MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n"
|
||||
"cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB\n"
|
||||
"AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM\n"
|
||||
"f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX\n"
|
||||
"mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7\n"
|
||||
"zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P\n"
|
||||
"fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc\n"
|
||||
"vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4\n"
|
||||
"Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp\n"
|
||||
"zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO\n"
|
||||
"Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW\n"
|
||||
"k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+\n"
|
||||
"DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF\n"
|
||||
"lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
|
||||
"HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW\n"
|
||||
"Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1\n"
|
||||
"d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z\n"
|
||||
"XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR\n"
|
||||
"gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3\n"
|
||||
"d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv\n"
|
||||
"J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg\n"
|
||||
"DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM\n"
|
||||
"+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy\n"
|
||||
"F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9\n"
|
||||
"SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws\n"
|
||||
"E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl\n"
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
static const char pem2[] = "-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH\n"
|
||||
"MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM\n"
|
||||
"QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy\n"
|
||||
"MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl\n"
|
||||
"cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB\n"
|
||||
"AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv\n"
|
||||
"CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg\n"
|
||||
"GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu\n"
|
||||
"XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd\n"
|
||||
"re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu\n"
|
||||
"PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1\n"
|
||||
"mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K\n"
|
||||
"8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj\n"
|
||||
"x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR\n"
|
||||
"nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0\n"
|
||||
"kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok\n"
|
||||
"twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV\n"
|
||||
"HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp\n"
|
||||
"8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT\n"
|
||||
"vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT\n"
|
||||
"z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA\n"
|
||||
"pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb\n"
|
||||
"pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB\n"
|
||||
"R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R\n"
|
||||
"RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk\n"
|
||||
"0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC\n"
|
||||
"5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF\n"
|
||||
"izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn\n"
|
||||
"yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC\n"
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
static const char pem3[] = "-----BEGIN CERTIFICATE-----\n"
|
||||
"MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw\n"
|
||||
"CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n"
|
||||
"MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n"
|
||||
"MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n"
|
||||
"Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA\n"
|
||||
"IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout\n"
|
||||
"736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A\n"
|
||||
"DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"
|
||||
"DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk\n"
|
||||
"fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA\n"
|
||||
"njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd\n"
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
static const char pem4[] = "-----BEGIN CERTIFICATE-----\n"
|
||||
"MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw\n"
|
||||
"CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU\n"
|
||||
"MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw\n"
|
||||
"MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp\n"
|
||||
"Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA\n"
|
||||
"IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu\n"
|
||||
"hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l\n"
|
||||
"xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud\n"
|
||||
"DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0\n"
|
||||
"CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx\n"
|
||||
"sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==\n"
|
||||
"-----END CERTIFICATE-----";
|
||||
|
||||
static int prepare(const char* currentFileV2)
|
||||
{
|
||||
int rc = -1;
|
||||
const char* hosts[] = { "#somecomment\r\n"
|
||||
"someurl 3389 ff:11:22:dd c3ViamVjdA== aXNzdWVy\r\n"
|
||||
" \t#anothercomment\r\n"
|
||||
"otherurl\t3389\taa:bb:cc:dd\tsubject2\tissuer2\r" };
|
||||
FILE* fc = nullptr;
|
||||
fc = winpr_fopen(currentFileV2, "w+");
|
||||
|
||||
if (!fc)
|
||||
goto finish;
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(hosts); i++)
|
||||
{
|
||||
if (fwrite(hosts[i], strlen(hosts[i]), 1, fc) != 1)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
finish:
|
||||
|
||||
if (fc)
|
||||
(void)fclose(fc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL setup_config(rdpSettings** settings)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
char* path = nullptr;
|
||||
char sname[8192];
|
||||
SYSTEMTIME systemTime;
|
||||
|
||||
if (!settings)
|
||||
goto fail;
|
||||
*settings = freerdp_settings_new(0);
|
||||
if (!*settings)
|
||||
goto fail;
|
||||
|
||||
GetSystemTime(&systemTime);
|
||||
(void)sprintf_s(sname, sizeof(sname),
|
||||
"TestKnownHostsCurrent-%04" PRIu16 "%02" PRIu16 "%02" PRIu16 "%02" PRIu16
|
||||
"%02" PRIu16 "%02" PRIu16 "%04" PRIu16,
|
||||
systemTime.wYear, systemTime.wMonth, systemTime.wDay, systemTime.wHour,
|
||||
systemTime.wMinute, systemTime.wSecond, systemTime.wMilliseconds);
|
||||
|
||||
path = GetKnownSubPath(KNOWN_PATH_TEMP, sname);
|
||||
if (!path)
|
||||
goto fail;
|
||||
if (!winpr_PathFileExists(path))
|
||||
{
|
||||
if (!CreateDirectoryA(path, nullptr))
|
||||
{
|
||||
(void)fprintf(stderr, "Could not create %s!\n", path);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rc = freerdp_settings_set_string(*settings, FreeRDP_ConfigPath, path);
|
||||
fail:
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static BOOL equal(const char* a, const char* b)
|
||||
{
|
||||
if (!a && !b)
|
||||
return TRUE;
|
||||
if (!a || !b)
|
||||
return FALSE;
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static BOOL compare(const rdpCertificateData* data, const rdpCertificateData* stored)
|
||||
{
|
||||
if (!data || !stored)
|
||||
return FALSE;
|
||||
if (!equal(freerdp_certificate_data_get_subject(data),
|
||||
freerdp_certificate_data_get_subject(stored)))
|
||||
return FALSE;
|
||||
if (!equal(freerdp_certificate_data_get_issuer(data),
|
||||
freerdp_certificate_data_get_issuer(stored)))
|
||||
return FALSE;
|
||||
if (!equal(freerdp_certificate_data_get_fingerprint(data),
|
||||
freerdp_certificate_data_get_fingerprint(stored)))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL pem_equal(const char* a, const char* b)
|
||||
{
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
|
||||
static BOOL compare_ex(const rdpCertificateData* data, const rdpCertificateData* stored)
|
||||
{
|
||||
if (!compare(data, stored))
|
||||
return FALSE;
|
||||
if (!pem_equal(freerdp_certificate_data_get_pem(data),
|
||||
freerdp_certificate_data_get_pem(stored)))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test_get_data(rdpCertificateStore* store, const rdpCertificateData* data)
|
||||
{
|
||||
BOOL res = 0;
|
||||
rdpCertificateData* stored = freerdp_certificate_store_load_data(
|
||||
store, freerdp_certificate_data_get_host(data), freerdp_certificate_data_get_port(data));
|
||||
if (!stored)
|
||||
return FALSE;
|
||||
|
||||
res = compare(data, stored);
|
||||
freerdp_certificate_data_free(stored);
|
||||
return res;
|
||||
}
|
||||
|
||||
static BOOL test_get_data_ex(rdpCertificateStore* store, const rdpCertificateData* data)
|
||||
{
|
||||
BOOL res = 0;
|
||||
rdpCertificateData* stored = freerdp_certificate_store_load_data(
|
||||
store, freerdp_certificate_data_get_host(data), freerdp_certificate_data_get_port(data));
|
||||
if (!stored)
|
||||
return FALSE;
|
||||
|
||||
res = compare_ex(data, stored);
|
||||
freerdp_certificate_data_free(stored);
|
||||
return res;
|
||||
}
|
||||
|
||||
static BOOL test_certs_dir(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
rdpSettings* settings = nullptr;
|
||||
rdpCertificateStore* store = nullptr;
|
||||
rdpCertificateData* data1 = nullptr;
|
||||
rdpCertificateData* data2 = nullptr;
|
||||
rdpCertificateData* data3 = nullptr;
|
||||
rdpCertificateData* data4 = nullptr;
|
||||
|
||||
printf("%s\n", __func__);
|
||||
if (!setup_config(&settings))
|
||||
goto fail;
|
||||
|
||||
printf("freerdp_certificate_store_new()\n");
|
||||
store = freerdp_certificate_store_new(settings);
|
||||
if (!store)
|
||||
goto fail;
|
||||
|
||||
{
|
||||
printf("freerdp_certificate_data_new()\n");
|
||||
data1 = freerdp_certificate_data_new_from_pem("somehost", 1234, pem1, strlen(pem1));
|
||||
data2 = freerdp_certificate_data_new_from_pem("otherhost", 4321, pem2, strlen(pem2));
|
||||
data3 = freerdp_certificate_data_new_from_pem("otherhost4", 444, pem3, strlen(pem3));
|
||||
data4 = freerdp_certificate_data_new_from_pem("otherhost", 4321, pem4, strlen(pem4));
|
||||
if (!data1 || !data2 || !data3 || !data4)
|
||||
goto fail;
|
||||
|
||||
/* Find non existing in empty store */
|
||||
printf("freerdp_certificate_store_load_data on empty store\n");
|
||||
if (test_get_data(store, data1))
|
||||
goto fail;
|
||||
if (test_get_data_ex(store, data1))
|
||||
goto fail;
|
||||
if (test_get_data(store, data2))
|
||||
goto fail;
|
||||
if (test_get_data_ex(store, data2))
|
||||
goto fail;
|
||||
if (test_get_data(store, data3))
|
||||
goto fail;
|
||||
if (test_get_data_ex(store, data3))
|
||||
goto fail;
|
||||
|
||||
/* Add certificates */
|
||||
printf("freerdp_certificate_store_save_data\n");
|
||||
if (!freerdp_certificate_store_save_data(store, data1))
|
||||
goto fail;
|
||||
if (!freerdp_certificate_store_save_data(store, data2))
|
||||
goto fail;
|
||||
|
||||
/* Find non existing in non empty store */
|
||||
printf("freerdp_certificate_store_load_data on filled store, non existing value\n");
|
||||
if (test_get_data(store, data3))
|
||||
goto fail;
|
||||
if (test_get_data_ex(store, data3))
|
||||
goto fail;
|
||||
|
||||
/* Add remaining certs */
|
||||
printf("freerdp_certificate_store_save_data\n");
|
||||
if (!freerdp_certificate_store_save_data(store, data3))
|
||||
goto fail;
|
||||
|
||||
/* Check existing can all be found */
|
||||
printf("freerdp_certificate_store_load_data on filled store, existing value\n");
|
||||
if (!test_get_data(store, data1))
|
||||
goto fail;
|
||||
if (!test_get_data_ex(store, data1))
|
||||
goto fail;
|
||||
if (!test_get_data(store, data2))
|
||||
goto fail;
|
||||
if (!test_get_data_ex(store, data2))
|
||||
goto fail;
|
||||
if (!test_get_data(store, data3))
|
||||
goto fail;
|
||||
if (!test_get_data_ex(store, data3))
|
||||
goto fail;
|
||||
|
||||
/* Modify existing entry */
|
||||
printf("freerdp_certificate_store_save_data modify data\n");
|
||||
if (!freerdp_certificate_store_save_data(store, data4))
|
||||
goto fail;
|
||||
|
||||
/* Check new data is in store */
|
||||
printf("freerdp_certificate_store_load_data check modified data can be loaded\n");
|
||||
if (!test_get_data(store, data4))
|
||||
goto fail;
|
||||
if (!test_get_data_ex(store, data4))
|
||||
goto fail;
|
||||
|
||||
/* Check old data is no longer valid */
|
||||
printf("freerdp_certificate_store_load_data check original data no longer there\n");
|
||||
if (test_get_data(store, data2))
|
||||
goto fail;
|
||||
if (test_get_data_ex(store, data2))
|
||||
goto fail;
|
||||
|
||||
/* Delete a cert */
|
||||
printf("freerdp_certificate_store_remove_data\n");
|
||||
if (!freerdp_certificate_store_remove_data(store, data3))
|
||||
goto fail;
|
||||
/* Delete non existing, should succeed */
|
||||
printf("freerdp_certificate_store_remove_data missing value\n");
|
||||
if (!freerdp_certificate_store_remove_data(store, data3))
|
||||
goto fail;
|
||||
|
||||
printf("freerdp_certificate_store_load_data on filled store, existing value\n");
|
||||
if (!test_get_data(store, data1))
|
||||
goto fail;
|
||||
if (!test_get_data_ex(store, data1))
|
||||
goto fail;
|
||||
if (!test_get_data(store, data4))
|
||||
goto fail;
|
||||
if (!test_get_data_ex(store, data4))
|
||||
goto fail;
|
||||
|
||||
printf("freerdp_certificate_store_load_data on filled store, removed value\n");
|
||||
if (test_get_data(store, data3))
|
||||
goto fail;
|
||||
if (test_get_data_ex(store, data3))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
printf("freerdp_certificate_data_free %d\n", rc);
|
||||
freerdp_certificate_data_free(data1);
|
||||
freerdp_certificate_data_free(data2);
|
||||
freerdp_certificate_data_free(data3);
|
||||
freerdp_certificate_data_free(data4);
|
||||
freerdp_certificate_store_free(store);
|
||||
freerdp_settings_free(settings);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int TestKnownHosts(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test_certs_dir())
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
41
third_party/FreeRDP/libfreerdp/crypto/test/Test_x509_cert_info.pem
vendored
Normal file
41
third_party/FreeRDP/libfreerdp/crypto/test/Test_x509_cert_info.pem
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIHNzCCBR+gAwIBAgICEAAwDQYJKoZIhvcNAQEFBQAwcDEqMCgGA1UEAwwhQURN
|
||||
SU5JU1RSQVRJT04gQ0VOVFJBTEUgREVTIFRFU1RTMQswCQYDVQQGEwJGUjEcMBoG
|
||||
A1UECgwTTUlOSVNURVJFIERFUyBURVNUUzEXMBUGA1UECwwOMDAwMiAxMTAwMTQw
|
||||
MTYwHhcNMTgwNTE4MDkyNTU1WhcNMTkwNTEzMDkyNTU1WjCBvzEkMCIGA1UEAwwb
|
||||
VEVTVEpFQU4gVEVTVE1BUlRJTiA5OTk5OTk5MQswCQYDVQQGEwJGUjEcMBoGA1UE
|
||||
CgwTTUlOSVNURVJFIERFUyBURVNUUzEXMBUGA1UECwwOMDAwMiAxMTAwMTQwMTYx
|
||||
EjAQBgNVBAsMCVBFUlNPTk5FUzEXMBUGCgmSJomT8ixkAQEMBzk5OTk5OTkxETAP
|
||||
BgNVBCoMCFRFU1RKRUFOMRMwEQYDVQQEDApURVNUTUFSVElOMIICIjANBgkqhkiG
|
||||
9w0BAQEFAAOCAg8AMIICCgKCAgEA3yc22RDYc+Vc6F26/LONvaYkdTVDiCgbh9Ik
|
||||
6pLF5izNpfdQ/YZU25h/UPECdchYX31UEErVOYudOBOHtU4fNjTO0oK5Va/DoFln
|
||||
LnfwNpAlBZfogG+yy8fK4yLxG+raoSKDR/5P3hmTqKJqw1WpkwcVE2EDqkP1clMZ
|
||||
L5cvJj6gLJa2q0JCdoKe7NntZkgpIk5ZHUZm2JYC30xL7XHfvvb/i0OZLpPOIekT
|
||||
DCzxr9HTjbqe+BRZix2UiGpXzjIlDm6EEQNebZqf5kKgcbkxIDWcVraE0kO3TqJI
|
||||
P4FBUeuxLqGwQ0AMKrZ+j8U7KAoM9WUoIFcmm8nYGo4hT6ugNIQ9nwQSgyH3yGH1
|
||||
PU2k12Ovv2Ft8C/IFuusXxTOJprcFxtjE7qYZ44tmvlozlDOBOJYjLiURAh3r5LL
|
||||
TadgArZ3XVMyWlwlTEy9qX59izY9Zz27kd5H11DOz5ezopHAWwP6sgCvWeNDyx8Q
|
||||
I3jY8TYzJHahN2bknP2fqwwdGqFCrHItJx2DhDe2ruTk6vvbnwGgYqGzv+RtdNbW
|
||||
CL4IMEQQKG9AM40WCz9pu32/vOaQ+hrYyCQMCtli0DSauB+K2IFPsAcz5OAaITJv
|
||||
LenMt8mUP9NWHWfr5WYm0tuUCCU4dUT38MqkkdQv7oly1LHkvUdMU+Nk/Ki0Q83U
|
||||
9gMvaPcCAwEAAaOCAYkwggGFMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgXg
|
||||
MDIGA1UdJQQrMCkGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQCAgYHKwYB
|
||||
BQIDBDAdBgNVHQ4EFgQUXs4RKN+vUVsZjEW/J6qo6EZTLZUwHwYDVR0jBBgwFoAU
|
||||
fUXj4k7OA3d8KylcprhMptiOL10wgbIGA1UdEQSBqjCBp6A9BgYrBgEFAgKgMzAx
|
||||
oBYbFGtwbi50ZXN0LmV4YW1wbGUuY29toRcwFRsTdGVzdGplYW4udGVzdG1hcnRp
|
||||
bqBABgorBgEEAYI3FAIDoDIMMHRlc3RqZWFuLnRlc3RtYXJ0aW4uOTk5OTk5OUB1
|
||||
cG4udGVzdC5leGFtcGxlLmNvbYEkdGVzdGplYW4udGVzdG1hcnRpbkB0ZXN0LmV4
|
||||
YW1wbGUuY29tMDEGA1UdEgQqMCiCEnJvb3RjYS5leGFtcGxlLmNvbYISaW50ZWNh
|
||||
LmV4YW1wbGUuY29tMAkGA1UdIAQCMAAwDQYJKoZIhvcNAQEFBQADggIBAKRDovf+
|
||||
CCnV2mtXnzH5JlduOjPWJmGB5a8HLPvakfAm4wQ0YyAViE1tar0V9lhG6nCogWWa
|
||||
28D+eM5vLPjVE8ebq5UjIv76x6gWoJkQ3HtfVJvn9UfXwax6IqT7hb1fAHBqu0rj
|
||||
uSnSxf1wIzPMp9Lb5x3jBu9ryNMiLUzeY1slBvosOXKlmprPhGWfPYYNCZo2bGJI
|
||||
1w5alGDgTBcWKl7icJjAIuCpyRTnKCsaN3kyDU7C5aUhsm9AriPiNErzRI+l5+eu
|
||||
Ywg3MZ7Yfjd3rXb6JleT0ZnCh/nFtVLIccWaI4phCrYTGz6odNIqrZ6X23Pt6Rx3
|
||||
ZbQjtj4ipMdvbvJbS90aFMrTyfqhVLOxHy+setDcmPOixUgXlx8ZjFI9vgFUeJbo
|
||||
OKrkLw4ITUduO+9MplBX7Kt/iCS/CbTfPlHMv03Xb6rbjqHxTJZCCu5QMNHiBeHV
|
||||
l8FK5R6gv+9FuCl8uPHwGh/jelQp51cVORlQWeKpqWdwTi0Q3VeVeQAG5RR34xgT
|
||||
cQa8h9AqkxYajhxKUmbUlaoYGd8TwUQLrS2jZxp/9geyApVQLAQ27CyAK5HyHSCA
|
||||
uqCKsM0gFQyCL4IbXQyFMWgjXZYaorHFjVuMhYEkgWui/9sv+7sMAV5JzROeAw3l
|
||||
4+D7yhywwuRzH2SzoavzGpWGMUveVsdLMRk9
|
||||
-----END CERTIFICATE-----
|
||||
241
third_party/FreeRDP/libfreerdp/crypto/test/Test_x509_utils.c
vendored
Normal file
241
third_party/FreeRDP/libfreerdp/crypto/test/Test_x509_utils.c
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
#include <winpr/file.h>
|
||||
#include <winpr/string.h>
|
||||
#include "../x509_utils.h"
|
||||
|
||||
typedef char* (*get_field_pr)(const X509*);
|
||||
typedef struct
|
||||
{
|
||||
enum
|
||||
{
|
||||
DISABLED,
|
||||
ENABLED,
|
||||
} status;
|
||||
const char* field_description;
|
||||
get_field_pr get_field;
|
||||
const char* expected_result;
|
||||
} certificate_test_t;
|
||||
|
||||
static char* x509_utils_subject_common_name_wo_length(const X509* xcert)
|
||||
{
|
||||
size_t length = 0;
|
||||
return x509_utils_get_common_name(xcert, &length);
|
||||
}
|
||||
|
||||
static char* certificate_path(const char* filename)
|
||||
{
|
||||
/*
|
||||
Assume the .pem file is in the same directory as this source file.
|
||||
Assume that __FILE__ will be a valid path to this file, even from the current working directory
|
||||
where the tests are run. (ie. no chdir occurs between compilation and test running, or __FILE__
|
||||
is an absolute path).
|
||||
*/
|
||||
static const char dirsep = '/';
|
||||
#ifdef TEST_SOURCE_DIR
|
||||
const char* file = TEST_SOURCE_DIR;
|
||||
const size_t flen = strlen(file) + sizeof(dirsep) + strlen(filename) + sizeof(char);
|
||||
char* result = calloc(1, flen);
|
||||
if (!result)
|
||||
return nullptr;
|
||||
(void)_snprintf(result, flen, "%s%c%s", file, dirsep, filename);
|
||||
return result;
|
||||
#else
|
||||
const char* file = __FILE__;
|
||||
const char* last_dirsep = strrchr(file, dirsep);
|
||||
|
||||
if (last_dirsep)
|
||||
{
|
||||
const size_t filenameLen = strlen(filename);
|
||||
const size_t dirsepLen = last_dirsep - file + 1;
|
||||
char* result = malloc(dirsepLen + filenameLen + 1);
|
||||
if (!result)
|
||||
return nullptr;
|
||||
strncpy(result, file, dirsepLen);
|
||||
strncpy(result + dirsepLen, filename, filenameLen + 1);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No dirsep => relative path in same directory */
|
||||
return _strdup(filename);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static const certificate_test_t certificate_tests[] = {
|
||||
|
||||
{ ENABLED, "Certificate Common Name", x509_utils_subject_common_name_wo_length,
|
||||
"TESTJEAN TESTMARTIN 9999999" },
|
||||
|
||||
{ ENABLED, "Certificate subject", x509_utils_get_subject,
|
||||
"CN = TESTJEAN TESTMARTIN 9999999, C = FR, O = MINISTERE DES TESTS, OU = 0002 110014016, OU "
|
||||
"= PERSONNES, UID = 9999999, GN = TESTJEAN, SN = TESTMARTIN" },
|
||||
|
||||
{ DISABLED, "Kerberos principal name", nullptr, "testjean.testmartin@kpn.test.example.com" },
|
||||
|
||||
{ ENABLED, "Certificate e-mail", x509_utils_get_email, "testjean.testmartin@test.example.com"
|
||||
|
||||
},
|
||||
|
||||
{ ENABLED, "Microsoft's Universal Principal Name", x509_utils_get_upn,
|
||||
"testjean.testmartin.9999999@upn.test.example.com" },
|
||||
|
||||
{ ENABLED, "Certificate issuer", x509_utils_get_issuer,
|
||||
"CN = ADMINISTRATION CENTRALE DES TESTS, C = FR, O = MINISTERE DES TESTS, OU = 0002 "
|
||||
"110014016" },
|
||||
};
|
||||
|
||||
static int TestCertificateFile(const char* certificate_path,
|
||||
const certificate_test_t* ccertificate_tests, size_t count)
|
||||
{
|
||||
int success = 0;
|
||||
|
||||
X509* certificate = x509_utils_from_pem(certificate_path, strlen(certificate_path), TRUE);
|
||||
|
||||
if (!certificate)
|
||||
{
|
||||
printf("%s: failure: cannot read certificate file '%s'\n", __func__, certificate_path);
|
||||
success = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
const certificate_test_t* test = &ccertificate_tests[i];
|
||||
char* result = nullptr;
|
||||
|
||||
if (test->status == DISABLED)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
result = (test->get_field ? test->get_field(certificate) : nullptr);
|
||||
|
||||
if (result)
|
||||
{
|
||||
printf("%s: crypto got %-40s -> \"%s\"\n", __func__, test->field_description, result);
|
||||
|
||||
if (0 != strcmp(result, test->expected_result))
|
||||
{
|
||||
printf("%s: failure: for %s, actual: \"%s\", expected \"%s\"\n", __func__,
|
||||
test->field_description, result, test->expected_result);
|
||||
success = -1;
|
||||
}
|
||||
|
||||
free(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s: failure: cannot get %s\n", __func__, test->field_description);
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
X509_free(certificate);
|
||||
return success;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
/*
|
||||
These certificates were generated with the following commands:
|
||||
|
||||
openssl ecparam -name P-256 -out /tmp/p256.pem
|
||||
openssl req -x509 -newkey ec:/tmp/p256.pem -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out ecdsa_sha1_cert.pem -sha1
|
||||
openssl req -x509 -newkey ec:/tmp/p256.pem -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out ecdsa_sha256_cert.pem -sha256
|
||||
openssl req -x509 -newkey ec:/tmp/p256.pem -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out ecdsa_sha384_cert.pem -sha384
|
||||
openssl req -x509 -newkey ec:/tmp/p256.pem -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out ecdsa_sha512_cert.pem -sha512
|
||||
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pkcs1_sha1_cert.pem -sha1
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pkcs1_sha256_cert.pem -sha256
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pkcs1_sha384_cert.pem -sha384
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pkcs1_sha512_cert.pem -sha512
|
||||
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pss_sha1_cert.pem -sha1 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:digest
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pss_sha256_cert.pem -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:digest
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pss_sha384_cert.pem -sha384 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:digest
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pss_sha512_cert.pem -sha512 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:digest
|
||||
openssl req -x509 -newkey rsa:2048 -keyout /dev/null -days 3650 -nodes -subj "/CN=Test" -out rsa_pss_sha256_mgf1_sha384_cert.pem -sha256 -sigopt rsa_padding_mode:pss -sigopt rsa_pss_saltlen:digest -sigopt rsa_mgf1_md:sha384
|
||||
*/
|
||||
/* clang-format on */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* filename;
|
||||
WINPR_MD_TYPE expected;
|
||||
} signature_alg_test_t;
|
||||
|
||||
static const signature_alg_test_t signature_alg_tests[] = {
|
||||
{ "rsa_pkcs1_sha1_cert.pem", WINPR_MD_SHA1 },
|
||||
{ "rsa_pkcs1_sha256_cert.pem", WINPR_MD_SHA256 },
|
||||
{ "rsa_pkcs1_sha384_cert.pem", WINPR_MD_SHA384 },
|
||||
{ "rsa_pkcs1_sha512_cert.pem", WINPR_MD_SHA512 },
|
||||
|
||||
{ "ecdsa_sha1_cert.pem", WINPR_MD_SHA1 },
|
||||
{ "ecdsa_sha256_cert.pem", WINPR_MD_SHA256 },
|
||||
{ "ecdsa_sha384_cert.pem", WINPR_MD_SHA384 },
|
||||
{ "ecdsa_sha512_cert.pem", WINPR_MD_SHA512 },
|
||||
|
||||
{ "rsa_pss_sha1_cert.pem", WINPR_MD_SHA1 },
|
||||
{ "rsa_pss_sha256_cert.pem", WINPR_MD_SHA256 },
|
||||
{ "rsa_pss_sha384_cert.pem", WINPR_MD_SHA384 },
|
||||
{ "rsa_pss_sha512_cert.pem", WINPR_MD_SHA512 },
|
||||
/*
|
||||
PSS may use different digests for the message hash and MGF-1 hash. In this case, RFC 5929
|
||||
leaves the tls-server-end-point hash unspecified, so it should return WINPR_MD_NONE.
|
||||
*/
|
||||
{ "rsa_pss_sha256_mgf1_sha384_cert.pem", WINPR_MD_NONE },
|
||||
};
|
||||
|
||||
static int TestSignatureAlgorithm(const signature_alg_test_t* test)
|
||||
{
|
||||
int success = 0;
|
||||
WINPR_MD_TYPE signature_alg = WINPR_MD_NONE;
|
||||
char* path = certificate_path(test->filename);
|
||||
X509* certificate = x509_utils_from_pem(path, strlen(path), TRUE);
|
||||
|
||||
if (!certificate)
|
||||
{
|
||||
printf("%s: failure: cannot read certificate file '%s'\n", __func__, path);
|
||||
success = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
signature_alg = x509_utils_get_signature_alg(certificate);
|
||||
if (signature_alg != test->expected)
|
||||
{
|
||||
const char* signature_alg_string =
|
||||
signature_alg == WINPR_MD_NONE ? "none" : winpr_md_type_to_string(signature_alg);
|
||||
const char* expected_string =
|
||||
test->expected == WINPR_MD_NONE ? "none" : winpr_md_type_to_string(test->expected);
|
||||
printf("%s: failure: for \"%s\", actual: %s, expected %s\n", __func__, test->filename,
|
||||
signature_alg_string, expected_string);
|
||||
success = -1;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
X509_free(certificate);
|
||||
free(path);
|
||||
return success;
|
||||
}
|
||||
|
||||
int Test_x509_utils(int argc, char* argv[])
|
||||
{
|
||||
char* cert_path = certificate_path("Test_x509_cert_info.pem");
|
||||
int ret = 0;
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
ret = TestCertificateFile(cert_path, certificate_tests, ARRAYSIZE(certificate_tests));
|
||||
free(cert_path);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(signature_alg_tests); i++)
|
||||
{
|
||||
ret = TestSignatureAlgorithm(&signature_alg_tests[i]);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha1_cert.pem
vendored
Normal file
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha1_cert.pem
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBcjCCARigAwIBAgIUP9Q+so71qPtrK898RUJibDMRSYQwCQYHKoZIzj0EATAP
|
||||
MQ0wCwYDVQQDDARUZXN0MB4XDTI0MDIwNjAzMDkzNFoXDTM0MDIwMzAzMDkzNFow
|
||||
DzENMAsGA1UEAwwEVGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHj9x4Vr
|
||||
7pGzpilUY799+mWmOsJwtxFZ3lPNRy+wsfxibRE6e2T0Gk2Ifysl8Vya6Ynwrd2d
|
||||
7ztAk+b6HF+1lgqjUzBRMB0GA1UdDgQWBBSX66LoFThh5RCXaeAS+sjGPmLxKTAf
|
||||
BgNVHSMEGDAWgBSX66LoFThh5RCXaeAS+sjGPmLxKTAPBgNVHRMBAf8EBTADAQH/
|
||||
MAkGByqGSM49BAEDSQAwRgIhAJf3H7PWAZ/5G2SbBKF5jzBVlmWLiVmfanLOvttf
|
||||
9DFUAiEA3CnntihpfkAGjUCav7CojYfz8hqe0d6F9ZStfzV4t3g=
|
||||
-----END CERTIFICATE-----
|
||||
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha256_cert.pem
vendored
Normal file
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha256_cert.pem
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBdDCCARmgAwIBAgIUUDFppYHwhd7smJSH6W8QSLttoNEwCgYIKoZIzj0EAwIw
|
||||
DzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA5MzRaFw0zNDAyMDMwMzA5MzRa
|
||||
MA8xDTALBgNVBAMMBFRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATfQ2ox
|
||||
CF1xh6Dwcsi3BqyUIlKxgY3J2qOSmOzepOMLWhPpiDsneKskpKx4b5JM92mmIyiq
|
||||
UMMR7mXlclDHyQtro1MwUTAdBgNVHQ4EFgQUgoV/fxICc75gTRslwgvs/I1YbOUw
|
||||
HwYDVR0jBBgwFoAUgoV/fxICc75gTRslwgvs/I1YbOUwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAKBggqhkjOPQQDAgNJADBGAiEAyVInWgy3JVEUPDSpjNseJKPie/hINfO6KbrK
|
||||
IqGQ0+ACIQDk/oXOIwFZr26TTghYKOn12aOuPCxOqeBu5ObeFMf91Q==
|
||||
-----END CERTIFICATE-----
|
||||
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha384_cert.pem
vendored
Normal file
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha384_cert.pem
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBczCCARmgAwIBAgIUDT9Rw/q4CH5WmNCTbGbNI964MQwwCgYIKoZIzj0EAwMw
|
||||
DzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA5MzRaFw0zNDAyMDMwMzA5MzRa
|
||||
MA8xDTALBgNVBAMMBFRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR0oA7y
|
||||
QeXAp65otDob8Uqmtthdub5T7fbzMr/qnUTxNYoUpXKnde28Cvan4QPCuepHmVPw
|
||||
sVx94UX8RIlrXAhdo1MwUTAdBgNVHQ4EFgQUFfghIBL0wxknjd9I8+Wub61VJk4w
|
||||
HwYDVR0jBBgwFoAUFfghIBL0wxknjd9I8+Wub61VJk4wDwYDVR0TAQH/BAUwAwEB
|
||||
/zAKBggqhkjOPQQDAwNIADBFAiB66sAH30kMoOsMHu5vb1hUl3DPRLb30WbtVSBC
|
||||
ZHEDyQIhAK1xgDA005XqcC77o8gzQFFsxIkQrCHTqre2LEGndxLA
|
||||
-----END CERTIFICATE-----
|
||||
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha512_cert.pem
vendored
Normal file
10
third_party/FreeRDP/libfreerdp/crypto/test/ecdsa_sha512_cert.pem
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIBdDCCARmgAwIBAgIUfb77WvmuJ7r/9aLrhvfHymxssoQwCgYIKoZIzj0EAwQw
|
||||
DzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA5MzRaFw0zNDAyMDMwMzA5MzRa
|
||||
MA8xDTALBgNVBAMMBFRlc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARewOb8
|
||||
HMJXad76YWUSaPLMUH8IKpzO0iZkQ2d1SSCylEMdrPJKhi54r7/y6m5LXMejyQzi
|
||||
eB2eiNju1yfs1tkoo1MwUTAdBgNVHQ4EFgQUGSveQiJxuzwWX1jIRXdHCzdvj7Ew
|
||||
HwYDVR0jBBgwFoAUGSveQiJxuzwWX1jIRXdHCzdvj7EwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAKBggqhkjOPQQDBANJADBGAiEAspDRGKH6Nlp+XUxyHKc3IGN5WVIg5ezGHJDR
|
||||
9+Q8RAkCIQDVWMxflgAII4D+t2Z8nT4bavUImHD26kbaGtR2/DYPVw==
|
||||
-----END CERTIFICATE-----
|
||||
2
third_party/FreeRDP/libfreerdp/crypto/test/known_hosts/known_hosts
vendored
Normal file
2
third_party/FreeRDP/libfreerdp/crypto/test/known_hosts/known_hosts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
someurl ff:11:22:dd
|
||||
otherurl aa:bb:cc:dd
|
||||
2
third_party/FreeRDP/libfreerdp/crypto/test/known_hosts/known_hosts.v2
vendored
Normal file
2
third_party/FreeRDP/libfreerdp/crypto/test/known_hosts/known_hosts.v2
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
someurl 3389 ff:11:22:dd
|
||||
otherurl 3389 aa:bb:cc:dd
|
||||
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha1_cert.pem
vendored
Normal file
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha1_cert.pem
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/zCCAeegAwIBAgIUNveSXnRIoI24dM6PxYjhcXQhsgkwDQYJKoZIhvcNAQEF
|
||||
BQAwDzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA2MzVaFw0zNDAyMDMwMzA2
|
||||
MzVaMA8xDTALBgNVBAMMBFRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQCy23VMgwiNO32ovOxt+7CJCR5Ep1qn1tV5//ONhLEoz+VhEbMTYQNHK1WY
|
||||
E9isGrcRUVLsBehIFP02ImgOGv1Yep/P1pY+A/fLpy4NhHoLYxmvdhAKQG3TB5P1
|
||||
s7GuXTaK4/Kp8CzVYP7xZu7zI2TWWolkCDYZvkewR5QOuyiAstvZp5IoIx0J9mo2
|
||||
rI5DqnSmK+zzaYTMaGyWFLXOQJZi+k+RUB3XUFZSid69thW0rfi7tC0fyUm7fP7H
|
||||
72/27aBmW1S/8hUYSfu88kCCmEEu+KGXbmyNPEVMJcM9cZ43TVMGUPodOXuDydm/
|
||||
IKnsZaRnGPi8IBzn0y6k/8ZdmJojAgMBAAGjUzBRMB0GA1UdDgQWBBRsqgoFZ83u
|
||||
IMZzUjsVI5N73Izq1DAfBgNVHSMEGDAWgBRsqgoFZ83uIMZzUjsVI5N73Izq1DAP
|
||||
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQCIFhCbHy6U6EYHogXE
|
||||
xnoHdtzitHTUU+mymWeQxWxSvZjWX8xdJdbWQyktSCChKrRnQE+P/e5+HOZFn9q5
|
||||
jwgj3HwZZwFqt/0nSX7pjEvTOmwEXTo/QBlyHaLSdrxbd85gahkXP1br6vI0yWcT
|
||||
kkKZCFiqbsGGqcoErRyZjYfJBgaZ5AMYXEKkKCgRJ59Sln+mW+fpta7dmgmnPIdX
|
||||
Jl/ovEHr0X+PgwLby8BxCb5pOyb6CQvUNWfngtzgm76vricszpmDl4HeBAb0IkZ1
|
||||
0hlnHEBNgP46/2EhPvD1QehYOmr5HRi2xSPC9gOW8pkbRRFuCDZwoSfav023xim6
|
||||
lOS3
|
||||
-----END CERTIFICATE-----
|
||||
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha256_cert.pem
vendored
Normal file
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha256_cert.pem
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/zCCAeegAwIBAgIUK9L1Ajn7PiMRVvR6YUoATBxgD2wwDQYJKoZIhvcNAQEL
|
||||
BQAwDzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA2MzVaFw0zNDAyMDMwMzA2
|
||||
MzVaMA8xDTALBgNVBAMMBFRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQC73wUpONU4o0abFykUC08A2deojU/+SGomnN8V51VDVeC2BGUljLabjABm
|
||||
iluh/yUJ0zDHp6x1spr6wdDVzRMvjjxC/G2HVzYRn/3zXhZ0q9avPnCe1hgawHZY
|
||||
FG4vgysJ1jtPSR97E4MvSg6v6mATCU2ttvceENFwo5FQ6nfBv+rHpepRyOKUtfsa
|
||||
gxRCWU0uHwyahNsYzWOrbkEcpoQAowAoHZh9EbjyNNbCX0/C3yew/GX8mNBz1UOV
|
||||
X4taJsOW52LKQ2xgSwl31m6VYmNqqfzTA6pr96PpYqsuAT3WYBBnIk+XT+Yhq3Cs
|
||||
n96PvHAovUiBwWptvzsICvtAUwCjAgMBAAGjUzBRMB0GA1UdDgQWBBQGUaK7joEk
|
||||
yFR6FtsA4UjF+FPrRTAfBgNVHSMEGDAWgBQGUaK7joEkyFR6FtsA4UjF+FPrRTAP
|
||||
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAkYpNiExDwuqfFCHpz
|
||||
jWFSkL9drTxMuasGfmq634FSe050TGKl8yUZhz215PoEDHcutGAw6JV59DJMI/wo
|
||||
Xq4MpJiCLlUu8BOixU41rlyc9XkV6twcnQlkVhYWV07390SP4uKGXRR03yGwjN7C
|
||||
RDv/4z4t9iMQhiIYkN0EXKvymjRMhb9GocfTQFSXq6vy0fr4MuwnuOkr6EcU41Hr
|
||||
pQ4nNLuj2P7cAaaFo5RaD/eXzsE4CfgoltmTp+Ir3deXG/RKrJ9V/YTx5d6pqssp
|
||||
5f7nDKmhiYn6wtF4TlOnujppT1Mr4UZF7lJAfwUX80bYQBbpfczHBKSYQ/Th5Mtx
|
||||
ediM
|
||||
-----END CERTIFICATE-----
|
||||
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha384_cert.pem
vendored
Normal file
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha384_cert.pem
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/zCCAeegAwIBAgIUHpfVpdCFW4e5gmPMyNN/CZou028wDQYJKoZIhvcNAQEM
|
||||
BQAwDzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA2MzVaFw0zNDAyMDMwMzA2
|
||||
MzVaMA8xDTALBgNVBAMMBFRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQCMlHin4N8tMbfDqIahZlyOhBX392Pcyo4bUM7ipUEdLdz1SSCf7/gh4SgH
|
||||
ihCbN/NWiYoobnR7iS6vBgUMQgzdivwOia0jydcifpf2UR2D1KjBnolALqaRYpDB
|
||||
zdEOnJ4Nm21sOlfCM/QoiMdPWZlbzisXyGBYHR8E8G5Snfy13cRvfV+M9/epbvwV
|
||||
1o4m/wPu2H+Q+XVRHJY1H7jAtjUtLSUwii0jc134c9nHOdqXB9fgcn7etkQKXWPv
|
||||
w7Dg/OWXURpABGjflS6w4UhECzlPInmd9fBtLngf7n9Sa4b0rcdWEWcTbWORmEbj
|
||||
xoHyWNiRbdzIc0zUb42DFuFgeUcFAgMBAAGjUzBRMB0GA1UdDgQWBBRm5loY68pA
|
||||
VVlVVcIL3zTv1sCYWjAfBgNVHSMEGDAWgBRm5loY68pAVVlVVcIL3zTv1sCYWjAP
|
||||
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4IBAQAJFNU9dUNpIbbsgyty
|
||||
RRd5SVD/4ziOOPoKO6jobBenPxNQNbaOQmENImW0WbgOHWW1kX15afCThMocibKl
|
||||
OIVoOf2tcrseAYdfsOzEMwDc1hI5y68vNRV32rJamix1223wPhs1xuoX8bn0t0VB
|
||||
RK4kgb9U1mxSKERjcgtp2Pph5DeflCQDeNayBGAA5PCL4ydO61DEKbVo1Cyqtw9n
|
||||
yhae7AUR4zzRnZEh1eePd06cXSIYwmTkiJLSF7ILsZnGcqy4bO8yJPrqXT01Iq0S
|
||||
RzQ2hgyldKD0kJ3EBmki3mIrnswCzNqyXux1CXIR1FjIA5SnwycqiiPUUPLckinq
|
||||
DtQX
|
||||
-----END CERTIFICATE-----
|
||||
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha512_cert.pem
vendored
Normal file
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pkcs1_sha512_cert.pem
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/zCCAeegAwIBAgIUTAXZy2Zojh8wh4YSdc2vMBiytGIwDQYJKoZIhvcNAQEN
|
||||
BQAwDzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA2MzVaFw0zNDAyMDMwMzA2
|
||||
MzVaMA8xDTALBgNVBAMMBFRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQDH2av9vKvlzlSB63ylb8OyacC6zkhoiH4ECkVt7DRvBBnHYX39eeXg1KNk
|
||||
yHBaLA+9ASXucckqAQ8hWlIW7y9KLYYsK8+ajDUnWkzPj+eOonSc2oTbSBtEP8V4
|
||||
3TihNGRgyLSZYj6HxUrFWW6pc0Kz7yAG83YNzR8uWCEZV8wYAdBqZDO1RAOd2tLr
|
||||
DFLI+DJwMtgDquT1Uo/xDsx0p9+tSGXm4eXjlZQguhA4tuP4eJP7qvwR+khJNN9X
|
||||
u2igfO3zMY26wX4m/kPdljxh5vRc2DVIePfKbTKLyfpsydQUSoKVzlSQG7QJAUmC
|
||||
jcqgIGQqYy8f6Nq4fRzgiSQOULmPAgMBAAGjUzBRMB0GA1UdDgQWBBQMYhVmmR0c
|
||||
9DJmJZOqHawdWDVFJDAfBgNVHSMEGDAWgBQMYhVmmR0c9DJmJZOqHawdWDVFJDAP
|
||||
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQBr2I9uvQ8Ccn5yw1Ig
|
||||
7k2Qmg/HOCFGh42Ufz1PAc9dc1CzBzMlFucJ42shES98Spyh4R+ZCJmlZ9PneViA
|
||||
s9NW+mHLAFJ2Fuct4XY8RnyDYqTne0in6eQykF33gl79sdYSPuBfAxMfJqUoQo+b
|
||||
tF0N0DA00i5z69wcF5LQJLRbeTh7T1qikkay3ODMJYpCDVb7GOhWCt4hOkxOszuL
|
||||
SoJ2gFMGoEKbt19IzcMctsSPgpQCNYZirU9x3l/Ptw5zgUQMEngwuutuhDMxb5Ht
|
||||
2QHTGt3jwzlOi+lvHFH1AMW3e8/XRZa7jFUa+KCr8vD3yfDimx9J0ESmlUrLxOZG
|
||||
ayG7
|
||||
-----END CERTIFICATE-----
|
||||
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha1_cert.pem
vendored
Normal file
19
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha1_cert.pem
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIC/zCCAeegAwIBAgIUDZuL7xQULUgo1YKeDIJDFdsVCuMwDQYJKoZIhvcNAQEK
|
||||
MAAwDzENMAsGA1UEAwwEVGVzdDAeFw0yNDAyMDYwMzA2MzVaFw0zNDAyMDMwMzA2
|
||||
MzVaMA8xDTALBgNVBAMMBFRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQCxLekSxv8aVwB5p9UImN+jipKNJUb8fOrtOVHjeO5jK9G920vneZsubpq/
|
||||
NngzpjT2A+HOkee9oNG92O8U7DGyGXiZugmeFE6kunPQ+GP5za3XfZqwvAu53+Pg
|
||||
oyrBGl5ssowRimRDXOH3/x7WSKD2lvQNgLWOS5NTIZethXx29Xj+/nKJ33im8ra/
|
||||
YcEB6CANHmo2bDCz8Q54iHjIOro+MiP10oQM2ERzuZREn/+xCFuYYGhXKb3fqy+r
|
||||
Ze/tIVqEr7yMVpp76RxFM3I4PadHt8T9Q5Oat9FXWaqG/1fBtBKXt6jElkqnd+vv
|
||||
KtRMEqQ4XNeMJi6Q4oyLsmxGB8q7AgMBAAGjUzBRMB0GA1UdDgQWBBQuCV/GISEn
|
||||
D18xN3d1KEOo13c/2zAfBgNVHSMEGDAWgBQuCV/GISEnD18xN3d1KEOo13c/2zAP
|
||||
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCjAAA4IBAQA+nnvGYJwVP5byl+XB
|
||||
1KoFLv4SOS9kDypjv+4Mjo3/houn7DAf1+6ewfmAN7edkElTngpz6rGzJgARULbO
|
||||
djKi6AJDDqF9NzWbJZC/UEVqqVY1Znw1v8Hwz31YFaoARLWwuKQrKjLZUHphsMok
|
||||
iWdwusebfQ1SK9b8QTW7s8CncC+PbOHH1UnHhM1XWGz49sWZo/KnHCGL0pGROSro
|
||||
gT2zEDDk/bpslalcavEGcw2wttaBiYovdpgUHzOIcTxLz/yQGAfaCk/cO8x5mS9y
|
||||
w6CZVaH6K1TrmXGWBoHtLQ+JMC7msms3PmBZ4XCc8zAqjhVI4o71Jlbrd/Bag0lm
|
||||
X+89
|
||||
-----END CERTIFICATE-----
|
||||
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha256_cert.pem
vendored
Normal file
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha256_cert.pem
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZzCCAhugAwIBAgIUChf3gsm9kG9E05UbcYnEzQ/fSfkwQQYJKoZIhvcNAQEK
|
||||
MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEF
|
||||
AKIDAgEgMA8xDTALBgNVBAMMBFRlc3QwHhcNMjQwMjA2MDMwNjM1WhcNMzQwMjAz
|
||||
MDMwNjM1WjAPMQ0wCwYDVQQDDARUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAtk22hPAmTxSTSs8MUJInf7N6byDo1LlEgw5juF8y1bVxhoF0U4Ug
|
||||
u0zqCVtar/JBPmcVofM4IU4+GoIRfI9qyyyD5EQup2e8exUn/Bku+7XTmlCSKfUI
|
||||
T4u/zpe/qJCyRwT6pLP4POtoqsmrRf+u7zVvS7VHafPioxLLrOIbB750AYmi7y/n
|
||||
h8MreJHrQ901IQV4Ktf2QgaFrjJFgXD307iTGoiRt+UxkmGsOOzFt+N91lM30ad+
|
||||
sCgmc1NVVyo6p4RByl7ilxlQGCATOQ9wTVwehgmtFGpU0denhqViNUU8yuPZ3pTD
|
||||
w1o9uWTAKdUuMySSUiKmmlE+qnlFfR9uPwIDAQABo1MwUTAdBgNVHQ4EFgQUQPus
|
||||
AuQ9cNE9E2+vZXKtKAtfDIUwHwYDVR0jBBgwFoAUQPusAuQ9cNE9E2+vZXKtKAtf
|
||||
DIUwDwYDVR0TAQH/BAUwAwEB/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQC
|
||||
AQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASADggEBAGpIH7ic
|
||||
GwD2vzTGgFhHrh4NkGu9OwI8WA342DKfJq0Cx+BjaFsglhjLVkbqP74XjgQUSqt+
|
||||
yp09xgrZdIP8yMJr7mjqQpV7tolB1yrD0h0jtoMe0Pc1+wVwjkMQjsewwSDJvV9O
|
||||
RjXqmzoIjUAXmASk5JdZ5oDBK6bg7m8/hJyEJnWdOuiVUJTyPz+Y1/6rpzwH/+xX
|
||||
x3sO6OaWMSIc/ovF1Y7kQ4mwgPjLuq1X8Dx7xM9rcJak5cGAwUwQqvOaD3y9ZQzg
|
||||
E+kH4mtWw29xRTejbiMSbnbfR8LfZdS2+10ESK66SXChVz3Q7shkR9Gs6kTJiXTu
|
||||
FUtRtO0G5aoSHeA=
|
||||
-----END CERTIFICATE-----
|
||||
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha256_mgf1_sha384_cert.pem
vendored
Normal file
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha256_mgf1_sha384_cert.pem
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZzCCAhugAwIBAgIUVvhEAv0+q7jndH6xf2RJjaiaIVswQQYJKoZIhvcNAQEK
|
||||
MDSgDzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIF
|
||||
AKIDAgEgMA8xDTALBgNVBAMMBFRlc3QwHhcNMjQwMjA2MDMwNjM2WhcNMzQwMjAz
|
||||
MDMwNjM2WjAPMQ0wCwYDVQQDDARUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAsC6mgspqVdpZrhHUz5zoY4Sklg+spYAz8axxEyJf3Tdg427ildSH
|
||||
BLi62qZ+gTXLHgUvdkMWEv8NWODHY5DNuTiL65LjV0gN7eIzVbzc0alTdbp+nc7H
|
||||
HHZHBedD3CRT4LHqlK9LVTYcQk8qNtnKJ7vxNJHN3vpmr0zxxJf3nle7Ymnx2FiK
|
||||
mXDu3vQEDSU6eyOu5dk0IsEWlMOCYu5w8dpbdGaE4az3IaHXsDnmfLfIWUaILQxw
|
||||
Mj0UhNg+vnZsanB7CWiLZOIawEpa6dx2Zcasyi8V6lZV1sxYQrskRbAj9uGtDmtd
|
||||
kTKeCxtj7Bgj9e6aIN2rh7keH5+pqissxwIDAQABo1MwUTAdBgNVHQ4EFgQUpXlx
|
||||
cN8y7RSFQjPjO3Kb1x0GWcYwHwYDVR0jBBgwFoAUpXlxcN8y7RSFQjPjO3Kb1x0G
|
||||
WcYwDwYDVR0TAQH/BAUwAwEB/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQC
|
||||
AQUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCASADggEBAKcp+pEt
|
||||
hei70aV9+j+p/cjChDSqQyipIvyqt0wdHiM/5WwGO4LnR/JxWqHHGtlQjgphKVpV
|
||||
bjRMBivrbb//LNb0cx5z3o9hx2H6ITwpwrRA9dvfE1C+hOBbxhUYNtk4jpH1DneX
|
||||
8l/A9Lm6kmZ02KrJok8VEGthtZqypkRAQFxStY2EuopzWVzdceJYa4AOB26r7F0T
|
||||
Z5BzO/Piy39lQtZGyMZ2R71ppEDWXVrSaqxV64aFnh3/2aCgFUzuV2FYr1NZ+zQu
|
||||
EBJZIdd0IvhcgHkiUD6qtlYNJ1H7Jf9hSRDM7d7AblhgxVB1eRU+7Ve1o47LfQqz
|
||||
iVybceMUSCyMFLk=
|
||||
-----END CERTIFICATE-----
|
||||
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha384_cert.pem
vendored
Normal file
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha384_cert.pem
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZzCCAhugAwIBAgIUI7KZPJ4nCR/qFZWD2bagetWGJRQwQQYJKoZIhvcNAQEK
|
||||
MDSgDzANBglghkgBZQMEAgIFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgIF
|
||||
AKIDAgEwMA8xDTALBgNVBAMMBFRlc3QwHhcNMjQwMjA2MDMwNjM2WhcNMzQwMjAz
|
||||
MDMwNjM2WjAPMQ0wCwYDVQQDDARUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA3/WFdrzn9QQjowwZqCmgIJcCWy+8aIjHLlE4OLWyv4rVAdQluFRA
|
||||
Af1lsKY+ZD6gvWOKhnSNT7z4WfH03vUNpkqOt1kqtjMsuRsy4Zh2n54LYM2IHkVh
|
||||
+oZpq8dBESkffAHOLwkl6Be/iZE3t4Z2hdrzhFEt1iGxtfwduIcku/geciLKM0D0
|
||||
1UHtVzb0762hx94IX506vxAdvNAK48gTSobBBWQJhHz2a2tvt2ON3eRian41qwxW
|
||||
Nsl7OUyss6PmVXYS3JbmZgyzT0nSHQWEVlEcQOI3UxjNqeK2HMyMDYLgIvVD+IER
|
||||
1nMT4AUyWDGkRR6bFITS2BmW7JbxQ40ZiwIDAQABo1MwUTAdBgNVHQ4EFgQUn9rP
|
||||
CfGH3OFxdNXCFbAQrYlgXd4wHwYDVR0jBBgwFoAUn9rPCfGH3OFxdNXCFbAQrYlg
|
||||
Xd4wDwYDVR0TAQH/BAUwAwEB/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQC
|
||||
AgUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATADggEBADJ6+6Us
|
||||
KXbcpyzapxqQGr0rGkGOPf45Vo2EY0H2A0YY9CHYrU/jq2xijHgnw89I3z9Z3h4q
|
||||
kSD51Rr/3V/e5ffcYwRabC6S515anOgxtCE4cgHEqgIdzrwD3EFGm74D+MnJRTy8
|
||||
UpE5pZTaHNRno80rz1kRYN2MHO/sHqQCpFoZ8SI3+Nik5m3FSe2Umb3FLTvrOAcm
|
||||
biGgj4cF52w1D7XAAo/3bAH9Rt0/FRK46nULoEX54RJHlFN8f3kzBucNNfoHNPBR
|
||||
2lMQJM1VzpPkjR5rLOwAYKEfvIvwDVEgDMpD4+P5/FMX/fnSm4kVaiZMwLLrtJlX
|
||||
pS9N0mDlr4wk9hw=
|
||||
-----END CERTIFICATE-----
|
||||
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha512_cert.pem
vendored
Normal file
21
third_party/FreeRDP/libfreerdp/crypto/test/rsa_pss_sha512_cert.pem
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDZzCCAhugAwIBAgIUCJHdINzBcxL45k+BWvKYcpH8vzQwQQYJKoZIhvcNAQEK
|
||||
MDSgDzANBglghkgBZQMEAgMFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgMF
|
||||
AKIDAgFAMA8xDTALBgNVBAMMBFRlc3QwHhcNMjQwMjA2MDMwNjM2WhcNMzQwMjAz
|
||||
MDMwNjM2WjAPMQ0wCwYDVQQDDARUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA6jzuBGtb+D/0ZWRqZAcZh6bkClCbHdiz1yOPuh4APfyfsFGDSRBt
|
||||
ArMH+l2/Mr7TXeAfdDHX//bNBclPzu0mKWtVamh7s3WWoPBX+r10ie94YxErFY+6
|
||||
Po5pGDnSabVawdnXd5FqCdFVpmXP12Ii9qKuRD13XAPJML0Cz9z4pOL0ioWvvUqn
|
||||
MyWwa8zT8pfK4AJe4XGilQ2uxwJV922XQxv6rY8aOFuwozkNa0/ceN1A2EKIwShB
|
||||
P3/3Z+9maz4YMg/VgmJfEY/xekawDZ7MC8CY9G/alE1YqHERvR5BwekrnFHSErM4
|
||||
ArSUJnavXm7rdB1OCp4kAKXkLvu2H/8AMQIDAQABo1MwUTAdBgNVHQ4EFgQUrLTl
|
||||
C9kRXzElbsDUCc/ePO75qNkwHwYDVR0jBBgwFoAUrLTlC9kRXzElbsDUCc/ePO75
|
||||
qNkwDwYDVR0TAQH/BAUwAwEB/zBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQC
|
||||
AwUAoRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAwUAogMCAUADggEBAGMyu2fZ
|
||||
NpvIJQxXPSfhgf8idvGwu7YFdZ/Ct0/HIHJ1h+j2WFwubr/Rcwqu+u6Nq09oMq+H
|
||||
5EWDtOona78WIQ/RrIs6ltVJBDpirIGjra0IKpYGqYHUEj00u1OZkiQzmMLRT80W
|
||||
jEe38fATXbpmLhXA8bqlOHuMot2OTWzKEtST4knAAYUCFPIS94mODR4faeqDBwIB
|
||||
JpYBj2sRwZDU4QbERvLTQMD27kE2ynF4duI4NB6k9w3fJSe60ki5m4avYmiQgj5/
|
||||
304UD/AEf+xlMCLh3R8ZGST10zV5M1Wm7czuQ0AKsv45pSltDvWl52OjL3W5CLAJ
|
||||
iu1eLWBVbFPTK68=
|
||||
-----END CERTIFICATE-----
|
||||
2111
third_party/FreeRDP/libfreerdp/crypto/tls.c
vendored
Normal file
2111
third_party/FreeRDP/libfreerdp/crypto/tls.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
139
third_party/FreeRDP/libfreerdp/crypto/tls.h
vendored
Normal file
139
third_party/FreeRDP/libfreerdp/crypto/tls.h
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Transport Layer Security
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.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 FREERDP_LIB_CRYPTO_TLS_H
|
||||
#define FREERDP_LIB_CRYPTO_TLS_H
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/crypto/certificate_store.h>
|
||||
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#define TLS_ALERT_LEVEL_WARNING 1
|
||||
#define TLS_ALERT_LEVEL_FATAL 2
|
||||
|
||||
#define TLS_ALERT_DESCRIPTION_CLOSE_NOTIFY 0
|
||||
#define TLS_ALERT_DESCRIPTION_UNEXPECTED_MESSAGE 10
|
||||
#define TLS_ALERT_DESCRIPTION_BAD_RECORD_MAC 20
|
||||
#define TLS_ALERT_DESCRIPTION_DECRYPTION_FAILED 21
|
||||
#define TLS_ALERT_DESCRIPTION_RECORD_OVERFLOW 22
|
||||
#define TLS_ALERT_DESCRIPTION_DECOMPRESSION_FAILURE 30
|
||||
#define TLS_ALERT_DESCRIPTION_HANSHAKE_FAILURE 40
|
||||
#define TLS_ALERT_DESCRIPTION_NO_CERTIFICATE 41
|
||||
#define TLS_ALERT_DESCRIPTION_BAD_CERTIFICATE 42
|
||||
#define TLS_ALERT_DESCRIPTION_UNSUPPORTED_CERTIFICATE 43
|
||||
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_REVOKED 44
|
||||
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_EXPIRED 45
|
||||
#define TLS_ALERT_DESCRIPTION_CERTIFICATE_UNKNOWN 46
|
||||
#define TLS_ALERT_DESCRIPTION_ILLEGAL_PARAMETER 47
|
||||
#define TLS_ALERT_DESCRIPTION_UNKNOWN_CA 48
|
||||
#define TLS_ALERT_DESCRIPTION_ACCESS_DENIED 49
|
||||
#define TLS_ALERT_DESCRIPTION_DECODE_ERROR 50
|
||||
#define TLS_ALERT_DESCRIPTION_DECRYPT_ERROR 51
|
||||
#define TLS_ALERT_DESCRIPTION_EXPORT_RESTRICTION 60
|
||||
#define TLS_ALERT_DESCRIPTION_PROTOCOL_VERSION 70
|
||||
#define TLS_ALERT_DESCRIPTION_INSUFFICIENT_SECURITY 71
|
||||
#define TLS_ALERT_DESCRIPTION_INTERNAL_ERROR 80
|
||||
#define TLS_ALERT_DESCRIPTION_USER_CANCELED 90
|
||||
#define TLS_ALERT_DESCRIPTION_NO_RENEGOTIATION 100
|
||||
#define TLS_ALERT_DESCRIPTION_UNSUPPORTED_EXTENSION 110
|
||||
|
||||
typedef struct rdp_tls rdpTls;
|
||||
|
||||
struct rdp_tls
|
||||
{
|
||||
SSL* ssl;
|
||||
BIO* bio;
|
||||
void* tsg;
|
||||
SSL_CTX* ctx;
|
||||
BYTE* PublicKey;
|
||||
DWORD PublicKeyLength;
|
||||
rdpContext* context;
|
||||
SecPkgContext_Bindings* Bindings;
|
||||
rdpCertificateStore* certificate_store;
|
||||
BIO* underlying;
|
||||
const char* hostname;
|
||||
const char* serverName;
|
||||
int port;
|
||||
int alertLevel;
|
||||
int alertDescription;
|
||||
BOOL isGatewayTransport;
|
||||
BOOL isClientMode;
|
||||
};
|
||||
|
||||
/** @brief result of a handshake operation */
|
||||
typedef enum
|
||||
{
|
||||
TLS_HANDSHAKE_SUCCESS, /*!< handshake was successful */
|
||||
TLS_HANDSHAKE_CONTINUE, /*!< handshake is not completed */
|
||||
TLS_HANDSHAKE_ERROR, /*!< an error (probably IO error) happened */
|
||||
TLS_HANDSHAKE_VERIFY_ERROR /*!< Certificate verification failed (client mode) */
|
||||
} TlsHandshakeResult;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL const SSL_METHOD* freerdp_tls_get_ssl_method(BOOL isDtls, BOOL isClient);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL int freerdp_tls_connect(rdpTls* tls, BIO* underlying);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL TlsHandshakeResult freerdp_tls_connect_ex(rdpTls* tls, BIO* underlying,
|
||||
const SSL_METHOD* methods);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL freerdp_tls_accept(rdpTls* tls, BIO* underlying, rdpSettings* settings);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL TlsHandshakeResult freerdp_tls_accept_ex(rdpTls* tls, BIO* underlying,
|
||||
rdpSettings* settings,
|
||||
const SSL_METHOD* methods);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL TlsHandshakeResult freerdp_tls_handshake(rdpTls* tls);
|
||||
|
||||
FREERDP_LOCAL BOOL freerdp_tls_send_alert(rdpTls* tls);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL int freerdp_tls_write_all(rdpTls* tls, const BYTE* data, size_t length);
|
||||
|
||||
FREERDP_LOCAL int freerdp_tls_set_alert_code(rdpTls* tls, int level, int description);
|
||||
|
||||
FREERDP_LOCAL void freerdp_tls_free(rdpTls* tls);
|
||||
|
||||
WINPR_ATTR_MALLOC(freerdp_tls_free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL rdpTls* freerdp_tls_new(rdpContext* context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_CRYPTO_TLS_H */
|
||||
934
third_party/FreeRDP/libfreerdp/crypto/x509_utils.c
vendored
Normal file
934
third_party/FreeRDP/libfreerdp/crypto/x509_utils.c
vendored
Normal file
@@ -0,0 +1,934 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Cryptographic Abstraction Layer
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <freerdp/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/string.h>
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "x509_utils.h"
|
||||
|
||||
#define TAG FREERDP_TAG("crypto")
|
||||
|
||||
BYTE* x509_utils_get_hash(const X509* xcert, const char* hash, size_t* length)
|
||||
{
|
||||
UINT32 fp_len = EVP_MAX_MD_SIZE;
|
||||
BYTE* fp = nullptr;
|
||||
const EVP_MD* md = EVP_get_digestbyname(hash);
|
||||
if (!md)
|
||||
{
|
||||
WLog_ERR(TAG, "System does not support %s hash!", hash);
|
||||
return nullptr;
|
||||
}
|
||||
if (!xcert || !length)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid arguments: xcert=%p, length=%p",
|
||||
WINPR_CXX_COMPAT_CAST(const void*, xcert),
|
||||
WINPR_CXX_COMPAT_CAST(const void*, length));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
fp = calloc(fp_len + 1, sizeof(BYTE));
|
||||
if (!fp)
|
||||
{
|
||||
WLog_ERR(TAG, "could not allocate %" PRIu32 " bytes", fp_len);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (X509_digest(xcert, md, fp, &fp_len) != 1)
|
||||
{
|
||||
free(fp);
|
||||
WLog_ERR(TAG, "certificate does not have a %s hash!", hash);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*length = fp_len;
|
||||
return fp;
|
||||
}
|
||||
|
||||
static char* crypto_print_name(const X509_NAME* name)
|
||||
{
|
||||
char* buffer = nullptr;
|
||||
BIO* outBIO = BIO_new(BIO_s_mem());
|
||||
|
||||
if (X509_NAME_print_ex(outBIO, name, 0, XN_FLAG_ONELINE) > 0)
|
||||
{
|
||||
UINT64 size = BIO_number_written(outBIO);
|
||||
if (size > INT_MAX)
|
||||
goto fail;
|
||||
buffer = calloc(1, (size_t)size + 1);
|
||||
|
||||
if (!buffer)
|
||||
goto fail;
|
||||
|
||||
ERR_clear_error();
|
||||
const int rc = BIO_read(outBIO, buffer, (int)size);
|
||||
if (rc <= 0)
|
||||
{
|
||||
free(buffer);
|
||||
buffer = nullptr;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
BIO_free_all(outBIO);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* x509_utils_get_subject(const X509* xcert)
|
||||
{
|
||||
char* subject = nullptr;
|
||||
if (!xcert)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid certificate nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
subject = crypto_print_name(X509_get_subject_name(xcert));
|
||||
if (!subject)
|
||||
WLog_WARN(TAG, "certificate does not have a subject!");
|
||||
return subject;
|
||||
}
|
||||
|
||||
/* GENERAL_NAME type labels */
|
||||
|
||||
static const char* general_name_type_labels[] = { "OTHERNAME", "EMAIL ", "DNS ",
|
||||
"X400 ", "DIRNAME ", "EDIPARTY ",
|
||||
"URI ", "IPADD ", "RID " };
|
||||
|
||||
static const char* general_name_type_label(int general_name_type)
|
||||
{
|
||||
if ((0 <= general_name_type) &&
|
||||
((size_t)general_name_type < ARRAYSIZE(general_name_type_labels)))
|
||||
{
|
||||
return general_name_type_labels[general_name_type];
|
||||
}
|
||||
else
|
||||
{
|
||||
static char buffer[80] = WINPR_C_ARRAY_INIT;
|
||||
(void)snprintf(buffer, sizeof(buffer), "Unknown general name type (%d)", general_name_type);
|
||||
return buffer;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
map_subject_alt_name(x509, general_name_type, mapper, data)
|
||||
|
||||
Call the function mapper with subjectAltNames found in the x509
|
||||
certificate and data. if generate_name_type is GEN_ALL, the the
|
||||
mapper is called for all the names, else it's called only for names
|
||||
of the given type.
|
||||
|
||||
|
||||
We implement two extractors:
|
||||
|
||||
- a string extractor that can be used to get the subjectAltNames of
|
||||
the following types: GEN_URI, GEN_DNS, GEN_EMAIL
|
||||
|
||||
- a ASN1_OBJECT filter/extractor that can be used to get the
|
||||
subjectAltNames of OTHERNAME type.
|
||||
|
||||
Note: usually, it's a string, but some type of otherNames can be
|
||||
associated with different classes of objects. eg. a KPN may be a
|
||||
sequence of realm and principal name, instead of a single string
|
||||
object.
|
||||
|
||||
Not implemented yet: extractors for the types: GEN_X400, GEN_DIRNAME,
|
||||
GEN_EDIPARTY, GEN_RID, GEN_IPADD (the later can contain nul-bytes).
|
||||
|
||||
|
||||
mapper(name, data, index, count)
|
||||
|
||||
The mapper is passed:
|
||||
- the GENERAL_NAME selected,
|
||||
- the data,
|
||||
- the index of the general name in the subjectAltNames,
|
||||
- the total number of names in the subjectAltNames.
|
||||
|
||||
The last parameter let's the mapper allocate arrays to collect objects.
|
||||
Note: if names are filtered, not all the indices from 0 to count-1 are
|
||||
passed to mapper, only the indices selected.
|
||||
|
||||
When the mapper returns 0, map_subject_alt_name stops the iteration immediately.
|
||||
|
||||
*/
|
||||
|
||||
#define GEN_ALL (-1)
|
||||
|
||||
typedef int (*general_name_mapper_pr)(GENERAL_NAME* name, void* data, int index, int count);
|
||||
|
||||
static void map_subject_alt_name(const X509* x509, int general_name_type,
|
||||
general_name_mapper_pr mapper, void* data)
|
||||
{
|
||||
int num = 0;
|
||||
STACK_OF(GENERAL_NAME)* gens = nullptr;
|
||||
gens = X509_get_ext_d2i(x509, NID_subject_alt_name, nullptr, nullptr);
|
||||
|
||||
if (!gens)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
num = sk_GENERAL_NAME_num(gens);
|
||||
|
||||
for (int i = 0; (i < num); i++)
|
||||
{
|
||||
GENERAL_NAME* name = sk_GENERAL_NAME_value(gens, i);
|
||||
|
||||
if (name)
|
||||
{
|
||||
if ((general_name_type == GEN_ALL) || (general_name_type == name->type))
|
||||
{
|
||||
if (!mapper(name, data, i, num))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sk_GENERAL_NAME_pop_free(gens, GENERAL_NAME_free);
|
||||
}
|
||||
|
||||
/*
|
||||
extract_string -- string extractor
|
||||
|
||||
- the strings array is allocated lazily, when we first have to store a
|
||||
string.
|
||||
|
||||
- allocated contains the size of the strings array, or -1 if
|
||||
allocation failed.
|
||||
|
||||
- count contains the actual count of strings in the strings array.
|
||||
|
||||
- maximum limits the number of strings we can store in the strings
|
||||
array: beyond, the extractor returns 0 to short-cut the search.
|
||||
|
||||
extract_string stores in the string list OPENSSL strings,
|
||||
that must be freed with OPENSSL_free.
|
||||
|
||||
*/
|
||||
|
||||
typedef struct string_list
|
||||
{
|
||||
char** strings;
|
||||
size_t allocated;
|
||||
size_t count;
|
||||
size_t maximum;
|
||||
} string_list;
|
||||
|
||||
static void string_list_initialize(string_list* list)
|
||||
{
|
||||
list->strings = nullptr;
|
||||
list->allocated = 0;
|
||||
list->count = 0;
|
||||
list->maximum = INT_MAX;
|
||||
}
|
||||
|
||||
static void string_list_allocate(string_list* list, size_t allocate_count)
|
||||
{
|
||||
if (!list->strings && list->allocated == 0)
|
||||
{
|
||||
list->strings = (char**)calloc(allocate_count, sizeof(char*));
|
||||
list->allocated = list->strings ? allocate_count : 0;
|
||||
list->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void string_list_free(string_list* list)
|
||||
{
|
||||
/* Note: we don't free the contents of the strings array: this */
|
||||
/* is handled by the caller, either by returning this */
|
||||
/* content, or freeing it itself. */
|
||||
free((void*)list->strings);
|
||||
}
|
||||
|
||||
static int extract_string(GENERAL_NAME* name, void* data, int index, int count)
|
||||
{
|
||||
string_list* list = data;
|
||||
unsigned char* cstring = nullptr;
|
||||
ASN1_STRING* str = nullptr;
|
||||
|
||||
WINPR_UNUSED(index);
|
||||
|
||||
switch (name->type)
|
||||
{
|
||||
case GEN_URI:
|
||||
str = name->d.uniformResourceIdentifier;
|
||||
break;
|
||||
|
||||
case GEN_DNS:
|
||||
str = name->d.dNSName;
|
||||
break;
|
||||
|
||||
case GEN_EMAIL:
|
||||
str = name->d.rfc822Name;
|
||||
break;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((ASN1_STRING_to_UTF8(&cstring, str)) < 0)
|
||||
{
|
||||
WLog_ERR(TAG, "ASN1_STRING_to_UTF8() failed for %s: %s",
|
||||
general_name_type_label(name->type), ERR_error_string(ERR_get_error(), nullptr));
|
||||
return 1;
|
||||
}
|
||||
|
||||
string_list_allocate(list, WINPR_ASSERTING_INT_CAST(WINPR_CIPHER_TYPE, count));
|
||||
|
||||
if (list->allocated <= 0)
|
||||
{
|
||||
OPENSSL_free(cstring);
|
||||
return 0;
|
||||
}
|
||||
|
||||
list->strings[list->count] = (char*)cstring;
|
||||
list->count++;
|
||||
|
||||
if (list->count >= list->maximum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
extract_othername_object -- object extractor.
|
||||
|
||||
- the objects array is allocated lazily, when we first have to store a
|
||||
string.
|
||||
|
||||
- allocated contains the size of the objects array, or -1 if
|
||||
allocation failed.
|
||||
|
||||
- count contains the actual count of objects in the objects array.
|
||||
|
||||
- maximum limits the number of objects we can store in the objects
|
||||
array: beyond, the extractor returns 0 to short-cut the search.
|
||||
|
||||
extract_othername_objects stores in the objects array ASN1_TYPE *
|
||||
pointers directly obtained from the GENERAL_NAME.
|
||||
*/
|
||||
|
||||
typedef struct object_list
|
||||
{
|
||||
ASN1_OBJECT* type_id;
|
||||
char** strings;
|
||||
size_t allocated;
|
||||
size_t count;
|
||||
size_t maximum;
|
||||
} object_list;
|
||||
|
||||
static void object_list_initialize(object_list* list)
|
||||
{
|
||||
list->type_id = nullptr;
|
||||
list->strings = nullptr;
|
||||
list->allocated = 0;
|
||||
list->count = 0;
|
||||
list->maximum = INT_MAX;
|
||||
}
|
||||
|
||||
static void object_list_allocate(object_list* list, size_t allocate_count)
|
||||
{
|
||||
if (!list->strings && (list->allocated == 0) && (allocate_count > 0))
|
||||
{
|
||||
list->strings = (char**)calloc(allocate_count, sizeof(list->strings[0]));
|
||||
list->allocated = list->strings ? allocate_count : 0;
|
||||
list->count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char* object_string(ASN1_TYPE* object)
|
||||
{
|
||||
char* result = nullptr;
|
||||
unsigned char* utf8String = nullptr;
|
||||
|
||||
/* TODO: check that object.type is a string type. */
|
||||
const int length = ASN1_STRING_to_UTF8(&utf8String, object->value.asn1_string);
|
||||
|
||||
if (length < 0)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result = strndup((char*)utf8String, WINPR_ASSERTING_INT_CAST(size_t, length));
|
||||
OPENSSL_free(utf8String);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void object_list_free(object_list* list)
|
||||
{
|
||||
WINPR_ASSERT(list);
|
||||
free((void*)list->strings);
|
||||
}
|
||||
|
||||
static int extract_othername_object_as_string(GENERAL_NAME* name, void* data, int index, int count)
|
||||
{
|
||||
object_list* list = data;
|
||||
WINPR_UNUSED(index);
|
||||
|
||||
if (count < 0)
|
||||
return -1;
|
||||
|
||||
if (name->type != GEN_OTHERNAME)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (0 != OBJ_cmp(name->d.otherName->type_id, list->type_id))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
object_list_allocate(list, WINPR_ASSERTING_INT_CAST(size_t, count));
|
||||
|
||||
if (list->allocated <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
list->strings[list->count] = object_string(name->d.otherName->value);
|
||||
|
||||
if (list->strings[list->count])
|
||||
{
|
||||
list->count++;
|
||||
}
|
||||
|
||||
if (list->count >= list->maximum)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char* x509_utils_get_email(const X509* x509)
|
||||
{
|
||||
char* result = nullptr;
|
||||
string_list list;
|
||||
string_list_initialize(&list);
|
||||
list.maximum = 1;
|
||||
map_subject_alt_name(x509, GEN_EMAIL, extract_string, &list);
|
||||
|
||||
if (list.count == 0)
|
||||
{
|
||||
string_list_free(&list);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result = _strdup(list.strings[0]);
|
||||
OPENSSL_free(list.strings[0]);
|
||||
string_list_free(&list);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* x509_utils_get_upn(const X509* x509)
|
||||
{
|
||||
char* result = nullptr;
|
||||
object_list list = WINPR_C_ARRAY_INIT;
|
||||
object_list_initialize(&list);
|
||||
list.type_id = OBJ_nid2obj(NID_ms_upn);
|
||||
list.maximum = 1;
|
||||
map_subject_alt_name(x509, GEN_OTHERNAME, extract_othername_object_as_string, &list);
|
||||
|
||||
if (list.count == 0)
|
||||
{
|
||||
object_list_free(&list);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result = list.strings[0];
|
||||
object_list_free(&list);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* x509_utils_get_date(const X509* x509, BOOL startDate)
|
||||
{
|
||||
WINPR_ASSERT(x509);
|
||||
|
||||
const ASN1_TIME* date = startDate ? X509_get0_notBefore(x509) : X509_get0_notAfter(x509);
|
||||
if (!date)
|
||||
return nullptr;
|
||||
|
||||
BIO* bmem = BIO_new(BIO_s_mem());
|
||||
if (!bmem)
|
||||
return nullptr;
|
||||
|
||||
char* str = nullptr;
|
||||
if (ASN1_TIME_print(bmem, date))
|
||||
{
|
||||
BUF_MEM* bptr = nullptr;
|
||||
|
||||
BIO_get_mem_ptr(bmem, &bptr);
|
||||
str = strndup(bptr->data, bptr->length);
|
||||
}
|
||||
else
|
||||
{ // Log error
|
||||
}
|
||||
BIO_free_all(bmem);
|
||||
return str;
|
||||
}
|
||||
|
||||
void x509_utils_dns_names_free(size_t count, size_t* lengths, char** dns_names)
|
||||
{
|
||||
free(lengths);
|
||||
|
||||
if (dns_names)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
if (dns_names[i])
|
||||
{
|
||||
OPENSSL_free(dns_names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
free((void*)dns_names);
|
||||
}
|
||||
}
|
||||
|
||||
char** x509_utils_get_dns_names(const X509* xcert, size_t* count, size_t** lengths)
|
||||
{
|
||||
char** result = nullptr;
|
||||
string_list list = WINPR_C_ARRAY_INIT;
|
||||
string_list_initialize(&list);
|
||||
map_subject_alt_name(xcert, GEN_DNS, extract_string, &list);
|
||||
(*count) = list.count;
|
||||
|
||||
if (list.count <= 0)
|
||||
{
|
||||
string_list_free(&list);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* lengths are not useful, since we converted the
|
||||
strings to utf-8, there cannot be nul-bytes in them. */
|
||||
result = (char**)calloc(list.count, sizeof(*result));
|
||||
(*lengths) = calloc(list.count, sizeof(**lengths));
|
||||
|
||||
if (!result || !(*lengths))
|
||||
{
|
||||
string_list_free(&list);
|
||||
free((void*)result);
|
||||
free(*lengths);
|
||||
(*lengths) = nullptr;
|
||||
(*count) = 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < list.count; i++)
|
||||
{
|
||||
result[i] = list.strings[i];
|
||||
(*lengths)[i] = strlen(result[i]);
|
||||
}
|
||||
|
||||
string_list_free(&list);
|
||||
return result;
|
||||
}
|
||||
|
||||
char* x509_utils_get_issuer(const X509* xcert)
|
||||
{
|
||||
char* issuer = nullptr;
|
||||
if (!xcert)
|
||||
{
|
||||
WLog_ERR(TAG, "Invalid certificate nullptr");
|
||||
return nullptr;
|
||||
}
|
||||
issuer = crypto_print_name(X509_get_issuer_name(xcert));
|
||||
if (!issuer)
|
||||
WLog_WARN(TAG, "certificate does not have an issuer!");
|
||||
return issuer;
|
||||
}
|
||||
|
||||
static int asn1_object_cmp(const ASN1_OBJECT* const* a, const ASN1_OBJECT* const* b)
|
||||
{
|
||||
if (!a || !b)
|
||||
return (a == b) ? 0 : (a ? 1 : -1);
|
||||
|
||||
if (!*a || !*b)
|
||||
return (*a == *b) ? 0 : (*a ? 1 : -1);
|
||||
|
||||
return OBJ_cmp(*a, *b);
|
||||
}
|
||||
|
||||
BOOL x509_utils_check_eku(const X509* xcert, int nid)
|
||||
{
|
||||
BOOL ret = FALSE;
|
||||
STACK_OF(ASN1_OBJECT)* oid_stack = nullptr;
|
||||
ASN1_OBJECT* oid = nullptr;
|
||||
|
||||
if (!xcert)
|
||||
return FALSE;
|
||||
|
||||
oid = OBJ_nid2obj(nid);
|
||||
if (!oid)
|
||||
return FALSE;
|
||||
|
||||
oid_stack = X509_get_ext_d2i(xcert, NID_ext_key_usage, nullptr, nullptr);
|
||||
if (!oid_stack)
|
||||
return FALSE;
|
||||
|
||||
sk_ASN1_OBJECT_set_cmp_func(oid_stack, asn1_object_cmp);
|
||||
if (sk_ASN1_OBJECT_find(oid_stack, oid) >= 0)
|
||||
ret = TRUE;
|
||||
|
||||
sk_ASN1_OBJECT_pop_free(oid_stack, ASN1_OBJECT_free);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void x509_utils_print_info(const X509* xcert)
|
||||
{
|
||||
char* fp = nullptr;
|
||||
char* issuer = nullptr;
|
||||
char* subject = nullptr;
|
||||
subject = x509_utils_get_subject(xcert);
|
||||
issuer = x509_utils_get_issuer(xcert);
|
||||
fp = (char*)x509_utils_get_hash(xcert, "sha256", nullptr);
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
WLog_ERR(TAG, "error computing fingerprint");
|
||||
goto out_free_issuer;
|
||||
}
|
||||
|
||||
WLog_INFO(TAG, "Certificate details:");
|
||||
WLog_INFO(TAG, "\tSubject: %s", subject);
|
||||
WLog_INFO(TAG, "\tIssuer: %s", issuer);
|
||||
WLog_INFO(TAG, "\tThumbprint: %s", fp);
|
||||
WLog_INFO(TAG,
|
||||
"The above X.509 certificate could not be verified, possibly because you do not have "
|
||||
"the CA certificate in your certificate store, or the certificate has expired. "
|
||||
"Please look at the OpenSSL documentation on how to add a private CA to the store.");
|
||||
free(fp);
|
||||
out_free_issuer:
|
||||
free(issuer);
|
||||
free(subject);
|
||||
}
|
||||
|
||||
X509* x509_utils_from_pem(const char* data, size_t len, BOOL fromFile)
|
||||
{
|
||||
X509* x509 = nullptr;
|
||||
BIO* bio = nullptr;
|
||||
if (fromFile)
|
||||
bio = BIO_new_file(data, "rb");
|
||||
else
|
||||
{
|
||||
if (len > INT_MAX)
|
||||
return nullptr;
|
||||
|
||||
bio = BIO_new_mem_buf(data, (int)len);
|
||||
}
|
||||
|
||||
if (!bio)
|
||||
{
|
||||
WLog_ERR(TAG, "BIO_new failed for certificate");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||||
BIO_free_all(bio);
|
||||
if (!x509)
|
||||
WLog_ERR(TAG, "PEM_read_bio_X509 returned nullptr [input length %" PRIuz "]", len);
|
||||
|
||||
return x509;
|
||||
}
|
||||
|
||||
static WINPR_MD_TYPE hash_nid_to_winpr(int hash_nid)
|
||||
{
|
||||
switch (hash_nid)
|
||||
{
|
||||
case NID_md2:
|
||||
return WINPR_MD_MD2;
|
||||
case NID_md4:
|
||||
return WINPR_MD_MD4;
|
||||
case NID_md5:
|
||||
return WINPR_MD_MD5;
|
||||
case NID_sha1:
|
||||
return WINPR_MD_SHA1;
|
||||
case NID_sha224:
|
||||
return WINPR_MD_SHA224;
|
||||
case NID_sha256:
|
||||
return WINPR_MD_SHA256;
|
||||
case NID_sha384:
|
||||
return WINPR_MD_SHA384;
|
||||
case NID_sha512:
|
||||
return WINPR_MD_SHA512;
|
||||
case NID_ripemd160:
|
||||
return WINPR_MD_RIPEMD160;
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x1010101fL) && !defined(LIBRESSL_VERSION_NUMBER)
|
||||
case NID_sha3_224:
|
||||
return WINPR_MD_SHA3_224;
|
||||
case NID_sha3_256:
|
||||
return WINPR_MD_SHA3_256;
|
||||
case NID_sha3_384:
|
||||
return WINPR_MD_SHA3_384;
|
||||
case NID_sha3_512:
|
||||
return WINPR_MD_SHA3_512;
|
||||
case NID_shake128:
|
||||
return WINPR_MD_SHAKE128;
|
||||
case NID_shake256:
|
||||
return WINPR_MD_SHAKE256;
|
||||
#endif
|
||||
case NID_undef:
|
||||
default:
|
||||
return WINPR_MD_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static WINPR_MD_TYPE get_rsa_pss_digest(const X509_ALGOR* alg)
|
||||
{
|
||||
WINPR_MD_TYPE ret = WINPR_MD_NONE;
|
||||
WINPR_MD_TYPE message_digest = WINPR_MD_NONE;
|
||||
WINPR_MD_TYPE mgf1_digest = WINPR_MD_NONE;
|
||||
int param_type = 0;
|
||||
const void* param_value = nullptr;
|
||||
const ASN1_STRING* sequence = nullptr;
|
||||
const unsigned char* inp = nullptr;
|
||||
RSA_PSS_PARAMS* params = nullptr;
|
||||
X509_ALGOR* mgf1_digest_alg = nullptr;
|
||||
|
||||
/* The RSA-PSS digest is encoded in a complex structure, defined in
|
||||
https://www.rfc-editor.org/rfc/rfc4055.html. */
|
||||
X509_ALGOR_get0(nullptr, ¶m_type, ¶m_value, alg);
|
||||
|
||||
/* param_type and param_value the parameter in ASN1_TYPE form, but split into two parameters. A
|
||||
SEQUENCE is has type V_ASN1_SEQUENCE, and the value is an ASN1_STRING with the encoded
|
||||
structure. */
|
||||
if (param_type != V_ASN1_SEQUENCE)
|
||||
goto end;
|
||||
sequence = param_value;
|
||||
|
||||
/* Decode the structure. */
|
||||
inp = ASN1_STRING_get0_data(sequence);
|
||||
params = d2i_RSA_PSS_PARAMS(nullptr, &inp, ASN1_STRING_length(sequence));
|
||||
if (params == nullptr)
|
||||
goto end;
|
||||
|
||||
/* RSA-PSS uses two hash algorithms, a message digest and also an MGF function which is, itself,
|
||||
parameterized by a hash function. Both fields default to SHA-1, so we must also check for the
|
||||
value being nullptr. */
|
||||
message_digest = WINPR_MD_SHA1;
|
||||
if (params->hashAlgorithm != nullptr)
|
||||
{
|
||||
const ASN1_OBJECT* obj = nullptr;
|
||||
X509_ALGOR_get0(&obj, nullptr, nullptr, params->hashAlgorithm);
|
||||
message_digest = hash_nid_to_winpr(OBJ_obj2nid(obj));
|
||||
if (message_digest == WINPR_MD_NONE)
|
||||
goto end;
|
||||
}
|
||||
|
||||
mgf1_digest = WINPR_MD_SHA1;
|
||||
if (params->maskGenAlgorithm != nullptr)
|
||||
{
|
||||
const ASN1_OBJECT* obj = nullptr;
|
||||
int mgf_param_type = 0;
|
||||
const void* mgf_param_value = nullptr;
|
||||
const ASN1_STRING* mgf_param_sequence = nullptr;
|
||||
/* First, check this is MGF-1, the only one ever defined. */
|
||||
X509_ALGOR_get0(&obj, &mgf_param_type, &mgf_param_value, params->maskGenAlgorithm);
|
||||
if (OBJ_obj2nid(obj) != NID_mgf1)
|
||||
goto end;
|
||||
|
||||
/* MGF-1 is, itself, parameterized by a hash function, encoded as an AlgorithmIdentifier. */
|
||||
if (mgf_param_type != V_ASN1_SEQUENCE)
|
||||
goto end;
|
||||
mgf_param_sequence = mgf_param_value;
|
||||
inp = ASN1_STRING_get0_data(mgf_param_sequence);
|
||||
mgf1_digest_alg = d2i_X509_ALGOR(nullptr, &inp, ASN1_STRING_length(mgf_param_sequence));
|
||||
if (mgf1_digest_alg == nullptr)
|
||||
goto end;
|
||||
|
||||
/* Finally, extract the digest. */
|
||||
X509_ALGOR_get0(&obj, nullptr, nullptr, mgf1_digest_alg);
|
||||
mgf1_digest = hash_nid_to_winpr(OBJ_obj2nid(obj));
|
||||
if (mgf1_digest == WINPR_MD_NONE)
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* If the two digests do not match, it is ambiguous which to return. tls-server-end-point leaves
|
||||
it undefined, so return none.
|
||||
https://www.rfc-editor.org/rfc/rfc5929.html#section-4.1 */
|
||||
if (message_digest != mgf1_digest)
|
||||
goto end;
|
||||
ret = message_digest;
|
||||
|
||||
end:
|
||||
RSA_PSS_PARAMS_free(params);
|
||||
X509_ALGOR_free(mgf1_digest_alg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
WINPR_MD_TYPE x509_utils_get_signature_alg(const X509* xcert)
|
||||
{
|
||||
WINPR_ASSERT(xcert);
|
||||
|
||||
const int nid = X509_get_signature_nid(xcert);
|
||||
|
||||
if (nid == NID_rsassaPss)
|
||||
{
|
||||
const X509_ALGOR* alg = nullptr;
|
||||
X509_get0_signature(nullptr, &alg, xcert);
|
||||
return get_rsa_pss_digest(alg);
|
||||
}
|
||||
|
||||
int hash_nid = 0;
|
||||
if (OBJ_find_sigid_algs(nid, &hash_nid, nullptr) != 1)
|
||||
return WINPR_MD_NONE;
|
||||
|
||||
return hash_nid_to_winpr(hash_nid);
|
||||
}
|
||||
|
||||
char* x509_utils_get_common_name(const X509* xcert, size_t* plength)
|
||||
{
|
||||
X509_NAME* subject_name = X509_get_subject_name(xcert);
|
||||
if (subject_name == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const int index = X509_NAME_get_index_by_NID(subject_name, NID_commonName, -1);
|
||||
if (index < 0)
|
||||
return nullptr;
|
||||
|
||||
const X509_NAME_ENTRY* entry = X509_NAME_get_entry(subject_name, index);
|
||||
if (entry == nullptr)
|
||||
return nullptr;
|
||||
|
||||
const ASN1_STRING* entry_data = X509_NAME_ENTRY_get_data(entry);
|
||||
if (entry_data == nullptr)
|
||||
return nullptr;
|
||||
|
||||
BYTE* common_name_raw = nullptr;
|
||||
const int length = ASN1_STRING_to_UTF8(&common_name_raw, entry_data);
|
||||
if (length < 0)
|
||||
return nullptr;
|
||||
|
||||
if (plength)
|
||||
*plength = (size_t)length;
|
||||
|
||||
char* common_name = _strdup((char*)common_name_raw);
|
||||
OPENSSL_free(common_name_raw);
|
||||
return common_name;
|
||||
}
|
||||
|
||||
static int verify_cb(int ok, X509_STORE_CTX* csc)
|
||||
{
|
||||
if (ok != 1)
|
||||
{
|
||||
WINPR_ASSERT(csc);
|
||||
int err = X509_STORE_CTX_get_error(csc);
|
||||
int derr = X509_STORE_CTX_get_error_depth(csc);
|
||||
X509* where = X509_STORE_CTX_get_current_cert(csc);
|
||||
const char* what = X509_verify_cert_error_string(err);
|
||||
char* name = x509_utils_get_subject(where);
|
||||
|
||||
WLog_WARN(TAG, "Certificate verification failure '%s (%d)' at stack position %d", what, err,
|
||||
derr);
|
||||
WLog_WARN(TAG, "%s", name);
|
||||
|
||||
free(name);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
BOOL x509_utils_verify(X509* xcert, STACK_OF(X509) * chain, const char* certificate_store_path)
|
||||
{
|
||||
const int purposes[3] = { X509_PURPOSE_SSL_SERVER, X509_PURPOSE_SSL_CLIENT, X509_PURPOSE_ANY };
|
||||
X509_STORE_CTX* csc = nullptr;
|
||||
BOOL status = FALSE;
|
||||
X509_LOOKUP* lookup = nullptr;
|
||||
|
||||
if (!xcert)
|
||||
return FALSE;
|
||||
|
||||
X509_STORE* cert_ctx = X509_STORE_new();
|
||||
|
||||
if (cert_ctx == nullptr)
|
||||
goto end;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
||||
OpenSSL_add_all_algorithms();
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS | OPENSSL_INIT_ADD_ALL_DIGESTS |
|
||||
OPENSSL_INIT_LOAD_CONFIG,
|
||||
nullptr);
|
||||
#endif
|
||||
|
||||
if (X509_STORE_set_default_paths(cert_ctx) != 1)
|
||||
goto end;
|
||||
|
||||
lookup = X509_STORE_add_lookup(cert_ctx, X509_LOOKUP_hash_dir());
|
||||
|
||||
if (lookup == nullptr)
|
||||
goto end;
|
||||
|
||||
X509_LOOKUP_add_dir(lookup, nullptr, X509_FILETYPE_DEFAULT);
|
||||
|
||||
if (certificate_store_path != nullptr)
|
||||
{
|
||||
X509_LOOKUP_add_dir(lookup, certificate_store_path, X509_FILETYPE_PEM);
|
||||
}
|
||||
|
||||
X509_STORE_set_flags(cert_ctx, 0);
|
||||
|
||||
for (size_t i = 0; i < ARRAYSIZE(purposes); i++)
|
||||
{
|
||||
int err = -1;
|
||||
int rc = -1;
|
||||
int purpose = purposes[i];
|
||||
csc = X509_STORE_CTX_new();
|
||||
|
||||
if (csc == nullptr)
|
||||
goto skip;
|
||||
if (!X509_STORE_CTX_init(csc, cert_ctx, xcert, chain))
|
||||
goto skip;
|
||||
|
||||
X509_STORE_CTX_set_purpose(csc, purpose);
|
||||
X509_STORE_CTX_set_verify_cb(csc, verify_cb);
|
||||
|
||||
rc = X509_verify_cert(csc);
|
||||
err = X509_STORE_CTX_get_error(csc);
|
||||
skip:
|
||||
X509_STORE_CTX_free(csc);
|
||||
if (rc == 1)
|
||||
{
|
||||
status = TRUE;
|
||||
break;
|
||||
}
|
||||
else if (err != X509_V_ERR_INVALID_PURPOSE)
|
||||
break;
|
||||
}
|
||||
|
||||
X509_STORE_free(cert_ctx);
|
||||
end:
|
||||
return status;
|
||||
}
|
||||
96
third_party/FreeRDP/libfreerdp/crypto/x509_utils.h
vendored
Normal file
96
third_party/FreeRDP/libfreerdp/crypto/x509_utils.h
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Cryptographic Abstraction Layer
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2023 Armin Novak <anovak@thincast.com>
|
||||
* Copyright 2023 Thincast Technologies GmbH
|
||||
*
|
||||
* 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 FREERDP_LIB_X509_UTILS_H
|
||||
#define FREERDP_LIB_X509_UTILS_H
|
||||
|
||||
#include <winpr/custom-crypto.h>
|
||||
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#include <freerdp/api.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL WINPR_MD_TYPE x509_utils_get_signature_alg(const X509* xcert);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BYTE* x509_utils_get_hash(const X509* xcert, const char* hash, size_t* length);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BYTE* x509_utils_to_pem(const X509* xcert, const STACK_OF(X509) * chain,
|
||||
size_t* length);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL X509* x509_utils_from_pem(const char* data, size_t length, BOOL fromFile);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char* x509_utils_get_subject(const X509* xcert);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char* x509_utils_get_issuer(const X509* xcert);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char* x509_utils_get_email(const X509* x509);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char* x509_utils_get_upn(const X509* x509);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char* x509_utils_get_date(const X509* x509, BOOL startDate);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char* x509_utils_get_common_name(const X509* xcert, size_t* plength);
|
||||
|
||||
WINPR_ATTR_MALLOC(free, 1)
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL char** x509_utils_get_dns_names(const X509* xcert, size_t* count,
|
||||
size_t** pplengths);
|
||||
|
||||
FREERDP_LOCAL void x509_utils_dns_names_free(size_t count, size_t* lengths, char** dns_names);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL x509_utils_check_eku(const X509* xcert, int nid);
|
||||
|
||||
FREERDP_LOCAL void x509_utils_print_info(const X509* xcert);
|
||||
|
||||
WINPR_ATTR_NODISCARD
|
||||
FREERDP_LOCAL BOOL x509_utils_verify(X509* xcert, STACK_OF(X509) * chain,
|
||||
const char* certificate_store_path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* FREERDP_LIB_X509_UTILS_H */
|
||||
Reference in New Issue
Block a user