Hi Daniel, Sorry for the delay. On 26.07.2020 03:21, Daniel Lehman wrote:
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com> --- dlls/wininet/http.c | 120 ++++++++++++++++++++++++++++++++++++++ dlls/wininet/resource.h | 3 + dlls/wininet/tests/http.c | 112 ++++++++++++++++++++++++++++++++++- dlls/wininet/wininet.rc | 12 ++++ 4 files changed, 245 insertions(+), 2 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 56c995805b..379455fddb 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -35,6 +35,7 @@ #include <stdarg.h> #include <stdio.h> #include <time.h> +#include <math.h> #include <assert.h> #include <errno.h> #include <limits.h> @@ -54,6 +55,7 @@
#include "internet.h" #include "zlib.h" +#include "resource.h" #include "wine/debug.h" #include "wine/exception.h"
@@ -2273,6 +2275,124 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe } return ERROR_NOT_SUPPORTED; } + case INTERNET_OPTION_SECURITY_CERTIFICATE: { + char fmt[256]; + const char nullA[] = "(null)"; /* always appears in English */ + CERT_CONTEXT *context; + char *subject = NULL; + char *issuer = NULL; + char *start_date = NULL; + char *start_time = NULL; + char *expiry_date = NULL; + char *expiry_time = NULL; + char strength[16]; + int subject_len, issuer_len; + int start_date_len, start_time_len; + int expiry_date_len, expiry_time_len; + SYSTEMTIME start, expiry; + DWORD needed, keysize; + + if (PRIMARYLANGID(GetUserDefaultLangID()) != LANG_ENGLISH) + FIXME("INTERNET_OPTION_SECURITY_CERTIFICATE currently English-only\n"); + + if(!req->netconn) + return ERROR_INTERNET_INVALID_OPERATION; + + if(!size) + return ERROR_INVALID_PARAMETER; + + if(!buffer) { + *size = 1; + return ERROR_INSUFFICIENT_BUFFER; + } + + context = (CERT_CONTEXT *)NETCON_GetCert(req->netconn); + if(!context)(Decoding strings directly to return buffer would be another option). + return ERROR_NOT_SUPPORTED; + + needed = LoadStringA(WININET_hModule, IDS_CERT_FORMAT, fmt, sizeof(fmt)); + needed += 1 - 20 * 2 + 9; /* include room for \0, subtract 20 format specifiers, add 9 \r */ + if(needed > *size) goto error; + + subject_len = CertNameToStrA(context->dwCertEncodingType, &context->pCertInfo->Subject, + CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0); + needed += subject_len - 1; /* minus \0 */ + if(needed > *size) goto error; + + issuer_len = CertNameToStrA(context->dwCertEncodingType, &context->pCertInfo->Issuer, + CERT_SIMPLE_NAME_STR|CERT_NAME_STR_CRLF_FLAG, NULL, 0); + needed += issuer_len - 1; + if(needed > *size) goto error; + + FileTimeToSystemTime(&context->pCertInfo->NotBefore, &start); + start_date_len = GetDateFormatA(LOCALE_USER_DEFAULT, 0, &start, NULL, NULL, 0); + start_time_len = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &start, NULL, NULL, 0); + needed += start_date_len + start_time_len - 2; + if(needed > *size) goto error; + + FileTimeToSystemTime(&context->pCertInfo->NotAfter, &expiry); + expiry_date_len = GetDateFormatA(LOCALE_USER_DEFAULT, 0, &expiry, NULL, NULL, 0); + expiry_time_len = GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &expiry, NULL, NULL, 0); + needed += expiry_date_len + expiry_time_len - 2; + if(needed > *size) goto error; + + needed += sizeof(nullA) * 3 - 3; /* protocol, signature type, encryption type */ + if(needed > *size) goto error; + + keysize = NETCON_GetCipherStrength(req->netconn); + needed += keysize ? floor(log10(keysize))+1 : 1; + needed += LoadStringA(WININET_hModule, keysize >= 128 ? IDS_CERT_HIGH : IDS_CERT_LOW, + strength, sizeof(strength)); + if(needed > *size) goto error; + + if(!(subject = heap_alloc(subject_len)) || + !(issuer = heap_alloc(issuer_len)) || + !(start_date = heap_alloc(start_date_len)) || + !(start_time = heap_alloc(start_time_len)) || + !(expiry_date = heap_alloc(expiry_date_len)) || + !(expiry_time = heap_alloc(expiry_time_len))) + goto error;
If you're using dynamic allocation anyway, you could as well move INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT to a helper and operate on INTERNET_CERTIFICATE_INFO here, maybe even combined with _cprintf for size check. It should simplify things a bit. Date and time strings should be fine with buffers on a stack. (Decoding strings directly to return buffer would be another option, but it's necessarily worth the complication).
diff --git a/dlls/wininet/wininet.rc b/dlls/wininet/wininet.rc index b6e35629ca..7e2830e7ff 100644 --- a/dlls/wininet/wininet.rc +++ b/dlls/wininet/wininet.rc @@ -29,6 +29,18 @@ STRINGTABLE IDS_CERT_DATE_INVALID "The date on the certificate is invalid." IDS_CERT_CN_INVALID "The name on the certificate does not match the site." IDS_CERT_ERRORS "There is at least one unspecified security problem with this certificate." + + /* each %c is a \r */ + IDS_CERT_FORMAT "Subject:%c\n%s%c\n" \ + "Issuer:%c\n%s%c\n" \ + "Effective Date:\t%s %s%c\n" \ + "Expiration Date:\t%s %s%c\n" \ + "Security Protocol:\t%s%c\n" \ + "Signature Type:\t%s%c\n" \ + "Encryption Type:\t%s%c\n" \ + "Privacy Strength:\t%s (%u bits)" + IDS_CERT_HIGH "High" + IDS_CERT_LOW "Low"
You could use \015 as \r replacement instead of %c trick. Thanks, Jacek