From 43788445840df8a1e043501941864eac8c3518dc Mon Sep 17 00:00:00 2001 From: Kimura Yukihiro Date: Tue, 22 Feb 2022 17:44:56 +0000 Subject: [PATCH 01/10] 8254085: javax/swing/text/Caret/TestCaretPositionJTextPane.java failed with "RuntimeException: Wrong caret position" Backport-of: 51a865d66a5dddbbaaa4bb656fa02ecd1bee1a0b --- test/jdk/javax/swing/text/Caret/TestCaretPositionJTextPane.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/javax/swing/text/Caret/TestCaretPositionJTextPane.java b/test/jdk/javax/swing/text/Caret/TestCaretPositionJTextPane.java index 84750e5974a..a6928dbb532 100644 --- a/test/jdk/javax/swing/text/Caret/TestCaretPositionJTextPane.java +++ b/test/jdk/javax/swing/text/Caret/TestCaretPositionJTextPane.java @@ -98,7 +98,7 @@ public static void main(String args[]) throws Exception { robot.waitForIdle(); Point p = textPane.getLocationOnScreen(); - robot.mouseMove(p.x+ 480, p.y+6); + robot.mouseMove(p.x+ 380, p.y+6); robot.waitForIdle(); robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); robot.waitForIdle(); From ffa5ae86c93774089b29f0a1d73e7273c40d7174 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 23 Feb 2022 13:42:17 +0000 Subject: [PATCH 02/10] 8247515: OSX pc_to_symbol() lookup does not work with core files Backport-of: ab729d7075d718b146b643d1b4c2735adaeb7194 --- .../macosx/native/libsaproc/libproc_impl.c | 17 ++-- .../macosx/native/libsaproc/libproc_impl.h | 9 +- .../macosx/native/libsaproc/ps_core.c | 22 +++-- .../macosx/native/libsaproc/symtab.c | 96 +++++++++++++------ 4 files changed, 100 insertions(+), 44 deletions(-) diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c index a7e4b0b5874..ed61b6d1cac 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -208,11 +208,11 @@ void Prelease(struct ps_prochandle* ph) { free(ph); } -lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { - return add_lib_info_fd(ph, libname, -1, base); +lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base, size_t memsz) { + return add_lib_info_fd(ph, libname, -1, base, memsz); } -lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { +lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base, size_t memsz) { lib_info* newlib; print_debug("add_lib_info_fd %s\n", libname); @@ -229,6 +229,7 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, strcpy(newlib->name, libname); newlib->base = base; + newlib->memsz = memsz; if (fd == -1) { if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { @@ -262,7 +263,7 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, if (newlib->symtab == NULL) { print_debug("symbol table build failed for %s\n", newlib->name); } else { - print_debug("built symbol table for %s\n", newlib->name); + print_debug("built symbol table for 0x%lx %s\n", newlib, newlib->name); } // even if symbol table building fails, we add the lib_info. @@ -305,8 +306,12 @@ uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { const char* res = NULL; lib_info* lib = ph->libs; + print_debug("symbol_for_pc: addr 0x%lx\n", addr); while (lib) { - if (lib->symtab && addr >= lib->base) { + print_debug("symbol_for_pc: checking lib 0x%lx 0x%lx %s\n", lib->base, lib->memsz, lib->name); + if (lib->symtab && addr >= lib->base && addr < lib->base + lib->memsz) { + print_debug("symbol_for_pc: address=0x%lx offset=0x%lx found inside lib base=0x%lx memsz=0x%lx %s\n", + addr, addr - lib->base, lib->base, lib->memsz, lib->name); res = nearest_symbol(lib->symtab, addr - lib->base, poffset); if (res) return res; } diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h index 8b4af29cc3a..a7cfeaaf209 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h @@ -149,6 +149,7 @@ typedef struct lib_info { struct symtab* symtab; int fd; // file descriptor for lib struct lib_info* next; + size_t memsz; } lib_info; // list of threads @@ -162,8 +163,8 @@ typedef struct sa_thread_info { // list of virtual memory maps typedef struct map_info { int fd; // file descriptor - off_t offset; // file offset of this mapping - uintptr_t vaddr; // starting virtual address + uint64_t offset; // file offset of this mapping + uint64_t vaddr; // starting virtual address size_t memsz; // size of the mapping struct map_info* next; } map_info; @@ -224,11 +225,11 @@ typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lw bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb); // adds a new shared object to lib list, returns NULL on failure -lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base); +lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base, size_t memsz); // adds a new shared object to lib list, supply open lib file descriptor as well lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, - uintptr_t base); + uintptr_t base, size_t memsz); sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); // a test for ELF signature without using libelf diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c index cd52e765851..f8aaac0cae7 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c @@ -615,6 +615,7 @@ static bool read_core_segments(struct ps_prochandle* ph) { goto err; } offset += lcmd.cmdsize; // next command position + //print_debug("LC: 0x%x\n", lcmd.cmd); if (lcmd.cmd == LC_SEGMENT_64) { lseek(fd, -sizeof(load_command), SEEK_CUR); if (read(fd, (void *)&segcmd, sizeof(segment_command_64)) != sizeof(segment_command_64)) { @@ -625,8 +626,9 @@ static bool read_core_segments(struct ps_prochandle* ph) { print_debug("Failed to add map_info at i = %d\n", i); goto err; } - print_debug("segment added: %" PRIu64 " 0x%" PRIx64 " %d\n", - segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize); + print_debug("LC_SEGMENT_64 added: nsects=%d fileoff=0x%llx vmaddr=0x%llx vmsize=0x%llx filesize=0x%llx %s\n", + segcmd.nsects, segcmd.fileoff, segcmd.vmaddr, segcmd.vmsize, + segcmd.filesize, &segcmd.segname[0]); } else if (lcmd.cmd == LC_THREAD || lcmd.cmd == LC_UNIXTHREAD) { typedef struct thread_fc { uint32_t flavor; @@ -898,7 +900,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { // only search core file! continue; } - print_debug("map_info %d: vmaddr = 0x%016" PRIx64 " fileoff = %" PRIu64 " vmsize = %" PRIu64 "\n", + print_debug("map_info %d: vmaddr = 0x%016llx fileoff = 0x%llx vmsize = 0x%lx\n", j, iter->vaddr, iter->offset, iter->memsz); lseek(fd, fpos, SEEK_SET); // we assume .dylib loaded at segment address --- which is true for JVM libraries @@ -922,7 +924,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { continue; } lseek(fd, -sizeof(uint32_t), SEEK_CUR); - // this is the file begining to core file. + // This is the begining of the mach-o file in the segment. if (read(fd, (void *)&header, sizeof(mach_header_64)) != sizeof(mach_header_64)) { goto err; } @@ -955,18 +957,26 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { if (name[j] == '\0') break; j++; } - print_debug("%s\n", name); + print_debug("%d %s\n", lcmd.cmd, name); // changed name from @rpath/xxxx.dylib to real path if (strrchr(name, '@')) { get_real_path(ph, name); print_debug("get_real_path returned: %s\n", name); + } else { + break; // Ignore non-relative paths, which are system libs. See JDK-8249779. } - add_lib_info(ph, name, iter->vaddr); + add_lib_info(ph, name, iter->vaddr, iter->memsz); break; } } // done with the file, advanced to next page to search more files +#if 0 + // This line is disabled due to JDK-8249779. Instead we break out of the loop + // and don't attempt to find any more mach-o files in this segment. fpos = (ltell(fd) + pagesize - 1) / pagesize * pagesize; +#else + break; +#endif } } return true; diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c index 1edc849c542..df70737392c 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -57,12 +58,14 @@ typedef struct symtab { void build_search_table(symtab_t *symtab) { int i; + print_debug("build_search_table\n"); for (i = 0; i < symtab->num_symbols; i++) { DBT key, value; key.data = symtab->symbols[i].name; key.size = strlen(key.data) + 1; value.data = &(symtab->symbols[i]); value.size = sizeof(symtab_symbol); + //print_debug("build_search_table: %d 0x%x %s\n", i, symtab->symbols[i].offset, symtab->symbols[i].name); (*symtab->hash_table->put)(symtab->hash_table, &key, &value, 0); // check result @@ -92,10 +95,11 @@ void build_search_table(symtab_t *symtab) { // read symbol table from given fd. struct symtab* build_symtab(int fd) { symtab_t* symtab = NULL; - int i; + int i, j; mach_header_64 header; off_t image_start; + print_debug("build_symtab\n"); if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) { print_debug("failed in get fat header\n"); return NULL; @@ -151,6 +155,7 @@ struct symtab* build_symtab(int fd) { if (symtab->hash_table == NULL) goto quit; + // allocate the symtab symtab->num_symbols = symtabcmd.nsyms; symtab->symbols = (symtab_symbol *)malloc(sizeof(symtab_symbol) * symtab->num_symbols); symtab->strs = (char *)malloc(sizeof(char) * symtabcmd.strsize); @@ -158,17 +163,8 @@ struct symtab* build_symtab(int fd) { print_debug("out of memory: allocating symtab.symbol or symtab.strs\n"); goto quit; } - lseek(fd, image_start + symtabcmd.symoff, SEEK_SET); - for (i = 0; i < symtab->num_symbols; i++) { - if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) { - print_debug("read nlist_64 failed at %i\n", i); - goto quit; - } - symtab->symbols[i].offset = lentry.n_value; - symtab->symbols[i].size = lentry.n_un.n_strx; // index - } - // string table + // read in the string table lseek(fd, image_start + symtabcmd.stroff, SEEK_SET); int size = read(fd, (void *)(symtab->strs), symtabcmd.strsize * sizeof(char)); if (size != symtabcmd.strsize * sizeof(char)) { @@ -176,21 +172,42 @@ struct symtab* build_symtab(int fd) { goto quit; } - for (i = 0; i < symtab->num_symbols; i++) { - symtab->symbols[i].name = symtab->strs + symtab->symbols[i].size; - if (i > 0) { - // fix size - symtab->symbols[i - 1].size = symtab->symbols[i].size - symtab->symbols[i - 1].size; - print_debug("%s size = %d\n", symtab->symbols[i - 1].name, symtab->symbols[i - 1].size); + // read in each nlist_64 from the symbol table and use to fill in symtab->symbols + lseek(fd, image_start + symtabcmd.symoff, SEEK_SET); + i = 0; + for (j = 0; j < symtab->num_symbols; j++) { + if (read(fd, (void *)&lentry, sizeof(nlist_64)) != sizeof(nlist_64)) { + print_debug("read nlist_64 failed at %j\n", j); + goto quit; + } + + uintptr_t offset = lentry.n_value; // offset of the symbol code/data in the file + uintptr_t stridx = lentry.n_un.n_strx; // offset of symbol string in the symtabcmd.symoff section + if (stridx == 0 || offset == 0) { + continue; // Skip this entry. It's not a reference to code or data } + symtab->symbols[i].offset = offset; + symtab->symbols[i].name = symtab->strs + stridx; + symtab->symbols[i].size = strlen(symtab->symbols[i].name); - if (i == symtab->num_symbols - 1) { - // last index - symtab->symbols[i].size = - symtabcmd.strsize - symtab->symbols[i].size; - print_debug("%s size = %d\n", symtab->symbols[i].name, symtab->symbols[i].size); + if (symtab->symbols[i].size == 0) { + continue; // Skip this entry. It points to an empty string. } + + print_debug("symbol read: %d %d n_type=0x%x n_sect=0x%x n_desc=0x%x n_strx=0x%lx offset=0x%lx %s\n", + j, i, lentry.n_type, lentry.n_sect, lentry.n_desc, stridx, offset, symtab->symbols[i].name); + i++; + } + + // Update symtab->num_symbols to be the actual number of symbols we added. Since the symbols + // array was allocated larger, reallocate it to the proper size. + print_debug("build_symtab: included %d of %d entries.\n", i, symtab->num_symbols); + symtab->num_symbols = i; + symtab->symbols = (symtab_symbol *)realloc(symtab->symbols, sizeof(symtab_symbol) * symtab->num_symbols); + if (symtab->symbols == NULL) { + print_debug("out of memory: reallocating symtab.symbol\n"); + goto quit; } // build a hashtable for fast query @@ -389,14 +406,37 @@ uintptr_t search_symbol(struct symtab* symtab, uintptr_t base, const char *sym_n const char* nearest_symbol(struct symtab* symtab, uintptr_t offset, uintptr_t* poffset) { int n = 0; + char* result = NULL; + ptrdiff_t lowest_offset_from_sym = -1; if (!symtab) return NULL; + // Search the symbol table for the symbol that is closest to the specified offset, but is not under. + // + // Note we can't just use the first symbol that is >= the offset because the symbols may not be + // sorted by offset. + // + // Note this is a rather slow search that is O(n/2), and libjvm has as many as 250k symbols. + // Probably would be good to sort the array and do a binary search, or use a hash table like + // we do for name -> address lookups. However, this functionality is not used often and + // generally just involves one lookup, such as with the clhsdb "findpc" command. for (; n < symtab->num_symbols; n++) { symtab_symbol* sym = &(symtab->symbols[n]); - if (sym->name != NULL && - offset >= sym->offset && offset < sym->offset + sym->size) { - if (poffset) *poffset = (offset - sym->offset); - return sym->name; + if (sym->size != 0 && offset >= sym->offset) { + ptrdiff_t offset_from_sym = offset - sym->offset; + if (offset_from_sym >= 0) { // ignore symbols that come after "offset" + if (lowest_offset_from_sym == -1 || offset_from_sym < lowest_offset_from_sym) { + lowest_offset_from_sym = offset_from_sym; + result = sym->name; + //print_debug("nearest_symbol: found %d %s 0x%x 0x%x 0x%x\n", + // n, sym->name, offset, sym->offset, lowest_offset_from_sym); + } + } } } - return NULL; + print_debug("nearest_symbol: found symbol %d file_offset=0x%lx sym_offset=0x%lx %s\n", + n, offset, lowest_offset_from_sym, result); + // Save the offset from the symbol if requested. + if (result != NULL && poffset) { + *poffset = lowest_offset_from_sym; + } + return result; } From 6f9d287bbe65b0311764baf536c9046053036ff2 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 24 Feb 2022 08:22:48 +0000 Subject: [PATCH 03/10] 8277488: Add expiry exception for Digicert (geotrustglobalca) expiring in May 2022 Backport-of: d3749de47832c6de4bcee9cf64a0b698e796b2f2 --- test/jdk/sun/security/lib/cacerts/VerifyCACerts.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 91d78e8fecc..122a0190177 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -260,6 +260,8 @@ public class VerifyCACerts { add("luxtrustglobalrootca [jdk]"); // Valid until: Wed Mar 17 11:33:33 PDT 2021 add("quovadisrootca [jdk]"); + // Valid until: Sat May 21 04:00:00 GMT 2022 + add("geotrustglobalca [jdk]"); } }; From 16cbd3290deacb93c86201e99f95f6a021b5e469 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 24 Feb 2022 11:16:40 +0000 Subject: [PATCH 04/10] 8250750: JDK-8247515 fix for OSX pc_to_symbol() lookup fails with some symbols Backport-of: d12fdfa3b75a72c7f78a625f3774a35ac147960e --- .../macosx/native/libsaproc/libproc_impl.c | 13 ++++++------- .../macosx/native/libsaproc/libproc_impl.h | 6 +++--- .../macosx/native/libsaproc/ps_core.c | 2 +- .../macosx/native/libsaproc/symtab.c | 14 +++++++++++++- .../macosx/native/libsaproc/symtab.h | 4 ++-- 5 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c index ed61b6d1cac..9c902c6450f 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.c @@ -208,12 +208,12 @@ void Prelease(struct ps_prochandle* ph) { free(ph); } -lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base, size_t memsz) { - return add_lib_info_fd(ph, libname, -1, base, memsz); +lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { + return add_lib_info_fd(ph, libname, -1, base); } -lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base, size_t memsz) { - lib_info* newlib; +lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { + lib_info* newlib; print_debug("add_lib_info_fd %s\n", libname); if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { @@ -229,7 +229,6 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, strcpy(newlib->name, libname); newlib->base = base; - newlib->memsz = memsz; if (fd == -1) { if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { @@ -259,11 +258,11 @@ lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, } #endif // __APPLE__ - newlib->symtab = build_symtab(newlib->fd); + newlib->symtab = build_symtab(newlib->fd, &newlib->memsz); if (newlib->symtab == NULL) { print_debug("symbol table build failed for %s\n", newlib->name); } else { - print_debug("built symbol table for 0x%lx %s\n", newlib, newlib->name); + print_debug("built symbol table for 0x%lx memsz=0x%lx %s\n", newlib, newlib->memsz, newlib->name); } // even if symbol table building fails, we add the lib_info. diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h index a7cfeaaf209..96fcf680453 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/libproc_impl.h @@ -47,6 +47,7 @@ #include #include #include +#include #ifndef register_t #define register_t uint64_t @@ -225,11 +226,10 @@ typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lw bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb); // adds a new shared object to lib list, returns NULL on failure -lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base, size_t memsz); +lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base); // adds a new shared object to lib list, supply open lib file descriptor as well -lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, - uintptr_t base, size_t memsz); +lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base); sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id); // a test for ELF signature without using libelf diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c index f8aaac0cae7..9228522e63e 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/ps_core.c @@ -965,7 +965,7 @@ static bool read_shared_lib_info(struct ps_prochandle* ph) { } else { break; // Ignore non-relative paths, which are system libs. See JDK-8249779. } - add_lib_info(ph, name, iter->vaddr, iter->memsz); + add_lib_info(ph, name, iter->vaddr); break; } } diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c index df70737392c..52fd791117d 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.c @@ -93,11 +93,12 @@ void build_search_table(symtab_t *symtab) { } // read symbol table from given fd. -struct symtab* build_symtab(int fd) { +struct symtab* build_symtab(int fd, size_t *p_max_offset) { symtab_t* symtab = NULL; int i, j; mach_header_64 header; off_t image_start; + size_t max_offset = 0; print_debug("build_symtab\n"); if (!get_arch_off(fd, CPU_TYPE_X86_64, &image_start)) { @@ -187,6 +188,11 @@ struct symtab* build_symtab(int fd) { if (stridx == 0 || offset == 0) { continue; // Skip this entry. It's not a reference to code or data } + if (lentry.n_type == N_OSO) { + // This is an object file name/path. These entries have something other than + // an offset in lentry.n_value, so we need to ignore them. + continue; + } symtab->symbols[i].offset = offset; symtab->symbols[i].name = symtab->strs + stridx; symtab->symbols[i].size = strlen(symtab->symbols[i].name); @@ -195,6 +201,11 @@ struct symtab* build_symtab(int fd) { continue; // Skip this entry. It points to an empty string. } + // Track the maximum offset we've seen. This is used to determine the address range + // that the library covers. + if (offset > max_offset) { + max_offset = (offset + 4096) & ~0xfff; // Round up to next page boundary + } print_debug("symbol read: %d %d n_type=0x%x n_sect=0x%x n_desc=0x%x n_strx=0x%lx offset=0x%lx %s\n", j, i, lentry.n_type, lentry.n_sect, lentry.n_desc, stridx, offset, symtab->symbols[i].name); i++; @@ -212,6 +223,7 @@ struct symtab* build_symtab(int fd) { // build a hashtable for fast query build_search_table(symtab); + *p_max_offset = max_offset; return symtab; quit: if (symtab) destroy_symtab(symtab); diff --git a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h index f5f8645dabc..a55fbaa1467 100644 --- a/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h +++ b/src/jdk.hotspot.agent/macosx/native/libsaproc/symtab.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ struct symtab; // build symbol table for a given ELF or MachO file escriptor -struct symtab* build_symtab(int fd); +struct symtab* build_symtab(int fd, size_t *p_max_offset); // destroy the symbol table void destroy_symtab(struct symtab* symtab); From 68c63203f553cf99100c8b111837deb32a7d080a Mon Sep 17 00:00:00 2001 From: Kimura Yukihiro <81151783+yukikimmura@users.noreply.github.com> Date: Thu, 24 Feb 2022 23:47:01 +0000 Subject: [PATCH 05/10] 8214004: Missing space between compiler thread name and task info in hs_err Reviewed-by: phh --- src/hotspot/share/runtime/thread.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 6ef3f9605e7..159e87742db 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -4785,6 +4785,7 @@ void Threads::print_threads_compiling(outputStream* st, char* buf, int buflen, b CompileTask* task = ct->task(); if (task != NULL) { thread->print_name_on_error(st, buf, buflen); + st->print(" "); task->print(st, NULL, short_form, true); } } From 80a27773cbba61c0cb47de15c48f7fb9ecb69f4a Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 25 Feb 2022 22:23:14 +0000 Subject: [PATCH 06/10] 8282372: [11] build issue on MacOS/aarch64 12.2.1 using Xcode 13.1: call to 'log2_intptr' is ambiguous Reviewed-by: clanger --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 6f98db7455f..7e23c16a442 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -89,7 +89,7 @@ class MacroAssembler: public Assembler { = (operand_valid_for_logical_immediate(false /*is32*/, (uint64_t)Universe::narrow_klass_base()) && ((uint64_t)Universe::narrow_klass_base() - > (1ULL << log2_intptr(Universe::narrow_klass_range())))); + > (1ULL << log2_intptr(checked_cast(Universe::narrow_klass_range()))))); } // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code. From ba6c4c163c5cf43fad129402f19389dde7d8aeb4 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Sat, 26 Feb 2022 04:38:49 +0000 Subject: [PATCH 07/10] 8261107: ArrayIndexOutOfBoundsException in the ICC_Profile.getInstance(InputStream) Backport-of: 06b33a0ad78d1577711af22020cf5fdf25112523 --- .../classes/java/awt/color/ICC_Profile.java | 4 +- .../ICC_Profile/GetInstanceBrokenStream.java | 54 +++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/awt/color/ICC_Profile/GetInstanceBrokenStream.java diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index 2f85d51dffc..de99302f1eb 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -1030,10 +1030,10 @@ public static ICC_Profile getInstance(InputStream s) throws IOException { static byte[] getProfileDataFromStream(InputStream s) throws IOException { BufferedInputStream bis = new BufferedInputStream(s); - bis.mark(128); + bis.mark(128); // 128 is the length of the ICC profile header byte[] header = bis.readNBytes(128); - if (header[36] != 0x61 || header[37] != 0x63 || + if (header.length < 128 || header[36] != 0x61 || header[37] != 0x63 || header[38] != 0x73 || header[39] != 0x70) { return null; /* not a valid profile */ } diff --git a/test/jdk/java/awt/color/ICC_Profile/GetInstanceBrokenStream.java b/test/jdk/java/awt/color/ICC_Profile/GetInstanceBrokenStream.java new file mode 100644 index 00000000000..b98cae0cdca --- /dev/null +++ b/test/jdk/java/awt/color/ICC_Profile/GetInstanceBrokenStream.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ICC_Profile; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * @test + * @bug 8261107 + * @summary Short and broken streams should be reported as unsupported + */ +public final class GetInstanceBrokenStream { + + public static void main(String[] args) throws IOException { + // Empty header + testHeader(new byte[]{}); + // Short header + testHeader(new byte[]{-12, 3, 45}); + // Broken header + testHeader(new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 0x61, 0x63, 0x73, 0x70}); + } + + private static void testHeader(byte[] data) throws IOException { + ByteArrayInputStream bais = new ByteArrayInputStream(data); + try { + ICC_Profile.getInstance(bais); + } catch (IllegalArgumentException e) { + // expected + } + } +} From 80919eb2fff99409544c3c4d429912707f2fb2d5 Mon Sep 17 00:00:00 2001 From: Zdenek Zambersky Date: Mon, 28 Feb 2022 17:12:07 +0000 Subject: [PATCH 08/10] 8279669: test/jdk/com/sun/jdi/TestScaffold.java uses wrong condition Reviewed-by: sgehwolf Backport-of: 4c52eb39431c2479b0d140907bdcc0311d30f871 --- test/jdk/com/sun/jdi/TestScaffold.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/jdk/com/sun/jdi/TestScaffold.java b/test/jdk/com/sun/jdi/TestScaffold.java index 2561c5b5ba6..1d3843b9224 100644 --- a/test/jdk/com/sun/jdi/TestScaffold.java +++ b/test/jdk/com/sun/jdi/TestScaffold.java @@ -535,9 +535,10 @@ public void eventReceived(Event event) { Location loc = ((Locatable)event).location(); ReferenceType rt = loc.declaringType(); String name = rt.name(); - if (name.startsWith("java.") && - !name.startsWith("sun.") && - !name.startsWith("com.")) { + if (name.startsWith("java.") + || name.startsWith("sun.") + || name.startsWith("com.") + || name.startsWith("jdk.")) { if (mainStartClass != null) { redefine(mainStartClass); } From c0effc24b7c68834a804dd1494a658e674494f11 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 1 Mar 2022 16:11:26 +0000 Subject: [PATCH 09/10] 8211333: AArch64: Fix another build failure after JDK-8211029 Reviewed-by: aph Backport-of: 21af2af13ecc7739b6e28b0a46896108570e564c --- src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 669b08b9266..4bab77d542f 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1492,7 +1492,7 @@ void MacroAssembler::movptr(Register r, uintptr_t imm64) { #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%"PRIX64, (uint64_t)imm64); + snprintf(buffer, sizeof(buffer), "0x%" PRIX64, (uint64_t)imm64); block_comment(buffer); } #endif @@ -1555,7 +1555,7 @@ void MacroAssembler::mov_immediate64(Register dst, uint64_t imm64) #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%"PRIX64, imm64); + snprintf(buffer, sizeof(buffer), "0x%" PRIX64, imm64); block_comment(buffer); } #endif @@ -1668,7 +1668,7 @@ void MacroAssembler::mov_immediate32(Register dst, uint32_t imm32) #ifndef PRODUCT { char buffer[64]; - snprintf(buffer, sizeof(buffer), "0x%"PRIX32, imm32); + snprintf(buffer, sizeof(buffer), "0x%" PRIX32, imm32); block_comment(buffer); } #endif From 5cad68f586b1d75403ba7339828221ff6f167c53 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 1 Mar 2022 16:58:10 +0000 Subject: [PATCH 10/10] 8255410: Add ChaCha20 and Poly1305 support to SunPKCS11 provider Reviewed-by: mdoerr Backport-of: 5d8c1cc8a05e0d9aedd6d54b8147d374c2290024 --- .../sun/security/pkcs11/P11AEADCipher.java | 288 ++++++++++------ .../sun/security/pkcs11/P11KeyGenerator.java | 6 +- .../security/pkcs11/P11SecretKeyFactory.java | 5 + .../sun/security/pkcs11/SunPKCS11.java | 22 +- .../security/pkcs11/wrapper/CK_MECHANISM.java | 7 +- .../CK_SALSA20_CHACHA20_POLY1305_PARAMS.java | 80 +++++ .../share/native/libj2pkcs11/p11_convert.c | 74 +++- .../share/native/libj2pkcs11/p11_util.c | 7 +- .../share/native/libj2pkcs11/pkcs11wrapper.h | 4 +- .../pkcs11/Cipher/TestChaChaPoly.java | 323 ++++++++++++++++++ .../pkcs11/Cipher/TestChaChaPolyKAT.java | 233 +++++++++++++ .../pkcs11/Cipher/TestChaChaPolyNoReuse.java | 267 +++++++++++++++ .../Cipher/TestChaChaPolyOutputSize.java | 164 +++++++++ .../security/pkcs11/Cipher/TestKATForGCM.java | 12 - .../pkcs11/KeyGenerator/TestChaCha20.java | 91 +++++ test/jdk/sun/security/pkcs11/PKCS11Test.java | 34 ++ .../pkcs11/SecretKeyFactory/TestGeneral.java | 119 +++++++ .../pkcs11/tls/TestLeadingZeroesP11.java | 29 -- 18 files changed, 1608 insertions(+), 157 deletions(-) create mode 100644 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_SALSA20_CHACHA20_POLY1305_PARAMS.java create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java create mode 100644 test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java create mode 100644 test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java index 7913d755d4e..fa8fb3f7ed7 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11AEADCipher.java @@ -42,28 +42,38 @@ /** * P11 AEAD Cipher implementation class. This class currently supports - * AES with GCM mode. + * AES cipher in GCM mode and CHACHA20-POLY1305 cipher. * * Note that AEAD modes do not use padding, so this class does not have - * its own padding impl. In addition, NSS CKM_AES_GCM only supports single-part - * encryption/decryption, thus the current impl uses PKCS#11 C_Encrypt/C_Decrypt - * calls and buffers data until doFinal is called. - * - * Note that PKCS#11 standard currently only supports GCM and CCM AEAD modes. - * There are no provisions for other AEAD modes yet. + * its own padding impl. In addition, some vendors such as NSS may not support + * multi-part encryption/decryption for AEAD cipher algorithms, thus the + * current impl uses PKCS#11 C_Encrypt/C_Decrypt calls and buffers data until + * doFinal is called. * * @since 13 */ final class P11AEADCipher extends CipherSpi { - // mode constant for GCM mode - private static final int MODE_GCM = 10; + // supported AEAD algorithms/transformations + private enum Transformation { + AES_GCM("AES", "GCM", "NOPADDING", 16, 16), + CHACHA20_POLY1305("CHACHA20", "NONE", "NOPADDING", 12, 16); - // default constants for GCM - private static final int GCM_DEFAULT_TAG_LEN = 16; - private static final int GCM_DEFAULT_IV_LEN = 16; + final String keyAlgo; + final String mode; + final String padding; + final int defIvLen; // in bytes + final int defTagLen; // in bytes - private static final String ALGO = "AES"; + Transformation(String keyAlgo, String mode, String padding, + int defIvLen, int defTagLen) { + this.keyAlgo = keyAlgo; + this.mode = mode; + this.padding = padding; + this.defIvLen = defIvLen; + this.defTagLen = defTagLen; + } + } // token instance private final Token token; @@ -71,10 +81,10 @@ final class P11AEADCipher extends CipherSpi { // mechanism id private final long mechanism; - // mode, one of MODE_* above - private final int blockMode; + // type of this AEAD cipher, one of Transformation enum above + private final Transformation type; - // acceptable key size, -1 if more than 1 key sizes are accepted + // acceptable key size in bytes, -1 if more than 1 key sizes are accepted private final int fixedKeySize; // associated session, if any @@ -111,99 +121,129 @@ final class P11AEADCipher extends CipherSpi { this.mechanism = mechanism; String[] algoParts = algorithm.split("/"); - if (algoParts.length != 3) { - throw new ProviderException("Unsupported Transformation format: " + - algorithm); - } - if (!algoParts[0].startsWith("AES")) { - throw new ProviderException("Only support AES for AEAD cipher mode"); - } - int index = algoParts[0].indexOf('_'); - if (index != -1) { - // should be well-formed since we specify what we support - fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1)) >> 3; + if (algoParts[0].startsWith("AES")) { + // for AES_GCM, need 3 parts + if (algoParts.length != 3) { + throw new AssertionError("Invalid Transformation format: " + + algorithm); + } + int index = algoParts[0].indexOf('_'); + if (index != -1) { + // should be well-formed since we specify what we support + fixedKeySize = Integer.parseInt(algoParts[0].substring(index+1)) >> 3; + } else { + fixedKeySize = -1; + } + this.type = Transformation.AES_GCM; + engineSetMode(algoParts[1]); + try { + engineSetPadding(algoParts[2]); + } catch (NoSuchPaddingException e) { + throw new NoSuchAlgorithmException(); + } + } else if (algoParts[0].equals("ChaCha20-Poly1305")) { + fixedKeySize = 32; + this.type = Transformation.CHACHA20_POLY1305; + if (algoParts.length > 3) { + throw new AssertionError( + "Invalid Transformation format: " + algorithm); + } else { + if (algoParts.length > 1) { + engineSetMode(algoParts[1]); + } + try { + if (algoParts.length > 2) { + engineSetPadding(algoParts[2]); + } + } catch (NoSuchPaddingException e) { + throw new NoSuchAlgorithmException(); + } + } } else { - fixedKeySize = -1; - } - this.blockMode = parseMode(algoParts[1]); - if (!algoParts[2].equals("NoPadding")) { - throw new ProviderException("Only NoPadding is supported for AEAD cipher mode"); + throw new AssertionError("Unsupported transformation " + algorithm); } } + @Override protected void engineSetMode(String mode) throws NoSuchAlgorithmException { - // Disallow change of mode for now since currently it's explicitly - // defined in transformation strings - throw new NoSuchAlgorithmException("Unsupported mode " + mode); - } - - private int parseMode(String mode) throws NoSuchAlgorithmException { - mode = mode.toUpperCase(Locale.ENGLISH); - int result; - if (mode.equals("GCM")) { - result = MODE_GCM; - } else { + if (!mode.toUpperCase(Locale.ENGLISH).equals(type.mode)) { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } - return result; } // see JCE spec + @Override protected void engineSetPadding(String padding) throws NoSuchPaddingException { - // Disallow change of padding for now since currently it's explicitly - // defined in transformation strings - throw new NoSuchPaddingException("Unsupported padding " + padding); + if (!padding.toUpperCase(Locale.ENGLISH).equals(type.padding)) { + throw new NoSuchPaddingException("Unsupported padding " + padding); + } } // see JCE spec + @Override protected int engineGetBlockSize() { - return 16; // constant; only AES is supported + switch (type) { + case AES_GCM: return 16; + case CHACHA20_POLY1305: return 0; + default: throw new AssertionError("Unsupported type " + type); + } } // see JCE spec + @Override protected int engineGetOutputSize(int inputLen) { return doFinalLength(inputLen); } // see JCE spec + @Override protected byte[] engineGetIV() { return (iv == null) ? null : iv.clone(); } // see JCE spec protected AlgorithmParameters engineGetParameters() { - if (encrypt && iv == null && tagLen == -1) { - switch (blockMode) { - case MODE_GCM: - iv = new byte[GCM_DEFAULT_IV_LEN]; - tagLen = GCM_DEFAULT_TAG_LEN; - break; - default: - throw new ProviderException("Unsupported mode"); - } - random.nextBytes(iv); - } - try { - AlgorithmParameterSpec spec; - String apAlgo; - switch (blockMode) { - case MODE_GCM: - apAlgo = "GCM"; + String apAlgo; + AlgorithmParameterSpec spec = null; + switch (type) { + case AES_GCM: + apAlgo = "GCM"; + if (encrypt && iv == null && tagLen == -1) { + iv = new byte[type.defIvLen]; + tagLen = type.defTagLen; + random.nextBytes(iv); + } + if (iv != null) { spec = new GCMParameterSpec(tagLen << 3, iv); - break; - default: - throw new ProviderException("Unsupported mode"); + } + break; + case CHACHA20_POLY1305: + if (encrypt && iv == null) { + iv = new byte[type.defIvLen]; + random.nextBytes(iv); + } + apAlgo = "ChaCha20-Poly1305"; + if (iv != null) { + spec = new IvParameterSpec(iv); + } + break; + default: + throw new AssertionError("Unsupported type " + type); + } + if (spec != null) { + try { + AlgorithmParameters params = + AlgorithmParameters.getInstance(apAlgo); + params.init(spec); + return params; + } catch (GeneralSecurityException e) { + // NoSuchAlgorithmException, NoSuchProviderException + // InvalidParameterSpecException + throw new ProviderException("Could not encode parameters", e); } - AlgorithmParameters params = - AlgorithmParameters.getInstance(apAlgo); - params.init(spec); - return params; - } catch (GeneralSecurityException e) { - // NoSuchAlgorithmException, NoSuchProviderException - // InvalidParameterSpecException - throw new ProviderException("Could not encode parameters", e); } + return null; } // see JCE spec @@ -231,20 +271,30 @@ protected void engineInit(int opmode, Key key, updateCalled = false; byte[] ivValue = null; int tagLen = -1; - if (params != null) { - switch (blockMode) { - case MODE_GCM: - if (!(params instanceof GCMParameterSpec)) { - throw new InvalidAlgorithmParameterException - ("Only GCMParameterSpec is supported"); + switch (type) { + case AES_GCM: + if (params != null) { + if (!(params instanceof GCMParameterSpec)) { + throw new InvalidAlgorithmParameterException + ("Only GCMParameterSpec is supported"); + } + ivValue = ((GCMParameterSpec) params).getIV(); + tagLen = ((GCMParameterSpec) params).getTLen() >> 3; + } + break; + case CHACHA20_POLY1305: + if (params != null) { + if (!(params instanceof IvParameterSpec)) { + throw new InvalidAlgorithmParameterException + ("Only IvParameterSpec is supported"); + } + ivValue = ((IvParameterSpec) params).getIV(); + tagLen = type.defTagLen; } - ivValue = ((GCMParameterSpec) params).getIV(); - tagLen = ((GCMParameterSpec) params).getTLen() >> 3; break; default: - throw new ProviderException("Unsupported mode"); - } - } + throw new AssertionError("Unsupported type " + type); + }; implInit(opmode, key, ivValue, tagLen, sr); } @@ -260,13 +310,17 @@ protected void engineInit(int opmode, Key key, AlgorithmParameters params, try { AlgorithmParameterSpec paramSpec = null; if (params != null) { - switch (blockMode) { - case MODE_GCM: + switch (type) { + case AES_GCM: paramSpec = params.getParameterSpec(GCMParameterSpec.class); break; + case CHACHA20_POLY1305: + paramSpec = + params.getParameterSpec(IvParameterSpec.class); + break; default: - throw new ProviderException("Unsupported mode"); + throw new AssertionError("Unsupported type " + type); } } engineInit(opmode, key, paramSpec, sr); @@ -285,15 +339,16 @@ private void implInit(int opmode, Key key, byte[] iv, int tagLen, key.getEncoded().length) != fixedKeySize) { throw new InvalidKeyException("Key size is invalid"); } - P11Key newKey = P11SecretKeyFactory.convertKey(token, key, ALGO); + P11Key newKey = P11SecretKeyFactory.convertKey(token, key, + type.keyAlgo); switch (opmode) { case Cipher.ENCRYPT_MODE: encrypt = true; requireReinit = Arrays.equals(iv, lastEncIv) && (newKey == lastEncKey); if (requireReinit) { - throw new InvalidAlgorithmParameterException - ("Cannot reuse iv for GCM encryption"); + throw new InvalidAlgorithmParameterException( + "Cannot reuse the same key and iv pair"); } break; case Cipher.DECRYPT_MODE: @@ -309,16 +364,22 @@ private void implInit(int opmode, Key key, byte[] iv, int tagLen, if (sr != null) { this.random = sr; } + if (iv == null && tagLen == -1) { // generate default values - switch (blockMode) { - case MODE_GCM: - iv = new byte[GCM_DEFAULT_IV_LEN]; + switch (type) { + case AES_GCM: + iv = new byte[type.defIvLen]; + this.random.nextBytes(iv); + tagLen = type.defTagLen; + break; + case CHACHA20_POLY1305: + iv = new byte[type.defIvLen]; this.random.nextBytes(iv); - tagLen = GCM_DEFAULT_TAG_LEN; + tagLen = type.defTagLen; break; default: - throw new ProviderException("Unsupported mode"); + throw new AssertionError("Unsupported type " + type); } } this.iv = iv; @@ -382,7 +443,7 @@ private void initialize() throws PKCS11Exception { } if (requireReinit) { throw new IllegalStateException - ("Must use either different key or iv for GCM encryption"); + ("Must use either different key or iv"); } token.ensureValid(); @@ -392,13 +453,17 @@ private void initialize() throws PKCS11Exception { long p11KeyID = p11Key.getKeyID(); try { CK_MECHANISM mechWithParams; - switch (blockMode) { - case MODE_GCM: + switch (type) { + case AES_GCM: mechWithParams = new CK_MECHANISM(mechanism, new CK_GCM_PARAMS(tagLen << 3, iv, aad)); break; + case CHACHA20_POLY1305: + mechWithParams = new CK_MECHANISM(mechanism, + new CK_SALSA20_CHACHA20_POLY1305_PARAMS(iv, aad)); + break; default: - throw new ProviderException("Unsupported mode: " + blockMode); + throw new AssertionError("Unsupported type: " + type); } if (session == null) { session = token.getOpSession(); @@ -431,10 +496,13 @@ private int doFinalLength(int inLen) { if (encrypt) { result += tagLen; } else { - // PKCS11Exception: CKR_BUFFER_TOO_SMALL - //result -= tagLen; + // In earlier NSS versions, AES_GCM would report + // CKR_BUFFER_TOO_SMALL error if minus tagLen + if (type == Transformation.CHACHA20_POLY1305) { + result -= tagLen; + } } - return result; + return (result > 0? result : 0); } // reset the states to the pre-initialized values @@ -492,7 +560,7 @@ protected synchronized void engineUpdateAAD(byte[] src, int srcOfs, int srcLen) } if (requireReinit) { throw new IllegalStateException - ("Must use either different key or iv for GCM encryption"); + ("Must use either different key or iv for encryption"); } if (p11Key == null) { throw new IllegalStateException("Need to initialize Cipher first"); @@ -595,6 +663,7 @@ private int implDoFinal(byte[] in, int inOfs, int inLen, if (outLen < requiredOutLen) { throw new ShortBufferException(); } + boolean doCancel = true; try { ensureInitialized(); @@ -712,6 +781,7 @@ private int implDoFinal(ByteBuffer inBuffer, ByteBuffer outBuffer) outAddr, outArray, outOfs, outLen); doCancel = false; } + inBuffer.position(inBuffer.limit()); outBuffer.position(outBuffer.position() + k); return k; } catch (PKCS11Exception e) { @@ -748,8 +818,8 @@ private void handleException(PKCS11Exception e) } else if (errorCode == CKR_ENCRYPTED_DATA_INVALID || // Solaris-specific errorCode == CKR_GENERAL_ERROR) { - throw (BadPaddingException) - (new BadPaddingException(e.toString()).initCause(e)); + throw (AEADBadTagException) + (new AEADBadTagException(e.toString()).initCause(e)); } } @@ -772,7 +842,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, @Override protected int engineGetKeySize(Key key) throws InvalidKeyException { int n = P11SecretKeyFactory.convertKey - (token, key, ALGO).length(); + (token, key, type.keyAlgo).length(); return n; } } diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java index 4df62de6db1..926414608cb 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11KeyGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -194,6 +194,10 @@ private void setDefaultKeySize() { keySize = 128; keyType = CKK_BLOWFISH; break; + case (int)CKM_CHACHA20_KEY_GEN: + keySize = 256; + keyType = CKK_CHACHA20; + break; default: throw new ProviderException("Unknown mechanism " + mechanism); } diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java index 68a3a0665c0..c98960f7fcc 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11SecretKeyFactory.java @@ -68,6 +68,7 @@ final class P11SecretKeyFactory extends SecretKeyFactorySpi { addKeyType("DESede", CKK_DES3); addKeyType("AES", CKK_AES); addKeyType("Blowfish", CKK_BLOWFISH); + addKeyType("ChaCha20", CKK_CHACHA20); // we don't implement RC2 or IDEA, but we want to be able to generate // keys for those SSL/TLS ciphersuites. @@ -237,6 +238,10 @@ private static P11Key createKey(Token token, byte[] encoded, P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n, token); break; + case (int)CKK_CHACHA20: + keyLength = P11KeyGenerator.checkKeySize( + CKM_CHACHA20_KEY_GEN, n, token); + break; case (int)CKK_GENERIC_SECRET: case (int)PCKK_TLSPREMASTER: case (int)PCKK_TLSRSAPREMASTER: diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index 5e227f45315..099caac605f 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,6 +40,8 @@ import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.PasswordCallback; +import com.sun.crypto.provider.ChaCha20Poly1305Parameters; + import jdk.internal.misc.InnocuousThread; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; @@ -600,6 +602,8 @@ private static void register(Descriptor d) { m(CKM_AES_KEY_GEN)); d(KG, "Blowfish", P11KeyGenerator, m(CKM_BLOWFISH_KEY_GEN)); + d(KG, "ChaCha20", P11KeyGenerator, + m(CKM_CHACHA20_KEY_GEN)); // register (Secret)KeyFactories if there are any mechanisms // for a particular algorithm that we support @@ -626,6 +630,11 @@ private static void register(Descriptor d) { d(AGP, "GCM", "sun.security.util.GCMParameters", m(CKM_AES_GCM)); + d(AGP, "ChaCha20-Poly1305", + "com.sun.crypto.provider.ChaCha20Poly1305Parameters", + s("1.2.840.113549.1.9.16.3.18", "OID.1.2.840.113549.1.9.16.3.18"), + m(CKM_CHACHA20_POLY1305)); + d(KA, "DH", P11KeyAgreement, s("DiffieHellman"), m(CKM_DH_PKCS_DERIVE)); d(KA, "ECDH", "sun.security.pkcs11.P11ECDHKeyAgreement", @@ -642,6 +651,8 @@ private static void register(Descriptor d) { m(CKM_AES_CBC)); d(SKF, "Blowfish", P11SecretKeyFactory, m(CKM_BLOWFISH_CBC)); + d(SKF, "ChaCha20", P11SecretKeyFactory, + m(CKM_CHACHA20_POLY1305)); // XXX attributes for Ciphers (supported modes, padding) d(CIP, "ARCFOUR", P11Cipher, s("RC4"), @@ -709,6 +720,10 @@ private static void register(Descriptor d) { d(CIP, "Blowfish/CBC/PKCS5Padding", P11Cipher, m(CKM_BLOWFISH_CBC)); + d(CIP, "ChaCha20-Poly1305", P11AEADCipher, + s("1.2.840.113549.1.9.16.3.18", "OID.1.2.840.113549.1.9.16.3.18"), + m(CKM_CHACHA20_POLY1305)); + d(CIP, "RSA/ECB/PKCS1Padding", P11RSACipher, s("RSA"), m(CKM_RSA_PKCS)); d(CIP, "RSA/ECB/NoPadding", P11RSACipher, @@ -1165,7 +1180,8 @@ public Object newInstance0(Object param) throws } else if (type == CIP) { if (algorithm.startsWith("RSA")) { return new P11RSACipher(token, algorithm, mechanism); - } else if (algorithm.endsWith("GCM/NoPadding")) { + } else if (algorithm.endsWith("GCM/NoPadding") || + algorithm.startsWith("ChaCha20-Poly1305")) { return new P11AEADCipher(token, algorithm, mechanism); } else { return new P11Cipher(token, algorithm, mechanism); @@ -1218,6 +1234,8 @@ public Object newInstance0(Object param) throws return new sun.security.util.ECParameters(); } else if (algorithm == "GCM") { return new sun.security.util.GCMParameters(); + } else if (algorithm == "ChaCha20-Poly1305") { + return new ChaCha20Poly1305Parameters(); // from SunJCE } else { throw new NoSuchAlgorithmException("Unsupported algorithm: " + algorithm); diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java index 1e546462163..db5474fa888 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_MECHANISM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -155,6 +155,11 @@ public CK_MECHANISM(long mechanism, CK_CCM_PARAMS params) { init(mechanism, params); } + public CK_MECHANISM(long mechanism, + CK_SALSA20_CHACHA20_POLY1305_PARAMS params) { + init(mechanism, params); + } + // For PSS. the parameter may be set multiple times, use the // CK_MECHANISM(long) constructor and setParameter(CK_RSA_PKCS_PSS_PARAMS) // methods instead of creating yet another constructor diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_SALSA20_CHACHA20_POLY1305_PARAMS.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_SALSA20_CHACHA20_POLY1305_PARAMS.java new file mode 100644 index 00000000000..280279ba821 --- /dev/null +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/CK_SALSA20_CHACHA20_POLY1305_PARAMS.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.pkcs11.wrapper; + +/** + * This class represents the necessary parameters required by the + * CKM_CHACHA20_POLY1305 and CKM_SALSA20_POLY1305 mechanisms as defined in + * CK_SALSA20_CHACHA20_POLY1305_PARAMS structure.

+ * PKCS#11 structure: + *

+ * typedef struct CK_SALSA20_CHACHA20_POLY1305_PARAMS {
+ *   CK_BYTE_PTR  pNonce;
+ *   CK_ULONG     ulNonceLen;
+ *   CK_BYTE_PTR  pAAD;
+ *   CK_ULONG     ulAADLen;
+ * } CK_SALSA20_CHACHA20_POLY1305_PARAMS;
+ * 
+ * + * @since 17 + */ +public class CK_SALSA20_CHACHA20_POLY1305_PARAMS { + + private final byte[] nonce; + private final byte[] aad; + + public CK_SALSA20_CHACHA20_POLY1305_PARAMS(byte[] nonce, byte[] aad) { + this.nonce = nonce; + this.aad = aad; + } + + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append(Constants.INDENT); + sb.append("Nonce: "); + if (nonce == null) { + sb.append("null"); + } else { + sb.append("0x"); + for (byte b: nonce) { + sb.append(String.format("%02x", b)); + } + } + sb.append(Constants.NEWLINE); + sb.append(Constants.INDENT); + sb.append("AAD: "); + if (aad == null) { + sb.append("null"); + } else { + sb.append("0x"); + for (byte b: aad) { + sb.append(String.format("%02x", b)); + } + } + return sb.toString(); + } +} diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c index 59901210471..666c5eb9b3b 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_convert.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -1159,6 +1159,73 @@ jCCMParamsToCKCCMParamPtr(JNIEnv *env, jobject jParam, CK_ULONG *pLength) return NULL; } +/* + * converts the Java CK_SALSA20_CHACHA20_POLY1305_PARAMS object to a + * CK_SALSA20_CHACHA20_POLY1305_PARAMS pointer + * + * @param env - used to call JNI functions to get the Java classes and objects + * @param jParam - the Java CK_SALSA20_CHACHA20_POLY1305_PARAMS object to + * convert + * @param pLength - length of the allocated memory of the returned pointer + * @return pointer to the new CK_SALSA20_CHACHA20_POLY1305_PARAMS structure + */ +CK_SALSA20_CHACHA20_POLY1305_PARAMS_PTR +jSalsaChaChaPolyParamsToCKSalsaChaChaPolyParamPtr( + JNIEnv *env, jobject jParam, CK_ULONG *pLength) +{ + CK_SALSA20_CHACHA20_POLY1305_PARAMS_PTR ckParamPtr; + jclass jParamsClass; + jfieldID fieldID; + jobject jNonce, jAad; + + if (pLength != NULL) { + *pLength = 0; + } + + // retrieve java values + jParamsClass = (*env)->FindClass(env, + CLASS_SALSA20_CHACHA20_POLY1305_PARAMS); + if (jParamsClass == NULL) { return NULL; } + if (!(*env)->IsInstanceOf(env, jParam, jParamsClass)) { + return NULL; + } + fieldID = (*env)->GetFieldID(env, jParamsClass, "nonce", "[B"); + if (fieldID == NULL) { return NULL; } + jNonce = (*env)->GetObjectField(env, jParam, fieldID); + fieldID = (*env)->GetFieldID(env, jParamsClass, "aad", "[B"); + if (fieldID == NULL) { return NULL; } + jAad = (*env)->GetObjectField(env, jParam, fieldID); + // allocate memory for CK_SALSA20_CHACHA20_POLY1305_PARAMS pointer + ckParamPtr = calloc(1, sizeof(CK_SALSA20_CHACHA20_POLY1305_PARAMS)); + if (ckParamPtr == NULL) { + throwOutOfMemoryError(env, 0); + return NULL; + } + + // populate using java values + jByteArrayToCKByteArray(env, jNonce, &(ckParamPtr->pNonce), + &(ckParamPtr->ulNonceLen)); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + + jByteArrayToCKByteArray(env, jAad, &(ckParamPtr->pAAD), + &(ckParamPtr->ulAADLen)); + if ((*env)->ExceptionCheck(env)) { + goto cleanup; + } + + if (pLength != NULL) { + *pLength = sizeof(CK_SALSA20_CHACHA20_POLY1305_PARAMS); + } + return ckParamPtr; +cleanup: + free(ckParamPtr->pNonce); + free(ckParamPtr->pAAD); + free(ckParamPtr); + return NULL; +} + /* * converts a Java CK_MECHANISM object into a CK_MECHANISM pointer * pointer. @@ -1437,6 +1504,11 @@ CK_VOID_PTR jMechParamToCKMechParamPtrSlow(JNIEnv *env, jobject jParam, case CKM_AES_CCM: ckpParamPtr = jCCMParamsToCKCCMParamPtr(env, jParam, ckpLength); break; + case CKM_CHACHA20_POLY1305: + ckpParamPtr = + jSalsaChaChaPolyParamsToCKSalsaChaChaPolyParamPtr(env, + jParam, ckpLength); + break; case CKM_RSA_PKCS_OAEP: ckpParamPtr = jRsaPkcsOaepParamToCKRsaPkcsOaepParamPtr(env, jParam, ckpLength); break; diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c index cba1bf309b7..27006b9da0e 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -323,6 +323,11 @@ void freeCKMechanismPtr(CK_MECHANISM_PTR mechPtr) { free(((CK_CCM_PARAMS*)tmp)->pNonce); free(((CK_CCM_PARAMS*)tmp)->pAAD); break; + case CKM_CHACHA20_POLY1305: + TRACE0("[ CK_SALSA20_CHACHA20_POLY1305_PARAMS ]\n"); + free(((CK_SALSA20_CHACHA20_POLY1305_PARAMS*)tmp)->pNonce); + free(((CK_SALSA20_CHACHA20_POLY1305_PARAMS*)tmp)->pAAD); + break; case CKM_TLS_PRF: case CKM_NSS_TLS_PRF_GENERAL: TRACE0("[ CK_TLS_PRF_PARAMS ]\n"); diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h index 513810d10a0..7159fc982a2 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/pkcs11wrapper.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -256,6 +256,8 @@ void printDebug(const char *format, ...); #define CLASS_AES_CTR_PARAMS "sun/security/pkcs11/wrapper/CK_AES_CTR_PARAMS" #define CLASS_GCM_PARAMS "sun/security/pkcs11/wrapper/CK_GCM_PARAMS" #define CLASS_CCM_PARAMS "sun/security/pkcs11/wrapper/CK_CCM_PARAMS" +#define CLASS_SALSA20_CHACHA20_POLY1305_PARAMS \ + "sun/security/pkcs11/wrapper/CK_SALSA20_CHACHA20_POLY1305_PARAMS" #define CLASS_RSA_PKCS_PSS_PARAMS "sun/security/pkcs11/wrapper/CK_RSA_PKCS_PSS_PARAMS" #define CLASS_RSA_PKCS_OAEP_PARAMS "sun/security/pkcs11/wrapper/CK_RSA_PKCS_OAEP_PARAMS" diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java new file mode 100644 index 00000000000..076660b3923 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPoly.java @@ -0,0 +1,323 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8255410 + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main/othervm TestChaChaPoly + * @summary test for PKCS#11 ChaCha20-Poly1305 Cipher. + */ + +import java.nio.ByteBuffer; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.InvalidParameterSpecException; +import java.util.Arrays; + +import javax.crypto.Cipher; +import javax.crypto.spec.ChaCha20ParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.crypto.NoSuchPaddingException; + +import jdk.test.lib.Utils; + +public class TestChaChaPoly extends PKCS11Test { + + private static final byte[] NONCE + = HexToBytes("012345670123456701234567"); + private static final SecretKeySpec KEY = new SecretKeySpec( + HexToBytes("0123456701234567012345670123456701234567012345670123456701234567"), + "ChaCha20"); + private static final ChaCha20ParameterSpec CHACHA20_PARAM_SPEC + = new ChaCha20ParameterSpec(NONCE, 0); + private static final IvParameterSpec IV_PARAM_SPEC + = new IvParameterSpec(NONCE); + private static final String ALGO = "ChaCha20-Poly1305"; + private static final SecureRandom RAND = new SecureRandom(); + private static Provider p; + + @Override + public void main(Provider p) throws Exception { + System.out.println("Testing " + p.getName()); + try { + Cipher.getInstance(ALGO, p); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("Skip; no support for " + ALGO); + return; + } + this.p = p; + testTransformations(); + testInit(); + testAEAD(); + testGetBlockSize(); + testGetIV(); + testInterop("SunJCE"); + } + + private static void testTransformations() throws Exception { + System.out.println("== transformations =="); + + checkTransformation(p, ALGO, true); + checkTransformation(p, ALGO + "/None/NoPadding", true); + checkTransformation(p, ALGO + "/ECB/NoPadding", false); + checkTransformation(p, ALGO + "/None/PKCS5Padding", false); + } + + private static void checkTransformation(Provider p, String t, + boolean expected) throws Exception { + try { + Cipher.getInstance(t, p); + if (!expected) { + throw new RuntimeException( "Should reject transformation: " + + t); + } else { + System.out.println("Accepted transformation: " + t); + } + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + if (!expected) { + System.out.println("Rejected transformation: " + t); + } else { + throw new RuntimeException("Should accept transformation: " + + t, e); + } + } + } + + private static void testInit() throws Exception { + testInitOnCrypt(Cipher.ENCRYPT_MODE); + testInitOnCrypt(Cipher.DECRYPT_MODE); + } + + private static void testInitOnCrypt(int opMode) throws Exception { + System.out.println("== init (" + getOpModeName(opMode) + ") =="); + + // Need to acquire new Cipher object as ChaCha20-Poly1305 cipher + // disallow reusing the same key and iv pair + Cipher.getInstance(ALGO, p).init(opMode, KEY, IV_PARAM_SPEC); + Cipher c = Cipher.getInstance(ALGO, p); + c.init(opMode, KEY, IV_PARAM_SPEC, RAND); + AlgorithmParameters params = c.getParameters(); + Cipher.getInstance(ALGO, p).init(opMode, KEY, params, RAND); + + try { + // try with invalid param + Cipher.getInstance(ALGO, p).init(opMode, KEY, CHACHA20_PARAM_SPEC); + throw new RuntimeException("Should reject non-IvparameterSpec"); + } catch (InvalidAlgorithmParameterException e) { + System.out.println("Expected IAPE - " + e); + } + } + + private static void testAEAD() throws Exception { + byte[] expectedPt = HexToBytes("01234567"); + byte[] ct = testUpdateAAD(Cipher.ENCRYPT_MODE, expectedPt); + byte[] pt = testUpdateAAD(Cipher.DECRYPT_MODE, ct); + if (pt != null && !Arrays.equals(pt, expectedPt)) { + System.out.println("ciphertext: " + Arrays.toString(ct)); + System.out.println("plaintext: " + Arrays.toString(pt)); + throw new RuntimeException("AEAD failed"); + } + } + + private static byte[] testUpdateAAD(int opMode, byte[] input) + throws Exception { + String opModeName = getOpModeName(opMode); + System.out.println("== updateAAD (" + opModeName + ") =="); + + byte[] aad = HexToBytes("0000"); + ByteBuffer aadBuf = ByteBuffer.wrap(aad); + + Cipher ccp = Cipher.getInstance(ALGO, p); + try { + ccp.updateAAD(aadBuf); + throw new RuntimeException( + "Should throw ISE for setting AAD on uninit'ed Cipher"); + } catch (IllegalStateException e) { + System.out.println("Expected ISE - " + e); + } + + ccp.init(opMode, KEY, IV_PARAM_SPEC); + ccp.update(input); + try { + ccp.updateAAD(aad); + throw new RuntimeException( + "Should throw ISE for setting AAD after update"); + } catch (IllegalStateException e) { + System.out.println("Expected ISE - " + e); + } + + ccp.init(opMode, KEY, IV_PARAM_SPEC); + ccp.updateAAD(aadBuf); + return ccp.doFinal(input); + } + + private static void testGetBlockSize() throws Exception { + testGetBlockSize(Cipher.ENCRYPT_MODE); + testGetBlockSize(Cipher.DECRYPT_MODE); + } + + private static void testGetBlockSize(int opMode) throws Exception { + System.out.println("== getBlockSize (" + getOpModeName(opMode) + ") =="); + Cipher c = Cipher.getInstance(ALGO, p); + if (c.getBlockSize() != 0) { + throw new RuntimeException("Block size must be 0"); + } + } + + private static void testGetIV() throws Exception { + testGetIV(Cipher.ENCRYPT_MODE); + testGetIV(Cipher.DECRYPT_MODE); + } + + private static void testGetIV(int opMode) throws Exception { + System.out.println("== getIv (" + getOpModeName(opMode) + ") =="); + + try { + Cipher.getInstance(ALGO, p).getIV(); + Cipher.getInstance(ALGO, p).getParameters(); + } catch (Exception e) { + throw new RuntimeException("Should not throw ex", e); + } + // first init w/ key only + AlgorithmParameters params = null; + for (int i = 0; i < 6; i++) { + System.out.println("IV test# " + i); + Cipher c = Cipher.getInstance(ALGO, p); + byte[] expectedIV = NONCE; + try { + switch (i) { + case 0: { + c.init(opMode, KEY); + expectedIV = null; // randomly-generated + break; + } + case 1: { + c.init(opMode, KEY, RAND); + expectedIV = null; // randomly-generated + break; + } + case 2: { + c.init(opMode, KEY, IV_PARAM_SPEC); + params = c.getParameters(); + if (params == null) { + throw new RuntimeException("Params should not be null"); + } + break; + } + case 3: c.init(opMode, KEY, IV_PARAM_SPEC, RAND); break; + case 4: c.init(opMode, KEY, params); break; + case 5: c.init(opMode, KEY, params, RAND); break; + } + checkIV(c, expectedIV); + System.out.println("=> Passed"); + } catch (GeneralSecurityException e) { + if (opMode == Cipher.DECRYPT_MODE && i < 2) { + System.out.println("=> Passed: Expected Ex thrown"); + } else { + throw new RuntimeException("Should not throw ex", e); + } + } + } + } + + private static void checkIV(Cipher c, byte[] expectedIv) { + // the specified cipher has been initialized; the returned IV and + // AlgorithmParameters object should be non-null + byte[] iv = c.getIV(); + AlgorithmParameters params = c.getParameters(); + // fail if either is null + if (iv == null || params == null) { + throw new RuntimeException("getIV()/getParameters() should " + + "not return null"); + } + + // check iv matches if not null + if (expectedIv != null && !Arrays.equals(expectedIv, iv)) { + throw new RuntimeException("IV should match expected value"); + } + + try { + byte[] iv2 = params.getParameterSpec(IvParameterSpec.class).getIV(); + if (!Arrays.equals(iv, iv2)) { + throw new RuntimeException("IV values should be consistent"); + } + } catch (InvalidParameterSpecException ipe) { + // should never happen + throw new AssertionError(); + } + } + + private static void testInterop(String interopProv) throws Exception { + testInterop(Cipher.getInstance(ALGO, p), + Cipher.getInstance(ALGO, interopProv)); + testInterop(Cipher.getInstance(ALGO, interopProv), + Cipher.getInstance(ALGO, p)); + } + + private static void testInterop(Cipher encCipher, Cipher decCipher) + throws Exception { + System.out.println("Interop: " + encCipher.getProvider().getName() + + " -> " + encCipher.getProvider().getName()); + byte[] pt = HexToBytes("012345678901234567890123456789"); + encCipher.init(Cipher.ENCRYPT_MODE, KEY); + byte[] ct = encCipher.doFinal(pt); + decCipher.init(Cipher.DECRYPT_MODE, KEY, encCipher.getParameters()); + byte[] pt2 = decCipher.doFinal(ct); + if (!Arrays.equals(pt, pt2)) { + System.out.println("HexDump/pt: " + toHexString(pt)); + System.out.println("HexDump/pt2: " + toHexString(pt2)); + throw new RuntimeException("Recovered data should match"); + } + System.out.println("=> Passed"); + } + + private static String getOpModeName(int opMode) { + switch (opMode) { + case Cipher.ENCRYPT_MODE: + return "ENCRYPT"; + + case Cipher.DECRYPT_MODE: + return "DECRYPT"; + + case Cipher.WRAP_MODE: + return "WRAP"; + + case Cipher.UNWRAP_MODE: + return "UNWRAP"; + + default: + return ""; + } + } + + public static void main(String[] args) throws Exception { + main(new TestChaChaPoly(), args); + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java new file mode 100644 index 00000000000..da1d91cc3de --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyKAT.java @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8255410 + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @build jdk.test.lib.Convert + * @run main/othervm TestChaChaPolyKAT + * @summary ChaCha20-Poly1305 Cipher Implementation (KAT) + */ + +import java.util.*; +import java.security.GeneralSecurityException; +import java.security.Provider; +import java.security.NoSuchAlgorithmException; +import javax.crypto.Cipher; +import javax.crypto.spec.ChaCha20ParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.crypto.AEADBadTagException; +import java.nio.ByteBuffer; +import jdk.test.lib.Convert; + +public class TestChaChaPolyKAT extends PKCS11Test { + + public static class TestData { + public TestData(String name, String keyStr, String nonceStr, int ctr, + int dir, String inputStr, String aadStr, String outStr) { + testName = Objects.requireNonNull(name); + key = HexToBytes(Objects.requireNonNull(keyStr)); + nonce = HexToBytes(Objects.requireNonNull(nonceStr)); + if ((counter = ctr) < 0) { + throw new IllegalArgumentException( + "counter must be 0 or greater"); + } + direction = dir; + if ((direction != Cipher.ENCRYPT_MODE) && + (direction != Cipher.DECRYPT_MODE)) { + throw new IllegalArgumentException( + "Direction must be ENCRYPT_MODE or DECRYPT_MODE"); + } + input = HexToBytes(Objects.requireNonNull(inputStr)); + aad = (aadStr != null) ? HexToBytes(aadStr) : null; + expOutput = HexToBytes(Objects.requireNonNull(outStr)); + } + + public final String testName; + public final byte[] key; + public final byte[] nonce; + public final int counter; + public final int direction; + public final byte[] input; + public final byte[] aad; + public final byte[] expOutput; + } + + private static final String ALGO = "ChaCha20-Poly1305"; + + public static final List aeadTestList = + new LinkedList() {{ + add(new TestData("RFC 7539 Sample AEAD Test Vector", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "070000004041424344454647", + 1, Cipher.ENCRYPT_MODE, + "4c616469657320616e642047656e746c656d656e206f662074686520636c6173" + + "73206f66202739393a204966204920636f756c64206f6666657220796f75206f" + + "6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73" + + "637265656e20776f756c642062652069742e", + "50515253c0c1c2c3c4c5c6c7", + "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6" + + "3dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b36" + + "92ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc" + + "3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd060" + + "0691")); + add(new TestData("RFC 7539 A.5 Sample Decryption", + "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", + "000000000102030405060708", + 1, Cipher.DECRYPT_MODE, + "64a0861575861af460f062c79be643bd5e805cfd345cf389f108670ac76c8cb2" + + "4c6cfc18755d43eea09ee94e382d26b0bdb7b73c321b0100d4f03b7f355894cf" + + "332f830e710b97ce98c8a84abd0b948114ad176e008d33bd60f982b1ff37c855" + + "9797a06ef4f0ef61c186324e2b3506383606907b6a7c02b0f9f6157b53c867e4" + + "b9166c767b804d46a59b5216cde7a4e99040c5a40433225ee282a1b0a06c523e" + + "af4534d7f83fa1155b0047718cbc546a0d072b04b3564eea1b422273f548271a" + + "0bb2316053fa76991955ebd63159434ecebb4e466dae5a1073a6727627097a10" + + "49e617d91d361094fa68f0ff77987130305beaba2eda04df997b714d6c6f2c29" + + "a6ad5cb4022b02709beead9d67890cbb22392336fea1851f38", + "f33388860000000000004e91", + "496e7465726e65742d4472616674732061726520647261667420646f63756d65" + + "6e74732076616c696420666f722061206d6178696d756d206f6620736978206d" + + "6f6e74687320616e64206d617920626520757064617465642c207265706c6163" + + "65642c206f72206f62736f6c65746564206279206f7468657220646f63756d65" + + "6e747320617420616e792074696d652e20497420697320696e617070726f7072" + + "6961746520746f2075736520496e7465726e65742d4472616674732061732072" + + "65666572656e6365206d6174657269616c206f7220746f206369746520746865" + + "6d206f74686572207468616e206173202fe2809c776f726b20696e2070726f67" + + "726573732e2fe2809d")); + }}; + + @Override + public void main(Provider p) throws Exception { + System.out.println("Testing " + p.getName()); + + try { + Cipher.getInstance(ALGO, p); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("Skip; no support for " + ALGO); + return; + } + + int testsPassed = 0; + int testNumber = 0; + + System.out.println("----- AEAD Tests -----"); + for (TestData test : aeadTestList) { + System.out.println("*** Test " + ++testNumber + ": " + + test.testName); + if (runAEADTest(p, test)) { + testsPassed++; + } + } + System.out.println(); + + System.out.println("Total tests: " + testNumber + + ", Passed: " + testsPassed + ", Failed: " + + (testNumber - testsPassed)); + if (testsPassed != testNumber) { + throw new RuntimeException("One or more tests failed. " + + "Check output for details"); + } + } + + private static boolean runAEADTest(Provider p, TestData testData) + throws GeneralSecurityException { + boolean result = false; + + Cipher mambo = Cipher.getInstance(ALGO, p); + SecretKeySpec mamboKey = new SecretKeySpec(testData.key, "ChaCha20"); + IvParameterSpec mamboSpec = new IvParameterSpec(testData.nonce); + + mambo.init(testData.direction, mamboKey, mamboSpec); + + byte[] out = new byte[mambo.getOutputSize(testData.input.length)]; + int outOff = 0; + try { + mambo.updateAAD(testData.aad); + outOff += mambo.update(testData.input, 0, testData.input.length, + out, outOff); + outOff += mambo.doFinal(out, outOff); + } catch (AEADBadTagException abte) { + // If we get a bad tag or derive a tag mismatch, log it + // and register it as a failure + System.out.println("FAIL: " + abte); + return false; + } + + if (!Arrays.equals(out, 0, outOff, testData.expOutput, 0, outOff)) { + System.out.println("ERROR - Output Mismatch!"); + System.out.println("Expected:\n" + + dumpHexBytes(testData.expOutput, 16, "\n", " ")); + System.out.println("Actual:\n" + + dumpHexBytes(out, 16, "\n", " ")); + System.out.println(); + } else { + result = true; + } + + return result; + } + + /** + * Dump the hex bytes of a buffer into string form. + * + * @param data The array of bytes to dump to stdout. + * @param itemsPerLine The number of bytes to display per line + * if the {@code lineDelim} character is blank then all bytes + * will be printed on a single line. + * @param lineDelim The delimiter between lines + * @param itemDelim The delimiter between bytes + * + * @return The hexdump of the byte array + */ + private static String dumpHexBytes(byte[] data, int itemsPerLine, + String lineDelim, String itemDelim) { + return dumpHexBytes(ByteBuffer.wrap(data), itemsPerLine, lineDelim, + itemDelim); + } + + private static String dumpHexBytes(ByteBuffer data, int itemsPerLine, + String lineDelim, String itemDelim) { + StringBuilder sb = new StringBuilder(); + if (data != null) { + data.mark(); + int i = 0; + while (data.remaining() > 0) { + if (i % itemsPerLine == 0 && i != 0) { + sb.append(lineDelim); + } + sb.append(String.format("%02X", data.get())).append(itemDelim); + i++; + } + data.reset(); + } + + return sb.toString(); + } + + public static void main(String[] args) throws Exception { + main(new TestChaChaPolyKAT(), args); + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java new file mode 100644 index 00000000000..0a760535631 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyNoReuse.java @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8255410 + * @library /test/lib .. + * @run main/othervm TestChaChaPolyNoReuse + * @summary Test PKCS#11 ChaCha20-Poly1305 Cipher Implementation + * (key/nonce reuse check) + */ + +import java.util.*; +import javax.crypto.Cipher; +import java.security.spec.AlgorithmParameterSpec; +import java.security.Provider; +import java.security.NoSuchAlgorithmException; +import javax.crypto.spec.ChaCha20ParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.crypto.AEADBadTagException; +import javax.crypto.SecretKey; +import java.security.InvalidKeyException; +import java.security.InvalidAlgorithmParameterException; + +public class TestChaChaPolyNoReuse extends PKCS11Test { + + private static final String KEY_ALGO = "ChaCha20"; + private static final String CIPHER_ALGO = "ChaCha20-Poly1305"; + + /** + * Basic TestMethod interface definition + */ + public interface TestMethod { + /** + * Runs the actual test case + * + * @param provider the provider to provide the requested Cipher obj. + * + * @return true if the test passes, false otherwise. + */ + boolean run(Provider p); + } + + public static class TestData { + public TestData(String name, String keyStr, String nonceStr, int ctr, + int dir, String inputStr, String aadStr, String outStr) { + testName = Objects.requireNonNull(name); + key = HexToBytes(keyStr); + nonce = HexToBytes(nonceStr); + if ((counter = ctr) < 0) { + throw new IllegalArgumentException( + "counter must be 0 or greater"); + } + direction = dir; + if (direction != Cipher.ENCRYPT_MODE) { + throw new IllegalArgumentException( + "Direction must be ENCRYPT_MODE"); + } + input = HexToBytes(inputStr); + aad = (aadStr != null) ? HexToBytes(aadStr) : null; + expOutput = HexToBytes(outStr); + } + + public final String testName; + public final byte[] key; + public final byte[] nonce; + public final int counter; + public final int direction; + public final byte[] input; + public final byte[] aad; + public final byte[] expOutput; + } + + public static final List aeadTestList = + new LinkedList() {{ + add(new TestData("RFC 7539 Sample AEAD Test Vector", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "070000004041424344454647", + 1, Cipher.ENCRYPT_MODE, + "4c616469657320616e642047656e746c656d656e206f662074686520636c6173" + + "73206f66202739393a204966204920636f756c64206f6666657220796f75206f" + + "6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73" + + "637265656e20776f756c642062652069742e", + "50515253c0c1c2c3c4c5c6c7", + "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d6" + + "3dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b36" + + "92ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc" + + "3ff4def08e4b7a9de576d26586cec64b61161ae10b594f09e26a7e902ecbd060" + + "0691")); + }}; + + /** + * Make sure we do not use this Cipher object without initializing it + * at all + */ + public static final TestMethod noInitTest = new TestMethod() { + @Override + public boolean run(Provider p) { + System.out.println("----- No Init Test -----"); + try { + Cipher cipher = Cipher.getInstance(CIPHER_ALGO, p); + TestData testData = aeadTestList.get(0); + + // Attempting to use the cipher without initializing it + // should throw an IllegalStateException + try { + cipher.updateAAD(testData.aad); + throw new RuntimeException( + "Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + // Do nothing, this is what we expected to happen + } + } catch (Exception exc) { + System.out.println("Unexpected exception: " + exc); + exc.printStackTrace(); + return false; + } + + return true; + } + }; + + /** + * Attempt to run two full encryption operations without an init in + * between. + */ + public static final TestMethod encTwiceNoInit = new TestMethod() { + @Override + public boolean run(Provider p) { + System.out.println("----- Encrypt 2nd time without init -----"); + try { + AlgorithmParameterSpec spec; + Cipher cipher = Cipher.getInstance(CIPHER_ALGO, p); + TestData testData = aeadTestList.get(0); + spec = new IvParameterSpec(testData.nonce); + SecretKey key = new SecretKeySpec(testData.key, KEY_ALGO); + + // Initialize and encrypt + cipher.init(testData.direction, key, spec); + cipher.updateAAD(testData.aad); + cipher.doFinal(testData.input); + System.out.println("First encryption complete"); + + // Now attempt to encrypt again without changing the key/IV + // This should fail. + try { + cipher.updateAAD(testData.aad); + } catch (IllegalStateException ise) { + // Do nothing, this is what we expected to happen + } + try { + cipher.doFinal(testData.input); + throw new RuntimeException( + "Expected IllegalStateException not thrown"); + } catch (IllegalStateException ise) { + // Do nothing, this is what we expected to happen + } + } catch (Exception exc) { + System.out.println("Unexpected exception: " + exc); + exc.printStackTrace(); + return false; + } + + return true; + } + }; + + /** + * Encrypt once successfully, then attempt to init with the same + * key and nonce. + */ + public static final TestMethod encTwiceInitSameParams = new TestMethod() { + @Override + public boolean run(Provider p) { + System.out.println("----- Encrypt, then init with same params " + + "-----"); + try { + AlgorithmParameterSpec spec; + Cipher cipher = Cipher.getInstance(CIPHER_ALGO, p); + TestData testData = aeadTestList.get(0); + spec = new IvParameterSpec(testData.nonce); + SecretKey key = new SecretKeySpec(testData.key, KEY_ALGO); + + // Initialize then encrypt + cipher.init(testData.direction, key, spec); + cipher.updateAAD(testData.aad); + cipher.doFinal(testData.input); + System.out.println("First encryption complete"); + + // Initializing after the completed encryption with + // the same key and nonce should fail. + try { + cipher.init(testData.direction, key, spec); + throw new RuntimeException( + "Expected IKE or IAPE not thrown"); + } catch (InvalidKeyException | + InvalidAlgorithmParameterException e) { + // Do nothing, this is what we expected to happen + } + } catch (Exception exc) { + System.out.println("Unexpected exception: " + exc); + exc.printStackTrace(); + return false; + } + + return true; + } + }; + + public static final List testMethodList = + Arrays.asList(noInitTest, encTwiceNoInit, encTwiceInitSameParams); + + @Override + public void main(Provider p) throws Exception { + System.out.println("Testing " + p.getName()); + try { + Cipher.getInstance(CIPHER_ALGO, p); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("Skip; no support for " + CIPHER_ALGO); + return; + } + + int testsPassed = 0; + int testNumber = 0; + + for (TestMethod tm : testMethodList) { + testNumber++; + boolean result = tm.run(p); + System.out.println("Result: " + (result ? "PASS" : "FAIL")); + if (result) { + testsPassed++; + } + } + + System.out.println("Total Tests: " + testNumber + + ", Tests passed: " + testsPassed); + if (testsPassed < testNumber) { + throw new RuntimeException( + "Not all tests passed. See output for failure info"); + } + } + + public static void main(String[] args) throws Exception { + main(new TestChaChaPolyNoReuse(), args); + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java new file mode 100644 index 00000000000..57a7b9a4606 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestChaChaPolyOutputSize.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8255410 + * @summary Check ChaCha20-Poly1305 cipher output size + * @library /test/lib .. + * @build jdk.test.lib.Convert + * @run main TestChaChaPolyOutputSize + */ + +import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.Provider; +import java.security.NoSuchAlgorithmException; +import javax.crypto.Cipher; +import javax.crypto.spec.ChaCha20ParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +public class TestChaChaPolyOutputSize extends PKCS11Test { + + private static final SecureRandom SR = new SecureRandom(); + + private static final SecretKeySpec KEY = new SecretKeySpec(new byte[32], + "ChaCha20"); + + private static final String ALGO = "ChaCha20-Poly1305"; + + public static void main(String args[]) throws Exception { + main(new TestChaChaPolyOutputSize(), args); + } + + @Override + public void main(Provider p) throws GeneralSecurityException { + System.out.println("Testing " + p.getName()); + try { + Cipher.getInstance(ALGO, p); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("Skip; no support for " + ALGO); + return; + } + testGetOutSize(p); + testMultiPartAEADDec(p); + } + + private static void testGetOutSize(Provider p) + throws GeneralSecurityException { + + Cipher ccp = Cipher.getInstance(ALGO, p); + ccp.init(Cipher.ENCRYPT_MODE, KEY, + new IvParameterSpec(getRandBuf(12))); + + // Encryption lengths are calculated as the input length plus the tag + // length (16). + testOutLen(ccp, 0, 16); + testOutLen(ccp, 5, 21); + testOutLen(ccp, 5120, 5136); + // perform an update, then test with a final block + byte[] input = new byte[5120]; + SR.nextBytes(input); + byte[] updateOut = ccp.update(input); + testOutLen(ccp, 1024, 1040 + + (5120 - (updateOut == null? 0 : updateOut.length))); + + // Decryption lengths are handled differently for AEAD mode. The length + // should be zero for anything up to and including the first 16 bytes + // (since that's the tag). Anything above that should be the input + // length plus any unprocessed input (via update calls), minus the + // 16 byte tag. + ccp.init(Cipher.DECRYPT_MODE, KEY, new IvParameterSpec(getRandBuf(12))); + testOutLen(ccp, 0, 0); + testOutLen(ccp, 5, 0); + testOutLen(ccp, 16, 0); + testOutLen(ccp, 5120, 5104); + // Perform an update, then test with the length of a final chunk + // of data. + updateOut = ccp.update(input); + testOutLen(ccp, 1024, 6128 - (updateOut == null? 0 : updateOut.length)); + } + + private static void testMultiPartAEADDec(Provider p) + throws GeneralSecurityException { + IvParameterSpec ivps = new IvParameterSpec(getRandBuf(12)); + + // Encrypt some data so we can test decryption. + byte[] pText = getRandBuf(2048); + ByteBuffer pTextBase = ByteBuffer.wrap(pText); + + Cipher enc = Cipher.getInstance(ALGO, p); + enc.init(Cipher.ENCRYPT_MODE, KEY, ivps); + ByteBuffer ctBuf = ByteBuffer.allocateDirect( + enc.getOutputSize(pText.length)); + enc.doFinal(pTextBase, ctBuf); + + // Create a new direct plain text ByteBuffer which will catch the + // decrypted data. + ByteBuffer ptBuf = ByteBuffer.allocateDirect(pText.length); + + // Set the cipher text buffer limit to roughly half the data so we can + // do an update/final sequence. + ctBuf.position(0).limit(1024); + + Cipher dec = Cipher.getInstance(ALGO, p); + dec.init(Cipher.DECRYPT_MODE, KEY, ivps); + dec.update(ctBuf, ptBuf); + System.out.println("CTBuf: " + ctBuf); + System.out.println("PTBuf: " + ptBuf); + ctBuf.limit(ctBuf.capacity()); + dec.doFinal(ctBuf, ptBuf); + + // NOTE: do not use flip() which will set limit based on current + // position. ptBuf curr pos = 2048 vs pTextBase pos = 0 + ptBuf.flip(); + pTextBase.flip(); + System.out.println("PT Base:" + pTextBase); + System.out.println("PT Actual:" + ptBuf); + + if (pTextBase.compareTo(ptBuf) != 0) { + StringBuilder sb = new StringBuilder(); + sb.append("Plaintext mismatch: Original: "). + append(pTextBase.toString()).append("\nActual :"). + append(ptBuf); + throw new RuntimeException(sb.toString()); + } + } + + private static void testOutLen(Cipher c, int inLen, int expOut) { + int actualOut = c.getOutputSize(inLen); + if (actualOut != expOut) { + throw new RuntimeException("Cipher " + c + ", in: " + inLen + + ", expOut: " + expOut + ", actual: " + actualOut); + } + } + + private static byte[] getRandBuf(int len) { + byte[] buf = new byte[len]; + SR.nextBytes(buf); + return buf; + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java index 67e94cecf68..55806f7723d 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestKATForGCM.java @@ -39,18 +39,6 @@ public class TestKATForGCM extends PKCS11Test { - // Utility methods - private static byte[] HexToBytes(String hexVal) { - if (hexVal == null) return new byte[0]; - byte[] result = new byte[hexVal.length()/2]; - for (int i = 0; i < result.length; i++) { - // 2 characters at a time - String byteVal = hexVal.substring(2*i, 2*i +2); - result[i] = Integer.valueOf(byteVal, 16).byteValue(); - } - return result; - } - private static class TestVector { SecretKey key; byte[] plainText; diff --git a/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java new file mode 100644 index 00000000000..cdb18dcee61 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/KeyGenerator/TestChaCha20.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8255410 + * @modules jdk.crypto.cryptoki + * @summary Check ChaCha20 key generator. + * @library /test/lib .. + * @run main/othervm TestChaCha20 + */ +import java.security.Provider; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.ChaCha20ParameterSpec; + +public class TestChaCha20 extends PKCS11Test { + + private static final String ALGO = "ChaCha20"; + + public static void main(String[] args) throws Exception { + main(new TestChaCha20(), args); + } + + @Override + public void main(Provider p) throws Exception { + System.out.println("Testing " + p.getName()); + KeyGenerator kg; + try { + kg = KeyGenerator.getInstance(ALGO, p); + } catch (NoSuchAlgorithmException nsae) { + System.out.println("Skip; no support for " + ALGO); + return; + } + + try { + kg.init(new ChaCha20ParameterSpec(new byte[12], 0)); + throw new RuntimeException( + "ChaCha20 key generation should not need any paramSpec"); + } catch (InvalidAlgorithmParameterException e) { + System.out.println("Expected IAPE: " + e.getMessage()); + } + + for (int keySize : new int[] { 32, 64, 128, 256, 512, 1024 }) { + try { + kg.init(keySize); + if (keySize != 256) { + throw new RuntimeException(keySize + " is invalid keysize"); + } + } catch (InvalidParameterException e) { + if (keySize == 256) { + throw new RuntimeException("IPE thrown for valid keySize"); + } else { + System.out.println("Expected IPE thrown for " + keySize); + } + } + } + + //kg.init(256); + SecretKey key = kg.generateKey(); + byte[] keyValue = key.getEncoded(); + System.out.println("Key: " + toHexString(keyValue)); + if (keyValue.length != 32) { + throw new RuntimeException("The size of generated key must be 256"); + } + } +} diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index b914c80581a..7ae0b684017 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -111,6 +111,40 @@ public static enum ECCState { None, Basic, Extended }; static double nss3_version = -1; static Provider pkcs11 = newPKCS11Provider(); + // Utility methods + // Used to backport HexFormat from 17. + protected static byte[] HexToBytes(String hexVal) { + if (hexVal == null) return new byte[0]; + byte[] result = new byte[hexVal.length()/2]; + for (int i = 0; i < result.length; i++) { + // 2 characters at a time + String byteVal = hexVal.substring(2*i, 2*i +2); + result[i] = Integer.valueOf(byteVal, 16).byteValue(); + } + return result; + } + private static void byte2hex(byte b, StringBuffer buf) { + char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + int high = ((b & 0xf0) >> 4); + int low = (b & 0x0f); + buf.append(hexChars[high]); + buf.append(hexChars[low]); + } + protected static String toHexString(byte[] block) { + StringBuffer buf = new StringBuffer(); + + int len = block.length; + + for (int i = 0; i < len; i++) { + byte2hex(block[i], buf); + if (i < len-1) { + buf.append(":"); + } + } + return buf.toString(); + } + public static Provider newPKCS11Provider() { ServiceLoader sl = ServiceLoader.load(java.security.Provider.class); Iterator iter = sl.iterator(); diff --git a/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java b/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java new file mode 100644 index 00000000000..bca594c66bd --- /dev/null +++ b/test/jdk/sun/security/pkcs11/SecretKeyFactory/TestGeneral.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8255410 + * @summary test the general SecretKeyFactory functionality + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + * @run main/othervm TestGeneral + */ + +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.util.Arrays; +import javax.crypto.SecretKeyFactory; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +public class TestGeneral extends PKCS11Test { + + private enum TestResult { + PASS, + FAIL, + TBD // unused for now + } + + public static void main(String[] args) throws Exception { + main(new TestGeneral(), args); + } + + private void test(String algorithm, SecretKey key, Provider p, + TestResult expected) throws RuntimeException { + System.out.println("Testing " + algorithm + " SKF from " + p.getName()); + SecretKeyFactory skf; + try { + skf = SecretKeyFactory.getInstance(algorithm, p); + } catch (NoSuchAlgorithmException e) { + System.out.println("Not supported, skipping: " + e); + return; + } + try { + SecretKey key2 = skf.translateKey(key); + if (expected == TestResult.FAIL) { + throw new RuntimeException("translateKey() should FAIL"); + } + System.out.println("=> translated key"); + if (!key2.getAlgorithm().equalsIgnoreCase(algorithm)) { + throw new RuntimeException("translated key algorithm mismatch"); + } + System.out.println("=> checked key algorithm"); + + // proceed to check encodings if format match + if (key2.getFormat().equalsIgnoreCase(key.getFormat())) { + if (key2.getEncoded() != null && + !Arrays.equals(key.getEncoded(), key2.getEncoded())) { + throw new RuntimeException( + "translated key encoding mismatch"); + } + System.out.println("=> checked key format and encoding"); + } + } catch (Exception e) { + if (expected == TestResult.PASS) { + e.printStackTrace(); + throw new RuntimeException("translateKey() should pass", e); + } + } + } + + @Override + public void main(Provider p) throws Exception { + + byte[] rawBytes = new byte[32]; + new SecureRandom().nextBytes(rawBytes); + + SecretKey aes_128Key = new SecretKeySpec(rawBytes, 0, 16, "AES"); + SecretKey aes_256Key = new SecretKeySpec(rawBytes, 0, 32, "AES"); + SecretKey bf_128Key = new SecretKeySpec(rawBytes, 0, 16, "Blowfish"); + SecretKey cc20Key = new SecretKeySpec(rawBytes, 0, 32, "ChaCha20"); + + // fixed key length + test("AES", aes_128Key, p, TestResult.PASS); + test("AES", aes_256Key, p, TestResult.PASS); + test("AES", cc20Key, p, TestResult.FAIL); + + test("ChaCha20", aes_128Key, p, TestResult.FAIL); + test("ChaCha20", aes_256Key, p, TestResult.FAIL); + test("ChaCha20", cc20Key, p, TestResult.PASS); + + // variable key length + // Different PKCS11 impls may have different ranges + // of supported key sizes for variable-key-length + // algorithms. + test("Blowfish", aes_128Key, p, TestResult.FAIL); + test("Blowfish", cc20Key, p, TestResult.FAIL); + test("Blowfish", bf_128Key, p, TestResult.PASS); + } +} diff --git a/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java b/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java index beae7253df3..12e06b19c4b 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java +++ b/test/jdk/sun/security/pkcs11/tls/TestLeadingZeroesP11.java @@ -107,35 +107,6 @@ public void main(Provider p) throws Exception { } - /* - * Converts a byte to hex digit and writes to the supplied buffer - */ - private void byte2hex(byte b, StringBuffer buf) { - char[] hexChars = { '0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - int high = ((b & 0xf0) >> 4); - int low = (b & 0x0f); - buf.append(hexChars[high]); - buf.append(hexChars[low]); - } - - /* - * Converts a byte array to hex string - */ - private String toHexString(byte[] block) { - StringBuffer buf = new StringBuffer(); - - int len = block.length; - - for (int i = 0; i < len; i++) { - byte2hex(block[i], buf); - if (i < len-1) { - buf.append(":"); - } - } - return buf.toString(); - } - private static final byte alicePubKeyEnc[] = { (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x24, (byte)0x30, (byte)0x81, (byte)0x99, (byte)0x06,