mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[pki] improve ASN.1 parser
* Enable search from OIDs expressed as strings and ignore non UNIVERSAL classes
This commit is contained in:
		
							parent
							
								
									a73e695ba4
								
							
						
					
					
						commit
						94e4c0905b
					
				
					 4 changed files with 119 additions and 28 deletions
				
			
		
							
								
								
									
										126
									
								
								src/parser.c
									
										
									
									
									
								
							
							
						
						
									
										126
									
								
								src/parser.c
									
										
									
									
									
								
							|  | @ -1266,29 +1266,34 @@ char* replace_char(const char* src, const char c, const char* rep) | ||||||
| 	return res; | 	return res; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void* get_oid_data_from_asn1_internal(const uint8_t* buf, size_t buf_len, const void* oid, | static void* get_data_from_asn1_internal(const uint8_t* buf, size_t buf_len, const void* oid, | ||||||
| 			size_t oid_len, uint8_t asn1_type, size_t* data_len, BOOL* matched) | 			size_t oid_len, uint8_t asn1_type, size_t* data_len, BOOL* matched) | ||||||
| { | { | ||||||
| 	void* ret; | 	void* ret; | ||||||
| 	size_t pos = 0, len, len_len, i; | 	size_t pos = 0, len, len_len, i; | ||||||
| 	uint8_t tag; | 	uint8_t tag; | ||||||
| 	BOOL is_sequence; | 	BOOL is_sequence, is_universal_tag; | ||||||
| 
 | 
 | ||||||
| 	while (pos < buf_len) { | 	while (pos < buf_len) { | ||||||
| 		is_sequence = buf[pos] & 0x20;	// Only need to handle the sequence attribute
 | 		is_sequence = buf[pos] & 0x20; | ||||||
|  | 		is_universal_tag = ((buf[pos] & 0xC0) == 0x00); | ||||||
| 		tag = buf[pos++] & 0x1F; | 		tag = buf[pos++] & 0x1F; | ||||||
|  | 		if (tag == 0x1F) { | ||||||
|  | 			uprintf("get_data_from_asn1: Long form tags are unsupported"); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// Compute the length
 | 		// Compute the length
 | ||||||
| 		len = 0; | 		len = 0; | ||||||
| 		len_len = 1; | 		len_len = 1; | ||||||
| 		if (tag == 0x05) {	// ignore "NULL" tag
 | 		if ((is_universal_tag) && (tag == 0x05)) {	// ignore "NULL" tag
 | ||||||
| 			pos++; | 			pos++; | ||||||
| 		} else { | 		} else { | ||||||
| 			if (buf[pos] & 0x80) { | 			if (buf[pos] & 0x80) { | ||||||
| 				len_len = buf[pos++] & 0x7F; | 				len_len = buf[pos++] & 0x7F; | ||||||
| 				// The data we're dealing with is not expected to ever be larger than 64K
 | 				// The data we're dealing with is not expected to ever be larger than 64K
 | ||||||
| 				if (len_len > 2) { | 				if (len_len > 2) { | ||||||
| 					uprintf("get_oid_data_from_asn1: Length fields larger than 2 bytes are unsupported"); | 					uprintf("get_data_from_asn1: Length fields larger than 2 bytes are unsupported"); | ||||||
| 					return NULL; | 					return NULL; | ||||||
| 				} | 				} | ||||||
| 				for (i = 0; i < len_len; i++) { | 				for (i = 0; i < len_len; i++) { | ||||||
|  | @ -1300,23 +1305,23 @@ static void* get_oid_data_from_asn1_internal(const uint8_t* buf, size_t buf_len, | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			if (len > buf_len - pos) { | 			if (len > buf_len - pos) { | ||||||
| 				uprintf("get_oid_data_from_asn1: Overflow error (computed length %d is larger than remaining data)", len); | 				uprintf("get_data_from_asn1: Overflow error (computed length %d is larger than remaining data)", len); | ||||||
| 				return NULL; | 				return NULL; | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (len != 0) { | 		if (len != 0) { | ||||||
| 			if (is_sequence) { | 			if (is_sequence) { | ||||||
| 				ret = get_oid_data_from_asn1_internal(&buf[pos], len, oid, oid_len, asn1_type, data_len, matched); | 				ret = get_data_from_asn1_internal(&buf[pos], len, oid, oid_len, asn1_type, data_len, matched); | ||||||
| 				if (ret != NULL) | 				if (ret != NULL) | ||||||
| 					return ret; | 					return ret; | ||||||
| 			} else { | 			} else if (is_universal_tag) {	// Only process tags that belong to the UNIVERSAL class
 | ||||||
| 				// NB: 0x06 = "OID" tag
 | 				// NB: 0x06 = "OID" tag
 | ||||||
| 				if ((!*matched) && (tag == 0x06) && (len == oid_len) && (memcmp(&buf[pos], oid, oid_len) == 0)) { | 				if ((!*matched) && (tag == 0x06) && (len == oid_len) && (memcmp(&buf[pos], oid, oid_len) == 0)) { | ||||||
| 					*matched = TRUE; | 					*matched = TRUE; | ||||||
| 				} else if ((*matched) && (tag == asn1_type)) { | 				} else if ((*matched) && (tag == asn1_type)) { | ||||||
| 					*data_len = len; | 					*data_len = len; | ||||||
| 					return (void*) &buf[pos]; | 					return (void*)&buf[pos]; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			pos += len; | 			pos += len; | ||||||
|  | @ -1326,15 +1331,104 @@ static void* get_oid_data_from_asn1_internal(const uint8_t* buf, size_t buf_len, | ||||||
| 	return NULL; | 	return NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Helper functions to convert an OID string to an OID byte array
 | ||||||
|  | // Taken from from openpgp-oid.c
 | ||||||
|  | static size_t make_flagged_int(unsigned long value, uint8_t *buf, size_t buflen) | ||||||
|  | { | ||||||
|  | 	BOOL more = FALSE; | ||||||
|  | 	int shift; | ||||||
|  | 
 | ||||||
|  | 	for (shift = 28; shift > 0; shift -= 7) { | ||||||
|  | 		if (more || value >= ((unsigned long)1 << shift)) { | ||||||
|  | 			buf[buflen++] = (uint8_t) (0x80 | (value >> shift)); | ||||||
|  | 			value -= (value >> shift) << shift; | ||||||
|  | 			more = TRUE; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	buf[buflen++] = (uint8_t) value; | ||||||
|  | 	return buflen; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Convert OID string 'oid_str' to an OID byte array of size 'ret_len'
 | ||||||
|  | // The returned array must be freed by the caller.
 | ||||||
|  | static uint8_t* oid_from_str(const char* oid_str, size_t* ret_len) | ||||||
|  | { | ||||||
|  | 	uint8_t* oid = NULL; | ||||||
|  | 	unsigned long val1 = 0, val; | ||||||
|  | 	const char *endp; | ||||||
|  | 	int arcno = 0; | ||||||
|  | 	size_t oid_len = 0; | ||||||
|  | 
 | ||||||
|  | 	if ((oid_str == NULL) || (oid_str[0] == 0)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	// We can safely assume that the encoded OID is shorter than the string.
 | ||||||
|  | 	oid = malloc(1 + strlen(oid_str) + 2); | ||||||
|  | 	if (oid == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	do { | ||||||
|  | 		arcno++; | ||||||
|  | 		val = strtoul(oid_str, (char**)&endp, 10); | ||||||
|  | 		if (!isdigit(*oid_str) || !(*endp == '.' || !*endp)) | ||||||
|  | 			goto err; | ||||||
|  | 		if (*endp == '.') | ||||||
|  | 			oid_str = endp + 1; | ||||||
|  | 
 | ||||||
|  | 		if (arcno == 1) { | ||||||
|  | 			if (val > 2) | ||||||
|  | 				break; // Not allowed, error caught below.
 | ||||||
|  | 			val1 = val; | ||||||
|  | 		} else if (arcno == 2) { | ||||||
|  | 			// Need to combine the first two arcs in one byte.
 | ||||||
|  | 			if (val1 < 2) { | ||||||
|  | 				if (val > 39) | ||||||
|  | 					goto err; | ||||||
|  | 				oid[oid_len++] = (uint8_t)(val1 * 40 + val); | ||||||
|  | 			} else { | ||||||
|  | 				val += 80; | ||||||
|  | 				oid_len = make_flagged_int(val, oid, oid_len); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
|  | 			oid_len = make_flagged_int(val, oid, oid_len); | ||||||
|  | 		} | ||||||
|  | 	} while (*endp == '.'); | ||||||
|  | 
 | ||||||
|  | 	// It is not possible to encode only the first arc.
 | ||||||
|  | 	if (arcno == 1 || oid_len < 2 || oid_len > 254) | ||||||
|  | 		goto err; | ||||||
|  | 
 | ||||||
|  | 	*ret_len = oid_len; | ||||||
|  | 	return oid; | ||||||
|  | 
 | ||||||
|  | err: | ||||||
|  | 	free(oid); | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * Parse an ASN.1 binary buffer and return a pointer to the first instance of OID data of type 'asn1_type', |  * Parse an ASN.1 binary buffer and return a pointer to the first instance of OID data of type 'asn1_type', | ||||||
|  * matching the binary OID 'oid' (of size 'oid_len'). If successful, the length or the returned data is |  * matching the OID 'oid_str' (expressed as an OID string). If successful, the length or the returned data | ||||||
|  * placed in 'data_len'. |  * is placed in 'data_len'. Note: Only the UNIVERSAL class is supported for 'asn1_type' (other classes are | ||||||
|  * If 'oid' is NULL, the first data element of type 'asn1_type' is returned. |  * ignored). If 'oid_str' is NULL or empty, the first data element of type 'asn1_type' is returned. | ||||||
|  */ |  */ | ||||||
| void* get_oid_data_from_asn1(const uint8_t* buf, size_t buf_len, const uint8_t* oid, size_t oid_len, | void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char* oid_str, uint8_t asn1_type, size_t* data_len) | ||||||
| 	uint8_t asn1_type, size_t* data_len) |  | ||||||
| { | { | ||||||
| 	BOOL matched = (oid == NULL); | 	void* ret; | ||||||
| 	return get_oid_data_from_asn1_internal(buf, buf_len, oid, oid_len, asn1_type, data_len, &matched); | 	uint8_t* oid = NULL; | ||||||
|  | 	size_t oid_len = 0; | ||||||
|  | 	BOOL matched = ((oid_str == NULL) || (oid_str[0] == 0)); | ||||||
|  | 
 | ||||||
|  | 	if (!matched) { | ||||||
|  | 		// We have an OID string to convert
 | ||||||
|  | 		oid = oid_from_str(oid_str, &oid_len); | ||||||
|  | 		if (oid == NULL) { | ||||||
|  | 			uprintf("get_oid_data_from_asn1: Could not convert OID string '%s'", oid_str); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ret = get_data_from_asn1_internal(buf, buf_len, oid, oid_len, asn1_type, data_len, &matched); | ||||||
|  | 	free(oid); | ||||||
|  | 	return ret; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -239,8 +239,6 @@ out: | ||||||
| // The timestamping authorities we use are RFC 3161 compliant
 | // The timestamping authorities we use are RFC 3161 compliant
 | ||||||
| static uint64_t GetRFC3161TimeStamp(PCMSG_SIGNER_INFO pSignerInfo) | static uint64_t GetRFC3161TimeStamp(PCMSG_SIGNER_INFO pSignerInfo) | ||||||
| { | { | ||||||
| 	// Binary representation of szOID_TIMESTAMP_TOKEN or "1.2.840.113549.1.9.16.1.4"
 |  | ||||||
| 	const uint8_t OID_RFC3161_timeStamp[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x04 }; |  | ||||||
| 	BOOL r, found = FALSE; | 	BOOL r, found = FALSE; | ||||||
| 	DWORD n, dwSize; | 	DWORD n, dwSize; | ||||||
| 	PCRYPT_CONTENT_INFO pCounterSignerInfo = NULL; | 	PCRYPT_CONTENT_INFO pCounterSignerInfo = NULL; | ||||||
|  | @ -273,12 +271,12 @@ static uint64_t GetRFC3161TimeStamp(PCMSG_SIGNER_INFO pSignerInfo) | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// Get the RFC 3161 timestamp message
 | 			// Get the RFC 3161 timestamp message
 | ||||||
| 			timestamp_token = get_oid_data_from_asn1(pCounterSignerInfo->Content.pbData, | 			timestamp_token = get_data_from_asn1(pCounterSignerInfo->Content.pbData, | ||||||
| 				pCounterSignerInfo->Content.cbData, OID_RFC3161_timeStamp, sizeof(OID_RFC3161_timeStamp), | 				pCounterSignerInfo->Content.cbData, szOID_TIMESTAMP_TOKEN, | ||||||
| 				// 0x04 = "Octet String" ASN.1 tag
 | 				// 0x04 = "Octet String" ASN.1 tag
 | ||||||
| 				0x04, ×tamp_token_size); | 				0x04, ×tamp_token_size); | ||||||
| 			if (timestamp_token) { | 			if (timestamp_token) { | ||||||
| 				timestamp_str = get_oid_data_from_asn1(timestamp_token, timestamp_token_size, NULL, 0, | 				timestamp_str = get_data_from_asn1(timestamp_token, timestamp_token_size, NULL, | ||||||
| 					// 0x18 = "Generalized Time" ASN.1 tag
 | 					// 0x18 = "Generalized Time" ASN.1 tag
 | ||||||
| 					0x18, ×tamp_str_size); | 					0x18, ×tamp_str_size); | ||||||
| 				if (timestamp_str) { | 				if (timestamp_str) { | ||||||
|  |  | ||||||
|  | @ -478,8 +478,7 @@ extern char* insert_section_data(const char* filename, const char* section, cons | ||||||
| extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix); | extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix); | ||||||
| extern char* replace_char(const char* src, const char c, const char* rep); | extern char* replace_char(const char* src, const char c, const char* rep); | ||||||
| extern void parse_update(char* buf, size_t len); | extern void parse_update(char* buf, size_t len); | ||||||
| extern void* get_oid_data_from_asn1(const uint8_t* buf, size_t buf_len, const uint8_t* oid, size_t oid_len, | extern void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char* oid_str, uint8_t asn1_type, size_t* data_len); | ||||||
| 	uint8_t asn1_type, size_t* data_len); |  | ||||||
| extern uint8_t WimExtractCheck(void); | extern uint8_t WimExtractCheck(void); | ||||||
| extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); | extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); | ||||||
| extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst); | extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst); | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | ||||||
| IDD_DIALOG DIALOGEX 12, 12, 242, 376 | IDD_DIALOG DIALOGEX 12, 12, 242, 376 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_ACCEPTFILES | EXSTYLE WS_EX_ACCEPTFILES | ||||||
| CAPTION "Rufus 2.17.1190" | CAPTION "Rufus 2.17.1191" | ||||||
| FONT 8, "Segoe UI Symbol", 400, 0, 0x0 | FONT 8, "Segoe UI Symbol", 400, 0, 0x0 | ||||||
| BEGIN | BEGIN | ||||||
|     LTEXT           "Device",IDS_DEVICE_TXT,9,6,200,8 |     LTEXT           "Device",IDS_DEVICE_TXT,9,6,200,8 | ||||||
|  | @ -366,8 +366,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 2,17,1190,0 |  FILEVERSION 2,17,1191,0 | ||||||
|  PRODUCTVERSION 2,17,1190,0 |  PRODUCTVERSION 2,17,1191,0 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -384,13 +384,13 @@ BEGIN | ||||||
|         BEGIN |         BEGIN | ||||||
|             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" |             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" | ||||||
|             VALUE "FileDescription", "Rufus" |             VALUE "FileDescription", "Rufus" | ||||||
|             VALUE "FileVersion", "2.17.1190" |             VALUE "FileVersion", "2.17.1191" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)" | ||||||
|             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" |             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" | ||||||
|             VALUE "OriginalFilename", "rufus.exe" |             VALUE "OriginalFilename", "rufus.exe" | ||||||
|             VALUE "ProductName", "Rufus" |             VALUE "ProductName", "Rufus" | ||||||
|             VALUE "ProductVersion", "2.17.1190" |             VALUE "ProductVersion", "2.17.1191" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue