Wine-devel
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
February 2019
- 73 participants
- 737 discussions
[PATCH v4 1/7] comctl32/listbox: Resize the entire item array at once in SetCount
by Gabriel Ivăncescu 13 Feb '19
by Gabriel Ivăncescu 13 Feb '19
13 Feb '19
Signed-off-by: Gabriel Ivăncescu <gabrielopcode(a)gmail.com>
---
v4: Dumb mistake with get_item_string in patch 5, sorry for noise.
dlls/comctl32/listbox.c | 43 ++++++++++++++++++++++++++++-------------
1 file changed, 30 insertions(+), 13 deletions(-)
diff --git a/dlls/comctl32/listbox.c b/dlls/comctl32/listbox.c
index c92c2a2..db7d474 100644
--- a/dlls/comctl32/listbox.c
+++ b/dlls/comctl32/listbox.c
@@ -144,6 +144,12 @@ static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
descr->items_size = items_size;
descr->items = items;
}
+
+ if ((descr->style & LBS_NODATA) && items_size > descr->nb_items)
+ {
+ memset(&descr->items[descr->nb_items], 0,
+ (items_size - descr->nb_items) * sizeof(LB_ITEMDATA));
+ }
return TRUE;
}
@@ -1742,25 +1748,36 @@ static void LISTBOX_ResetContent( LB_DESCR *descr )
/***********************************************************************
* LISTBOX_SetCount
*/
-static LRESULT LISTBOX_SetCount( LB_DESCR *descr, INT count )
+static LRESULT LISTBOX_SetCount( LB_DESCR *descr, UINT count )
{
- LRESULT ret;
+ UINT orig_num = descr->nb_items;
if (!(descr->style & LBS_NODATA)) return LB_ERR;
- /* FIXME: this is far from optimal... */
- if (count > descr->nb_items)
- {
- while (count > descr->nb_items)
- if ((ret = LISTBOX_InsertString( descr, -1, 0 )) < 0)
- return ret;
- }
- else if (count < descr->nb_items)
+ if (!resize_storage(descr, count))
+ return LB_ERRSPACE;
+ descr->nb_items = count;
+
+ if (count)
{
- while (count < descr->nb_items)
- if ((ret = LISTBOX_RemoveItem( descr, (descr->nb_items - 1) )) < 0)
- return ret;
+ LISTBOX_UpdateScroll(descr);
+ if (count < orig_num)
+ {
+ descr->anchor_item = min(descr->anchor_item, count - 1);
+ if (descr->selected_item >= count)
+ descr->selected_item = -1;
+
+ /* If we removed the scrollbar, reset the top of the list */
+ if (count <= descr->page_size && orig_num > descr->page_size)
+ LISTBOX_SetTopItem(descr, 0, TRUE);
+
+ descr->focus_item = min(descr->focus_item, count - 1);
+ }
+
+ /* If it was empty before growing, set focus to the first item */
+ else if (orig_num == 0) LISTBOX_SetCaretIndex(descr, 0, FALSE);
}
+ else SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
InvalidateRect( descr->self, NULL, TRUE );
return LB_OKAY;
--
2.20.1
2
13
[PATCH 2/3] wineps.drv: Add support for GETFACENAME and DOWNLOADFACE escapes.
by Dmitry Timoshkov 13 Feb '19
by Dmitry Timoshkov 13 Feb '19
13 Feb '19
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/wineps.drv/download.c | 26 ++++++++++++++++++++++++++
dlls/wineps.drv/escape.c | 21 ++++++++++++++++++---
dlls/wineps.drv/psdrv.h | 1 +
3 files changed, 45 insertions(+), 3 deletions(-)
diff --git a/dlls/wineps.drv/download.c b/dlls/wineps.drv/download.c
index dc77cf1170..86188d2b55 100644
--- a/dlls/wineps.drv/download.c
+++ b/dlls/wineps.drv/download.c
@@ -259,6 +259,32 @@ static BOOL is_fake_italic( HDC hdc )
return !(mac_style & 2);
}
+char *PSDRV_get_download_name(PHYSDEV dev, BOOL vertical)
+{
+ PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
+ char *ps_name;
+ LPOUTLINETEXTMETRICA potm;
+ DWORD len = GetOutlineTextMetricsA(dev->hdc, 0, NULL);
+ LOGFONTW lf;
+
+ assert(physDev->font.fontloc == Download);
+
+ if (!GetObjectW(GetCurrentObject(dev->hdc, OBJ_FONT), sizeof(lf), &lf))
+ return NULL;
+
+ potm = HeapAlloc(GetProcessHeap(), 0, len);
+ if (!potm)
+ return NULL;
+
+ GetOutlineTextMetricsA(dev->hdc, len, potm);
+
+ ps_name = NULL;
+ get_download_name(dev, potm, &ps_name, vertical);
+ HeapFree(GetProcessHeap(), 0, potm);
+
+ return ps_name;
+}
+
/****************************************************************************
* PSDRV_WriteSetDownloadFont
*
diff --git a/dlls/wineps.drv/escape.c b/dlls/wineps.drv/escape.c
index 44d790b298..db73c057ef 100644
--- a/dlls/wineps.drv/escape.c
+++ b/dlls/wineps.drv/escape.c
@@ -138,12 +138,27 @@ INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
return 1;
case GETFACENAME:
- FIXME("GETFACENAME: stub\n");
- lstrcpynA(out_data, "Courier", cbOutput);
+ if (physDev->font.fontloc == Download)
+ {
+ char *name = PSDRV_get_download_name(dev, physDev->font.set);
+ if (name)
+ {
+ TRACE("font name: %s\n", debugstr_a(name));
+ lstrcpynA(out_data, name, cbOutput);
+ HeapFree(GetProcessHeap(), 0, name);
+ }
+ else
+ lstrcpynA(out_data, "Courier", cbOutput);
+ }
+ else
+ {
+ TRACE("font name: %s\n", debugstr_a(physDev->font.fontinfo.Builtin.afm->FontName));
+ lstrcpynA(out_data, physDev->font.fontinfo.Builtin.afm->FontName, cbOutput);
+ }
return 1;
case DOWNLOADFACE:
- FIXME("DOWNLOADFACE: stub\n");
+ PSDRV_SetFont(dev, physDev->font.set);
return 1;
case MFCOMMENT:
diff --git a/dlls/wineps.drv/psdrv.h b/dlls/wineps.drv/psdrv.h
index 9cbee65ed8..55f345b87f 100644
--- a/dlls/wineps.drv/psdrv.h
+++ b/dlls/wineps.drv/psdrv.h
@@ -553,6 +553,7 @@ extern BOOL PSDRV_SelectBuiltinFont(PHYSDEV dev, HFONT hfont,
extern BOOL PSDRV_WriteSetBuiltinFont(PHYSDEV dev) DECLSPEC_HIDDEN;
extern BOOL PSDRV_WriteBuiltinGlyphShow(PHYSDEV dev, LPCWSTR str, INT count) DECLSPEC_HIDDEN;
+extern char *PSDRV_get_download_name(PHYSDEV dev, BOOL vertical) DECLSPEC_HIDDEN;
extern BOOL PSDRV_SelectDownloadFont(PHYSDEV dev) DECLSPEC_HIDDEN;
extern BOOL PSDRV_WriteSetDownloadFont(PHYSDEV dev, BOOL vertical) DECLSPEC_HIDDEN;
extern BOOL PSDRV_WriteDownloadGlyphShow(PHYSDEV dev, const WORD *glyphs, UINT count) DECLSPEC_HIDDEN;
--
2.20.1
2
3
[PATCH v2 2/2] wineps.drv: PostScript header should be written by StartDoc instead of StartPage.
by Huw Davies 13 Feb '19
by Huw Davies 13 Feb '19
13 Feb '19
From: Dmitry Timoshkov <dmitry(a)baikal.ru>
Otherwise a being created file has wrong signature if an application
directly injects PostScript code. This patch fixes printing from
Adobe PageMaker.
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/gdi32/tests/dc.c | 1 -
dlls/wineps.drv/escape.c | 18 ++++++++++++++----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/dlls/gdi32/tests/dc.c b/dlls/gdi32/tests/dc.c
index 82cf200f4c..2d9ef1dd88 100644
--- a/dlls/gdi32/tests/dc.c
+++ b/dlls/gdi32/tests/dc.c
@@ -1433,7 +1433,6 @@ static void print_something(HDC hdc)
while (*p == '\r' || *p == '\n') p++;
}
-todo_wine
ok(p && !memcmp(p, psadobe, sizeof(psadobe)), "wrong signature: %.14s\n", p ? p : buf);
DeleteFileA(file_name);
diff --git a/dlls/wineps.drv/escape.c b/dlls/wineps.drv/escape.c
index 44d790b298..b3eff6813c 100644
--- a/dlls/wineps.drv/escape.c
+++ b/dlls/wineps.drv/escape.c
@@ -397,15 +397,14 @@ INT PSDRV_StartPage( PHYSDEV dev )
{
PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
+ TRACE("%p\n", dev->hdc);
+
if(!physDev->job.OutOfPage) {
FIXME("Already started a page?\n");
return 1;
}
- if(physDev->job.PageNo++ == 0) {
- if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
- return 0;
- }
+ physDev->job.PageNo++;
if(!PSDRV_WriteNewPage( dev ))
return 0;
@@ -421,6 +420,8 @@ INT PSDRV_EndPage( PHYSDEV dev )
{
PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
+ TRACE("%p\n", dev->hdc);
+
if(physDev->job.OutOfPage) {
FIXME("Already ended a page?\n");
return 1;
@@ -483,6 +484,13 @@ INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
ClosePrinter(physDev->job.hprinter);
return 0;
}
+
+ if (!PSDRV_WriteHeader( dev, doc->lpszDocName )) {
+ WARN("Failed to write header\n");
+ ClosePrinter(physDev->job.hprinter);
+ return 0;
+ }
+
physDev->job.banding = FALSE;
physDev->job.OutOfPage = TRUE;
physDev->job.PageNo = 0;
@@ -501,6 +509,8 @@ INT PSDRV_EndDoc( PHYSDEV dev )
PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
INT ret = 1;
+ TRACE("%p\n", dev->hdc);
+
if(!physDev->job.id) {
FIXME("hJob == 0. Now what?\n");
return 0;
--
2.18.0
1
0
[PATCH v2 1/2] wineps.drv: Add stubs for escapes required by Adobe PageMaker.
by Huw Davies 13 Feb '19
by Huw Davies 13 Feb '19
13 Feb '19
From: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
---
dlls/gdi32/tests/dc.c | 7 -------
dlls/wineps.drv/escape.c | 41 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 41 insertions(+), 7 deletions(-)
diff --git a/dlls/gdi32/tests/dc.c b/dlls/gdi32/tests/dc.c
index 3179c97e46..82cf200f4c 100644
--- a/dlls/gdi32/tests/dc.c
+++ b/dlls/gdi32/tests/dc.c
@@ -1402,9 +1402,7 @@ static void print_something(HDC hdc)
strcpy(buf, "deadbeef");
ret = ExtEscape(hdc, DOWNLOADHEADER, 0, NULL, sizeof(buf), buf );
-todo_wine
ok(ret == 1, "DOWNLOADHEADER failed\n");
-todo_wine
ok(strcmp(buf, "deadbeef") != 0, "DOWNLOADHEADER failed\n");
strcpy(buf + 2, "\n% ===> after DOWNLOADHEADER <===\n");
@@ -1464,22 +1462,18 @@ static void test_pscript_printer_dc(void)
query = DOWNLOADFACE;
ret = Escape(hdc, QUERYESCSUPPORT, sizeof(query), (LPCSTR)&query, NULL);
-todo_wine
ok(ret == 1, "DOWNLOADFACE is not supported\n");
query = OPENCHANNEL;
ret = Escape(hdc, QUERYESCSUPPORT, sizeof(query), (LPCSTR)&query, NULL);
-todo_wine
ok(ret == 1, "OPENCHANNEL is not supported\n");
query = DOWNLOADHEADER;
ret = Escape(hdc, QUERYESCSUPPORT, sizeof(query), (LPCSTR)&query, NULL);
-todo_wine
ok(ret == 1, "DOWNLOADHEADER is not supported\n");
query = CLOSECHANNEL;
ret = Escape(hdc, QUERYESCSUPPORT, sizeof(query), (LPCSTR)&query, NULL);
-todo_wine
ok(ret == 1, "CLOSECHANNEL is not supported\n");
query = POSTSCRIPT_PASSTHROUGH;
@@ -1487,7 +1481,6 @@ todo_wine
ok(ret == 1, "POSTSCRIPT_PASSTHROUGH is not supported\n");
ret = ExtEscape(hdc, GETFACENAME, 0, NULL, sizeof(buf), buf);
-todo_wine
ok(ret == 1, "GETFACENAME failed\n");
trace("face name: %s\n", buf);
diff --git a/dlls/wineps.drv/escape.c b/dlls/wineps.drv/escape.c
index 43bbe18bb5..44d790b298 100644
--- a/dlls/wineps.drv/escape.c
+++ b/dlls/wineps.drv/escape.c
@@ -97,14 +97,55 @@ INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
case CLIP_TO_PATH:
case END_PATH:
/*case DRAWPATTERNRECT:*/
+
+ /* PageMaker checks for it */
+ case DOWNLOADHEADER:
+
+ /* PageMaker doesn't check for DOWNLOADFACE and GETFACENAME but
+ * uses them, they are supposed to be supported by any PS printer.
+ */
+ case DOWNLOADFACE:
+
+ /* PageMaker checks for these as a part of process of detecting
+ * a "fully compatible" PS printer, but doesn't actually use them.
+ */
+ case OPENCHANNEL:
+ case CLOSECHANNEL:
return TRUE;
+ /* Windows PS driver reports 0, but still supports this escape */
+ case GETFACENAME:
+ return FALSE; /* suppress the FIXME below */
+
default:
FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
return FALSE;
}
}
+ case OPENCHANNEL:
+ FIXME("OPENCHANNEL: stub\n");
+ return 1;
+
+ case CLOSECHANNEL:
+ FIXME("CLOSECHANNEL: stub\n");
+ return 1;
+
+ case DOWNLOADHEADER:
+ FIXME("DOWNLOADHEADER: stub\n");
+ /* should return name of the downloaded procset */
+ *(char *)out_data = 0;
+ return 1;
+
+ case GETFACENAME:
+ FIXME("GETFACENAME: stub\n");
+ lstrcpynA(out_data, "Courier", cbOutput);
+ return 1;
+
+ case DOWNLOADFACE:
+ FIXME("DOWNLOADFACE: stub\n");
+ return 1;
+
case MFCOMMENT:
{
FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
--
2.18.0
1
0
Signed-off-by: Gijs Vermeulen <gijsvrm(a)gmail.com>
---
dlls/msvcp140/msvcp140.spec | 2 +-
dlls/msvcp140/tests/msvcp140.c | 66 ++++++++++++++++++++++++++++++++++
dlls/msvcp90/ios.c | 6 ++++
3 files changed, 73 insertions(+), 1 deletion(-)
diff --git a/dlls/msvcp140/msvcp140.spec b/dlls/msvcp140/msvcp140.spec
index 6a4eb14c04..75ed8fb9a6 100644
--- a/dlls/msvcp140/msvcp140.spec
+++ b/dlls/msvcp140/msvcp140.spec
@@ -3632,7 +3632,7 @@
@ cdecl _Cnd_timedwait(ptr ptr ptr)
@ cdecl _Cnd_unregister_at_thread_exit(ptr)
@ cdecl _Cnd_wait(ptr ptr)
-@ stub _Copy_file
+@ cdecl _Copy_file(wstr wstr long)
@ stub _Cosh
@ cdecl _Current_get(ptr)
@ cdecl _Current_set(wstr) tr2_sys__Current_set_wchar
diff --git a/dlls/msvcp140/tests/msvcp140.c b/dlls/msvcp140/tests/msvcp140.c
index b2bdafa4ad..53fb0ebe9c 100644
--- a/dlls/msvcp140/tests/msvcp140.c
+++ b/dlls/msvcp140/tests/msvcp140.c
@@ -174,6 +174,7 @@ static int (__cdecl *p__Reschedule_chore)(const _Threadpool_chore*);
static void (__cdecl *p__Release_chore)(_Threadpool_chore*);
static void (__cdecl *p_Close_dir)(void*);
+static int (__cdecl *p_Copy_file)(WCHAR const*, WCHAR const*, MSVCP_bool);
static MSVCP_bool (__cdecl *p_Current_get)(WCHAR *);
static MSVCP_bool (__cdecl *p_Current_set)(WCHAR const *);
static int (__cdecl *p_Equivalent)(WCHAR const*, WCHAR const*);
@@ -266,6 +267,7 @@ static BOOL init(void)
}
SET(p_Close_dir, "_Close_dir");
+ SET(p_Copy_file, "_Copy_file");
SET(p_Current_get, "_Current_get");
SET(p_Current_set, "_Current_set");
SET(p_Equivalent, "_Equivalent");
@@ -1428,6 +1430,69 @@ static void test_Equivalent(void)
ok(SetCurrentDirectoryW(current_path), "SetCurrentDirectoryW failed\n");
}
+static void test_Copy_file(void)
+{
+ HANDLE file;
+ int ret, i;
+ LARGE_INTEGER file_size;
+ static const WCHAR wine_test_dirW[] =
+ {'w','i','n','e','_','t','e','s','t','_','d','i','r',0};
+ static const WCHAR wine_test_dirW_copy[] =
+ {'w','i','n','e','_','t','e','s','t','_','d','i','r','_','c','o','p','y',0};
+ static const WCHAR f1W[] =
+ {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1',0};
+ static const WCHAR f1W_copy[] =
+ {'w','i','n','e','_','t','e','s','t','_','d','i','r','/','f','1','_','c','o','p','y',0};
+ static const WCHAR f1W_copy_backslash[] =
+ {'w','i','n','e','_','t','e','s','t','_','d','i','r','\\','f','1','_','c','o','p','y',0};
+ static const WCHAR not_existW[] =
+ {'n','o','t','_','e','x','i','s','t',0};
+ static const WCHAR not_exist_dir_backslash_f1_copyW[] =
+ {'n','o','t','_','e','x','i','s','t','_','d','i','r','\\','f','1','_','c','o','p','y',0};
+ static const struct {
+ const WCHAR *source;
+ const WCHAR *dest;
+ MSVCP_bool fail_if_exists;
+ int last_error;
+ int last_error2;
+ } tests[] = {
+ { f1W, f1W_copy, TRUE, ERROR_SUCCESS, ERROR_SUCCESS },
+ { f1W, f1W_copy_backslash, TRUE, ERROR_SUCCESS, ERROR_SUCCESS },
+ { f1W, f1W_copy_backslash, TRUE, ERROR_SUCCESS, ERROR_SUCCESS },
+ { f1W, f1W_copy_backslash, FALSE, ERROR_SUCCESS, ERROR_SUCCESS },
+ { wine_test_dirW, f1W, TRUE, ERROR_ACCESS_DENIED, ERROR_ACCESS_DENIED },
+ { wine_test_dirW, wine_test_dirW_copy, TRUE, ERROR_ACCESS_DENIED, ERROR_ACCESS_DENIED },
+ { not_existW, wine_test_dirW, TRUE, ERROR_FILE_NOT_FOUND, ERROR_FILE_NOT_FOUND },
+ { f1W, not_exist_dir_backslash_f1_copyW, TRUE, ERROR_PATH_NOT_FOUND, ERROR_FILE_NOT_FOUND },
+ { f1W, wine_test_dirW, TRUE, ERROR_ACCESS_DENIED, ERROR_FILE_EXISTS }
+ };
+
+ ret = p_Make_dir(wine_test_dirW);
+ ok(ret == 1, "_Make_dir(): expect 1 got %d\n", ret);
+ file = CreateFileW(f1W, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ ok(file != INVALID_HANDLE_VALUE, "create file failed: INVALID_HANDLE_VALUE\n");
+ file_size.QuadPart = 7;
+ ok(SetFilePointerEx(file, file_size, NULL, FILE_BEGIN), "SetFilePointerEx failed\n");
+ ok(SetEndOfFile(file), "SetEndOfFile failed\n");
+ CloseHandle(file);
+
+ for(i=0; i<ARRAY_SIZE(tests); i++) {
+ errno = 0xdeadbeef;
+ ret = p_Copy_file(tests[i].source, tests[i].dest, tests[i].fail_if_exists);
+ ok(ret == tests[i].last_error || ret == tests[i].last_error2,
+ "_Copy_file(): test %d expect: %d, got %d\n", i+1, tests[i].last_error, ret);
+ ok(errno == 0xdeadbeef, "_Copy_file(): test %d errno expect 0xdeadbeef, got %d\n", i+1, errno);
+ if(ret == ERROR_SUCCESS)
+ ok(p_File_size(tests[i].source) == p_File_size(tests[i].dest),
+ "_Copy_file(): test %d failed, two files' size are not equal\n", i+1);
+ }
+
+ ok(DeleteFileW(f1W), "expect f1 to exist\n");
+ ok(DeleteFileW(f1W_copy), "expect f1_copy to exist\n");
+ ret = p_Remove_dir(wine_test_dirW);
+ ok(ret == 1, "_Remove_dir(): expect 1 got %d\n", ret);
+}
+
START_TEST(msvcp140)
{
if(!init()) return;
@@ -1452,5 +1517,6 @@ START_TEST(msvcp140)
test__Winerror_message();
test__Winerror_map();
test_Equivalent();
+ test_Copy_file();
FreeLibrary(msvcp);
}
diff --git a/dlls/msvcp90/ios.c b/dlls/msvcp90/ios.c
index 7f792d6ef9..00854f4ab5 100644
--- a/dlls/msvcp90/ios.c
+++ b/dlls/msvcp90/ios.c
@@ -15693,6 +15693,12 @@ int __cdecl tr2_sys__Copy_file_wchar(WCHAR const* source, WCHAR const* dest, MSV
return GetLastError();
}
+/* _Copy_file, msvcp140 version. */
+int __cdecl _Copy_file(WCHAR const* source, WCHAR const* dest, MSVCP_bool fail_if_exists)
+{
+ return tr2_sys__Copy_file_wchar(source, dest, FALSE);
+}
+
/* ?_Rename(a)sys@tr2(a)std@@YAHPB_W0(a)Z */
/* ?_Rename(a)sys@tr2(a)std@@YAHPEB_W0(a)Z */
int __cdecl tr2_sys__Rename_wchar(WCHAR const* old_path, WCHAR const* new_path)
--
2.20.1
2
1
Based on a patch by Jack Grigg.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42704
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/bcrypt/bcrypt.spec | 1 +
dlls/bcrypt/bcrypt_main.c | 91 ++++++++++++++++++++++++++++++++++++++
dlls/bcrypt/tests/bcrypt.c | 91 +++++++++++++++++++++++++++++++++++---
dlls/ncrypt/ncrypt.spec | 2 +-
include/bcrypt.h | 1 +
5 files changed, 180 insertions(+), 6 deletions(-)
diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec
index 891381f2a8..052a0996d4 100644
--- a/dlls/bcrypt/bcrypt.spec
+++ b/dlls/bcrypt/bcrypt.spec
@@ -8,6 +8,7 @@
@ stdcall BCryptDecrypt(ptr ptr long ptr ptr long ptr long ptr long)
@ stub BCryptDeleteContext
@ stub BCryptDeriveKey
+@ stdcall BCryptDeriveKeyPBKDF2(ptr ptr long ptr long int64 ptr long long)
@ stdcall BCryptDestroyHash(ptr)
@ stdcall BCryptDestroyKey(ptr)
@ stub BCryptDestroySecret
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index e511495eed..1b84ace8ab 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -1461,6 +1461,97 @@ NTSTATUS WINAPI BCryptSetProperty( BCRYPT_HANDLE handle, const WCHAR *prop, UCHA
}
}
+static NTSTATUS pbkdf2( BCRYPT_ALG_HANDLE algorithm, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len,
+ ULONGLONG iterations, ULONG i, UCHAR *dst, ULONG hash_len )
+{
+ BCRYPT_HASH_HANDLE handle = NULL;
+ NTSTATUS status = STATUS_INVALID_PARAMETER;
+ UCHAR bytes[4], *buf;
+ ULONG j, k;
+
+ if (!(buf = heap_alloc( hash_len ))) return STATUS_NO_MEMORY;
+
+ for (j = 0; j < iterations; j++)
+ {
+ status = BCryptCreateHash( algorithm, &handle, NULL, 0, pwd, pwd_len, 0 );
+ if (status != STATUS_SUCCESS)
+ goto done;
+
+ if (j == 0)
+ {
+ /* use salt || INT(i) */
+ status = BCryptHashData( handle, salt, salt_len, 0 );
+ if (status != STATUS_SUCCESS)
+ goto done;
+ bytes[0] = (i >> 24) & 0xff;
+ bytes[1] = (i >> 16) & 0xff;
+ bytes[2] = (i >> 8) & 0xff;
+ bytes[3] = i & 0xff;
+ status = BCryptHashData( handle, bytes, 4, 0 );
+ }
+ else status = BCryptHashData( handle, buf, hash_len, 0 ); /* use U_j */
+ if (status != STATUS_SUCCESS)
+ goto done;
+
+ status = BCryptFinishHash( handle, buf, hash_len, 0 );
+ if (status != STATUS_SUCCESS)
+ goto done;
+
+ if (j == 0) memcpy( dst, buf, hash_len );
+ else for (k = 0; k < hash_len; k++) dst[k] ^= buf[k];
+
+ BCryptDestroyHash( handle );
+ handle = NULL;
+ }
+
+done:
+ BCryptDestroyHash( handle );
+ heap_free( buf );
+ return status;
+}
+
+NTSTATUS WINAPI BCryptDeriveKeyPBKDF2( BCRYPT_ALG_HANDLE handle, UCHAR *pwd, ULONG pwd_len, UCHAR *salt, ULONG salt_len,
+ ULONGLONG iterations, UCHAR *dk, ULONG dk_len, ULONG flags )
+{
+ struct algorithm *alg = handle;
+ ULONG hash_len, block_count, bytes_left, i;
+ UCHAR *partial;
+ NTSTATUS status;
+
+ TRACE( "%p, %p, %u, %p, %u, %s, %p, %u, %08x\n", handle, pwd, pwd_len, salt, salt_len,
+ wine_dbgstr_longlong(iterations), dk, dk_len, flags );
+
+ if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
+
+ hash_len = alg_props[alg->id].hash_length;
+ if (dk_len <= 0 || dk_len > ((((ULONGLONG)1) << 32) - 1) * hash_len) return STATUS_INVALID_PARAMETER;
+
+ block_count = 1 + ((dk_len - 1) / hash_len); /* ceil(dk_len / hash_len) */
+ bytes_left = dk_len - (block_count - 1) * hash_len;
+
+ /* full blocks */
+ for (i = 1; i < block_count; i++)
+ {
+ status = pbkdf2( handle, pwd, pwd_len, salt, salt_len, iterations, i, dk + ((i - 1) * hash_len), hash_len );
+ if (status != STATUS_SUCCESS)
+ return status;
+ }
+
+ /* final partial block */
+ if (!(partial = heap_alloc( hash_len ))) return STATUS_NO_MEMORY;
+
+ status = pbkdf2( handle, pwd, pwd_len, salt, salt_len, iterations, block_count, partial, hash_len );
+ if (status != STATUS_SUCCESS)
+ {
+ heap_free( partial );
+ return status;
+ }
+ memcpy( dk + ((block_count - 1) * hash_len), partial, bytes_left );
+ heap_free( partial );
+
+ return STATUS_SUCCESS;
+}
+
BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
{
switch (reason)
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index ca7c22d5c4..5c1a9dc834 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -31,6 +31,8 @@ static NTSTATUS (WINAPI *pBCryptCreateHash)(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDL
ULONG, ULONG);
static NTSTATUS (WINAPI *pBCryptDecrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG,
ULONG *, ULONG);
+static NTSTATUS (WINAPI *pBCryptDeriveKeyPBKDF2)(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, PUCHAR, ULONG, ULONGLONG,
+ PUCHAR, ULONG, ULONG);
static NTSTATUS (WINAPI *pBCryptDestroyHash)(BCRYPT_HASH_HANDLE);
static NTSTATUS (WINAPI *pBCryptDestroyKey)(BCRYPT_KEY_HANDLE);
static NTSTATUS (WINAPI *pBCryptDuplicateHash)(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
@@ -373,6 +375,12 @@ static void test_BcryptHash(void)
char str[65];
NTSTATUS ret;
+ if (!pBCryptHash) /* < Win10 */
+ {
+ win_skip("BCryptHash is not available\n");
+ return;
+ }
+
alg = NULL;
ret = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_MD5_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
@@ -405,6 +413,81 @@ static void test_BcryptHash(void)
ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
}
+/* test vectors from RFC 6070 */
+static UCHAR password[] = "password";
+static UCHAR salt[] = "salt";
+static UCHAR long_password[] = "passwordPASSWORDpassword";
+static UCHAR long_salt[] = "saltSALTsaltSALTsaltSALTsaltSALTsalt";
+static UCHAR password_NUL[] = "pass\0word";
+static UCHAR salt_NUL[] = "sa\0lt";
+
+static UCHAR dk1[] = "0c60c80f961f0e71f3a9b524af6012062fe037a6";
+static UCHAR dk2[] = "ea6c014dc72d6f8ccd1ed92ace1d41f0d8de8957";
+static UCHAR dk3[] = "4b007901b765489abead49d926f721d065a429c1";
+static UCHAR dk4[] = "364dd6bc200ec7d197f1b85f4a61769010717124";
+static UCHAR dk5[] = "3d2eec4fe41c849b80c8d83662c0e44a8b291a964cf2f07038";
+static UCHAR dk6[] = "56fa6aa75548099dcc37d7f03425e0c3";
+
+static const struct
+{
+ ULONG pwd_len;
+ ULONG salt_len;
+ ULONGLONG iterations;
+ ULONG dk_len;
+ UCHAR *pwd;
+ UCHAR *salt;
+ const UCHAR *dk;
+} rfc6070[] =
+{
+ { 8, 4, 1, 20, password, salt, dk1 },
+ { 8, 4, 2, 20, password, salt, dk2 },
+ { 8, 4, 4096, 20, password, salt, dk3 },
+ { 8, 4, 1000000, 20, password, salt, dk4 },
+ { 24, 36, 4096, 25, long_password, long_salt, dk5 },
+ { 9, 5, 4096, 16, password_NUL, salt_NUL, dk6 }
+};
+
+static void test_BcryptDeriveKeyPBKDF2(void)
+{
+ BCRYPT_ALG_HANDLE alg;
+ UCHAR buf[25];
+ char str[51];
+ NTSTATUS ret;
+ ULONG i;
+
+ if (!pBCryptDeriveKeyPBKDF2) /* < Win7 */
+ {
+ win_skip("BCryptDeriveKeyPBKDF2 is not available\n");
+ return;
+ }
+
+ alg = NULL;
+ ret = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_SHA1_ALGORITHM, MS_PRIMITIVE_PROVIDER,
+ BCRYPT_ALG_HANDLE_HMAC_FLAG);
+ ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+ ok(alg != NULL, "alg not set\n");
+
+ test_hash_length(alg, 20);
+ test_alg_name(alg, "SHA1");
+
+ ret = pBCryptDeriveKeyPBKDF2(alg, rfc6070[0].pwd, rfc6070[0].pwd_len, rfc6070[0].salt, rfc6070[0].salt_len,
+ 0, buf, rfc6070[0].dk_len, 0);
+ ok(ret == STATUS_INVALID_PARAMETER, "got %08x\n", ret);
+
+ for (i = 0; i < ARRAY_SIZE(rfc6070); i++)
+ {
+ memset(buf, 0, sizeof(buf));
+ ret = pBCryptDeriveKeyPBKDF2(alg, rfc6070[i].pwd, rfc6070[i].pwd_len, rfc6070[i].salt, rfc6070[i].salt_len,
+ rfc6070[i].iterations, buf, rfc6070[i].dk_len, 0);
+ ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+ format_hash(buf, rfc6070[i].dk_len, str);
+ ok(!memcmp(str, rfc6070[i].dk, rfc6070[i].dk_len), "got %s\n", str);
+ }
+
+ ret = pBCryptCloseAlgorithmProvider(alg, 0);
+ ok(ret == STATUS_SUCCESS, "got %08x\n", ret);
+}
+
static void test_rng(void)
{
BCRYPT_ALG_HANDLE alg;
@@ -1762,6 +1845,7 @@ START_TEST(bcrypt)
pBCryptCloseAlgorithmProvider = (void *)GetProcAddress(module, "BCryptCloseAlgorithmProvider");
pBCryptCreateHash = (void *)GetProcAddress(module, "BCryptCreateHash");
pBCryptDecrypt = (void *)GetProcAddress(module, "BCryptDecrypt");
+ pBCryptDeriveKeyPBKDF2 = (void *)GetProcAddress(module, "BCryptDeriveKeyPBKDF2");
pBCryptDestroyHash = (void *)GetProcAddress(module, "BCryptDestroyHash");
pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey");
pBCryptDuplicateHash = (void *)GetProcAddress(module, "BCryptDuplicateHash");
@@ -1786,6 +1870,8 @@ START_TEST(bcrypt)
test_BCryptGenRandom();
test_BCryptGetFipsAlgorithmMode();
test_hashes();
+ test_BcryptHash();
+ test_BcryptDeriveKeyPBKDF2();
test_rng();
test_aes();
test_BCryptGenerateSymmetricKey();
@@ -1796,10 +1882,5 @@ START_TEST(bcrypt)
test_RSA();
test_ECDH();
- if (pBCryptHash) /* >= Win 10 */
- test_BcryptHash();
- else
- win_skip("BCryptHash is not available\n");
-
FreeLibrary(module);
}
diff --git a/dlls/ncrypt/ncrypt.spec b/dlls/ncrypt/ncrypt.spec
index c6e7f7fb6f..85fa5c0ea5 100644
--- a/dlls/ncrypt/ncrypt.spec
+++ b/dlls/ncrypt/ncrypt.spec
@@ -9,7 +9,7 @@
@ stub BCryptDeleteContext
@ stub BCryptDeriveKey
@ stub BCryptDeriveKeyCapi
-@ stub BCryptDeriveKeyPBKDF2
+@ stdcall BCryptDeriveKeyPBKDF2(ptr ptr long ptr long int64 ptr long long) bcrypt.BCryptDeriveKeyPBKDF2
@ stdcall BCryptDestroyHash(ptr) bcrypt.BCryptDestroyHash
@ stdcall BCryptDestroyKey(ptr) bcrypt.BCryptDestroyKey
@ stub BCryptDestroySecret
diff --git a/include/bcrypt.h b/include/bcrypt.h
index 919da6586b..ba78c1d9d0 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -225,6 +225,7 @@ typedef PVOID BCRYPT_HASH_HANDLE;
NTSTATUS WINAPI BCryptCloseAlgorithmProvider(BCRYPT_ALG_HANDLE, ULONG);
NTSTATUS WINAPI BCryptCreateHash(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDLE *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG);
NTSTATUS WINAPI BCryptDecrypt(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG *, ULONG);
+NTSTATUS WINAPI BCryptDeriveKeyPBKDF2(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, PUCHAR, ULONG, ULONGLONG, PUCHAR, ULONG, ULONG);
NTSTATUS WINAPI BCryptDestroyHash(BCRYPT_HASH_HANDLE);
NTSTATUS WINAPI BCryptDestroyKey(BCRYPT_KEY_HANDLE);
NTSTATUS WINAPI BCryptDuplicateHash(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
--
2.20.1
1
0
[PATCH 3/4] bcrypt: Add support for importing and exporting ECC private keys.
by Hans Leidekker 13 Feb '19
by Hans Leidekker 13 Feb '19
13 Feb '19
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/bcrypt/bcrypt_internal.h | 2 +
dlls/bcrypt/bcrypt_main.c | 55 ++++++++++++++++
dlls/bcrypt/gnutls.c | 121 +++++++++++++++++++++++++++++++++-
dlls/bcrypt/macos.c | 12 ++++
dlls/bcrypt/tests/bcrypt.c | 52 +++++++++++++--
5 files changed, 237 insertions(+), 5 deletions(-)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index b6e3d0b95f..943c33d2b2 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -230,6 +230,8 @@ NTSTATUS key_asymmetric_generate( struct key * ) DECLSPEC_HIDDEN;
NTSTATUS key_asymmetric_verify( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULONG, DWORD ) DECLSPEC_HIDDEN;
NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN;
BOOL key_is_symmetric( struct key * ) DECLSPEC_HIDDEN;
+NTSTATUS key_export_ecc( struct key *, UCHAR *, ULONG, ULONG * ) DECLSPEC_HIDDEN;
+NTSTATUS key_import_ecc( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
BOOL gnutls_initialize(void) DECLSPEC_HIDDEN;
void gnutls_uninitialize(void) DECLSPEC_HIDDEN;
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 0d504b8d54..e511495eed 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -821,6 +821,10 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U
memcpy( output, key->u.a.pubkey, key->u.a.pubkey_len );
return STATUS_SUCCESS;
}
+ else if (!strcmpW( type, BCRYPT_ECCPRIVATE_BLOB ))
+ {
+ return key_export_ecc( key, output, output_len, size );
+ }
FIXME( "unsupported key type %s\n", debugstr_w(type) );
return STATUS_NOT_IMPLEMENTED;
@@ -1055,6 +1059,45 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
*ret_key = key;
return STATUS_SUCCESS;
}
+ else if (!strcmpW( type, BCRYPT_ECCPRIVATE_BLOB ))
+ {
+ BCRYPT_ECCKEY_BLOB *ecc_blob = (BCRYPT_ECCKEY_BLOB *)input;
+ DWORD key_size, magic;
+
+ if (input_len < sizeof(*ecc_blob)) return STATUS_INVALID_PARAMETER;
+
+ switch (alg->id)
+ {
+ case ALG_ID_ECDH_P256:
+ key_size = 32;
+ magic = BCRYPT_ECDH_PRIVATE_P256_MAGIC;
+ break;
+
+ default:
+ FIXME( "algorithm %u does not yet support importing blob of type %s\n", alg->id, debugstr_w(type) );
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ if (ecc_blob->dwMagic != magic) return STATUS_NOT_SUPPORTED;
+ if (ecc_blob->cbKey != key_size || input_len < sizeof(*ecc_blob) + ecc_blob->cbKey * 3)
+ return STATUS_INVALID_PARAMETER;
+
+ if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
+ key->hdr.magic = MAGIC_KEY;
+ if ((status = key_asymmetric_init( key, alg, NULL, 0 )))
+ {
+ heap_free( key );
+ return status;
+ }
+ if ((status = key_import_ecc( key, input, input_len )))
+ {
+ heap_free( key );
+ return status;
+ }
+
+ *ret_key = key;
+ return STATUS_SUCCESS;
+ }
else if (!strcmpW( type, BCRYPT_RSAPUBLIC_BLOB ))
{
BCRYPT_RSAKEY_BLOB *rsa_blob = (BCRYPT_RSAKEY_BLOB *)input;
@@ -1163,6 +1206,18 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
ERR( "support for keys not available at build time\n" );
return STATUS_NOT_IMPLEMENTED;
}
+
+NTSTATUS key_export_ecc( struct key *key, UCHAR *output, ULONG len, ULONG *ret_len )
+{
+ ERR( "support for keys not available at build time\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS key_import_ecc( struct key *key, UCHAR *input, ULONG len )
+{
+ ERR( "support for keys not available at build time\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
#endif
NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle,
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c
index 5a656ccba2..2a7e37ef8a 100644
--- a/dlls/bcrypt/gnutls.c
+++ b/dlls/bcrypt/gnutls.c
@@ -70,6 +70,8 @@ static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t);
static gnutls_sign_algorithm_t (*pgnutls_pk_to_sign)(gnutls_pk_algorithm_t, gnutls_digest_algorithm_t);
static int (*pgnutls_pubkey_import_ecc_raw)(gnutls_pubkey_t, gnutls_ecc_curve_t,
const gnutls_datum_t *, const gnutls_datum_t *);
+static int (*pgnutls_privkey_import_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_t, const gnutls_datum_t *,
+ const gnutls_datum_t *, const gnutls_datum_t *);
static int (*pgnutls_pubkey_verify_hash2)(gnutls_pubkey_t, gnutls_sign_algorithm_t, unsigned int,
const gnutls_datum_t *, const gnutls_datum_t *);
@@ -120,6 +122,13 @@ static int compat_gnutls_privkey_export_ecc_raw(gnutls_privkey_t key, gnutls_ecc
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
+static int compat_gnutls_privkey_import_ecc_raw(gnutls_privkey_t key, gnutls_ecc_curve_t curve,
+ const gnutls_datum_t *x, const gnutls_datum_t *y,
+ const gnutls_datum_t *k)
+{
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+}
+
static gnutls_sign_algorithm_t compat_gnutls_pk_to_sign(gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash)
{
return GNUTLS_SIGN_UNKNOWN;
@@ -206,6 +215,11 @@ BOOL gnutls_initialize(void)
WARN("gnutls_privkey_export_ecc_raw not found\n");
pgnutls_privkey_export_ecc_raw = compat_gnutls_privkey_export_ecc_raw;
}
+ if (!(pgnutls_privkey_import_ecc_raw = wine_dlsym( libgnutls_handle, "gnutls_privkey_import_ecc_raw", NULL, 0 )))
+ {
+ WARN("gnutls_privkey_import_ecc_raw not found\n");
+ pgnutls_privkey_import_ecc_raw = compat_gnutls_privkey_import_ecc_raw;
+ }
if (!(pgnutls_pk_to_sign = wine_dlsym( libgnutls_handle, "gnutls_pk_to_sign", NULL, 0 )))
{
WARN("gnutls_pk_to_sign not found\n");
@@ -614,11 +628,116 @@ NTSTATUS key_asymmetric_generate( struct key *key )
if ((status = export_gnutls_pubkey_ecc( handle, &key->u.a.pubkey, &key->u.a.pubkey_len )))
{
pgnutls_privkey_deinit( handle );
- return STATUS_INTERNAL_ERROR;
+ return status;
}
key->u.a.handle = handle;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS key_export_ecc( struct key *key, UCHAR *buf, ULONG len, ULONG *ret_len )
+{
+ BCRYPT_ECCKEY_BLOB *ecc_blob;
+ gnutls_ecc_curve_t curve;
+ gnutls_datum_t x, y, d;
+ DWORD magic, size;
+ UCHAR *src, *dst;
+ int ret;
+
+ if ((ret = pgnutls_privkey_export_ecc_raw( key->u.a.handle, &curve, &x, &y, &d )))
+ {
+ pgnutls_perror( ret );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ switch (curve)
+ {
+ case GNUTLS_ECC_CURVE_SECP256R1:
+ magic = BCRYPT_ECDH_PRIVATE_P256_MAGIC;
+ size = 32;
+ break;
+
+ default:
+ FIXME( "curve %u not supported\n", curve );
+ free( x.data ); free( y.data ); free( d.data );
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ *ret_len = sizeof(*ecc_blob) + size * 3;
+ if (len >= *ret_len && buf)
+ {
+ ecc_blob = (BCRYPT_ECCKEY_BLOB *)buf;
+ ecc_blob->dwMagic = magic;
+ ecc_blob->cbKey = size;
+
+ dst = (UCHAR *)(ecc_blob + 1);
+ if (x.size == size + 1) src = x.data + 1;
+ else src = x.data;
+ memcpy( dst, src, size );
+
+ dst += size;
+ if (y.size == size + 1) src = y.data + 1;
+ else src = y.data;
+ memcpy( dst, src, size );
+
+ dst += size;
+ if (d.size == size + 1) src = d.data + 1;
+ else src = d.data;
+ memcpy( dst, src, size );
+ }
+
+ free( x.data ); free( y.data ); free( d.data );
+ return STATUS_SUCCESS;
+}
+NTSTATUS key_import_ecc( struct key *key, UCHAR *buf, ULONG len )
+{
+ BCRYPT_ECCKEY_BLOB *ecc_blob;
+ gnutls_ecc_curve_t curve;
+ gnutls_privkey_t handle;
+ gnutls_datum_t x, y, k;
+ NTSTATUS status;
+ int ret;
+
+ switch (key->alg_id)
+ {
+ case ALG_ID_ECDH_P256:
+ curve = GNUTLS_ECC_CURVE_SECP256R1;
+ break;
+
+ default:
+ FIXME( "algorithm %u not yet supported\n", key->alg_id );
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ if ((ret = pgnutls_privkey_init( &handle )))
+ {
+ pgnutls_perror( ret );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ ecc_blob = (BCRYPT_ECCKEY_BLOB *)buf;
+ x.data = (unsigned char *)(ecc_blob + 1);
+ x.size = ecc_blob->cbKey;
+ y.data = x.data + ecc_blob->cbKey;
+ y.size = ecc_blob->cbKey;
+ k.data = y.data + ecc_blob->cbKey;
+ k.size = ecc_blob->cbKey;
+
+ if ((ret = pgnutls_privkey_import_ecc_raw( handle, curve, &x, &y, &k )))
+ {
+ pgnutls_perror( ret );
+ pgnutls_privkey_deinit( handle );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ if ((status = export_gnutls_pubkey_ecc( handle, &key->u.a.pubkey, &key->u.a.pubkey_len )))
+ {
+ pgnutls_privkey_deinit( handle );
+ return status;
+ }
+
+ key->u.a.handle = handle;
return STATUS_SUCCESS;
}
diff --git a/dlls/bcrypt/macos.c b/dlls/bcrypt/macos.c
index 0e0ed8379d..cc99637c4b 100644
--- a/dlls/bcrypt/macos.c
+++ b/dlls/bcrypt/macos.c
@@ -205,6 +205,18 @@ NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *hash, ULO
return STATUS_NOT_IMPLEMENTED;
}
+NTSTATUS key_export_ecc( struct key *key, UCHAR *output, ULONG len, ULONG *ret_len )
+{
+ FIXME( "not implemented on Mac\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS key_import_ecc( struct key *key, UCHAR *input, ULONG len )
+{
+ FIXME( "not implemented on Mac\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
NTSTATUS key_asymmetric_generate( struct key *key )
{
FIXME( "not implemented on Mac\n" );
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index 819c1dc886..ca7c22d5c4 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -1657,12 +1657,23 @@ static void test_RSA(void)
ok(!ret, "pBCryptCloseAlgorithmProvider failed: %08x\n", ret);
}
+static BYTE eccprivkey[] =
+{
+ 0x45, 0x43, 0x4b, 0x32, 0x20, 0x00, 0x00, 0x00, 0xfb, 0xbd, 0x3d, 0x20, 0x1b, 0x6d, 0x66, 0xb3,
+ 0x7c, 0x9f, 0x89, 0xf3, 0xe4, 0x41, 0x16, 0xa5, 0x68, 0x52, 0x77, 0xac, 0xab, 0x55, 0xb2, 0x6c,
+ 0xb0, 0x23, 0x55, 0xcb, 0x96, 0x14, 0xfd, 0x0b, 0x1c, 0xef, 0xdf, 0x07, 0x6d, 0x31, 0xaf, 0x39,
+ 0xce, 0x8c, 0x8f, 0x9d, 0x75, 0xd0, 0x7b, 0xea, 0x81, 0xdc, 0x40, 0x21, 0x1f, 0x58, 0x22, 0x5f,
+ 0x72, 0x55, 0xfc, 0x58, 0x8a, 0xeb, 0x88, 0x5d, 0x02, 0x09, 0x90, 0xd2, 0xe3, 0x36, 0xac, 0xfe,
+ 0x83, 0x13, 0x6c, 0x88, 0x1a, 0xab, 0x9b, 0xdd, 0xaa, 0x8a, 0xee, 0x69, 0x9a, 0x6a, 0x62, 0x86,
+ 0x6a, 0x13, 0x69, 0x88, 0xb7, 0xd5, 0xa3, 0xcd
+};
+
static void test_ECDH(void)
{
BYTE *buf;
BCRYPT_ECCKEY_BLOB *ecckey;
BCRYPT_ALG_HANDLE alg;
- BCRYPT_KEY_HANDLE key;
+ BCRYPT_KEY_HANDLE key, privkey, pubkey;
NTSTATUS status;
ULONG size;
@@ -1682,7 +1693,6 @@ static void test_ECDH(void)
ok(status == STATUS_SUCCESS, "got %08x\n", status);
size = 0;
- SetLastError(0xdeadbeef);
status = pBCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &size, 0);
ok(status == STATUS_SUCCESS, "got %08x\n", status);
ok(size, "size not set\n");
@@ -1694,13 +1704,47 @@ static void test_ECDH(void)
ok(ecckey->dwMagic == BCRYPT_ECDH_PUBLIC_P256_MAGIC, "got %08x\n", ecckey->dwMagic);
ok(ecckey->cbKey == 32, "got %u\n", ecckey->cbKey);
ok(size == sizeof(*ecckey) + ecckey->cbKey * 2, "got %u\n", size);
- pBCryptDestroyKey(key);
- status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &key, buf, size, 0);
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &pubkey, buf, size, 0);
ok(status == STATUS_SUCCESS, "got %08x\n", status);
HeapFree(GetProcessHeap(), 0, buf);
+ size = 0;
+ status = pBCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ok(size, "size not set\n");
+
+ buf = HeapAlloc(GetProcessHeap(), 0, size);
+ status = pBCryptExportKey(key, NULL, BCRYPT_ECCPRIVATE_BLOB, buf, size, &size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ecckey = (BCRYPT_ECCKEY_BLOB *)buf;
+ ok(ecckey->dwMagic == BCRYPT_ECDH_PRIVATE_P256_MAGIC, "got %08x\n", ecckey->dwMagic);
+ ok(ecckey->cbKey == 32, "got %u\n", ecckey->cbKey);
+ ok(size == sizeof(*ecckey) + ecckey->cbKey * 3, "got %u\n", size);
+
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPRIVATE_BLOB, &privkey, buf, size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ HeapFree(GetProcessHeap(), 0, buf);
+ pBCryptDestroyKey(pubkey);
+ pBCryptDestroyKey(privkey);
pBCryptDestroyKey(key);
+
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPRIVATE_BLOB, &privkey, eccprivkey, sizeof(eccprivkey), 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+
+ size = 0;
+ status = pBCryptExportKey(privkey, NULL, BCRYPT_ECCPRIVATE_BLOB, NULL, 0, &size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ok(size, "size not set\n");
+
+ buf = HeapAlloc(GetProcessHeap(), 0, size);
+ status = pBCryptExportKey(privkey, NULL, BCRYPT_ECCPRIVATE_BLOB, buf, size, &size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ok(size == sizeof(eccprivkey), "got %u\n", size);
+ ok(!memcmp(buf, eccprivkey, size), "wrong data\n");
+ HeapFree(GetProcessHeap(), 0, buf);
+
+ pBCryptDestroyKey(privkey);
pBCryptCloseAlgorithmProvider(alg, 0);
}
--
2.20.1
1
0
[PATCH 2/4] bcrypt: Add support for importing and exporting ECC public keys.
by Hans Leidekker 13 Feb '19
by Hans Leidekker 13 Feb '19
13 Feb '19
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/bcrypt/bcrypt_main.c | 16 +++++++++++++++-
dlls/bcrypt/tests/bcrypt.c | 22 ++++++++++++++++++++++
2 files changed, 37 insertions(+), 1 deletion(-)
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index c41c409042..0d504b8d54 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -813,6 +813,14 @@ static NTSTATUS key_export( struct key *key, const WCHAR *type, UCHAR *output, U
memcpy( output + sizeof(len), key->u.s.secret, key->u.s.secret_len );
return STATUS_SUCCESS;
}
+ else if (!strcmpW( type, BCRYPT_ECCPUBLIC_BLOB ))
+ {
+ *size = key->u.a.pubkey_len;
+ if (output_len < key->u.a.pubkey_len) return STATUS_SUCCESS;
+
+ memcpy( output, key->u.a.pubkey, key->u.a.pubkey_len );
+ return STATUS_SUCCESS;
+ }
FIXME( "unsupported key type %s\n", debugstr_w(type) );
return STATUS_NOT_IMPLEMENTED;
@@ -1012,6 +1020,11 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
switch (alg->id)
{
+ case ALG_ID_ECDH_P256:
+ key_size = 32;
+ magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC;
+ break;
+
case ALG_ID_ECDSA_P256:
key_size = 32;
magic = BCRYPT_ECDSA_PUBLIC_P256_MAGIC;
@@ -1028,7 +1041,8 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
}
if (ecc_blob->dwMagic != magic) return STATUS_NOT_SUPPORTED;
- if (ecc_blob->cbKey != key_size) return STATUS_INVALID_PARAMETER;
+ if (ecc_blob->cbKey != key_size || input_len < sizeof(*ecc_blob) + ecc_blob->cbKey * 2)
+ return STATUS_INVALID_PARAMETER;
if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
key->hdr.magic = MAGIC_KEY;
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index 7274516840..819c1dc886 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -1659,9 +1659,12 @@ static void test_RSA(void)
static void test_ECDH(void)
{
+ BYTE *buf;
+ BCRYPT_ECCKEY_BLOB *ecckey;
BCRYPT_ALG_HANDLE alg;
BCRYPT_KEY_HANDLE key;
NTSTATUS status;
+ ULONG size;
status = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDH_P256_ALGORITHM, NULL, 0);
if (status)
@@ -1678,6 +1681,25 @@ static void test_ECDH(void)
status = pBCryptFinalizeKeyPair(key, 0);
ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ size = 0;
+ SetLastError(0xdeadbeef);
+ status = pBCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ok(size, "size not set\n");
+
+ buf = HeapAlloc(GetProcessHeap(), 0, size);
+ status = pBCryptExportKey(key, NULL, BCRYPT_ECCPUBLIC_BLOB, buf, size, &size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ecckey = (BCRYPT_ECCKEY_BLOB *)buf;
+ ok(ecckey->dwMagic == BCRYPT_ECDH_PUBLIC_P256_MAGIC, "got %08x\n", ecckey->dwMagic);
+ ok(ecckey->cbKey == 32, "got %u\n", ecckey->cbKey);
+ ok(size == sizeof(*ecckey) + ecckey->cbKey * 2, "got %u\n", size);
+ pBCryptDestroyKey(key);
+
+ status = pBCryptImportKeyPair(alg, NULL, BCRYPT_ECCPUBLIC_BLOB, &key, buf, size, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ HeapFree(GetProcessHeap(), 0, buf);
+
pBCryptDestroyKey(key);
pBCryptCloseAlgorithmProvider(alg, 0);
}
--
2.20.1
1
0
[PATCH 1/4] bcrypt: Implement BCryptGenerate/FinalizeKeyPair for ECDH P256.
by Hans Leidekker 13 Feb '19
by Hans Leidekker 13 Feb '19
13 Feb '19
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46564
Signed-off-by: Hans Leidekker <hans(a)codeweavers.com>
---
dlls/bcrypt/bcrypt.spec | 4 +-
dlls/bcrypt/bcrypt_internal.h | 7 +-
dlls/bcrypt/bcrypt_main.c | 55 +++++++++++-
dlls/bcrypt/gnutls.c | 164 +++++++++++++++++++++++++++++++---
dlls/bcrypt/macos.c | 6 ++
dlls/bcrypt/tests/bcrypt.c | 87 ++++++++++++------
dlls/ncrypt/ncrypt.spec | 4 +-
include/bcrypt.h | 12 ++-
8 files changed, 290 insertions(+), 49 deletions(-)
diff --git a/dlls/bcrypt/bcrypt.spec b/dlls/bcrypt/bcrypt.spec
index 78824d73b3..891381f2a8 100644
--- a/dlls/bcrypt/bcrypt.spec
+++ b/dlls/bcrypt/bcrypt.spec
@@ -21,11 +21,11 @@
@ stub BCryptEnumProviders
@ stub BCryptEnumRegisteredProviders
@ stdcall BCryptExportKey(ptr ptr wstr ptr long ptr long)
-@ stub BCryptFinalizeKeyPair
+@ stdcall BCryptFinalizeKeyPair(ptr long)
@ stdcall BCryptFinishHash(ptr ptr long long)
@ stub BCryptFreeBuffer
@ stdcall BCryptGenRandom(ptr ptr long long)
-@ stub BCryptGenerateKeyPair
+@ stdcall BCryptGenerateKeyPair(ptr ptr long long)
@ stdcall BCryptGenerateSymmetricKey(ptr ptr ptr long ptr long long)
@ stdcall BCryptGetFipsAlgorithmMode(ptr)
@ stdcall BCryptGetProperty(ptr wstr ptr long ptr long)
diff --git a/dlls/bcrypt/bcrypt_internal.h b/dlls/bcrypt/bcrypt_internal.h
index 593e78416e..b6e3d0b95f 100644
--- a/dlls/bcrypt/bcrypt_internal.h
+++ b/dlls/bcrypt/bcrypt_internal.h
@@ -125,6 +125,7 @@ enum alg_id
ALG_ID_SHA256,
ALG_ID_SHA384,
ALG_ID_SHA512,
+ ALG_ID_ECDH_P256,
ALG_ID_ECDSA_P256,
ALG_ID_ECDSA_P384,
};
@@ -156,8 +157,9 @@ struct key_symmetric
struct key_asymmetric
{
- UCHAR *pubkey;
- ULONG pubkey_len;
+ gnutls_privkey_t handle;
+ UCHAR *pubkey;
+ ULONG pubkey_len;
};
struct key
@@ -224,6 +226,7 @@ NTSTATUS key_symmetric_encrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULO
NTSTATUS key_symmetric_decrypt( struct key *, const UCHAR *, ULONG, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_symmetric_get_tag( struct key *, UCHAR *, ULONG ) DECLSPEC_HIDDEN;
NTSTATUS key_asymmetric_init( struct key *, struct algorithm *, const UCHAR *, ULONG ) DECLSPEC_HIDDEN;
+NTSTATUS key_asymmetric_generate( struct key * ) DECLSPEC_HIDDEN;
NTSTATUS key_asymmetric_verify( struct key *, void *, UCHAR *, ULONG, UCHAR *, ULONG, DWORD ) DECLSPEC_HIDDEN;
NTSTATUS key_destroy( struct key * ) DECLSPEC_HIDDEN;
BOOL key_is_symmetric( struct key * ) DECLSPEC_HIDDEN;
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index c236491ca6..c41c409042 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -114,6 +114,7 @@ alg_props[] =
/* ALG_ID_SHA256 */ { 286, 32, 512, BCRYPT_SHA256_ALGORITHM, FALSE },
/* ALG_ID_SHA384 */ { 382, 48, 1024, BCRYPT_SHA384_ALGORITHM, FALSE },
/* ALG_ID_SHA512 */ { 382, 64, 1024, BCRYPT_SHA512_ALGORITHM, FALSE },
+ /* ALG_ID_ECDH_P256 */ { 0, 0, 0, BCRYPT_ECDH_P256_ALGORITHM, FALSE },
/* ALG_ID_ECDSA_P256 */ { 0, 0, 0, BCRYPT_ECDSA_P256_ALGORITHM, FALSE },
/* ALG_ID_ECDSA_P384 */ { 0, 0, 0, BCRYPT_ECDSA_P384_ALGORITHM, FALSE },
};
@@ -184,6 +185,7 @@ NTSTATUS WINAPI BCryptOpenAlgorithmProvider( BCRYPT_ALG_HANDLE *handle, LPCWSTR
else if (!strcmpW( id, BCRYPT_SHA256_ALGORITHM )) alg_id = ALG_ID_SHA256;
else if (!strcmpW( id, BCRYPT_SHA384_ALGORITHM )) alg_id = ALG_ID_SHA384;
else if (!strcmpW( id, BCRYPT_SHA512_ALGORITHM )) alg_id = ALG_ID_SHA512;
+ else if (!strcmpW( id, BCRYPT_ECDH_P256_ALGORITHM )) alg_id = ALG_ID_ECDH_P256;
else if (!strcmpW( id, BCRYPT_ECDSA_P256_ALGORITHM )) alg_id = ALG_ID_ECDSA_P256;
else if (!strcmpW( id, BCRYPT_ECDSA_P384_ALGORITHM )) alg_id = ALG_ID_ECDSA_P384;
else
@@ -1028,7 +1030,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
if (ecc_blob->dwMagic != magic) return STATUS_NOT_SUPPORTED;
if (ecc_blob->cbKey != key_size) return STATUS_INVALID_PARAMETER;
- if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
+ if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
key->hdr.magic = MAGIC_KEY;
if ((status = key_asymmetric_init( key, alg, (BYTE *)ecc_blob, sizeof(*ecc_blob) + ecc_blob->cbKey * 2 )))
{
@@ -1047,7 +1049,7 @@ static NTSTATUS key_import_pair( struct algorithm *alg, const WCHAR *type, BCRYP
if (input_len < sizeof(*rsa_blob)) return STATUS_INVALID_PARAMETER;
if (alg->id != ALG_ID_RSA || rsa_blob->Magic != BCRYPT_RSAPUBLIC_MAGIC) return STATUS_NOT_SUPPORTED;
- if (!(key = heap_alloc( sizeof(*key) ))) return STATUS_NO_MEMORY;
+ if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
key->hdr.magic = MAGIC_KEY;
size = sizeof(*rsa_blob) + rsa_blob->cbPublicExp + rsa_blob->cbModulus;
@@ -1089,6 +1091,18 @@ static NTSTATUS key_duplicate( struct key *key_orig, struct key *key_copy )
return STATUS_NOT_IMPLEMENTED;
}
+NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
+{
+ ERR( "support for keys not available at build time\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS key_asymmetric_generate( struct key *key )
+{
+ ERR( "support for keys not available at build time\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *hash, ULONG hash_len, UCHAR *signature,
ULONG signature_len, DWORD flags )
{
@@ -1163,6 +1177,41 @@ NTSTATUS WINAPI BCryptGenerateSymmetricKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_
return STATUS_SUCCESS;
}
+NTSTATUS WINAPI BCryptGenerateKeyPair( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE *handle, ULONG key_len,
+ ULONG flags )
+{
+ struct algorithm *alg = algorithm;
+ struct key *key;
+ NTSTATUS status;
+
+ TRACE( "%p, %p, %u, %08x\n", algorithm, handle, key_len, flags );
+
+ if (!alg || alg->hdr.magic != MAGIC_ALG) return STATUS_INVALID_HANDLE;
+ if (!handle) return STATUS_INVALID_PARAMETER;
+
+ if (!(key = heap_alloc_zero( sizeof(*key) ))) return STATUS_NO_MEMORY;
+ key->hdr.magic = MAGIC_KEY;
+
+ if ((status = key_asymmetric_init( key, alg, NULL, 0 )))
+ {
+ heap_free( key );
+ return status;
+ }
+
+ *handle = key;
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS WINAPI BCryptFinalizeKeyPair( BCRYPT_KEY_HANDLE handle, ULONG flags )
+{
+ struct key *key = handle;
+
+ TRACE( "%p, %08x\n", key, flags );
+ if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
+
+ return key_asymmetric_generate( key );
+}
+
NTSTATUS WINAPI BCryptImportKey( BCRYPT_ALG_HANDLE algorithm, BCRYPT_KEY_HANDLE decrypt_key, LPCWSTR type,
BCRYPT_KEY_HANDLE *key, PUCHAR object, ULONG object_len, PUCHAR input,
ULONG input_len, ULONG flags )
@@ -1192,7 +1241,7 @@ NTSTATUS WINAPI BCryptExportKey( BCRYPT_KEY_HANDLE export_key, BCRYPT_KEY_HANDLE
TRACE("%p, %p, %s, %p, %u, %p, %u\n", key, encrypt_key, debugstr_w(type), output, output_len, size, flags);
if (!key || key->hdr.magic != MAGIC_KEY) return STATUS_INVALID_HANDLE;
- if (!output || !type || !size) return STATUS_INVALID_PARAMETER;
+ if (!type || !size) return STATUS_INVALID_PARAMETER;
if (encrypt_key)
{
diff --git a/dlls/bcrypt/gnutls.c b/dlls/bcrypt/gnutls.c
index 69276be925..5a656ccba2 100644
--- a/dlls/bcrypt/gnutls.c
+++ b/dlls/bcrypt/gnutls.c
@@ -52,6 +52,8 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
#define GNUTLS_CIPHER_AES_256_GCM 94
#define GNUTLS_PK_ECC 4
+#define GNUTLS_CURVE_TO_BITS(curve) (unsigned int)(((unsigned int)1<<31)|((unsigned int)(curve)))
+
typedef enum
{
GNUTLS_ECC_CURVE_INVALID,
@@ -65,15 +67,20 @@ typedef enum
/* Not present in gnutls version < 3.0 */
static int (*pgnutls_cipher_tag)(gnutls_cipher_hd_t, void *, size_t);
static int (*pgnutls_cipher_add_auth)(gnutls_cipher_hd_t, const void *, size_t);
+static gnutls_sign_algorithm_t (*pgnutls_pk_to_sign)(gnutls_pk_algorithm_t, gnutls_digest_algorithm_t);
static int (*pgnutls_pubkey_import_ecc_raw)(gnutls_pubkey_t, gnutls_ecc_curve_t,
const gnutls_datum_t *, const gnutls_datum_t *);
-static gnutls_sign_algorithm_t (*pgnutls_pk_to_sign)(gnutls_pk_algorithm_t, gnutls_digest_algorithm_t);
static int (*pgnutls_pubkey_verify_hash2)(gnutls_pubkey_t, gnutls_sign_algorithm_t, unsigned int,
const gnutls_datum_t *, const gnutls_datum_t *);
/* Not present in gnutls version < 2.11.0 */
static int (*pgnutls_pubkey_import_rsa_raw)(gnutls_pubkey_t key, const gnutls_datum_t *m, const gnutls_datum_t *e);
+/* Not present in gnutls version < 3.3.0 */
+static int (*pgnutls_privkey_export_ecc_raw)(gnutls_privkey_t, gnutls_ecc_curve_t *,
+ gnutls_datum_t *, gnutls_datum_t *, gnutls_datum_t *);
+static int (*pgnutls_privkey_generate)(gnutls_privkey_t, gnutls_pk_algorithm_t, unsigned int, unsigned int);
+
static void *libgnutls_handle;
#define MAKE_FUNCPTR(f) static typeof(f) * p##f
MAKE_FUNCPTR(gnutls_cipher_decrypt2);
@@ -85,8 +92,10 @@ MAKE_FUNCPTR(gnutls_global_init);
MAKE_FUNCPTR(gnutls_global_set_log_function);
MAKE_FUNCPTR(gnutls_global_set_log_level);
MAKE_FUNCPTR(gnutls_perror);
-MAKE_FUNCPTR(gnutls_pubkey_init);
+MAKE_FUNCPTR(gnutls_privkey_deinit);
+MAKE_FUNCPTR(gnutls_privkey_init);
MAKE_FUNCPTR(gnutls_pubkey_deinit);
+MAKE_FUNCPTR(gnutls_pubkey_init);
#undef MAKE_FUNCPTR
static int compat_gnutls_cipher_tag(gnutls_cipher_hd_t handle, void *tag, size_t tag_size)
@@ -102,7 +111,13 @@ static int compat_gnutls_cipher_add_auth(gnutls_cipher_hd_t handle, const void *
static int compat_gnutls_pubkey_import_ecc_raw(gnutls_pubkey_t key, gnutls_ecc_curve_t curve,
const gnutls_datum_t *x, const gnutls_datum_t *y)
{
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+}
+
+static int compat_gnutls_privkey_export_ecc_raw(gnutls_privkey_t key, gnutls_ecc_curve_t *curve,
+ gnutls_datum_t *x, gnutls_datum_t *y, gnutls_datum_t *k)
+{
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
static gnutls_sign_algorithm_t compat_gnutls_pk_to_sign(gnutls_pk_algorithm_t pk, gnutls_digest_algorithm_t hash)
@@ -114,12 +129,18 @@ static int compat_gnutls_pubkey_verify_hash2(gnutls_pubkey_t key, gnutls_sign_al
unsigned int flags, const gnutls_datum_t *hash,
const gnutls_datum_t *signature)
{
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
static int compat_gnutls_pubkey_import_rsa_raw(gnutls_pubkey_t key, const gnutls_datum_t *m, const gnutls_datum_t *e)
{
- return GNUTLS_E_UNKNOWN_CIPHER_TYPE;
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
+}
+
+static int compat_gnutls_privkey_generate(gnutls_privkey_t key, gnutls_pk_algorithm_t algo, unsigned int bits,
+ unsigned int flags)
+{
+ return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
static void gnutls_log( int level, const char *msg )
@@ -153,8 +174,10 @@ BOOL gnutls_initialize(void)
LOAD_FUNCPTR(gnutls_global_set_log_function)
LOAD_FUNCPTR(gnutls_global_set_log_level)
LOAD_FUNCPTR(gnutls_perror)
- LOAD_FUNCPTR(gnutls_pubkey_init);
+ LOAD_FUNCPTR(gnutls_privkey_deinit);
+ LOAD_FUNCPTR(gnutls_privkey_init);
LOAD_FUNCPTR(gnutls_pubkey_deinit);
+ LOAD_FUNCPTR(gnutls_pubkey_init);
#undef LOAD_FUNCPTR
if (!(pgnutls_cipher_tag = wine_dlsym( libgnutls_handle, "gnutls_cipher_tag", NULL, 0 )))
@@ -178,6 +201,11 @@ BOOL gnutls_initialize(void)
WARN("gnutls_pubkey_import_ecc_raw not found\n");
pgnutls_pubkey_import_ecc_raw = compat_gnutls_pubkey_import_ecc_raw;
}
+ if (!(pgnutls_privkey_export_ecc_raw = wine_dlsym( libgnutls_handle, "gnutls_privkey_export_ecc_raw", NULL, 0 )))
+ {
+ WARN("gnutls_privkey_export_ecc_raw not found\n");
+ pgnutls_privkey_export_ecc_raw = compat_gnutls_privkey_export_ecc_raw;
+ }
if (!(pgnutls_pk_to_sign = wine_dlsym( libgnutls_handle, "gnutls_pk_to_sign", NULL, 0 )))
{
WARN("gnutls_pk_to_sign not found\n");
@@ -193,6 +221,11 @@ BOOL gnutls_initialize(void)
WARN("gnutls_pubkey_import_rsa_raw not found\n");
pgnutls_pubkey_import_rsa_raw = compat_gnutls_pubkey_import_rsa_raw;
}
+ if (!(pgnutls_privkey_generate = wine_dlsym( libgnutls_handle, "gnutls_privkey_generate", NULL, 0 )))
+ {
+ WARN("gnutls_privkey_generate not found\n");
+ pgnutls_privkey_generate = compat_gnutls_privkey_generate;
+ }
if (TRACE_ON( bcrypt ))
{
@@ -488,12 +521,114 @@ NTSTATUS key_symmetric_get_tag( struct key *key, UCHAR *tag, ULONG len )
return STATUS_SUCCESS;
}
+static NTSTATUS export_gnutls_pubkey_ecc( gnutls_privkey_t gnutls_key, UCHAR **pubkey, ULONG *pubkey_len )
+{
+ BCRYPT_ECCKEY_BLOB *ecc_blob;
+ gnutls_ecc_curve_t curve;
+ gnutls_datum_t x, y;
+ DWORD magic, size;
+ UCHAR *src, *dst;
+ int ret;
+
+ if ((ret = pgnutls_privkey_export_ecc_raw( gnutls_key, &curve, &x, &y, NULL )))
+ {
+ pgnutls_perror( ret );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ switch (curve)
+ {
+ case GNUTLS_ECC_CURVE_SECP256R1:
+ magic = BCRYPT_ECDH_PUBLIC_P256_MAGIC;
+ size = 32;
+ break;
+
+ default:
+ FIXME( "curve %u not supported\n", curve );
+ free( x.data ); free( y.data );
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
+ if (!(ecc_blob = heap_alloc( sizeof(*ecc_blob) + x.size + y.size )))
+ {
+ pgnutls_perror( ret );
+ free( x.data ); free( y.data );
+ return STATUS_NO_MEMORY;
+ }
+
+ ecc_blob->dwMagic = magic;
+ ecc_blob->cbKey = size;
+
+ dst = (UCHAR *)(ecc_blob + 1);
+ if (x.size == size + 1) src = x.data + 1;
+ else src = x.data;
+ memcpy( dst, src, size );
+
+ dst += size;
+ if (y.size == size + 1) src = y.data + 1;
+ else src = y.data;
+ memcpy( dst, src, size );
+
+ *pubkey = (UCHAR *)ecc_blob;
+ *pubkey_len = sizeof(*ecc_blob) + ecc_blob->cbKey * 2;
+
+ free( x.data ); free( y.data );
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS key_asymmetric_generate( struct key *key )
+{
+ gnutls_pk_algorithm_t pk_alg;
+ gnutls_ecc_curve_t curve;
+ gnutls_privkey_t handle;
+ NTSTATUS status;
+ int ret;
+
+ if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
+
+ switch (key->alg_id)
+ {
+ case ALG_ID_ECDH_P256:
+ pk_alg = GNUTLS_PK_ECC; /* compatible with ECDSA and ECDH */
+ curve = GNUTLS_ECC_CURVE_SECP256R1;
+ break;
+
+ default:
+ FIXME( "algorithm %u not supported\n", key->alg_id );
+ return STATUS_NOT_SUPPORTED;
+ }
+
+ if ((ret = pgnutls_privkey_init( &handle )))
+ {
+ pgnutls_perror( ret );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ if ((ret = pgnutls_privkey_generate( handle, pk_alg, GNUTLS_CURVE_TO_BITS(curve), 0 )))
+ {
+ pgnutls_perror( ret );
+ pgnutls_privkey_deinit( handle );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ if ((status = export_gnutls_pubkey_ecc( handle, &key->u.a.pubkey, &key->u.a.pubkey_len )))
+ {
+ pgnutls_privkey_deinit( handle );
+ return STATUS_INTERNAL_ERROR;
+ }
+
+ key->u.a.handle = handle;
+
+ return STATUS_SUCCESS;
+}
+
NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHAR *pubkey, ULONG pubkey_len )
{
if (!libgnutls_handle) return STATUS_INTERNAL_ERROR;
switch (alg->id)
{
+ case ALG_ID_ECDH_P256:
case ALG_ID_ECDSA_P256:
case ALG_ID_ECDSA_P384:
case ALG_ID_RSA:
@@ -504,10 +639,13 @@ NTSTATUS key_asymmetric_init( struct key *key, struct algorithm *alg, const UCHA
return STATUS_NOT_SUPPORTED;
}
- if (!(key->u.a.pubkey = heap_alloc( pubkey_len ))) return STATUS_NO_MEMORY;
- memcpy( key->u.a.pubkey, pubkey, pubkey_len );
- key->u.a.pubkey_len = pubkey_len;
- key->alg_id = alg->id;
+ if (pubkey_len)
+ {
+ if (!(key->u.a.pubkey = heap_alloc( pubkey_len ))) return STATUS_NO_MEMORY;
+ memcpy( key->u.a.pubkey, pubkey, pubkey_len );
+ key->u.a.pubkey_len = pubkey_len;
+ }
+ key->alg_id = alg->id;
return STATUS_SUCCESS;
}
@@ -728,7 +866,11 @@ NTSTATUS key_destroy( struct key *key )
if (key->u.s.handle) pgnutls_cipher_deinit( key->u.s.handle );
heap_free( key->u.s.secret );
}
- else heap_free( key->u.a.pubkey );
+ else
+ {
+ if (key->u.a.handle) pgnutls_privkey_deinit( key->u.a.handle );
+ heap_free( key->u.a.pubkey );
+ }
heap_free( key );
return STATUS_SUCCESS;
}
diff --git a/dlls/bcrypt/macos.c b/dlls/bcrypt/macos.c
index a6eaee8b1d..0e0ed8379d 100644
--- a/dlls/bcrypt/macos.c
+++ b/dlls/bcrypt/macos.c
@@ -205,6 +205,12 @@ NTSTATUS key_asymmetric_verify( struct key *key, void *padding, UCHAR *hash, ULO
return STATUS_NOT_IMPLEMENTED;
}
+NTSTATUS key_asymmetric_generate( struct key *key )
+{
+ FIXME( "not implemented on Mac\n" );
+ return STATUS_NOT_IMPLEMENTED;
+}
+
NTSTATUS key_destroy( struct key *key )
{
if (key->u.s.ref_encrypt) CCCryptorRelease( key->u.s.ref_encrypt );
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index 5240c3bafb..7274516840 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -26,31 +26,34 @@
#include "wine/test.h"
-static NTSTATUS (WINAPI *pBCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE *, LPCWSTR, LPCWSTR, ULONG);
static NTSTATUS (WINAPI *pBCryptCloseAlgorithmProvider)(BCRYPT_ALG_HANDLE, ULONG);
-static NTSTATUS (WINAPI *pBCryptGetFipsAlgorithmMode)(BOOLEAN *);
static NTSTATUS (WINAPI *pBCryptCreateHash)(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDLE *, PUCHAR, ULONG, PUCHAR,
ULONG, ULONG);
-static NTSTATUS (WINAPI *pBCryptHash)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG, UCHAR *, ULONG, UCHAR *, ULONG);
-static NTSTATUS (WINAPI *pBCryptHashData)(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptDecrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG,
+ ULONG *, ULONG);
+static NTSTATUS (WINAPI *pBCryptDestroyHash)(BCRYPT_HASH_HANDLE);
+static NTSTATUS (WINAPI *pBCryptDestroyKey)(BCRYPT_KEY_HANDLE);
static NTSTATUS (WINAPI *pBCryptDuplicateHash)(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptDuplicateKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptEncrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG,
+ ULONG *, ULONG);
+static NTSTATUS (WINAPI *pBCryptExportKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
+static NTSTATUS (WINAPI *pBCryptFinalizeKeyPair)(BCRYPT_KEY_HANDLE, ULONG);
static NTSTATUS (WINAPI *pBCryptFinishHash)(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
-static NTSTATUS (WINAPI *pBCryptDestroyHash)(BCRYPT_HASH_HANDLE);
-static NTSTATUS (WINAPI *pBCryptGenRandom)(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, ULONG);
-static NTSTATUS (WINAPI *pBCryptGetProperty)(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
-static NTSTATUS (WINAPI *pBCryptSetProperty)(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptGenerateKeyPair)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE *, ULONG, ULONG);
static NTSTATUS (WINAPI *pBCryptGenerateSymmetricKey)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE *, PUCHAR, ULONG,
PUCHAR, ULONG, ULONG);
-static NTSTATUS (WINAPI *pBCryptEncrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG,
- ULONG *, ULONG);
-static NTSTATUS (WINAPI *pBCryptDecrypt)(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG,
- ULONG *, ULONG);
-static NTSTATUS (WINAPI *pBCryptDuplicateKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
-static NTSTATUS (WINAPI *pBCryptDestroyKey)(BCRYPT_KEY_HANDLE);
+static NTSTATUS (WINAPI *pBCryptGetFipsAlgorithmMode)(BOOLEAN *);
+static NTSTATUS (WINAPI *pBCryptGetProperty)(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
+static NTSTATUS (WINAPI *pBCryptGenRandom)(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptHash)(BCRYPT_ALG_HANDLE, UCHAR *, ULONG, UCHAR *, ULONG, UCHAR *, ULONG);
+static NTSTATUS (WINAPI *pBCryptHashData)(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
static NTSTATUS (WINAPI *pBCryptImportKey)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *,
PUCHAR, ULONG, PUCHAR, ULONG, ULONG);
-static NTSTATUS (WINAPI *pBCryptExportKey)(BCRYPT_KEY_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG *, ULONG);
-static NTSTATUS (WINAPI *pBCryptImportKeyPair)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptImportKeyPair)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *,
+ UCHAR *, ULONG, ULONG);
+static NTSTATUS (WINAPI *pBCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE *, LPCWSTR, LPCWSTR, ULONG);
+static NTSTATUS (WINAPI *pBCryptSetProperty)(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG);
static NTSTATUS (WINAPI *pBCryptVerifySignature)(BCRYPT_KEY_HANDLE, VOID *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG);
static void test_BCryptGenRandom(void)
@@ -1654,6 +1657,31 @@ static void test_RSA(void)
ok(!ret, "pBCryptCloseAlgorithmProvider failed: %08x\n", ret);
}
+static void test_ECDH(void)
+{
+ BCRYPT_ALG_HANDLE alg;
+ BCRYPT_KEY_HANDLE key;
+ NTSTATUS status;
+
+ status = pBCryptOpenAlgorithmProvider(&alg, BCRYPT_ECDH_P256_ALGORITHM, NULL, 0);
+ if (status)
+ {
+ skip("Failed to open BCRYPT_ECDH_P256_ALGORITHM provider %08x\n", status);
+ return;
+ }
+
+ key = NULL;
+ status = pBCryptGenerateKeyPair(alg, &key, 256, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+ ok(key != NULL, "key not set\n");
+
+ status = pBCryptFinalizeKeyPair(key, 0);
+ ok(status == STATUS_SUCCESS, "got %08x\n", status);
+
+ pBCryptDestroyKey(key);
+ pBCryptCloseAlgorithmProvider(alg, 0);
+}
+
START_TEST(bcrypt)
{
HMODULE module;
@@ -1665,26 +1693,28 @@ START_TEST(bcrypt)
return;
}
- pBCryptOpenAlgorithmProvider = (void *)GetProcAddress(module, "BCryptOpenAlgorithmProvider");
pBCryptCloseAlgorithmProvider = (void *)GetProcAddress(module, "BCryptCloseAlgorithmProvider");
- pBCryptGetFipsAlgorithmMode = (void *)GetProcAddress(module, "BCryptGetFipsAlgorithmMode");
pBCryptCreateHash = (void *)GetProcAddress(module, "BCryptCreateHash");
- pBCryptHash = (void *)GetProcAddress(module, "BCryptHash");
- pBCryptHashData = (void *)GetProcAddress(module, "BCryptHashData");
+ pBCryptDecrypt = (void *)GetProcAddress(module, "BCryptDecrypt");
+ pBCryptDestroyHash = (void *)GetProcAddress(module, "BCryptDestroyHash");
+ pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey");
pBCryptDuplicateHash = (void *)GetProcAddress(module, "BCryptDuplicateHash");
+ pBCryptDuplicateKey = (void *)GetProcAddress(module, "BCryptDuplicateKey");
+ pBCryptEncrypt = (void *)GetProcAddress(module, "BCryptEncrypt");
+ pBCryptExportKey = (void *)GetProcAddress(module, "BCryptExportKey");
+ pBCryptFinalizeKeyPair = (void *)GetProcAddress(module, "BCryptFinalizeKeyPair");
pBCryptFinishHash = (void *)GetProcAddress(module, "BCryptFinishHash");
- pBCryptDestroyHash = (void *)GetProcAddress(module, "BCryptDestroyHash");
+ pBCryptGenerateKeyPair = (void *)GetProcAddress(module, "BCryptGenerateKeyPair");
+ pBCryptGenerateSymmetricKey = (void *)GetProcAddress(module, "BCryptGenerateSymmetricKey");
pBCryptGenRandom = (void *)GetProcAddress(module, "BCryptGenRandom");
+ pBCryptGetFipsAlgorithmMode = (void *)GetProcAddress(module, "BCryptGetFipsAlgorithmMode");
pBCryptGetProperty = (void *)GetProcAddress(module, "BCryptGetProperty");
- pBCryptSetProperty = (void *)GetProcAddress(module, "BCryptSetProperty");
- pBCryptGenerateSymmetricKey = (void *)GetProcAddress(module, "BCryptGenerateSymmetricKey");
- pBCryptEncrypt = (void *)GetProcAddress(module, "BCryptEncrypt");
- pBCryptDecrypt = (void *)GetProcAddress(module, "BCryptDecrypt");
- pBCryptDuplicateKey = (void *)GetProcAddress(module, "BCryptDuplicateKey");
- pBCryptDestroyKey = (void *)GetProcAddress(module, "BCryptDestroyKey");
+ pBCryptHash = (void *)GetProcAddress(module, "BCryptHash");
+ pBCryptHashData = (void *)GetProcAddress(module, "BCryptHashData");
pBCryptImportKey = (void *)GetProcAddress(module, "BCryptImportKey");
- pBCryptExportKey = (void *)GetProcAddress(module, "BCryptExportKey");
pBCryptImportKeyPair = (void *)GetProcAddress(module, "BCryptImportKeyPair");
+ pBCryptOpenAlgorithmProvider = (void *)GetProcAddress(module, "BCryptOpenAlgorithmProvider");
+ pBCryptSetProperty = (void *)GetProcAddress(module, "BCryptSetProperty");
pBCryptVerifySignature = (void *)GetProcAddress(module, "BCryptVerifySignature");
test_BCryptGenRandom();
@@ -1698,6 +1728,7 @@ START_TEST(bcrypt)
test_key_import_export();
test_ECDSA();
test_RSA();
+ test_ECDH();
if (pBCryptHash) /* >= Win 10 */
test_BcryptHash();
diff --git a/dlls/ncrypt/ncrypt.spec b/dlls/ncrypt/ncrypt.spec
index e7b12e0059..c6e7f7fb6f 100644
--- a/dlls/ncrypt/ncrypt.spec
+++ b/dlls/ncrypt/ncrypt.spec
@@ -23,11 +23,11 @@
@ stub BCryptEnumProviders
@ stub BCryptEnumRegisteredProviders
@ stdcall BCryptExportKey(ptr ptr wstr ptr long ptr long) bcrypt.BCryptExportKey
-@ stub BCryptFinalizeKeyPair
+@ stdcall BCryptFinalizeKeyPair(ptr long) bcrypt.BCryptFinalizeKeyPair
@ stdcall BCryptFinishHash(ptr ptr long long) bcrypt.BCryptFinishHash
@ stub BCryptFreeBuffer
@ stdcall BCryptGenRandom(ptr ptr long long) bcrypt.BCryptGenRandom
-@ stub BCryptGenerateKeyPair
+@ stdcall BCryptGenerateKeyPair(ptr ptr long long) bcrypt.BCryptGenerateKeyPair
@ stdcall BCryptGenerateSymmetricKey(ptr ptr ptr long ptr long long) bcrypt.BCryptGenerateSymmetricKey
@ stdcall BCryptGetFipsAlgorithmMode(ptr) bcrypt.BCryptGetFipsAlgorithmMode
@ stdcall BCryptGetProperty(ptr wstr ptr long ptr long) bcrypt.BCryptGetProperty
diff --git a/include/bcrypt.h b/include/bcrypt.h
index df54f621fa..919da6586b 100644
--- a/include/bcrypt.h
+++ b/include/bcrypt.h
@@ -81,6 +81,7 @@ typedef LONG NTSTATUS;
#define BCRYPT_SHA256_ALGORITHM (const WCHAR []){'S','H','A','2','5','6',0}
#define BCRYPT_SHA384_ALGORITHM (const WCHAR []){'S','H','A','3','8','4',0}
#define BCRYPT_SHA512_ALGORITHM (const WCHAR []){'S','H','A','5','1','2',0}
+#define BCRYPT_ECDH_P256_ALGORITHM (const WCHAR []){'E','C','D','H','_','P','2','5','6',0}
#define BCRYPT_ECDSA_P256_ALGORITHM (const WCHAR []){'E','C','D','S','A','_','P','2','5','6',0}
#define BCRYPT_ECDSA_P384_ALGORITHM (const WCHAR []){'E','C','D','S','A','_','P','3','8','4',0}
#define BCRYPT_ECDSA_P521_ALGORITHM (const WCHAR []){'E','C','D','S','A','_','P','5','2','1',0}
@@ -99,6 +100,13 @@ typedef LONG NTSTATUS;
#define BCRYPT_ECDSA_PUBLIC_P521_MAGIC 0x35534345
#define BCRYPT_ECDSA_PRIVATE_P521_MAGIC 0x36534345
+#define BCRYPT_ECDH_PUBLIC_P256_MAGIC 0x314b4345
+#define BCRYPT_ECDH_PRIVATE_P256_MAGIC 0x324b4345
+#define BCRYPT_ECDH_PUBLIC_P384_MAGIC 0x334b4345
+#define BCRYPT_ECDH_PRIVATE_P384_MAGIC 0x344b4345
+#define BCRYPT_ECDH_PUBLIC_P521_MAGIC 0x354b4345
+#define BCRYPT_ECDH_PRIVATE_P521_MAGIC 0x364b4345
+
typedef struct _BCRYPT_ALGORITHM_IDENTIFIER
{
LPWSTR pszName;
@@ -219,9 +227,12 @@ NTSTATUS WINAPI BCryptCreateHash(BCRYPT_ALG_HANDLE, BCRYPT_HASH_HANDLE *, PUCHAR
NTSTATUS WINAPI BCryptDecrypt(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG *, ULONG);
NTSTATUS WINAPI BCryptDestroyHash(BCRYPT_HASH_HANDLE);
NTSTATUS WINAPI BCryptDestroyKey(BCRYPT_KEY_HANDLE);
+NTSTATUS WINAPI BCryptDuplicateHash(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
NTSTATUS WINAPI BCryptEncrypt(BCRYPT_KEY_HANDLE, PUCHAR, ULONG, VOID *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG *, ULONG);
NTSTATUS WINAPI BCryptEnumAlgorithms(ULONG, ULONG *, BCRYPT_ALGORITHM_IDENTIFIER **, ULONG);
+NTSTATUS WINAPI BCryptFinalizeKeyPair(BCRYPT_KEY_HANDLE, ULONG);
NTSTATUS WINAPI BCryptFinishHash(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
+NTSTATUS WINAPI BCryptGenerateKeyPair(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE *, ULONG, ULONG);
NTSTATUS WINAPI BCryptGenerateSymmetricKey(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE *, PUCHAR, ULONG, PUCHAR, ULONG, ULONG);
NTSTATUS WINAPI BCryptGenRandom(BCRYPT_ALG_HANDLE, PUCHAR, ULONG, ULONG);
NTSTATUS WINAPI BCryptGetFipsAlgorithmMode(BOOLEAN *);
@@ -231,7 +242,6 @@ NTSTATUS WINAPI BCryptHashData(BCRYPT_HASH_HANDLE, PUCHAR, ULONG, ULONG);
NTSTATUS WINAPI BCryptImportKeyPair(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE, LPCWSTR, BCRYPT_KEY_HANDLE *, UCHAR *, ULONG, ULONG);
NTSTATUS WINAPI BCryptOpenAlgorithmProvider(BCRYPT_ALG_HANDLE *, LPCWSTR, LPCWSTR, ULONG);
NTSTATUS WINAPI BCryptSetProperty(BCRYPT_HANDLE, LPCWSTR, PUCHAR, ULONG, ULONG);
-NTSTATUS WINAPI BCryptDuplicateHash(BCRYPT_HASH_HANDLE, BCRYPT_HASH_HANDLE *, UCHAR *, ULONG, ULONG);
NTSTATUS WINAPI BCryptVerifySignature(BCRYPT_KEY_HANDLE, void *, UCHAR *, ULONG, UCHAR *, ULONG, ULONG);
#endif /* __WINE_BCRYPT_H */
--
2.20.1
1
0
Signed-off-by: Daniel Lehman <dlehman25(a)gmail.com>
---
v2:
- call LCMapString
- rearrange and squash commits
---
dlls/kernel32/tests/locale.c | 187 +++++++++++++++++++++++++++++++++++
1 file changed, 187 insertions(+)
diff --git a/dlls/kernel32/tests/locale.c b/dlls/kernel32/tests/locale.c
index 0c05311a20..5b7b5fe1dc 100644
--- a/dlls/kernel32/tests/locale.c
+++ b/dlls/kernel32/tests/locale.c
@@ -5776,6 +5776,192 @@ todo_wine_if(ptest->todo[i])
}
}
+static void test_SpecialCasing(void)
+{
+ WCHAR exp;
+ int ret, i;
+ WCHAR buffer[8];
+ static const WCHAR azCyrlazW[] = {'a','z','-','C','y','r','l','-','a','z',0};
+ static const WCHAR azLatnazW[] = {'a','z','-','L','a','t','n','-','a','z',0};
+ static const WCHAR deDEW[] = {'d','e','-','D','E',0};
+ static const WCHAR elGRW[] = {'e','l','-','G','R',0};
+ static const WCHAR enUSW[] = {'e','n','-','U','S',0};
+ static const WCHAR hyAMW[] = {'h','y','-','A','M',0};
+ static const WCHAR ltLTW[] = {'l','t','-','L','T',0};
+ static const WCHAR trTRW[] = {'t','r','-','T','R',0};
+ static const WCHAR TRTRW[] = {'T','R','-','T','R',0};
+ struct test {
+ const WCHAR *lang;
+ DWORD flags;
+ WCHAR ch;
+ WCHAR exp; /* 0 if self */
+ WCHAR exp_ling; /* 0 if exp */
+ BOOL todo;
+ BOOL todo_ling;
+ } tests[] = {
+ {deDEW, LCMAP_UPPERCASE, 0x00DF}, /* LATIN SMALL LETTER SHARP S */
+
+ {enUSW, LCMAP_UPPERCASE, 0xFB00}, /* LATIN SMALL LIGATURE FF */
+ {enUSW, LCMAP_UPPERCASE, 0xFB01}, /* LATIN SMALL LIGATURE FI */
+ {enUSW, LCMAP_UPPERCASE, 0xFB02}, /* LATIN SMALL LIGATURE FL */
+ {enUSW, LCMAP_UPPERCASE, 0xFB03}, /* LATIN SMALL LIGATURE FFI */
+ {enUSW, LCMAP_UPPERCASE, 0xFB04}, /* LATIN SMALL LIGATURE FFL */
+ {enUSW, LCMAP_UPPERCASE, 0xFB05}, /* LATIN SMALL LIGATURE LONG S T */
+ {enUSW, LCMAP_UPPERCASE, 0xFB06}, /* LATIN SMALL LIGATURE ST */
+
+ {hyAMW, LCMAP_UPPERCASE, 0x0587}, /* ARMENIAN SMALL LIGATURE ECH YIWN */
+ {hyAMW, LCMAP_UPPERCASE, 0xFB13}, /* ARMENIAN SMALL LIGATURE MEN NOW */
+ {hyAMW, LCMAP_UPPERCASE, 0xFB14}, /* ARMENIAN SMALL LIGATURE MEN ECH */
+ {hyAMW, LCMAP_UPPERCASE, 0xFB15}, /* ARMENIAN SMALL LIGATURE MEN INI */
+ {hyAMW, LCMAP_UPPERCASE, 0xFB16}, /* ARMENIAN SMALL LIGATURE VEW NOW */
+ {hyAMW, LCMAP_UPPERCASE, 0xFB17}, /* ARMENIAN SMALL LIGATURE MEN XEH */
+
+ {enUSW, LCMAP_UPPERCASE, 0x0149}, /* LATIN SMALL LETTER N PRECEDED BY APOSTROPHE */
+ {elGRW, LCMAP_UPPERCASE, 0x0390}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */
+ {elGRW, LCMAP_UPPERCASE, 0x03B0}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */
+ {enUSW, LCMAP_UPPERCASE, 0x01F0}, /* LATIN SMALL LETTER J WITH CARON */
+ {enUSW, LCMAP_UPPERCASE, 0x1E96}, /* LATIN SMALL LETTER H WITH LINE BELOW */
+ {enUSW, LCMAP_UPPERCASE, 0x1E97}, /* LATIN SMALL LETTER T WITH DIAERESIS */
+ {enUSW, LCMAP_UPPERCASE, 0x1E98}, /* LATIN SMALL LETTER W WITH RING ABOVE */
+ {enUSW, LCMAP_UPPERCASE, 0x1E99}, /* LATIN SMALL LETTER Y WITH RING ABOVE */
+ {enUSW, LCMAP_UPPERCASE, 0x1E9A}, /* LATIN SMALL LETTER A WITH RIGHT HALF RING */
+ {elGRW, LCMAP_UPPERCASE, 0x1F50}, /* GREEK SMALL LETTER UPSILON WITH PSILI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F52}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA */
+ {elGRW, LCMAP_UPPERCASE, 0x1F54}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA */
+ {elGRW, LCMAP_UPPERCASE, 0x1F56}, /* GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FB6}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FC6}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FD2}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA */
+ {elGRW, LCMAP_UPPERCASE, 0x1FD3}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA */
+ {elGRW, LCMAP_UPPERCASE, 0x1FD6}, /* GREEK SMALL LETTER IOTA WITH PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FD7}, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FE2}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA */
+ {elGRW, LCMAP_UPPERCASE, 0x1FE3}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA */
+ {elGRW, LCMAP_UPPERCASE, 0x1FE4}, /* GREEK SMALL LETTER RHO WITH PSILI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FE6}, /* GREEK SMALL LETTER UPSILON WITH PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FE7}, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FF6}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI */
+
+ {elGRW, LCMAP_UPPERCASE, 0x1F80,0x1F88}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F81,0x1F89}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F82,0x1F8A}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F83,0x1F8B}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F84,0x1F8C}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F85,0x1F8D}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F86,0x1F8E}, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F87,0x1F8F}, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+
+ {elGRW, LCMAP_LOWERCASE, 0x1F88,0x1F80}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F89,0x1F81}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F8A,0x1F82}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F8B,0x1F83}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F8C,0x1F84}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F8D,0x1F85}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F8E,0x1F86}, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1F8F,0x1F87}, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+
+ {elGRW, LCMAP_UPPERCASE, 0x1F90,0x1F98}, /* GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F91,0x1F99}, /* GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F92,0x1F9A}, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F93,0x1F9B}, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F94,0x1F9C}, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F95,0x1F9D}, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F96,0x1F9E}, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1F97,0x1F9F}, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI */
+
+ {elGRW, LCMAP_LOWERCASE, 0x1FA8,0x1FA0}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FA9,0x1FA1}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FAA,0x1FA2}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FAB,0x1FA3}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FAC,0x1FA4}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FAD,0x1FA5}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FAE,0x1FA6}, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FAF,0x1FA7}, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI */
+
+ {elGRW, LCMAP_UPPERCASE, 0x1FB3,0x1FBC}, /* GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FBC,0x1FB3}, /* GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FC3,0x1FCC}, /* GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FCC,0x1FC3}, /* GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FF3,0x1FFC}, /* GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI */
+ {elGRW, LCMAP_LOWERCASE, 0x1FFC,0x1FF3}, /* GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI */
+
+ {elGRW, LCMAP_UPPERCASE, 0x1FB2}, /* GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FB4}, /* GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FC2}, /* GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FC4}, /* GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FF2}, /* GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FF4}, /* GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI */
+
+ {elGRW, LCMAP_UPPERCASE, 0x1FB7}, /* GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FC7}, /* GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI */
+ {elGRW, LCMAP_UPPERCASE, 0x1FF7}, /* GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI */
+
+ {elGRW, LCMAP_LOWERCASE, 0x03A3,0x03C3}, /* GREEK CAPITAL LETTER SIGMA */
+
+ {ltLTW, LCMAP_LOWERCASE, 'J','j'}, /* LATIN CAPITAL LETTER J */
+ {ltLTW, LCMAP_LOWERCASE, 0x012E,0x012F}, /* LATIN CAPITAL LETTER I WITH OGONEK */
+ {ltLTW, LCMAP_LOWERCASE, 0x00CC,0x00EC}, /* LATIN CAPITAL LETTER I WITH GRAVE */
+ {ltLTW, LCMAP_LOWERCASE, 0x00CD,0x00ED}, /* LATIN CAPITAL LETTER I WITH ACUTE */
+ {ltLTW, LCMAP_LOWERCASE, 0x0128,0x0129}, /* LATIN CAPITAL LETTER I WITH TILDE */
+
+ {enUSW, LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
+ {ltLTW, LCMAP_UPPERCASE, 'i', 'I'}, /* LATIN SMALL LETTER I */
+ {trTRW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, FALSE, TRUE}, /* LATIN SMALL LETTER I */
+ {TRTRW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, FALSE, TRUE}, /* LATIN SMALL LETTER I */
+ {azCyrlazW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, FALSE, TRUE}, /* LATIN SMALL LETTER I */
+ {azLatnazW, LCMAP_UPPERCASE, 'i', 'I', 0x0130, FALSE, TRUE}, /* LATIN SMALL LETTER I */
+
+ {enUSW, LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
+ {ltLTW, LCMAP_LOWERCASE, 'I', 'i'}, /* LATIN CAPITAL LETTER I */
+ {trTRW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, FALSE, TRUE}, /* LATIN CAPITAL LETTER I */
+ {TRTRW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, FALSE, TRUE}, /* LATIN CAPITAL LETTER I */
+ {azCyrlazW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, FALSE, TRUE}, /* LATIN CAPITAL LETTER I */
+ {azLatnazW, LCMAP_LOWERCASE, 'I', 'i', 0x0131, FALSE, TRUE}, /* LATIN CAPITAL LETTER I */
+
+ {enUSW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ {trTRW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ {TRTRW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ {azCyrlazW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+ {azLatnazW, LCMAP_LOWERCASE, 0x0130,0,'i', TRUE}, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */
+
+ {enUSW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
+ {trTRW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
+ {TRTRW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
+ {azCyrlazW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
+ {azLatnazW, LCMAP_UPPERCASE, 0x0131,0,'I', TRUE}, /* LATIN SMALL LETTER DOTLESS I */
+ };
+
+ if (!pLCMapStringEx)
+ {
+ win_skip("LCMapStringEx not available\n");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ memset(buffer, 0, sizeof(buffer));
+ ret = pLCMapStringEx(tests[i].lang, tests[i].flags,
+ &tests[i].ch, 1, buffer, ARRAY_SIZE(buffer), NULL, NULL, 0);
+ ok(ret == 1, "expected 1, got %d for %04x for %s\n", ret, tests[i].ch,
+ wine_dbgstr_w(tests[i].lang));
+ exp = tests[i].exp ? tests[i].exp : tests[i].ch;
+ todo_wine_if(tests[i].todo)
+ ok(buffer[0] == exp || broken(buffer[0] != exp),
+ "expected %04x, got %04x for %04x for %s\n",
+ exp, buffer[0], tests[i].ch, wine_dbgstr_w(tests[i].lang));
+
+ memset(buffer, 0, sizeof(buffer));
+ ret = pLCMapStringEx(tests[i].lang, tests[i].flags|LCMAP_LINGUISTIC_CASING,
+ &tests[i].ch, 1, buffer, ARRAY_SIZE(buffer), NULL, NULL, 0);
+ ok(ret == 1, "expected 1, got %d for %04x for %s\n", ret, tests[i].ch,
+ wine_dbgstr_w(tests[i].lang));
+ exp = tests[i].exp_ling ? tests[i].exp_ling : exp;
+ todo_wine_if(tests[i].todo_ling)
+ ok(buffer[0] == exp || broken(buffer[0] != exp),
+ "expected %04x, got %04x for %04x for %s\n",
+ exp, buffer[0], tests[i].ch, wine_dbgstr_w(tests[i].lang));
+ }
+}
+
START_TEST(locale)
{
InitFunctionPointers();
@@ -5826,6 +6012,7 @@ START_TEST(locale)
test_FindStringOrdinal();
test_SetThreadUILanguage();
test_NormalizeString();
+ test_SpecialCasing();
/* this requires collation table patch to make it MS compatible */
if (0) test_sorting();
}
--
2.17.1
2
4