diff options
Diffstat (limited to 'src/mscrypto')
-rw-r--r-- | src/mscrypto/Makefile.am | 62 | ||||
-rw-r--r-- | src/mscrypto/Makefile.in | 799 | ||||
-rw-r--r-- | src/mscrypto/README | 39 | ||||
-rw-r--r-- | src/mscrypto/app.c | 1289 | ||||
-rw-r--r-- | src/mscrypto/certkeys.c | 2615 | ||||
-rw-r--r-- | src/mscrypto/ciphers.c | 937 | ||||
-rw-r--r-- | src/mscrypto/crypto.c | 889 | ||||
-rw-r--r-- | src/mscrypto/csp_calg.h | 105 | ||||
-rw-r--r-- | src/mscrypto/csp_oid.h | 114 | ||||
-rw-r--r-- | src/mscrypto/digests.c | 668 | ||||
-rw-r--r-- | src/mscrypto/globals.h | 39 | ||||
-rw-r--r-- | src/mscrypto/hmac.c | 963 | ||||
-rw-r--r-- | src/mscrypto/keysstore.c | 620 | ||||
-rw-r--r-- | src/mscrypto/kt_rsa.c | 631 | ||||
-rw-r--r-- | src/mscrypto/kw_aes.c | 662 | ||||
-rw-r--r-- | src/mscrypto/kw_des.c | 730 | ||||
-rw-r--r-- | src/mscrypto/mingw-crypt32.def | 36 | ||||
-rw-r--r-- | src/mscrypto/private.h | 130 | ||||
-rw-r--r-- | src/mscrypto/signatures.c | 960 | ||||
-rw-r--r-- | src/mscrypto/symkeys.c | 824 | ||||
-rw-r--r-- | src/mscrypto/x509.c | 2281 | ||||
-rw-r--r-- | src/mscrypto/x509vfy.c | 1406 | ||||
-rw-r--r-- | src/mscrypto/xmlsec-mingw.h | 210 |
23 files changed, 17009 insertions, 0 deletions
diff --git a/src/mscrypto/Makefile.am b/src/mscrypto/Makefile.am new file mode 100644 index 00000000..5cea654b --- /dev/null +++ b/src/mscrypto/Makefile.am @@ -0,0 +1,62 @@ +NULL = + +EXTRA_DIST = \ + mingw-crypt32.def \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-mscrypto.la \ + $(NULL) + +libxmlsec1_mscrypto_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(MSCRYPTO_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_mscrypto_la_SOURCES =\ + globals.h \ + private.h \ + app.c \ + certkeys.c \ + ciphers.c \ + crypto.c \ + digests.c \ + hmac.c \ + keysstore.c \ + kw_aes.c \ + kw_des.c \ + kt_rsa.c \ + signatures.c \ + symkeys.c \ + x509.c \ + x509vfy.c \ + csp_calg.h \ + csp_oid.h \ + xmlsec-mingw.h \ + $(NULL) + +if SHAREDLIB_HACK +libxmlsec1_mscrypto_la_SOURCES += ../strings.c +endif + +libxmlsec1_mscrypto_la_LIBADD = \ + $(MSCRYPTO_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + ../libxmlsec1.la \ + $(NULL) + +libxmlsec1_mscrypto_la_DEPENDENCIES = \ + mingw-crypt32.def \ + $(NULL) + +libxmlsec1_mscrypto_la_LDFLAGS = \ + @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) diff --git a/src/mscrypto/Makefile.in b/src/mscrypto/Makefile.in new file mode 100644 index 00000000..72d22a3b --- /dev/null +++ b/src/mscrypto/Makefile.in @@ -0,0 +1,799 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@SHAREDLIB_HACK_TRUE@am__append_1 = ../strings.c +subdir = src/mscrypto +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +am__libxmlsec1_mscrypto_la_SOURCES_DIST = globals.h private.h app.c \ + certkeys.c ciphers.c crypto.c digests.c hmac.c keysstore.c \ + kw_aes.c kw_des.c kt_rsa.c signatures.c symkeys.c x509.c \ + x509vfy.c csp_calg.h csp_oid.h xmlsec-mingw.h ../strings.c +am__objects_1 = +@SHAREDLIB_HACK_TRUE@am__objects_2 = \ +@SHAREDLIB_HACK_TRUE@ libxmlsec1_mscrypto_la-strings.lo +am_libxmlsec1_mscrypto_la_OBJECTS = libxmlsec1_mscrypto_la-app.lo \ + libxmlsec1_mscrypto_la-certkeys.lo \ + libxmlsec1_mscrypto_la-ciphers.lo \ + libxmlsec1_mscrypto_la-crypto.lo \ + libxmlsec1_mscrypto_la-digests.lo \ + libxmlsec1_mscrypto_la-hmac.lo \ + libxmlsec1_mscrypto_la-keysstore.lo \ + libxmlsec1_mscrypto_la-kw_aes.lo \ + libxmlsec1_mscrypto_la-kw_des.lo \ + libxmlsec1_mscrypto_la-kt_rsa.lo \ + libxmlsec1_mscrypto_la-signatures.lo \ + libxmlsec1_mscrypto_la-symkeys.lo \ + libxmlsec1_mscrypto_la-x509.lo \ + libxmlsec1_mscrypto_la-x509vfy.lo $(am__objects_1) \ + $(am__objects_2) +libxmlsec1_mscrypto_la_OBJECTS = $(am_libxmlsec1_mscrypto_la_OBJECTS) +libxmlsec1_mscrypto_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libxmlsec1_mscrypto_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libxmlsec1_mscrypto_la_SOURCES) +DIST_SOURCES = $(am__libxmlsec1_mscrypto_la_SOURCES_DIST) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CP = @CP@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GCRYPT_CFLAGS = @GCRYPT_CFLAGS@ +GCRYPT_CRYPTO_LIB = @GCRYPT_CRYPTO_LIB@ +GCRYPT_LIBS = @GCRYPT_LIBS@ +GCRYPT_MIN_VERSION = @GCRYPT_MIN_VERSION@ +GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ +GNUTLS_CRYPTO_LIB = @GNUTLS_CRYPTO_LIB@ +GNUTLS_LIBS = @GNUTLS_LIBS@ +GNUTLS_MIN_VERSION = @GNUTLS_MIN_VERSION@ +GREP = @GREP@ +HELP2MAN = @HELP2MAN@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_CONFIG = @LIBXML_CONFIG@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIBXML_MIN_VERSION = @LIBXML_MIN_VERSION@ +LIBXSLT_CFLAGS = @LIBXSLT_CFLAGS@ +LIBXSLT_CONFIG = @LIBXSLT_CONFIG@ +LIBXSLT_LIBS = @LIBXSLT_LIBS@ +LIBXSLT_MIN_VERSION = @LIBXSLT_MIN_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAN2HTML = @MAN2HTML@ +MKDIR_P = @MKDIR_P@ +MOZILLA_MIN_VERSION = @MOZILLA_MIN_VERSION@ +MSCRYPTO_CFLAGS = @MSCRYPTO_CFLAGS@ +MSCRYPTO_CRYPTO_LIB = @MSCRYPTO_CRYPTO_LIB@ +MSCRYPTO_LIBS = @MSCRYPTO_LIBS@ +MV = @MV@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NSPR_MIN_VERSION = @NSPR_MIN_VERSION@ +NSPR_PACKAGE = @NSPR_PACKAGE@ +NSS_CFLAGS = @NSS_CFLAGS@ +NSS_CRYPTO_LIB = @NSS_CRYPTO_LIB@ +NSS_LIBS = @NSS_LIBS@ +NSS_MIN_VERSION = @NSS_MIN_VERSION@ +NSS_PACKAGE = @NSS_PACKAGE@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ +OPENSSL_CRYPTO_LIB = @OPENSSL_CRYPTO_LIB@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OPENSSL_MIN_VERSION = @OPENSSL_MIN_VERSION@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKGCONFIG_PRESENT = @PKGCONFIG_PRESENT@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TAR = @TAR@ +U = @U@ +VERSION = @VERSION@ +XMLSEC_APP_DEFINES = @XMLSEC_APP_DEFINES@ +XMLSEC_CFLAGS = @XMLSEC_CFLAGS@ +XMLSEC_CORE_CFLAGS = @XMLSEC_CORE_CFLAGS@ +XMLSEC_CORE_LIBS = @XMLSEC_CORE_LIBS@ +XMLSEC_CRYPTO = @XMLSEC_CRYPTO@ +XMLSEC_CRYPTO_CFLAGS = @XMLSEC_CRYPTO_CFLAGS@ +XMLSEC_CRYPTO_DISABLED_LIST = @XMLSEC_CRYPTO_DISABLED_LIST@ +XMLSEC_CRYPTO_EXTRA_LDFLAGS = @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ +XMLSEC_CRYPTO_LIB = @XMLSEC_CRYPTO_LIB@ +XMLSEC_CRYPTO_LIBS = @XMLSEC_CRYPTO_LIBS@ +XMLSEC_CRYPTO_LIST = @XMLSEC_CRYPTO_LIST@ +XMLSEC_CRYPTO_PC_FILES_LIST = @XMLSEC_CRYPTO_PC_FILES_LIST@ +XMLSEC_DEFINES = @XMLSEC_DEFINES@ +XMLSEC_DL_INCLUDES = @XMLSEC_DL_INCLUDES@ +XMLSEC_DL_LIBS = @XMLSEC_DL_LIBS@ +XMLSEC_DOCDIR = @XMLSEC_DOCDIR@ +XMLSEC_EXTRA_LDFLAGS = @XMLSEC_EXTRA_LDFLAGS@ +XMLSEC_GCRYPT_CFLAGS = @XMLSEC_GCRYPT_CFLAGS@ +XMLSEC_GCRYPT_LIBS = @XMLSEC_GCRYPT_LIBS@ +XMLSEC_GNUTLS_CFLAGS = @XMLSEC_GNUTLS_CFLAGS@ +XMLSEC_GNUTLS_LIBS = @XMLSEC_GNUTLS_LIBS@ +XMLSEC_LIBDIR = @XMLSEC_LIBDIR@ +XMLSEC_LIBS = @XMLSEC_LIBS@ +XMLSEC_NO_AES = @XMLSEC_NO_AES@ +XMLSEC_NO_APPS_CRYPTO_DYNAMIC_LOADING = @XMLSEC_NO_APPS_CRYPTO_DYNAMIC_LOADING@ +XMLSEC_NO_CRYPTO_DYNAMIC_LOADING = @XMLSEC_NO_CRYPTO_DYNAMIC_LOADING@ +XMLSEC_NO_DES = @XMLSEC_NO_DES@ +XMLSEC_NO_DSA = @XMLSEC_NO_DSA@ +XMLSEC_NO_GCRYPT = @XMLSEC_NO_GCRYPT@ +XMLSEC_NO_GNUTLS = @XMLSEC_NO_GNUTLS@ +XMLSEC_NO_GOST = @XMLSEC_NO_GOST@ +XMLSEC_NO_HMAC = @XMLSEC_NO_HMAC@ +XMLSEC_NO_LIBXSLT = @XMLSEC_NO_LIBXSLT@ +XMLSEC_NO_MD5 = @XMLSEC_NO_MD5@ +XMLSEC_NO_MSCRYPTO = @XMLSEC_NO_MSCRYPTO@ +XMLSEC_NO_NSS = @XMLSEC_NO_NSS@ +XMLSEC_NO_OPENSSL = @XMLSEC_NO_OPENSSL@ +XMLSEC_NO_RIPEMD160 = @XMLSEC_NO_RIPEMD160@ +XMLSEC_NO_RSA = @XMLSEC_NO_RSA@ +XMLSEC_NO_SHA1 = @XMLSEC_NO_SHA1@ +XMLSEC_NO_SHA224 = @XMLSEC_NO_SHA224@ +XMLSEC_NO_SHA256 = @XMLSEC_NO_SHA256@ +XMLSEC_NO_SHA384 = @XMLSEC_NO_SHA384@ +XMLSEC_NO_SHA512 = @XMLSEC_NO_SHA512@ +XMLSEC_NO_X509 = @XMLSEC_NO_X509@ +XMLSEC_NO_XKMS = @XMLSEC_NO_XKMS@ +XMLSEC_NO_XMLDSIG = @XMLSEC_NO_XMLDSIG@ +XMLSEC_NO_XMLENC = @XMLSEC_NO_XMLENC@ +XMLSEC_NSS_CFLAGS = @XMLSEC_NSS_CFLAGS@ +XMLSEC_NSS_LIBS = @XMLSEC_NSS_LIBS@ +XMLSEC_OPENSSL_CFLAGS = @XMLSEC_OPENSSL_CFLAGS@ +XMLSEC_OPENSSL_LIBS = @XMLSEC_OPENSSL_LIBS@ +XMLSEC_PACKAGE = @XMLSEC_PACKAGE@ +XMLSEC_STATIC_BINARIES = @XMLSEC_STATIC_BINARIES@ +XMLSEC_VERSION = @XMLSEC_VERSION@ +XMLSEC_VERSION_INFO = @XMLSEC_VERSION_INFO@ +XMLSEC_VERSION_MAJOR = @XMLSEC_VERSION_MAJOR@ +XMLSEC_VERSION_MINOR = @XMLSEC_VERSION_MINOR@ +XMLSEC_VERSION_SAFE = @XMLSEC_VERSION_SAFE@ +XMLSEC_VERSION_SUBMINOR = @XMLSEC_VERSION_SUBMINOR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +NULL = +EXTRA_DIST = \ + mingw-crypt32.def \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-mscrypto.la \ + $(NULL) + +libxmlsec1_mscrypto_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(MSCRYPTO_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_mscrypto_la_SOURCES = globals.h private.h app.c certkeys.c \ + ciphers.c crypto.c digests.c hmac.c keysstore.c kw_aes.c \ + kw_des.c kt_rsa.c signatures.c symkeys.c x509.c x509vfy.c \ + csp_calg.h csp_oid.h xmlsec-mingw.h $(NULL) $(am__append_1) +libxmlsec1_mscrypto_la_LIBADD = \ + $(MSCRYPTO_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + ../libxmlsec1.la \ + $(NULL) + +libxmlsec1_mscrypto_la_DEPENDENCIES = \ + mingw-crypt32.def \ + $(NULL) + +libxmlsec1_mscrypto_la_LDFLAGS = \ + @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/mscrypto/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/mscrypto/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libxmlsec1-mscrypto.la: $(libxmlsec1_mscrypto_la_OBJECTS) $(libxmlsec1_mscrypto_la_DEPENDENCIES) + $(libxmlsec1_mscrypto_la_LINK) -rpath $(libdir) $(libxmlsec1_mscrypto_la_OBJECTS) $(libxmlsec1_mscrypto_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-app.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-certkeys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-ciphers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-crypto.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-digests.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-hmac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-keysstore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-kt_rsa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-kw_aes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-kw_des.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-signatures.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-strings.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-symkeys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-x509.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_mscrypto_la-x509vfy.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libxmlsec1_mscrypto_la-app.lo: app.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-app.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-app.Tpo -c -o libxmlsec1_mscrypto_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-app.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-app.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='app.c' object='libxmlsec1_mscrypto_la-app.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c + +libxmlsec1_mscrypto_la-certkeys.lo: certkeys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-certkeys.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-certkeys.Tpo -c -o libxmlsec1_mscrypto_la-certkeys.lo `test -f 'certkeys.c' || echo '$(srcdir)/'`certkeys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-certkeys.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-certkeys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='certkeys.c' object='libxmlsec1_mscrypto_la-certkeys.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-certkeys.lo `test -f 'certkeys.c' || echo '$(srcdir)/'`certkeys.c + +libxmlsec1_mscrypto_la-ciphers.lo: ciphers.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-ciphers.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-ciphers.Tpo -c -o libxmlsec1_mscrypto_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-ciphers.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-ciphers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ciphers.c' object='libxmlsec1_mscrypto_la-ciphers.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c + +libxmlsec1_mscrypto_la-crypto.lo: crypto.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-crypto.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-crypto.Tpo -c -o libxmlsec1_mscrypto_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-crypto.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto.c' object='libxmlsec1_mscrypto_la-crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c + +libxmlsec1_mscrypto_la-digests.lo: digests.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-digests.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-digests.Tpo -c -o libxmlsec1_mscrypto_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-digests.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-digests.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='digests.c' object='libxmlsec1_mscrypto_la-digests.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c + +libxmlsec1_mscrypto_la-hmac.lo: hmac.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-hmac.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-hmac.Tpo -c -o libxmlsec1_mscrypto_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-hmac.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hmac.c' object='libxmlsec1_mscrypto_la-hmac.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c + +libxmlsec1_mscrypto_la-keysstore.lo: keysstore.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-keysstore.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-keysstore.Tpo -c -o libxmlsec1_mscrypto_la-keysstore.lo `test -f 'keysstore.c' || echo '$(srcdir)/'`keysstore.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-keysstore.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-keysstore.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keysstore.c' object='libxmlsec1_mscrypto_la-keysstore.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-keysstore.lo `test -f 'keysstore.c' || echo '$(srcdir)/'`keysstore.c + +libxmlsec1_mscrypto_la-kw_aes.lo: kw_aes.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-kw_aes.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-kw_aes.Tpo -c -o libxmlsec1_mscrypto_la-kw_aes.lo `test -f 'kw_aes.c' || echo '$(srcdir)/'`kw_aes.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-kw_aes.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-kw_aes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kw_aes.c' object='libxmlsec1_mscrypto_la-kw_aes.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-kw_aes.lo `test -f 'kw_aes.c' || echo '$(srcdir)/'`kw_aes.c + +libxmlsec1_mscrypto_la-kw_des.lo: kw_des.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-kw_des.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-kw_des.Tpo -c -o libxmlsec1_mscrypto_la-kw_des.lo `test -f 'kw_des.c' || echo '$(srcdir)/'`kw_des.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-kw_des.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-kw_des.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kw_des.c' object='libxmlsec1_mscrypto_la-kw_des.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-kw_des.lo `test -f 'kw_des.c' || echo '$(srcdir)/'`kw_des.c + +libxmlsec1_mscrypto_la-kt_rsa.lo: kt_rsa.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-kt_rsa.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-kt_rsa.Tpo -c -o libxmlsec1_mscrypto_la-kt_rsa.lo `test -f 'kt_rsa.c' || echo '$(srcdir)/'`kt_rsa.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-kt_rsa.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-kt_rsa.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kt_rsa.c' object='libxmlsec1_mscrypto_la-kt_rsa.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-kt_rsa.lo `test -f 'kt_rsa.c' || echo '$(srcdir)/'`kt_rsa.c + +libxmlsec1_mscrypto_la-signatures.lo: signatures.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-signatures.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-signatures.Tpo -c -o libxmlsec1_mscrypto_la-signatures.lo `test -f 'signatures.c' || echo '$(srcdir)/'`signatures.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-signatures.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-signatures.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='signatures.c' object='libxmlsec1_mscrypto_la-signatures.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-signatures.lo `test -f 'signatures.c' || echo '$(srcdir)/'`signatures.c + +libxmlsec1_mscrypto_la-symkeys.lo: symkeys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-symkeys.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-symkeys.Tpo -c -o libxmlsec1_mscrypto_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-symkeys.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-symkeys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='symkeys.c' object='libxmlsec1_mscrypto_la-symkeys.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c + +libxmlsec1_mscrypto_la-x509.lo: x509.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-x509.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-x509.Tpo -c -o libxmlsec1_mscrypto_la-x509.lo `test -f 'x509.c' || echo '$(srcdir)/'`x509.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-x509.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-x509.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x509.c' object='libxmlsec1_mscrypto_la-x509.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-x509.lo `test -f 'x509.c' || echo '$(srcdir)/'`x509.c + +libxmlsec1_mscrypto_la-x509vfy.lo: x509vfy.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-x509vfy.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-x509vfy.Tpo -c -o libxmlsec1_mscrypto_la-x509vfy.lo `test -f 'x509vfy.c' || echo '$(srcdir)/'`x509vfy.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-x509vfy.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-x509vfy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x509vfy.c' object='libxmlsec1_mscrypto_la-x509vfy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-x509vfy.lo `test -f 'x509vfy.c' || echo '$(srcdir)/'`x509vfy.c + +libxmlsec1_mscrypto_la-strings.lo: ../strings.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_mscrypto_la-strings.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_mscrypto_la-strings.Tpo -c -o libxmlsec1_mscrypto_la-strings.lo `test -f '../strings.c' || echo '$(srcdir)/'`../strings.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_mscrypto_la-strings.Tpo $(DEPDIR)/libxmlsec1_mscrypto_la-strings.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../strings.c' object='libxmlsec1_mscrypto_la-strings.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_mscrypto_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_mscrypto_la-strings.lo `test -f '../strings.c' || echo '$(srcdir)/'`../strings.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/mscrypto/README b/src/mscrypto/README new file mode 100644 index 00000000..0b3f4b6b --- /dev/null +++ b/src/mscrypto/README @@ -0,0 +1,39 @@ +WHAT VERSION OF WINDOWS? +------------------------------------------------------------------------ + +The xmlsec-mscrypto lib is developed on a windows XP machine with MS Visual +Studio (6 and .NET). The MS Crypto API has been evolving a lot with the +new releases of windows and internet explorer. MS CryptoAPI libraries +are distributed with ie and with the windows OS. Full functionality will +only be achieved on windows XP. AES is for example not supported on pre +XP versions of Windows (workarounds for this are possible, I believe). +Direct RSA de/encryption, used by xmlsec-mscrypto, is only possible from +Win 2000 (possibly also with a newer version of ie, with strong encryption +patch installed). It's very likely more of these issues are lying around, a +nd until it is tested on older windows systems it is uncertain what will work. + +KEYS MANAGER with MS Certificate store support. +------------------------------------------------------------------------ + +The default xmlsec-mscrypto keys manager is based upon the simple keys +store, found in the xmlsec core library. If keys are not found in the +simple keys store, than MS Certificate store is used to lookup keys. +The certificate store is only used on a READONLY base, so it is not possible +to store keys via the keys store into the MS certificate store. There are enough +other tools that can do that for you. + +When the xmlsec application is started, with the config parameter the name of +the (system) keystore can be given. That keystore will be used for certificates +and keys lookup. With the keyname now two types of values can be given: + - simple name (called friendly name with MS); + - full subject name (recommended) of the key's certificate. + +KNOWN ISSUES. +------------------------------------------------------------------------ +1) Default keys manager don't use trusted certs in MS Crypto Store +(http://bugzilla.gnome.org/show_bug.cgi?id=123668). + +2) The only supported file formats are PKCS#12 and DER certificates +(http://bugzilla.gnome.org/show_bug.cgi?id=123675). + + diff --git a/src/mscrypto/app.c b/src/mscrypto/app.c new file mode 100644 index 00000000..92894d90 --- /dev/null +++ b/src/mscrypto/app.c @@ -0,0 +1,1289 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/app.h> +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/certkeys.h> +#include <xmlsec/mscrypto/keysstore.h> +#include <xmlsec/mscrypto/x509.h> +#include "private.h" + + +/* I don't see any other way then to use a global var to get the + * config info to the mscrypto keysstore :( WK + */ +static LPTSTR gXmlSecMSCryptoAppCertStoreName = NULL; + +/** + * xmlSecMSCryptoAppInit: + * @config: the name of another then the default ms certificate store. + * + * General crypto engine initialization. This function is used + * by XMLSec command line utility and called before + * @xmlSecInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppInit(const char* config) { + /* initialize MSCrypto crypto engine */ + + /* config parameter can contain *another* ms certs store name + * then the default (MY) + */ + if (NULL != config && strlen(config) > 0) { + if (gXmlSecMSCryptoAppCertStoreName != NULL) { + /* This should not happen, initialize twice */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "config=%s, config already set", + xmlSecErrorsSafeString(config)); + return (-1); + } + +#ifdef UNICODE + gXmlSecMSCryptoAppCertStoreName = xmlSecMSCryptoConvertLocaleToUnicode(config); + if (gXmlSecMSCryptoAppCertStoreName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoConvertLocaleToUnicode", + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "config=%s", + xmlSecErrorsSafeString(config)); + return (-1); + } +#else /* UNICODE */ + gXmlSecMSCryptoAppCertStoreName = xmlStrdup(config); + if (gXmlSecMSCryptoAppCertStoreName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlStrdup", + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "config=%s", + xmlSecErrorsSafeString(config)); + return (-1); + } +#endif /* UNICODE */ + } + + return(0); +} + +/** + * xmlSecMSCryptoAppShutdown: + * + * General crypto engine shutdown. This function is used + * by XMLSec command line utility and called after + * @xmlSecShutdown function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppShutdown(void) { + /* shutdown MSCrypto crypto engine */ + if (NULL != gXmlSecMSCryptoAppCertStoreName) { + xmlFree(gXmlSecMSCryptoAppCertStoreName); + gXmlSecMSCryptoAppCertStoreName = NULL; + } + return(0); +} + +/** + * xmlSecMSCryptoAppGetCertStoreName: + * + * Gets the MS Crypto certs store name set by @xmlSecMSCryptoAppInit function. + * + * Returns: the MS Crypto certs name used by xmlsec-mscrypto. + */ +LPCTSTR +xmlSecMSCryptoAppGetCertStoreName(void) { + return(gXmlSecMSCryptoAppCertStoreName); +} + +/************************************************************************************* + * Keys + *************************************************************************************/ + +/** + * xmlSecMSCryptoAppKeyLoad: + * @filename: the key filename. + * @format: the key file format. + * @pwd: the key file password. + * @pwdCallback: the key password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key from the a file. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecMSCryptoAppKeyLoad(const char *filename, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + xmlSecBuffer buffer; + xmlSecKeyPtr key = NULL; + int ret; + + xmlSecAssert2(filename != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + switch (format) { + case xmlSecKeyDataFormatPkcs12: + key = xmlSecMSCryptoAppPkcs12Load(filename, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoAppPkcs12Load", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; + case xmlSecKeyDataFormatCertDer: + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecBufferReadFile(&buffer, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferReadFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return (NULL); + } + + key = xmlSecMSCryptoAppKeyLoadMemory(xmlSecBufferGetData(&buffer), + xmlSecBufferGetSize(&buffer), format, + pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoAppKeyLoadMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + xmlSecBufferFinalize(&buffer); + break; + default: + /* Any other format like PEM keys is currently not supported */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(NULL); + } + + return(key); +} + +/** + * xmlSecMSCryptoAppKeyLoadMemory: + * @data: the key binary data. + * @dataSize: the key data size. + * @format: the key format. + * @pwd: the key password. + * @pwdCallback: the key password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key from the a file. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecMSCryptoAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + PCCERT_CONTEXT pCert = NULL; + PCCERT_CONTEXT tmpcert = NULL; + xmlSecKeyDataPtr x509Data = NULL; + xmlSecKeyDataPtr keyData = NULL; + xmlSecKeyPtr key = NULL; + xmlSecKeyPtr res = NULL; + int ret; + + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(dataSize > 0, NULL); + xmlSecAssert2(format == xmlSecKeyDataFormatCertDer, NULL); + + pCert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, data, dataSize); + if (NULL == pCert) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertCreateCertificateContext", + XMLSEC_ERRORS_R_IO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + x509Data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataX509Id); + if(x509Data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecMSCryptoKeyDataX509Id))); + goto done; + } + + tmpcert = CertDuplicateCertificateContext(pCert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecMSCryptoKeyDataX509AdoptKeyCert(x509Data, tmpcert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + CertFreeCertificateContext(tmpcert); + goto done; + } + tmpcert = NULL; + + keyData = xmlSecMSCryptoCertAdopt(pCert, xmlSecKeyDataTypePublic); + if(keyData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoCertAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + pCert = NULL; + + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecKeySetValue(key, keyData); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + keyData = NULL; + + ret = xmlSecKeyAdoptData(key, x509Data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyAdoptData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + x509Data = NULL; + + /* success */ + res = key; + key = NULL; +done: + if(pCert != NULL) { + CertFreeCertificateContext(pCert); + } + if(tmpcert != NULL) { + CertFreeCertificateContext(tmpcert); + } + if(x509Data != NULL) { + xmlSecKeyDataDestroy(x509Data); + } + if(keyData != NULL) { + xmlSecKeyDataDestroy(keyData); + } + if(key != NULL) { + xmlSecKeyDestroy(key); + } + return(res); +} + + +/********************************************************************************** + * X509 certificates + **********************************************************************************/ + +#ifndef XMLSEC_NO_X509 + +/** + * xmlSecMSCryptoAppKeyCertLoad: + * @key: the pointer to key. + * @filename: the certificate filename. + * @format: the certificate file format. + * + * Reads the certificate from $@filename and adds it to key. + * + * Returns: 0 on success or a negative value otherwise. + */ + +int +xmlSecMSCryptoAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, + xmlSecKeyDataFormat format) { + xmlSecBuffer buffer; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferReadFile(&buffer, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferReadFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return (-1); + } + + ret = xmlSecMSCryptoAppKeyCertLoadMemory(key, xmlSecBufferGetData(&buffer), + xmlSecBufferGetSize(&buffer), format); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoAppKeyCertLoadMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(-1); + } + + xmlSecBufferFinalize(&buffer); + return(0); +} + +/** + * xmlSecMSCryptoAppKeyCertLoadMemory: + * @key: the pointer to key. + * @data: the binary certificate. + * @dataSize: size of certificate binary (data) + * @format: the certificate file format. + * + * Reads the certificate from $@data and adds it to key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format) { + PCCERT_CONTEXT pCert; + xmlSecKeyDataPtr kdata; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + kdata = xmlSecKeyEnsureData(key, xmlSecMSCryptoKeyDataX509Id); + if(kdata == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecMSCryptoKeyDataX509Id))); + return(-1); + } + + /* For now only DER certificates are supported */ + /* adjust cert format */ + switch(format) { + case xmlSecKeyDataFormatDer: + case xmlSecKeyDataFormatCertDer: + pCert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, data, dataSize); + if (NULL == pCert) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertCreateCertificateContext", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "format=%d", format); + return(-1); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(kdata, pCert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(kdata))); + CertFreeCertificateContext(pCert); + return(-1); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", (int)format); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoAppPkcs12Load: + * @filename: the PKCS12 key filename. + * @pwd: the PKCS12 file password. + * @pwdCallback: the password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key and all associated certificates from the PKCS12 file + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecMSCryptoAppPkcs12Load(const char *filename, + const char *pwd, + void* pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + xmlSecBuffer buffer; + xmlSecKeyPtr key; + int ret; + + xmlSecAssert2(filename != NULL, NULL); + xmlSecAssert2(pwd != NULL, NULL); + + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecBufferReadFile(&buffer, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferReadFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return (NULL); + } + if(xmlSecBufferGetData(&buffer) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + + key = xmlSecMSCryptoAppPkcs12LoadMemory(xmlSecBufferGetData(&buffer), + xmlSecBufferGetSize(&buffer), pwd, + pwdCallback, pwdCallbackCtx); + if (key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoAppPkcs12LoadMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + + xmlSecBufferFinalize(&buffer); + return(key); +} + +/** + * xmlSecMSCryptoAppPkcs12LoadMemory: + * @data: the binary PKCS12 key in data. + * @dataSize: size of binary pkcs12 data + * @pwd: the PKCS12 file password. + * @pwdCallback: the password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key and all associated certificates from the PKCS12 binary + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecMSCryptoAppPkcs12LoadMemory(const xmlSecByte* data, + xmlSecSize dataSize, + const char *pwd, + void* pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + CRYPT_DATA_BLOB pfx; + HCERTSTORE hCertStore = NULL; + PCCERT_CONTEXT tmpcert = NULL; + PCCERT_CONTEXT pCert = NULL; + WCHAR* wcPwd = NULL; + xmlSecKeyDataPtr x509Data = NULL; + xmlSecKeyDataPtr keyData = NULL; + xmlSecKeyPtr key = NULL; + int ret; + + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(dataSize > 1, NULL); + xmlSecAssert2(pwd != NULL, NULL); + + memset(&pfx, 0, sizeof(pfx)); + pfx.pbData = (BYTE *)data; + pfx.cbData = dataSize; + + if(FALSE == PFXIsPFXBlob(&pfx)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PFXIsPFXBlob", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%ld", + pfx.cbData); + goto done; + } + + wcPwd = xmlSecMSCryptoConvertLocaleToUnicode(pwd); + if (wcPwd == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoConvertLocaleToUnicode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "wcPwd"); + goto done; + } + + if (FALSE == PFXVerifyPassword(&pfx, wcPwd, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PFXVerifyPassword", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + hCertStore = PFXImportCertStore(&pfx, wcPwd, CRYPT_EXPORTABLE); + if (NULL == hCertStore) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PFXImportCertStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + x509Data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataX509Id); + if(x509Data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecMSCryptoKeyDataX509Id))); + goto done; + } + + while (pCert = CertEnumCertificatesInStore(hCertStore, pCert)) { + DWORD dwData = 0; + DWORD dwDataLen = sizeof(DWORD); + + /* Find the certificate that has the private key */ + if((TRUE == CertGetCertificateContextProperty(pCert, CERT_KEY_SPEC_PROP_ID, &dwData, &dwDataLen)) && (dwData > 0)) { + tmpcert = CertDuplicateCertificateContext(pCert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + keyData = xmlSecMSCryptoCertAdopt(tmpcert, xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + if(keyData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoCertAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + tmpcert = NULL; + + tmpcert = CertDuplicateCertificateContext(pCert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecMSCryptoKeyDataX509AdoptKeyCert(x509Data, tmpcert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + tmpcert = NULL; + } + + /* load certificate in the x509 key data */ + tmpcert = CertDuplicateCertificateContext(pCert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(x509Data, tmpcert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + tmpcert = NULL; + } + + if (keyData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoAppPkcs12Load", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "private key not found in PKCS12 file"); + goto done; + } + + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecKeySetValue(key, keyData); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + xmlSecKeyDestroy(key); + key = NULL; + goto done; + } + keyData = NULL; + + ret = xmlSecKeyAdoptData(key, x509Data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyAdoptData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + xmlSecKeyDestroy(key); + key = NULL; + goto done; + } + x509Data = NULL; + +done: + if(hCertStore != NULL) { + CertCloseStore(hCertStore, 0); + } + if(wcPwd != NULL) { + xmlFree(wcPwd); + } + if(x509Data != NULL) { + xmlSecKeyDataDestroy(x509Data); + } + if(keyData != NULL) { + xmlSecKeyDataDestroy(keyData); + } + if(tmpcert != NULL) { + CertFreeCertificateContext(tmpcert); + } + return(key); +} + +/** + * xmlSecMSCryptoAppKeysMngrCertLoad: + * @mngr: the keys manager. + * @filename: the certificate file. + * @format: the certificate file format. + * @type: the flag that indicates is the certificate in @filename + * trusted or not. + * + * Reads cert from @filename and adds to the list of trusted or known + * untrusted certs in @store (not implemented yet). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, + xmlSecKeyDataFormat format, + xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecBuffer buffer; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferReadFile(&buffer, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferReadFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return (-1); + } + + ret = xmlSecMSCryptoAppKeysMngrCertLoadMemory(mngr, xmlSecBufferGetData(&buffer), + xmlSecBufferGetSize(&buffer), format, type); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoAppKeysMngrCertLoadMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return(-1); + } + + xmlSecBufferFinalize(&buffer); + return(ret); +} + +/** + * xmlSecMSCryptoAppKeysMngrCertLoadMemory: + * @mngr: the keys manager. + * @data: the binary certificate. + * @dataSize: size of binary certificate (data) + * @format: the certificate file format. + * @type: the flag that indicates is the certificate in @filename + * trusted or not. + * + * Reads cert from @data and adds to the list of trusted or known + * untrusted certs in @store. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecKeyDataFormat format, + xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecKeyDataStorePtr x509Store; + PCCERT_CONTEXT pCert = NULL; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize > 0, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCryptoX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoX509StoreId"); + return(-1); + } + + switch (format) { + case xmlSecKeyDataFormatDer: + case xmlSecKeyDataFormatCertDer: + pCert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + data, dataSize); + if (NULL == pCert) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertCreateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(-1); + } + + xmlSecAssert2(pCert != NULL, -1); + ret = xmlSecMSCryptoX509StoreAdoptCert(x509Store, pCert, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509StoreAdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(pCert); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrAdoptKeyStore: + * @mngr: the keys manager. + * @keyStore: the pointer to keys store. + * + * Adds @keyStore to the list of key stores in the keys manager @mngr. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrAdoptKeyStore(xmlSecKeysMngrPtr mngr, HCERTSTORE keyStore) +{ + xmlSecKeyDataStorePtr x509Store ; + + xmlSecAssert2( mngr != NULL, -1 ) ; + xmlSecAssert2( keyStore != NULL, -1 ) ; + + x509Store = xmlSecKeysMngrGetDataStore( mngr, xmlSecMSCryptoX509StoreId) ; + if( x509Store == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecKeysMngrGetDataStore" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1) ; + } + + if( xmlSecMSCryptoX509StoreAdoptKeyStore( x509Store, keyStore ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecKeyDataStoreGetName( x509Store ) ) , + "xmlSecMSCryptoX509StoreAdoptKeyStore" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1) ; + } + + return (0) ; +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrAdoptTrustedStore: + * @mngr: the keys manager. + * @trustedStore: the pointer to certs store. + * + * Adds @trustedStore to the list of trusted cert stores in the keys manager @mngr. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrAdoptTrustedStore(xmlSecKeysMngrPtr mngr, HCERTSTORE trustedStore) +{ + xmlSecKeyDataStorePtr x509Store ; + + xmlSecAssert2( mngr != NULL, -1 ) ; + xmlSecAssert2( trustedStore != NULL, -1 ) ; + + x509Store = xmlSecKeysMngrGetDataStore( mngr, xmlSecMSCryptoX509StoreId ) ; + if( x509Store == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecKeysMngrGetDataStore" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1) ; + } + + if( xmlSecMSCryptoX509StoreAdoptTrustedStore( x509Store, trustedStore ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecKeyDataStoreGetName( x509Store ) ) , + "xmlSecMSCryptoX509StoreAdoptKeyStore" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1) ; + } + + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrAdoptUntrustedStore: + * @mngr: the keys manager. + * @untrustedStore: the pointer to certs store. + * + * Adds @trustedStore to the list of un-trusted cert stores in the keys manager @mngr. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrAdoptUntrustedStore(xmlSecKeysMngrPtr mngr, HCERTSTORE untrustedStore) +{ + xmlSecKeyDataStorePtr x509Store ; + + xmlSecAssert2( mngr != NULL, -1 ) ; + xmlSecAssert2( untrustedStore != NULL, -1 ) ; + + x509Store = xmlSecKeysMngrGetDataStore( mngr, xmlSecMSCryptoX509StoreId); + if( x509Store == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecKeysMngrGetDataStore" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + if( xmlSecMSCryptoX509StoreAdoptUntrustedStore( x509Store, untrustedStore ) < 0) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecKeyDataStoreGetName( x509Store ) ) , + "xmlSecMSCryptoX509StoreAdoptKeyStore" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + return(0) ; +} + +#endif /* XMLSEC_NO_X509 */ + +/** + * xmlSecMSCryptoAppDefaultKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Initializes @mngr with simple keys store #xmlSecSimpleKeysStoreId + * and a default MSCrypto crypto key data stores. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + + /* create MSCrypto keys store if needed */ + if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) { + xmlSecKeyStorePtr keysStore; + + keysStore = xmlSecKeyStoreCreate(xmlSecMSCryptoKeysStoreId); + if(keysStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoKeysStoreId"); + return(-1); + } + + ret = xmlSecKeysMngrAdoptKeysStore(mngr, keysStore); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrAdoptKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyStoreDestroy(keysStore); + return(-1); + } + } + + ret = xmlSecMSCryptoKeysMngrInit(mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeysMngrInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + mngr->getKey = xmlSecKeysMngrGetKey; + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrAdoptKey: + * @mngr: the pointer to keys manager. + * @key: the pointer to key. + * + * Adds @key to the keys manager @mngr created with #xmlSecMSCryptoAppDefaultKeysMngrInit + * function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr mngr, xmlSecKeyPtr key) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(key != NULL, -1); + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecMSCryptoKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeysStoreAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrLoad: + * @mngr: the pointer to keys manager. + * @uri: the uri. + * + * Loads XML keys file from @uri to the keys manager @mngr created + * with #xmlSecMSCryptoAppDefaultKeysMngrInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrLoad(xmlSecKeysMngrPtr mngr, const char* uri) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(uri != NULL, -1); + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecMSCryptoKeysStoreLoad(store, uri, mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeysStoreLoad", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", xmlSecErrorsSafeString(uri)); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrSave: + * @mngr: the pointer to keys manager. + * @filename: the destination filename. + * @type: the type of keys to save (public/private/symmetric). + * + * Saves keys from @mngr to XML keys file. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrSave(xmlSecKeysMngrPtr mngr, const char* filename, xmlSecKeyDataType type) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecMSCryptoKeysStoreSave(store, filename, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeysStoreSave", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename%s", xmlSecErrorsSafeString(filename)); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrPrivateKeyLoad: + * @mngr: the pointer to keys manager. + * @hKey: the key handle. + * + * Adds private key @hKey to the keys manager @mngr. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrPrivateKeyLoad(xmlSecKeysMngrPtr mngr, HCRYPTKEY hKey) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(hKey != 0, -1); + + /* TODO */ + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrPublicKeyLoad: + * @mngr: the pointer to keys manager. + * @hKey: the key handle. + * + * Adds public key @hKey to the keys manager @mngr. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrPublicKeyLoad(xmlSecKeysMngrPtr mngr, HCRYPTKEY hKey) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(hKey != 0, -1); + + /* TODO */ + return(0); +} + +/** + * xmlSecMSCryptoAppDefaultKeysMngrSymKeyLoad: + * @mngr: the pointer to keys manager. + * @hKey: the key handle. + * + * Adds symmetric key @hKey to the keys manager @mngr. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoAppDefaultKeysMngrSymKeyLoad(xmlSecKeysMngrPtr mngr, HCRYPTKEY hKey) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(hKey != 0, -1); + + /* TODO */ + return(0); +} + +/** + * xmlSecMSCryptoAppGetDefaultPwdCallback: + * + * Gets default password callback. + * + * Returns: default password callback. + */ +void* +xmlSecMSCryptoAppGetDefaultPwdCallback(void) { + return(NULL); +} + diff --git a/src/mscrypto/certkeys.c b/src/mscrypto/certkeys.c new file mode 100644 index 00000000..90daa827 --- /dev/null +++ b/src/mscrypto/certkeys.c @@ -0,0 +1,2615 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#ifndef XMLSEC_NO_GOST +#include "csp_oid.h" +#include "csp_calg.h" +#endif + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/bn.h> + +#include <xmlsec/mscrypto/certkeys.h> +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/x509.h> +#include "private.h" + +// GOST CSP don't support keys duplicating, so we use NT4 analogs for these... +#ifndef XMLSEC_NO_GOST +#ifndef XMLSEC_MSCRYPTO_NT4 +#define XMLSEC_MSCRYPTO_NT4 +#endif +#endif + + +/************************************************************************** + * + * Internal MSCrypto PCCERT_CONTEXT key CTX + * + *************************************************************************/ +typedef struct _xmlSecMSCryptoKeyDataCtx xmlSecMSCryptoKeyDataCtx, + *xmlSecMSCryptoKeyDataCtxPtr; + +#ifdef XMLSEC_MSCRYPTO_NT4 +/*- + * A wrapper of HCRYPTKEY, a reference countor is introduced, the function is + * the same as CryptDuplicateKey. Because the CryptDuplicateKey is not support + * by WINNT 4.0, the wrapper will enable the library work on WINNT 4.0 + */ +struct _mscrypt_key { + HCRYPTKEY hKey ; + volatile LONG refcnt ; +} ; + +/*- + * A wrapper of HCRYPTPROV, a reference countor is introduced, the function is + * the same as CryptContextAddRef. Because the CryptContextAddRef is not support + * by WINNT 4.0, the wrapper will enable the library work on WINNT 4.0 + */ +struct _mscrypt_prov { + HCRYPTPROV hProv ; + BOOL fCallerFreeProv ; + volatile LONG refcnt ; +} ; +#endif /* XMLSEC_MSCRYPTO_NT4 */ + +/* + * Since MSCrypto does not provide direct handles to private keys, we support + * only private keys linked to a certificate context. The certificate context + * also provides the public key. Only when no certificate context is used, and + * a public key from xml document is provided, we need HCRYPTKEY.... The focus + * now is however directed to certificates. Wouter + */ +struct _xmlSecMSCryptoKeyDataCtx { +#ifndef XMLSEC_MSCRYPTO_NT4 + HCRYPTPROV hProv; + BOOL fCallerFreeProv; + HCRYPTKEY hKey; +#else /* XMLSEC_MSCRYPTO_NT4 */ + struct _mscrypt_prov* p_prov ; + struct _mscrypt_key* p_key ; +#endif /* XMLSEC_MSCRYPTO_NT4 */ + PCCERT_CONTEXT pCert; + const xmlSecMSCryptoProviderInfo * providers; + DWORD dwKeySpec; + xmlSecKeyDataType type; +}; + +#ifndef XMLSEC_MSCRYPTO_NT4 + +/******************************** Provider *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetProvider(ctx) (ctx)->hProv + +static void +xmlSecMSCryptoKeyDataCtxCreateProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->hProv = 0; + ctx->fCallerFreeProv = FALSE; +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if ((ctx->hProv != 0) && (ctx->fCallerFreeProv)) { + CryptReleaseContext(ctx->hProv, 0); + } + ctx->hProv = 0; + ctx->fCallerFreeProv = FALSE; +} + +static void +xmlSecMSCryptoKeyDataCtxSetProvider(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTPROV hProv, BOOL fCallerFreeProv) +{ + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + ctx->hProv = hProv; + ctx->fCallerFreeProv = fCallerFreeProv; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateProvider(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctxDst); + + if(ctxSrc->hProv != 0) { + if(!CryptContextAddRef(ctxSrc->hProv, NULL, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptContextAddRef", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctxDst->hProv = ctxSrc->hProv; + ctxDst->fCallerFreeProv = TRUE; + } + return(0); +} + + +/******************************** Key *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetKey(ctx) ((ctx)->hKey) + +static void +xmlSecMSCryptoKeyDataCtxCreateKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->hKey = 0; +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if (ctx->hKey != 0) { + CryptDestroyKey(ctx->hKey); + } + ctx->hKey = 0; +} + +static void +xmlSecMSCryptoKeyDataCtxSetKey(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTKEY hKey) { + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + ctx->hKey = hKey; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateKey(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctxDst); + if (ctxSrc->hKey != 0) { + if (!CryptDuplicateKey(ctxSrc->hKey, NULL, 0, &(ctxDst->hKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptDuplicateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +#else /* XMLSEC_MSCRYPTO_NT4 */ + +/******************************** Provider *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetProvider(ctx) (((ctx)->p_prov) ? ((ctx)->p_prov->hProv) : 0) + +static void +xmlSecMSCryptoKeyDataCtxCreateProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->p_prov = (struct _mscrypt_prov*)xmlMalloc(sizeof(struct _mscrypt_prov)); + if(ctx->p_prov == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE, + "mscrypt_create_prov" , + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE + ); + } + memset(ctx->p_prov, 0, sizeof(struct _mscrypt_prov)); +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyProvider(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if(ctx->p_prov != NULL) { + if(InterlockedDecrement(&(ctx->p_prov->refcnt)) <= 0) { + if((ctx->p_prov->hProv != 0) && (ctx->p_prov->fCallerFreeProv)) { + CryptReleaseContext(ctx->p_prov->hProv, 0) ; + } + memset(ctx->p_prov, 0, sizeof(struct _mscrypt_prov)); + xmlFree(ctx->p_prov) ; + } + ctx->p_prov = NULL; + } +} + +static void +xmlSecMSCryptoKeyDataCtxSetProvider(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTPROV hProv, BOOL fCallerFreeProv) +{ + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + + if((ctx->p_prov != NULL) && (ctx->p_prov->refcnt == 1)) { + if((ctx->p_prov->hProv != 0) && (ctx->p_prov->fCallerFreeProv)) { + CryptReleaseContext(ctx->p_prov->hProv, 0) ; + } + memset(ctx->p_prov, 0, sizeof(struct _mscrypt_prov)); + } else { + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + xmlSecMSCryptoKeyDataCtxCreateProvider(ctx); + } + + ctx->p_prov->hProv = hProv; + ctx->p_prov->fCallerFreeProv = fCallerFreeProv; + ctx->p_prov->refcnt = 1; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateProvider(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctxDst); + + if (ctxSrc->p_prov != NULL) { + ctxDst->p_prov = ctxSrc->p_prov; + InterlockedIncrement(&(ctxDst->p_prov->refcnt)); + } + + return(0); +} + +/******************************** Key *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetKey(ctx) (((ctx)->p_key) ? ((ctx)->p_key->hKey) : 0) + +static void +xmlSecMSCryptoKeyDataCtxCreateKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->p_key = (struct _mscrypt_key*)xmlMalloc(sizeof(struct _mscrypt_key)); + if(ctx->p_key == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE, + "mscrypt_create_key" , + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE + ); + } + memset(ctx->p_key, 0, sizeof(struct _mscrypt_key)); +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyKey(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if(ctx->p_key != NULL) { + if(InterlockedDecrement(&(ctx->p_key->refcnt)) <= 0) { + if(ctx->p_key->hKey != 0) { + CryptDestroyKey(ctx->p_key->hKey) ; + } + memset(ctx->p_key, 0, sizeof(struct _mscrypt_key)); + xmlFree(ctx->p_key) ; + } + ctx->p_key = NULL; + } +} + +static void +xmlSecMSCryptoKeyDataCtxSetKey(xmlSecMSCryptoKeyDataCtxPtr ctx, HCRYPTKEY hKey) { + xmlSecAssert(ctx != NULL); + + if((ctx->p_key != NULL) && (ctx->p_key->refcnt == 1)) { + if(ctx->p_key->hKey != 0) { + CryptDestroyKey(ctx->p_key->hKey) ; + } + memset(ctx->p_key, 0, sizeof(struct _mscrypt_key)); + } else { + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + xmlSecMSCryptoKeyDataCtxCreateKey(ctx); + } + ctx->p_key->hKey = hKey; + ctx->p_key->refcnt = 1; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateKey(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctxDst); + if (ctxSrc->p_key != NULL) { + ctxDst->p_key = ctxSrc->p_key; + InterlockedIncrement(&(ctxDst->p_key->refcnt)); + } + + return(0); +} + +#endif /* XMLSEC_MSCRYPTO_NT4 */ + +/******************************** Cert *****************************************/ +#define xmlSecMSCryptoKeyDataCtxGetCert(ctx) ((ctx)->pCert) + +static void +xmlSecMSCryptoKeyDataCtxCreateCert(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->pCert = NULL; +} + +static void +xmlSecMSCryptoKeyDataCtxDestroyCert(xmlSecMSCryptoKeyDataCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + if(ctx->pCert != NULL) { + CertFreeCertificateContext(ctx->pCert); + } + ctx->pCert = NULL; +} + +static void +xmlSecMSCryptoKeyDataCtxSetCert(xmlSecMSCryptoKeyDataCtxPtr ctx, PCCERT_CONTEXT pCert) { + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyCert(ctx); + ctx->pCert = pCert; +} + +static int +xmlSecMSCryptoKeyDataCtxDuplicateCert(xmlSecMSCryptoKeyDataCtxPtr ctxDst, xmlSecMSCryptoKeyDataCtxPtr ctxSrc) { + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxSrc != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyCert(ctxDst); + if(ctxSrc->pCert != NULL) { + ctxDst->pCert = xmlSecMSCryptoCertDup(ctxSrc->pCert); + if(ctxDst->pCert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoPCCDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +/****************************************************************************** + * + * xmlSecMSCryptoKeyDataCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecMSCryptoKeyDataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecMSCryptoKeyDataCtx)) +#define xmlSecMSCryptoKeyDataGetCtx(data) \ + ((xmlSecMSCryptoKeyDataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + +static int xmlSecMSCryptoKeyDataDuplicate (xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataFinalize (xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataGetSize (xmlSecKeyDataPtr data); + +/** + * xmlSecMSCryptoKeyDataAdoptCert: + * @data: the pointer to MSCrypto pccert data. + * @pCert: the pointer to PCCERT key. + * + * Sets the value of key data. + * + * Returns: 0 on success or a negative value otherwise. + */ +static int +xmlSecMSCryptoKeyDataAdoptCert(xmlSecKeyDataPtr data, PCCERT_CONTEXT pCert, xmlSecKeyDataType type) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTKEY hKey = 0; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), -1); + xmlSecAssert2(pCert != NULL, -1); + xmlSecAssert2(pCert->pCertInfo != NULL, -1); + xmlSecAssert2((type & (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate)) != 0, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + xmlSecMSCryptoKeyDataCtxDestroyCert(ctx); + + ctx->type = type; + + /* Now we acquire a context for this key(pair). The context is needed + * for the real crypto stuff in MS Crypto. + */ + if((type & xmlSecKeyDataTypePrivate) != 0){ + HCRYPTPROV hProv = 0; + BOOL fCallerFreeProv = FALSE; + + if (!CryptAcquireCertificatePrivateKey(pCert, + CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, + &hProv, + &(ctx->dwKeySpec), + &fCallerFreeProv)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptAcquireCertificatePrivateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecMSCryptoKeyDataCtxSetProvider(ctx, hProv, fCallerFreeProv); + } else if((type & xmlSecKeyDataTypePublic) != 0){ + HCRYPTPROV hProv; + + hProv = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, FALSE); + if (hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecMSCryptoKeyDataCtxSetProvider(ctx, hProv, TRUE); + ctx->dwKeySpec = 0; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "Unsupported keytype"); + return(-1); + } + + /* CryptImportPublicKeyInfo is only needed when a real key handle + * is needed. The key handle is needed for de/encrypting and for + * verifying of a signature, *not* for signing. We could call + * CryptImportPublicKeyInfo in xmlSecMSCryptoKeyDataGetKey instead + * so no unnessecary calls to CryptImportPublicKeyInfo are being + * made. WK + */ + if(!CryptImportPublicKeyInfo(xmlSecMSCryptoKeyDataCtxGetProvider(ctx), + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &(pCert->pCertInfo->SubjectPublicKeyInfo), + &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptImportPublicKeyInfo", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + xmlSecMSCryptoKeyDataCtxSetKey(ctx, hKey); + xmlSecMSCryptoKeyDataCtxSetCert(ctx, pCert); + return(0); +} + +static int +xmlSecMSCryptoKeyDataAdoptKey(xmlSecKeyDataPtr data, + HCRYPTPROV hProv, + BOOL fCallerFreeProv, + HCRYPTKEY hKey, + DWORD dwKeySpec, + xmlSecKeyDataType type) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), -1); + xmlSecAssert2(hKey != 0, -1); + xmlSecAssert2(type & (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate), -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + xmlSecMSCryptoKeyDataCtxSetProvider(ctx, hProv, fCallerFreeProv); + xmlSecMSCryptoKeyDataCtxSetKey(ctx, hKey); + xmlSecMSCryptoKeyDataCtxSetCert(ctx, NULL); + + ctx->dwKeySpec = dwKeySpec; + ctx->type = type; + + return(0); +} + +/** + * xmlSecMSCryptoKeyDataGetKey: + * @data: the key data to retrieve certificate from. + * @type: type of key requested (public/private) + * + * Native MSCrypto key retrieval from xmlsec keydata. The + * returned HKEY must not be destroyed by the caller. + * + * Returns: HKEY on success or NULL otherwise. + */ +HCRYPTKEY +xmlSecMSCryptoKeyDataGetKey(xmlSecKeyDataPtr data, xmlSecKeyDataType type) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(xmlSecMSCryptoKeyDataCtxGetKey(ctx)); +} + +/** + * xmlSecMSCryptoKeyDataGetDecryptKey: + * @data: the key data pointer + * + * Native MSCrypto decrypt key retrieval from xmlsec keydata. The + * returned HKEY must not be destroyed by the caller. + * + * Returns: HKEY on success or NULL otherwise. + */ +HCRYPTKEY +xmlSecMSCryptoKeyDataGetDecryptKey(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTKEY hKey; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + if( !CryptGetUserKey(xmlSecMSCryptoKeyDataCtxGetProvider(ctx), AT_KEYEXCHANGE, &(hKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetUserKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + return (hKey); +} + +/** + * xmlSecMSCryptoKeyDataGetCert: + * @data: the key data to retrieve certificate from. + * + * Native MSCrypto certificate retrieval from xmlsec keydata. The + * returned PCCERT_CONTEXT must not be released by the caller. + * + * Returns: PCCERT_CONTEXT on success or NULL otherwise. + */ +PCCERT_CONTEXT +xmlSecMSCryptoKeyDataGetCert(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(xmlSecMSCryptoKeyDataCtxGetCert(ctx)); +} + +/** + * xmlSecMSCryptoKeyDataGetMSCryptoProvider: + * @data: the key data + * + * Gets crypto provider handle + * + * Returns: the crypto provider handler or 0 if there is an error. + */ +HCRYPTPROV +xmlSecMSCryptoKeyDataGetMSCryptoProvider(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(xmlSecMSCryptoKeyDataCtxGetProvider(ctx)); +} + +/** + * xmlSecMSCryptoKeyDataGetMSCryptoKeySpec: + * @data: the key data + * + * Gets key spec info. + * + * Returns: the key spec info from key data + */ +DWORD +xmlSecMSCryptoKeyDataGetMSCryptoKeySpec(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(ctx->dwKeySpec); +} + +static int +xmlSecMSCryptoKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecMSCryptoKeyDataCtxPtr ctxDst; + xmlSecMSCryptoKeyDataCtxPtr ctxSrc; + + xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecMSCryptoKeyDataSize), -1); + xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecMSCryptoKeyDataSize), -1); + + ctxDst = xmlSecMSCryptoKeyDataGetCtx(dst); + xmlSecAssert2(ctxDst != NULL, -1); + + ctxSrc = xmlSecMSCryptoKeyDataGetCtx(src); + xmlSecAssert2(ctxSrc != NULL, -1); + + if(xmlSecMSCryptoKeyDataCtxDuplicateProvider(ctxDst, ctxSrc) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataCtxDuplicateProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(xmlSecMSCryptoKeyDataCtxDuplicateKey(ctxDst, ctxSrc) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataCtxDuplicateKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(xmlSecMSCryptoKeyDataCtxDuplicateCert(ctxDst, ctxSrc) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataCtxDuplicateCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctxDst->dwKeySpec = ctxSrc->dwKeySpec; + ctxDst->providers = ctxSrc->providers; + ctxDst->type = ctxSrc->type; + + return(0); +} + +static void +xmlSecMSCryptoKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize)); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKeyDataCtx)); + + xmlSecMSCryptoKeyDataCtxCreateProvider(ctx); + xmlSecMSCryptoKeyDataCtxCreateKey(ctx); + xmlSecMSCryptoKeyDataCtxCreateCert(ctx); +} + +static void +xmlSecMSCryptoKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize)); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + xmlSecMSCryptoKeyDataCtxDestroyKey(ctx); + xmlSecMSCryptoKeyDataCtxDestroyCert(ctx); + xmlSecMSCryptoKeyDataCtxDestroyProvider(ctx); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKeyDataCtx)); +} + +static int +xmlSecMSCryptoKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), 0); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + if(xmlSecMSCryptoKeyDataCtxGetCert(ctx) != NULL) { + xmlSecAssert2(xmlSecMSCryptoKeyDataCtxGetCert(ctx)->pCertInfo != NULL, 0); + return (CertGetPublicKeyLength(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &(xmlSecMSCryptoKeyDataCtxGetCert(ctx)->pCertInfo->SubjectPublicKeyInfo))); + } else if (xmlSecMSCryptoKeyDataCtxGetKey(ctx) != 0) { + DWORD length = 0; + DWORD lenlen = sizeof(DWORD); + + if (!CryptGetKeyParam(xmlSecMSCryptoKeyDataCtxGetKey(ctx), KP_KEYLEN, (BYTE *)&length, &lenlen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + return(length); + } + + return (0); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), xmlSecKeyDataTypeUnknown); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, xmlSecKeyDataTypeUnknown); + + /* We could make a call to CryptFindCertificateKeyProvInfo here, to find out if + * we *really* have a private key or not. However if the certificate is not + * linked to a private key, the call takes an ridiculous amount of time. + * the way it is now is better I think. WK. + */ + return(ctx->type); +} + +/** + * xmlSecMSCryptoCertDup: + * @pCert: the pointer to cert. + * + * Duplicates the @pCert. + * + * Returns: pointer to newly created PCCERT_CONTEXT object or + * NULL if an error occurs. + */ +PCCERT_CONTEXT xmlSecMSCryptoCertDup(PCCERT_CONTEXT pCert) { + PCCERT_CONTEXT ret; + + xmlSecAssert2(pCert != NULL, NULL); + + ret = CertDuplicateCertificateContext(pCert); + if(ret == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(ret); +} + + +/** + * xmlSecMSCryptoCertAdopt: + * @pCert: the pointer to cert. + * @type: the expected key type. + * + * Creates key data value from the cert. + * + * Returns: pointer to newly created xmlsec key or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecMSCryptoCertAdopt(PCCERT_CONTEXT pCert, xmlSecKeyDataType type) { + xmlSecKeyDataPtr data = NULL; + int ret; + + xmlSecAssert2(pCert != NULL, NULL); + xmlSecAssert2(pCert->pCertInfo != NULL, NULL); + xmlSecAssert2(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId != NULL, NULL); + +#ifndef XMLSEC_NO_RSA + if (!strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_RSA_RSA)) { + data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataRsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoDataRsaId"); + return(NULL); + } + } +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA + if (!strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_X957_DSA /*szOID_DSALG_SIGN*/)) { + data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataDsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoKeyDataDsaId"); + return(NULL); + } + } +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + if (!strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_MAGPRO_PUBKEY_SIGN_R3410_2001_CP) || + !strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_MAGPRO_PUBKEY_SIGN_R3410_2001) || + !strcmp(pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId, szOID_MAGPRO_PUBKEY_SIGN_R3410_94_CP)) { + data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataGost2001Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoKeyDataGost2001Id"); + return(NULL); + } + } +#endif /* XMLSEC_NO_GOST*/ + + if (NULL == data) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "PCCERT_CONTEXT key type %s not supported", pCert->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId); + return(NULL); + } + + xmlSecAssert2(data != NULL, NULL); + + ret = xmlSecMSCryptoKeyDataAdoptCert(data, pCert, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoPCCDataAdoptPCC", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + return(data); +} + + +#ifndef XMLSEC_NO_RSA +/************************************************************************** + * + * <dsig:RSAKeyValue> processing + * + * http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue + * The RSAKeyValue Element + * + * RSA key values have two fields: Modulus and Exponent. + * + * <RSAKeyValue> + * <Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W + * jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV + * 5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U= + * </Modulus> + * <Exponent>AQAB</Exponent> + * </RSAKeyValue> + * + * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are + * represented in XML as octet strings as defined by the ds:CryptoBinary type. + * + * Schema Definition: + * + * <element name="RSAKeyValue" type="ds:RSAKeyValueType"/> + * <complexType name="RSAKeyValueType"> + * <sequence> + * <element name="Modulus" type="ds:CryptoBinary"/> + * <element name="Exponent" type="ds:CryptoBinary"/> + * </sequence> + * </complexType> + * + * DTD Definition: + * + * <!ELEMENT RSAKeyValue (Modulus, Exponent) > + * <!ELEMENT Modulus (#PCDATA) > + * <!ELEMENT Exponent (#PCDATA) > + * + * ============================================================================ + * + * + *************************************************************************/ + +static int xmlSecMSCryptoKeyDataRsaInitialize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataRsaFinalize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataRsaXmlRead(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataRsaXmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataRsaGenerate(xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoKeyDataRsaGetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoKeyDataRsaGetSize(xmlSecKeyDataPtr data); +static void xmlSecMSCryptoKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output); +static void xmlSecMSCryptoKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataRsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoKeyDataSize, + + /* data */ + xmlSecNameRSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefRSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeRSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataRsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataRsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataRsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoKeyDataRsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataRsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoKeyDataRsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoKeyDataRsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoKeyDataRsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataRsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataRsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Rsa[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { MS_DEF_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + +/** + * xmlSecMSCryptoKeyDataRsaGetKlass: + * + * The MSCrypto RSA CertKey data klass. + * + * Returns: pointer to MSCrypto RSA key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataRsaGetKlass(void) { + return(&xmlSecMSCryptoKeyDataRsaKlass); +} + +static int +xmlSecMSCryptoKeyDataRsaInitialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + ctx->providers = xmlSecMSCryptoProviderInfo_Rsa; + return(0); +} + +static int +xmlSecMSCryptoKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataRsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataRsaId), -1); + + return(xmlSecMSCryptoKeyDataDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoKeyDataRsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId)); + + xmlSecMSCryptoKeyDataFinalize(data); +} + +static int +xmlSecMSCryptoKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecBn modulus, exponent; + xmlSecBuffer blob; + unsigned int blobBufferLen; + PUBLICKEYSTRUC* pubKeyStruc = NULL; + RSAPUBKEY* pubKey = NULL; + xmlSecByte* modulusBlob = NULL; + xmlSecKeyDataPtr data = NULL; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + xmlNodePtr cur; + int res = -1; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if(xmlSecKeyGetValue(key) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + "key already has a value"); + return(-1); + } + + /* initialize buffers */ + ret = xmlSecBnInitialize(&modulus, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "modulus"); + return(-1); + } + + ret = xmlSecBnInitialize(&exponent, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "exponent"); + xmlSecBnFinalize(&modulus); + return(-1); + } + + ret = xmlSecBufferInitialize(&blob, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "blob"); + xmlSecBnFinalize(&modulus); + xmlSecBnFinalize(&exponent); + return(-1); + } + + /* read xml */ + cur = xmlSecGetNextElementNode(node->children); + + /* first is Modulus node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAModulus, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + goto done; + } + + ret = xmlSecBnGetNodeValue(&modulus, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&modulus) == 0)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is Exponent node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeRSAExponent, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + goto done; + } + ret = xmlSecBnGetNodeValue(&exponent, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&exponent) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * MSCrypto does not support it. We just ignore it */ + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "no nodes expected"); + goto done; + } + + /* Now try to create the key */ + blobBufferLen = sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + xmlSecBnGetSize(&modulus); + ret = xmlSecBufferSetSize(&blob, blobBufferLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", blobBufferLen); + goto done; + } + + /* Set the PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC *)xmlSecBufferGetData(&blob); + pubKeyStruc->bType = PUBLICKEYBLOB; + pubKeyStruc->bVersion = 0x02; + pubKeyStruc->reserved = 0; + pubKeyStruc->aiKeyAlg = CALG_RSA_KEYX | CALG_RSA_SIGN; + + /* Set the public key header */ + pubKey = (RSAPUBKEY*) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC)); + pubKey->magic = 0x31415352; /* == RSA1 public */ + pubKey->bitlen = xmlSecBnGetSize(&modulus) * 8; /* Number of bits in prime modulus */ + pubKey->pubexp = 0; + if(sizeof(pubKey->pubexp) < xmlSecBnGetSize(&exponent)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "exponent size=%d", + xmlSecBnGetSize(&exponent)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&exponent) != NULL, -1); + memcpy(&(pubKey->pubexp), xmlSecBnGetData(&exponent), xmlSecBnGetSize(&exponent)); + + modulusBlob = (xmlSecByte*) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); + xmlSecAssert2(xmlSecBnGetData(&modulus) != NULL, -1); + memcpy(modulusBlob, xmlSecBnGetData(&modulus), xmlSecBnGetSize(&modulus)); + + /* Now that we have the blob, import */ + hProv = xmlSecMSCryptoFindProvider(xmlSecMSCryptoProviderInfo_Rsa, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + if (!CryptImportKey(hProv, xmlSecBufferGetData(&blob), xmlSecBufferGetSize(&blob), 0, 0, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptImportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, 0, xmlSecKeyDataTypePublic); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + goto done; + } + data = NULL; + + /* success */ + res = 0; + +done: + if (hProv == 0) { + CryptReleaseContext(hProv, 0); + } + if (hKey != 0) { + CryptDestroyKey(hKey); + } + if (data != 0) { + xmlSecKeyDataDestroy(data); + } + + xmlSecBnFinalize(&modulus); + xmlSecBnFinalize(&exponent); + xmlSecBufferFinalize(&blob); + return(res); +} + +static int +xmlSecMSCryptoKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + xmlSecBuffer buf; + DWORD dwBlobLen; + xmlSecByte* blob; + PUBLICKEYSTRUC* pubKeyStruc; + RSAPUBKEY *pubKey; + xmlSecSize modulusLen, exponentLen; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataRsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecMSCryptoKeyDataCtxGetKey(ctx) != 0, -1); + + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&buf, dwBlobLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", dwBlobLen); + return(-1); + } + + blob = xmlSecBufferGetData(&buf); + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, blob, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + if (dwBlobLen < sizeof(PUBLICKEYSTRUC)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld", dwBlobLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC*)blob; + if(pubKeyStruc->bVersion != 0x02) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion); + xmlSecBufferFinalize(&buf); + return(-1); + } + if(pubKeyStruc->bType != PUBLICKEYBLOB) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check RSAPUBKEY */ + pubKey = (RSAPUBKEY *)(blob + sizeof(PUBLICKEYSTRUC)); + if(pubKey->magic != 0x31415352) { /* RSA public key magic */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKey->magic=0x%08lx", pubKey->magic); + xmlSecBufferFinalize(&buf); + return(-1); + } + modulusLen = pubKey->bitlen / 8; + + if (dwBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + modulusLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld; modulusLen=%d", dwBlobLen, modulusLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY); + + /* first is Modulus node */ + cur = xmlSecAddChild(node, xmlSecNodeRSAModulus, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + ret = xmlSecBnBlobSetNodeValue(blob, modulusLen, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* next is Exponent node. */ + cur = xmlSecAddChild(node, xmlSecNodeRSAExponent, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* Remove leading zero's (from least significant end) */ + blob = (xmlSecByte*)(&(pubKey->pubexp)); + exponentLen = sizeof(pubKey->pubexp); + while (exponentLen > 0 && blob[exponentLen - 1] == 0) { + exponentLen--; + } + + ret = xmlSecBnBlobSetNodeValue(blob, exponentLen, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* next is PrivateExponent node: not supported in MSCrypto */ + + xmlSecBufferFinalize(&buf); + return(0); +} + +static int +xmlSecMSCryptoKeyDataRsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, + xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + DWORD dwKeySpec; + DWORD dwSize; + int res = -1; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + /* get provider */ + hProv = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + dwKeySpec = AT_KEYEXCHANGE | AT_SIGNATURE; + dwSize = ((sizeBits << 16) | CRYPT_EXPORTABLE); + if (!CryptGenKey(hProv, CALG_RSA_SIGN, dwSize, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptGenKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, dwKeySpec, + xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + /* success */ + res = 0; + +done: + if (hProv != 0) { + CryptReleaseContext(hProv, 0); + } + + if (hKey != 0) { + CryptDestroyKey(hKey); + } + + return(res); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataRsaGetType(xmlSecKeyDataPtr data) { + return(xmlSecMSCryptoKeyDataGetType(data)); +} + +static xmlSecSize +xmlSecMSCryptoKeyDataRsaGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId), 0); + + return (xmlSecMSCryptoKeyDataGetSize(data)); +} + +static void +xmlSecMSCryptoKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== rsa key: size = %d\n", + xmlSecMSCryptoKeyDataRsaGetSize(data)); +} + +static void xmlSecMSCryptoKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<RSAKeyValue size=\"%d\" />\n", + xmlSecMSCryptoKeyDataRsaGetSize(data)); +} + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA +/************************************************************************** + * + * <dsig:DSAKeyValue> processing + * + * + * The DSAKeyValue Element (http://www.w3.org/TR/xmldsig-core/#sec-DSAKeyValue) + * + * DSA keys and the DSA signature algorithm are specified in [DSS]. + * DSA public key values can have the following fields: + * + * * P - a prime modulus meeting the [DSS] requirements + * * Q - an integer in the range 2**159 < Q < 2**160 which is a prime + * divisor of P-1 + * * G - an integer with certain properties with respect to P and Q + * * Y - G**X mod P (where X is part of the private key and not made + * public) + * * J - (P - 1) / Q + * * seed - a DSA prime generation seed + * * pgenCounter - a DSA prime generation counter + * + * Parameter J is available for inclusion solely for efficiency as it is + * calculatable from P and Q. Parameters seed and pgenCounter are used in the + * DSA prime number generation algorithm specified in [DSS]. As such, they are + * optional but must either both be present or both be absent. This prime + * generation algorithm is designed to provide assurance that a weak prime is + * not being used and it yields a P and Q value. Parameters P, Q, and G can be + * public and common to a group of users. They might be known from application + * context. As such, they are optional but P and Q must either both appear or + * both be absent. If all of P, Q, seed, and pgenCounter are present, + * implementations are not required to check if they are consistent and are + * free to use either P and Q or seed and pgenCounter. All parameters are + * encoded as base64 [MIME] values. + * + * Arbitrary-length integers (e.g. "bignums" such as RSA moduli) are + * represented in XML as octet strings as defined by the ds:CryptoBinary type. + * + * Schema Definition: + * + * <element name="DSAKeyValue" type="ds:DSAKeyValueType"/> + * <complexType name="DSAKeyValueType"> + * <sequence> + * <sequence minOccurs="0"> + * <element name="P" type="ds:CryptoBinary"/> + * <element name="Q" type="ds:CryptoBinary"/> + * </sequence> + * <element name="G" type="ds:CryptoBinary" minOccurs="0"/> + * <element name="Y" type="ds:CryptoBinary"/> + * <element name="J" type="ds:CryptoBinary" minOccurs="0"/> + * <sequence minOccurs="0"> + * <element name="Seed" type="ds:CryptoBinary"/> + * <element name="PgenCounter" type="ds:CryptoBinary"/> + * </sequence> + * </sequence> + * </complexType> + * + * DTD Definition: + * + * <!ELEMENT DSAKeyValue ((P, Q)?, G?, Y, J?, (Seed, PgenCounter)?) > + * <!ELEMENT P (#PCDATA) > + * <!ELEMENT Q (#PCDATA) > + * <!ELEMENT G (#PCDATA) > + * <!ELEMENT Y (#PCDATA) > + * <!ELEMENT J (#PCDATA) > + * <!ELEMENT Seed (#PCDATA) > + * <!ELEMENT PgenCounter (#PCDATA) > + * + * ============================================================================ + * + * To support reading/writing private keys an X element added (before Y). + * todo: The current implementation does not support Seed and PgenCounter! + * by this the P, Q and G are *required*! + * + *************************************************************************/ +static int xmlSecMSCryptoKeyDataDsaInitialize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataDsaFinalize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataDsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataDsaXmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataDsaGenerate(xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoKeyDataDsaGetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoKeyDataDsaGetSize(xmlSecKeyDataPtr data); +static void xmlSecMSCryptoKeyDataDsaDebugDump(xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataDsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoKeyDataSize, + + /* data */ + xmlSecNameDSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeDSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataDsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataDsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataDsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoKeyDataDsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataDsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoKeyDataDsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoKeyDataDsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoKeyDataDsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataDsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataDsaDebugXmlDump,/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Dss[] = { + { MS_DEF_DSS_PROV, PROV_DSS }, + { NULL, 0 } +}; + + +/** + * xmlSecMSCryptoKeyDataDsaGetKlass: + * + * The DSA key data klass. + * + * Returns: pointer to DSA key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataDsaGetKlass(void) { + return(&xmlSecMSCryptoKeyDataDsaKlass); +} + + +static int +xmlSecMSCryptoKeyDataDsaInitialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + ctx->providers = xmlSecMSCryptoProviderInfo_Dss; + return(0); +} + +static int +xmlSecMSCryptoKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataDsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataDsaId), -1); + + return(xmlSecMSCryptoKeyDataDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoKeyDataDsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId)); + + xmlSecMSCryptoKeyDataFinalize(data); +} + +static int +xmlSecMSCryptoKeyDataDsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data = NULL; + xmlNodePtr cur; + xmlSecBn p, q, g, y; + xmlSecBuffer blob; + unsigned int blobBufferLen; + PUBLICKEYSTRUC *pubKeyStruc = NULL; + DSSPUBKEY *pubKey = NULL; + DSSSEED* seed = NULL; + BYTE *buf = NULL; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + xmlSecSize i; + int res = -1; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if(xmlSecKeyGetValue(key) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + "key already has a value"); + return(-1); + } + + /* initialize buffers */ + ret = xmlSecBnInitialize(&p, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "p"); + return(-1); + } + + ret = xmlSecBnInitialize(&q, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "q"); + xmlSecBnFinalize(&p); + return(-1); + } + + ret = xmlSecBnInitialize(&g, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "g"); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + return(-1); + } + + ret = xmlSecBnInitialize(&y, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "y"); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + xmlSecBnFinalize(&g); + return(-1); + } + + ret = xmlSecBufferInitialize(&blob, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "blob"); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + xmlSecBnFinalize(&g); + xmlSecBnFinalize(&y); + return(-1); + } + + /* read xml */ + cur = xmlSecGetNextElementNode(node->children); + + /* first is P node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAP, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + goto done; + } + + ret = xmlSecBnGetNodeValue(&p, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&p) == 0)){ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is Q node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAQ, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + goto done; + } + ret = xmlSecBnGetNodeValue(&q, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&q) == 0)){ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is G node. It is REQUIRED because we do not support Seed and PgenCounter*/ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAG, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + goto done; + } + ret = xmlSecBnGetNodeValue(&g, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&q) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * MSCrypto does not support it, we just ignore it */ + + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is Y node. */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeDSAY, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + goto done; + } + ret = xmlSecBnGetNodeValue(&y, cur, xmlSecBnBase64, 1); + if((ret < 0) || (xmlSecBnGetSize(&y) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnGetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", xmlSecErrorsSafeString(xmlSecNodeDSAY)); + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + /* todo: add support for J */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAJ, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* todo: add support for seed */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSASeed, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* todo: add support for pgencounter */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAPgenCounter, xmlSecDSigNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* we assume that sizeof(q) < 0x14, sizeof(g) <= sizeof(p) and sizeof(y) <= sizeof(p) */ + blobBufferLen = sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY) + 3 * xmlSecBnGetSize(&p) + 0x14 + sizeof(DSSSEED); + ret = xmlSecBufferSetSize(&blob, blobBufferLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", blobBufferLen); + goto done; + } + + /* Set PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC *)xmlSecBufferGetData(&blob); + pubKeyStruc->bType = PUBLICKEYBLOB; + pubKeyStruc->bVersion = 0x02; + pubKeyStruc->reserved = 0; + pubKeyStruc->aiKeyAlg = CALG_DSS_SIGN; + + /* Set the public key header */ + pubKey = (DSSPUBKEY *) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC)); + pubKey->magic = 0x31535344; /* == DSS1 pub key */ + pubKey->bitlen = xmlSecBnGetSize(&p) * 8; /* Number of bits in prime modulus */ + + /* copy the key data */ + buf = (BYTE*) (xmlSecBufferGetData(&blob) + sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY)); + + /* set p */ + xmlSecAssert2(xmlSecBnGetData(&p) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&p), xmlSecBnGetSize(&p)); + buf += xmlSecBnGetSize(&p); + + /* set q */ + if(xmlSecBnGetSize(&q) > 0x14) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "q", + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d > 0x14", xmlSecBnGetSize(&q)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&q) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&q), xmlSecBnGetSize(&q)); + buf += xmlSecBnGetSize(&q); + + /* Pad with zeros */ + for(i = xmlSecBnGetSize(&q); i < 0x14; ++i) { + *(buf++) = 0; + } + + /* set generator */ + if(xmlSecBnGetSize(&g) > xmlSecBnGetSize(&p)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "g", + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d > %d", + xmlSecBnGetSize(&g), + xmlSecBnGetSize(&p)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&g) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&g), xmlSecBnGetSize(&g)); + buf += xmlSecBnGetSize(&g); + /* Pad with zeros */ + for(i = xmlSecBnGetSize(&g); i < xmlSecBnGetSize(&p); ++i) { + *(buf++) = 0; + } + + /* Public key */ + if(xmlSecBnGetSize(&y) > xmlSecBnGetSize(&p)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "y", + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d > %d", + xmlSecBnGetSize(&y), + xmlSecBnGetSize(&p)); + goto done; + } + xmlSecAssert2(xmlSecBnGetData(&y) != NULL, -1); + memcpy(buf, xmlSecBnGetData(&y), xmlSecBnGetSize(&y)); + buf += xmlSecBnGetSize(&y); + /* Pad with zeros */ + for(i = xmlSecBnGetSize(&y); i < xmlSecBnGetSize(&p); ++i) { + *(buf++) = 0; + } + + /* Set seed to 0xFFFFFFFFF */ + seed = (DSSSEED*)buf; + memset(seed, 0, sizeof(*seed)); + seed->counter = 0xFFFFFFFF; /* SEED Counter set to 0xFFFFFFFF will cause seed to be ignored */ + + hProv = xmlSecMSCryptoFindProvider(xmlSecMSCryptoProviderInfo_Dss, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* import the key blob */ + if (!CryptImportKey(hProv, xmlSecBufferGetData(&blob), xmlSecBufferGetSize(&blob), 0, 0, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptImportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, 0, xmlSecKeyDataTypePublic); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + data = NULL; + + /* success */ + res = 0; + +done: + if (hKey != 0) { + CryptDestroyKey(hKey); + } + if (hProv != 0) { + CryptReleaseContext(hProv, 0); + } + if (data != NULL) { + xmlSecKeyDataDestroy(data); + } + + xmlSecBufferFinalize(&blob); + xmlSecBnFinalize(&p); + xmlSecBnFinalize(&q); + xmlSecBnFinalize(&g); + xmlSecBnFinalize(&y); + + return(res); +} + +static int +xmlSecMSCryptoKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + xmlSecBuffer buf; + DWORD dwBlobLen; + xmlSecByte* blob; + PUBLICKEYSTRUC* pubKeyStruc; + DSSPUBKEY *pubKey; + xmlSecSize keyLen, len; + xmlNodePtr cur; + int ret; + + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataDsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecMSCryptoKeyDataCtxGetKey(ctx) != 0, -1); + + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, NULL, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&buf, dwBlobLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", dwBlobLen); + return(-1); + } + + blob = xmlSecBufferGetData(&buf); + if (!CryptExportKey(xmlSecMSCryptoKeyDataCtxGetKey(ctx), 0, PUBLICKEYBLOB, 0, blob, &dwBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + if (dwBlobLen < sizeof(PUBLICKEYSTRUC)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld", dwBlobLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC*)blob; + if(pubKeyStruc->bVersion != 0x02) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion); + xmlSecBufferFinalize(&buf); + return(-1); + } + if(pubKeyStruc->bType != PUBLICKEYBLOB) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* check DSSPUBKEY */ + pubKey = (DSSPUBKEY*)(blob + sizeof(PUBLICKEYSTRUC)); + if(pubKey->magic != 0x31535344) { /* DSS key magic */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKey->magic=0x%08lx", pubKey->magic); + xmlSecBufferFinalize(&buf); + return(-1); + } + keyLen = pubKey->bitlen / 8; + + /* we assume that sizeof(q) < 0x14, sizeof(g) <= sizeof(p) and sizeof(y) <= sizeof(p) */ + if (dwBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY) + 3 * keyLen + 0x14 + sizeof(DSSSEED)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "blobLen=%ld; keyLen=%d", dwBlobLen, keyLen); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += sizeof(PUBLICKEYSTRUC) + sizeof(DSSPUBKEY); + + /* first is P node */ + cur = xmlSecAddChild(node, xmlSecNodeDSAP, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + ret = xmlSecBnBlobSetNodeValue(blob, keyLen, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += keyLen; + + /* next is Q node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAQ, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* we think that the size of q is 0x14, skip trailing zeros */ + for(len = 0x14; len > 0 && blob[len - 1] == 0; --len); + + ret = xmlSecBnBlobSetNodeValue(blob, len, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += 0x14; + + /* next is G node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAG, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* skip trailing zeros */ + for(len = keyLen; len > 0 && blob[len - 1] == 0; --len); + + ret = xmlSecBnBlobSetNodeValue(blob, len, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += keyLen; + + /* next is X node: not supported in MSCrypto */ + + /* next is Y node. */ + cur = xmlSecAddChild(node, xmlSecNodeDSAY, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + xmlSecBufferFinalize(&buf); + return(-1); + } + + /* skip trailing zeros */ + for(len = keyLen; len > 0 && blob[len - 1] == 0; --len); + + ret = xmlSecBnBlobSetNodeValue(blob, len, cur, xmlSecBnBase64, 1, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBnBlobSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + xmlSecBufferFinalize(&buf); + return(-1); + } + blob += keyLen; + + xmlSecBufferFinalize(&buf); + return(0); +} + +static int +xmlSecMSCryptoKeyDataDsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + HCRYPTPROV hProv = 0; + HCRYPTKEY hKey = 0; + DWORD dwKeySpec; + DWORD dwSize; + int res = -1; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecMSCryptoKeyDataSize), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + + hProv = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(hProv == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + dwKeySpec = AT_SIGNATURE; + dwSize = ((sizeBits << 16) | CRYPT_EXPORTABLE); + if (!CryptGenKey(hProv, CALG_DSS_SIGN, dwSize, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptGenKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecMSCryptoKeyDataAdoptKey(data, hProv, TRUE, hKey, dwKeySpec, + xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + hProv = 0; + hKey = 0; + + /* success */ + res = 0; + +done: + if (hProv != 0) { + CryptReleaseContext(hProv, 0); + } + + if (hKey != 0) { + CryptDestroyKey(hKey); + } + + return(res); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataDsaGetType(xmlSecKeyDataPtr data) { + return(xmlSecMSCryptoKeyDataGetType(data)); +} + +static xmlSecSize +xmlSecMSCryptoKeyDataDsaGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId), 0); + + return xmlSecMSCryptoKeyDataGetSize(data); +} + +static void +xmlSecMSCryptoKeyDataDsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecMSCryptoKeyDataDsaGetSize(data)); +} + +static void +xmlSecMSCryptoKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<DSAKeyValue size=\"%d\" />\n", + xmlSecMSCryptoKeyDataDsaGetSize(data)); +} + +#endif /* XMLSEC_NO_DSA */ + + +#ifndef XMLSEC_NO_GOST +/************************************************************************** + * + * GOST2001 xml key representation processing. Contain errors. + * + *************************************************************************/ +static int xmlSecMSCryptoKeyDataGost2001Initialize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataGost2001Duplicate(xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataGost2001Finalize(xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataGost2001XmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataGost2001XmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataGost2001Generate(xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoKeyDataGost2001GetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoKeyDataGost2001GetSize(xmlSecKeyDataPtr data); +static void xmlSecMSCryptoKeyDataGost2001DebugDump(xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoKeyDataGost2001DebugXmlDump(xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataGost2001Klass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoKeyDataSize, + + /* data */ + xmlSecNameGOST2001KeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefGOST2001KeyValue, /* const xmlChar* href; */ + xmlSecNodeGOST2001KeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataGost2001Initialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataGost2001Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataGost2001Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecMSCryptoKeyDataGost2001Generate,*/ /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataGost2001GetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoKeyDataGost2001GetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataGost2001DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataGost2001DebugXmlDump,/* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Gost[] = { + { MAGPRO_CSP, PROV_MAGPRO_GOST }, + { CRYPTOPRO_CSP, PROV_CRYPTOPRO_GOST }, + { NULL, 0 } +}; + +/** + * xmlSecMSCryptoKeyDataGost2001GetKlass: + * + * The GOST2001 key data klass. + * + * Returns: pointer to GOST2001 key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataGost2001GetKlass(void) { + return(&xmlSecMSCryptoKeyDataGost2001Klass); +} + + +static int +xmlSecMSCryptoKeyDataGost2001Initialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + ctx->providers = xmlSecMSCryptoProviderInfo_Gost; + return(0); +} + +static int +xmlSecMSCryptoKeyDataGost2001Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataGost2001Id), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataGost2001Id), -1); + + return(xmlSecMSCryptoKeyDataDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoKeyDataGost2001Finalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id)); + + xmlSecMSCryptoKeyDataFinalize(data); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataGost2001GetType(xmlSecKeyDataPtr data) { + return(xmlSecMSCryptoKeyDataGetType(data)); +} + +static xmlSecSize +xmlSecMSCryptoKeyDataGost2001GetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id), 0); + + return xmlSecMSCryptoKeyDataGetSize(data); +} + +static void +xmlSecMSCryptoKeyDataGost2001DebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecMSCryptoKeyDataGost2001GetSize(data)); +} + +static void +xmlSecMSCryptoKeyDataGost2001DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "<GOST2001KeyValue size=\"%d\" />\n", + xmlSecMSCryptoKeyDataGost2001GetSize(data)); +} + +#endif /* XMLSEC_NO_GOST*/ diff --git a/src/mscrypto/ciphers.c b/src/mscrypto/ciphers.c new file mode 100644 index 00000000..ea2edcd5 --- /dev/null +++ b/src/mscrypto/ciphers.c @@ -0,0 +1,937 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> + +#include "private.h" + + +/************************************************************************** + * + * Internal MSCrypto Block cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecMSCryptoBlockCipherCtx xmlSecMSCryptoBlockCipherCtx, + *xmlSecMSCryptoBlockCipherCtxPtr; +struct _xmlSecMSCryptoBlockCipherCtx { + ALG_ID algorithmIdentifier; + const xmlSecMSCryptoProviderInfo * providers; + xmlSecKeyDataId keyId; + xmlSecSize keySize; + + HCRYPTPROV cryptProvider; + HCRYPTKEY pubPrivKey; + HCRYPTKEY cryptKey; + int ctxInitialized; +}; +/* function declarations */ +static int xmlSecMSCryptoBlockCipherCtxUpdate (xmlSecMSCryptoBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); + + +static int +xmlSecMSCryptoBlockCipherCtxInit(xmlSecMSCryptoBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int blockLen; + int ret; + DWORD dwBlockLen, dwBlockLenLen; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cryptKey != 0, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + /* iv len == block len */ + dwBlockLenLen = sizeof(DWORD); + if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptGetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + blockLen = dwBlockLen / 8; + xmlSecAssert2(blockLen > 0, -1); + if(encrypt) { + unsigned char* iv; + size_t outSize; + + /* allocate space for IV */ + outSize = xmlSecBufferGetSize(out); + ret = xmlSecBufferSetSize(out, outSize + blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + blockLen); + return(-1); + } + iv = xmlSecBufferGetData(out) + outSize; + + /* generate and use random iv */ + if(!CryptGenRandom(ctx->cryptProvider, blockLen, iv)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptGenRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "len=%d", blockLen); + return(-1); + } + + if(!CryptSetKeyParam(ctx->cryptKey, KP_IV, iv, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + /* if we don't have enough data, exit and hope that + * we'll have iv next time */ + if(xmlSecBufferGetSize(in) < (size_t)blockLen) { + return(0); + } + xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1); + + /* set iv */ + if (!CryptSetKeyParam(ctx->cryptKey, KP_IV, xmlSecBufferGetData(in), 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* and remove from input */ + ret = xmlSecBufferRemoveHead(in, blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", blockLen); + return(-1); + + } + } + + ctx->ctxInitialized = 1; + return(0); +} + +static int +xmlSecMSCryptoBlockCipherCtxUpdate(xmlSecMSCryptoBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + size_t inSize, inBlocks, outSize; + int blockLen; + unsigned char* outBuf; + unsigned char* inBuf; + int ret; + DWORD dwBlockLen, dwBlockLenLen, dwCLen; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + dwBlockLenLen = sizeof(DWORD); + if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + blockLen = dwBlockLen / 8; + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(inSize < (size_t)blockLen) { + return(0); + } + + if(encrypt) { + inBlocks = inSize / ((size_t)blockLen); + } else { + /* we want to have the last block in the input buffer + * for padding check */ + inBlocks = (inSize - 1) / ((size_t)blockLen); + } + inSize = inBlocks * ((size_t)blockLen); + + /* we write out the input size plus may be one block */ + ret = xmlSecBufferSetMaxSize(out, outSize + inSize + blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + inSize + blockLen); + return(-1); + } + outBuf = xmlSecBufferGetData(out) + outSize; + inBuf = xmlSecBufferGetData(in); + xmlSecAssert2(inBuf != NULL, -1); + + memcpy(outBuf, inBuf, inSize); + dwCLen = inSize; + if(encrypt) { + if(!CryptEncrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen, inSize + blockLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + if (!CryptDecrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptSetKeyDecrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + /* Check if we really have de/encrypted the numbers of bytes that we requested */ + if (dwCLen != inSize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptEn/Decrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", dwCLen); + return(-1); + } + + /* set correct output buffer size */ + ret = xmlSecBufferSetSize(out, outSize + inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + inSize); + return(-1); + } + + /* remove the processed block from input */ + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + return(0); +} + +static int +xmlSecMSCryptoBlockCipherCtxFinal(xmlSecMSCryptoBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + size_t inSize, outSize; + int blockLen, outLen = 0; + unsigned char* inBuf; + unsigned char* outBuf; + int ret; + DWORD dwBlockLen, dwBlockLenLen, dwCLen; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + dwBlockLenLen = sizeof(DWORD); + if (!CryptGetKeyParam(ctx->cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptGetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + blockLen = dwBlockLen / 8; + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(encrypt != 0) { + xmlSecAssert2(inSize < (size_t)blockLen, -1); + + /* create padding */ + ret = xmlSecBufferSetMaxSize(in, blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", blockLen); + return(-1); + } + inBuf = xmlSecBufferGetData(in); + + /* create random padding */ + if((size_t)blockLen > (inSize + 1)) { + if (!CryptGenRandom(ctx->cryptProvider, blockLen - inSize - 1, inBuf + inSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptGenRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + inBuf[blockLen - 1] = blockLen - inSize; + inSize = blockLen; + } else { + if(inSize != (size_t)blockLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "data=%d;block=%d", inSize, blockLen); + return(-1); + } + inBuf = xmlSecBufferGetData(in); + } + + /* process last block */ + ret = xmlSecBufferSetMaxSize(out, outSize + 2 * blockLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + 2 * blockLen); + return(-1); + } + outBuf = xmlSecBufferGetData(out) + outSize; + memcpy(outBuf, inBuf, inSize); + + dwCLen = inSize; + if(encrypt) { + /* Set process last block to false, since we handle padding ourselves, and MSCrypto padding + * can be skipped. I hope this will work .... */ + if(!CryptEncrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen, inSize + blockLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + if (!CryptDecrypt(ctx->cryptKey, 0, FALSE, 0, outBuf, &dwCLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptDecrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* Check if we really have de/encrypted the numbers of bytes that we requested */ + if (dwCLen != inSize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "CryptEn/Decrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", dwCLen); + return(-1); + } + + if(encrypt == 0) { + /* check padding */ + if(inSize < outBuf[blockLen - 1]) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "padding=%d;buffer=%d", + outBuf[blockLen - 1], inSize); + return(-1); + } + outLen = inSize - outBuf[blockLen - 1]; + } else { + outLen = inSize; + } + + /* set correct output buffer size */ + ret = xmlSecBufferSetSize(out, outSize + outLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen); + return(-1); + } + + /* remove the processed block from input */ + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + return(0); +} + +/****************************************************************************** + * + * Block Cipher transforms + * + * xmlSecMSCryptoBlockCipherCtx block is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecMSCryptoBlockCipherSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoBlockCipherCtx)) +#define xmlSecMSCryptoBlockCipherGetCtx(transform) \ + ((xmlSecMSCryptoBlockCipherCtxPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecMSCryptoBlockCipherInitialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoBlockCipherFinalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoBlockCipherSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoBlockCipherSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoBlockCipherExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoBlockCipherCheckId (xmlSecTransformPtr transform); + + + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +#ifndef XMLSEC_NO_DES +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Des[] = { + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Aes[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { NULL, 0 } +}; +#endif /* XMLSEC_NO_AES */ + +static int +xmlSecMSCryptoBlockCipherCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DES + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDes3CbcId)) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes128CbcId) || + xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes192CbcId) || + xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformAes256CbcId)) { + + return(1); + } +#endif /* XMLSEC_NO_AES */ + + return(0); +} + +static int +xmlSecMSCryptoBlockCipherInitialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoBlockCipherCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1); + + ctx = xmlSecMSCryptoBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoBlockCipherCtx)); + +#ifndef XMLSEC_NO_DES + if(transform->id == xmlSecMSCryptoTransformDes3CbcId) { + ctx->algorithmIdentifier = CALG_3DES; + ctx->keyId = xmlSecMSCryptoKeyDataDesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Des; + ctx->keySize = 24; + } else +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(transform->id == xmlSecMSCryptoTransformAes128CbcId) { + ctx->algorithmIdentifier = CALG_AES_128; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Aes; + ctx->keySize = 16; + } else if(transform->id == xmlSecMSCryptoTransformAes192CbcId) { + ctx->algorithmIdentifier = CALG_AES_192; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Aes; + ctx->keySize = 24; + } else if(transform->id == xmlSecMSCryptoTransformAes256CbcId) { + ctx->algorithmIdentifier = CALG_AES_256; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Aes; + ctx->keySize = 32; + } else +#endif /* XMLSEC_NO_AES */ + + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->cryptProvider = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(ctx->cryptProvider == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + /* Create dummy key to be able to import plain session keys */ + if (!xmlSecMSCryptoCreatePrivateExponentOneKey(ctx->cryptProvider, &(ctx->pubPrivKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoCreatePrivateExponentOneKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + ctx->ctxInitialized = 0; + return(0); +} + +static void +xmlSecMSCryptoBlockCipherFinalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoBlockCipherCtxPtr ctx; + + xmlSecAssert(xmlSecMSCryptoBlockCipherCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize)); + + ctx = xmlSecMSCryptoBlockCipherGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (ctx->cryptKey) { + CryptDestroyKey(ctx->cryptKey); + } + if (ctx->pubPrivKey) { + CryptDestroyKey(ctx->pubPrivKey); + } + if (ctx->cryptProvider) { + CryptReleaseContext(ctx->cryptProvider, 0); + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoBlockCipherCtx)); +} + +static int +xmlSecMSCryptoBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecMSCryptoBlockCipherCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecMSCryptoBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cryptProvider != 0, -1); + + keyReq->keyId = ctx->keyId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + + keyReq->keyBitsSize = 8 * ctx->keySize; + return(0); +} + +static int +xmlSecMSCryptoBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoBlockCipherCtxPtr ctx; + xmlSecBufferPtr buffer; + BYTE* bufData; + + xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecMSCryptoBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cryptKey == 0, -1); + xmlSecAssert2(ctx->pubPrivKey != 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + xmlSecAssert2(ctx->keySize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + if(xmlSecBufferGetSize(buffer) < ctx->keySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "keySize=%d;expected=%d", + xmlSecBufferGetSize(buffer), ctx->keySize); + return(-1); + } + + bufData = xmlSecBufferGetData(buffer); + xmlSecAssert2(bufData != NULL, -1); + + /* Import this key and get an HCRYPTKEY handle */ + if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->cryptProvider, + ctx->pubPrivKey, + ctx->algorithmIdentifier, + bufData, + ctx->keySize, + TRUE, + &(ctx->cryptKey))) { + + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecMSCryptoBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoBlockCipherCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecMSCryptoBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoBlockCipherSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecMSCryptoBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + if(ctx->ctxInitialized == 0) { + ret = xmlSecMSCryptoBlockCipherCtxInit(ctx, + in, + out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), + transformCtx); + + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoBlockCipherCtxInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + if((ctx->ctxInitialized == 0) && (last != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "not enough data to initialize transform"); + return(-1); + } + if(ctx->ctxInitialized != 0) { + ret = xmlSecMSCryptoBlockCipherCtxUpdate(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoBlockCipherCtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(last) { + ret = xmlSecMSCryptoBlockCipherCtxFinal(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoBlockCipherCtxFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusFinished; + } + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + } else if(transform->status == xmlSecTransformStatusNone) { + /* the only way we can get here is if there is no enough data in the input */ + xmlSecAssert2(last == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} + +#ifndef XMLSEC_NO_AES +/********************************************************************* + * + * AES CBC cipher transforms + * + ********************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoAes128CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes128Cbc, /* const xmlChar* name; */ + xmlSecHrefAes128Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformAes128CbcGetKlass: + * + * AES 128 CBC encryption transform klass. + * + * Returns: pointer to AES 128 CBC encryption transform. + */ +xmlSecTransformId +xmlSecMSCryptoTransformAes128CbcGetKlass(void) { + return(&xmlSecMSCryptoAes128CbcKlass); +} + +static xmlSecTransformKlass xmlSecMSCryptoAes192CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes192Cbc, /* const xmlChar* name; */ + xmlSecHrefAes192Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformAes192CbcGetKlass: + * + * AES 192 CBC encryption transform klass. + * + * Returns: pointer to AES 192 CBC encryption transform. + */ +xmlSecTransformId +xmlSecMSCryptoTransformAes192CbcGetKlass(void) { + return(&xmlSecMSCryptoAes192CbcKlass); +} + +static xmlSecTransformKlass xmlSecMSCryptoAes256CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes256Cbc, /* const xmlChar* name; */ + xmlSecHrefAes256Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformAes256CbcGetKlass: + * + * AES 256 CBC encryption transform klass. + * + * Returns: pointer to AES 256 CBC encryption transform. + */ +xmlSecTransformId +xmlSecMSCryptoTransformAes256CbcGetKlass(void) { + return(&xmlSecMSCryptoAes256CbcKlass); +} + +#endif /* XMLSEC_NO_AES */ + + +#ifndef XMLSEC_NO_DES +static xmlSecTransformKlass xmlSecMSCryptoDes3CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoBlockCipherSize, /* size_t objSize */ + + xmlSecNameDes3Cbc, /* const xmlChar* name; */ + xmlSecHrefDes3Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod,/* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformDes3CbcGetKlass: + * + * Triple DES CBC encryption transform klass. + * + * Returns: pointer to Triple DES encryption transform. + */ +xmlSecTransformId +xmlSecMSCryptoTransformDes3CbcGetKlass(void) { + return(&xmlSecMSCryptoDes3CbcKlass); +} +#endif /* XMLSEC_NO_DES */ diff --git a/src/mscrypto/crypto.c b/src/mscrypto/crypto.c new file mode 100644 index 00000000..82ab101d --- /dev/null +++ b/src/mscrypto/crypto.c @@ -0,0 +1,889 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2005-2006 Cryptocom LTD (http://www.cryptocom.ru). + */ +#include "globals.h" + +#include <string.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/dl.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/private.h> + +#include <xmlsec/mscrypto/app.h> +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/x509.h> +#include "private.h" + +#if defined(__MINGW32__) +/* NOTE mingw.org project don't define any xxx_s function and may + * be never will define them. + * + * In this file is save to use non _s function as into destination + * buffer program code copy empty string and the size of source buffer + * (XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE=4096) is enough for any + * encoding. Also program code don't check result of _s functions. + */ + +static int +strcpy_s(char *dest, size_t n, const char *src) { + strcpy(dest, src); + return(0); +} + +static int +wcscpy_s(wchar_t *dest, size_t n, const wchar_t *src) { + wcscpy(dest, src); + return(0); +} +#endif + +#define XMLSEC_CONTAINER_NAME_A "xmlsec-key-container" +#define XMLSEC_CONTAINER_NAME_W L"xmlsec-key-container" +#ifdef UNICODE +#define XMLSEC_CONTAINER_NAME XMLSEC_CONTAINER_NAME_W +#else +#define XMLSEC_CONTAINER_NAME XMLSEC_CONTAINER_NAME_A +#endif + + +static xmlSecCryptoDLFunctionsPtr gXmlSecMSCryptoFunctions = NULL; + +/** + * xmlSecCryptoGetFunctions_mscrypto: + * + * Gets MSCrypto specific functions table. + * + * Returns: xmlsec-mscrypto functions table. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoGetFunctions_mscrypto(void) { + static xmlSecCryptoDLFunctions functions; + + if(gXmlSecMSCryptoFunctions != NULL) { + return(gXmlSecMSCryptoFunctions); + } + + memset(&functions, 0, sizeof(functions)); + gXmlSecMSCryptoFunctions = &functions; + + /******************************************************************** + * + * Crypto Init/shutdown + * + ********************************************************************/ + gXmlSecMSCryptoFunctions->cryptoInit = xmlSecMSCryptoInit; + gXmlSecMSCryptoFunctions->cryptoShutdown = xmlSecMSCryptoShutdown; + gXmlSecMSCryptoFunctions->cryptoKeysMngrInit = xmlSecMSCryptoKeysMngrInit; + + /******************************************************************** + * + * Key data ids + * + ********************************************************************/ +#ifndef XMLSEC_NO_DES + gXmlSecMSCryptoFunctions->keyDataDesGetKlass = xmlSecMSCryptoKeyDataDesGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + gXmlSecMSCryptoFunctions->keyDataAesGetKlass = xmlSecMSCryptoKeyDataAesGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_RSA + gXmlSecMSCryptoFunctions->keyDataRsaGetKlass = xmlSecMSCryptoKeyDataRsaGetKlass; +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecMSCryptoFunctions->keyDataHmacGetKlass = xmlSecMSCryptoKeyDataHmacGetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_DSA + gXmlSecMSCryptoFunctions->keyDataDsaGetKlass = xmlSecMSCryptoKeyDataDsaGetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + gXmlSecMSCryptoFunctions->keyDataGost2001GetKlass = xmlSecMSCryptoKeyDataGost2001GetKlass; +#endif /* XMLSEC_NO_GOST*/ + +#ifndef XMLSEC_NO_X509 + gXmlSecMSCryptoFunctions->keyDataX509GetKlass = xmlSecMSCryptoKeyDataX509GetKlass; + gXmlSecMSCryptoFunctions->keyDataRawX509CertGetKlass = xmlSecMSCryptoKeyDataRawX509CertGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /******************************************************************** + * + * Key data store ids + * + ********************************************************************/ +#ifndef XMLSEC_NO_X509 + gXmlSecMSCryptoFunctions->x509StoreGetKlass = xmlSecMSCryptoX509StoreGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /******************************************************************** + * + * Crypto transforms ids + * + ********************************************************************/ + + /******************************* AES ********************************/ +#ifndef XMLSEC_NO_AES + gXmlSecMSCryptoFunctions->transformAes128CbcGetKlass = xmlSecMSCryptoTransformAes128CbcGetKlass; + gXmlSecMSCryptoFunctions->transformAes192CbcGetKlass = xmlSecMSCryptoTransformAes192CbcGetKlass; + gXmlSecMSCryptoFunctions->transformAes256CbcGetKlass = xmlSecMSCryptoTransformAes256CbcGetKlass; + gXmlSecMSCryptoFunctions->transformKWAes128GetKlass = xmlSecMSCryptoTransformKWAes128GetKlass; + gXmlSecMSCryptoFunctions->transformKWAes192GetKlass = xmlSecMSCryptoTransformKWAes192GetKlass; + gXmlSecMSCryptoFunctions->transformKWAes256GetKlass = xmlSecMSCryptoTransformKWAes256GetKlass; +#endif /* XMLSEC_NO_AES */ + + /******************************* DES ********************************/ +#ifndef XMLSEC_NO_DES + gXmlSecMSCryptoFunctions->transformDes3CbcGetKlass = xmlSecMSCryptoTransformDes3CbcGetKlass; + gXmlSecMSCryptoFunctions->transformKWDes3GetKlass = xmlSecMSCryptoTransformKWDes3GetKlass; +#endif /* XMLSEC_NO_DES */ + + /******************************* DSA ********************************/ +#ifndef XMLSEC_NO_DSA + gXmlSecMSCryptoFunctions->transformDsaSha1GetKlass = xmlSecMSCryptoTransformDsaSha1GetKlass; +#endif /* XMLSEC_NO_DSA */ + + /******************************* GOST ********************************/ +#ifndef XMLSEC_NO_GOST + gXmlSecMSCryptoFunctions->transformGost2001GostR3411_94GetKlass = xmlSecMSCryptoTransformGost2001GostR3411_94GetKlass; +#endif /* XMLSEC_NO_GOST */ + +#ifndef XMLSEC_NO_GOST + gXmlSecMSCryptoFunctions->transformGostR3411_94GetKlass = xmlSecMSCryptoTransformGostR3411_94GetKlass; +#endif /* XMLSEC_NO_GOST */ + + /******************************* HMAC ********************************/ +#ifndef XMLSEC_NO_HMAC + +#ifndef XMLSEC_NO_MD5 + gXmlSecMSCryptoFunctions->transformHmacMd5GetKlass = xmlSecMSCryptoTransformHmacMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecMSCryptoFunctions->transformHmacSha1GetKlass = xmlSecMSCryptoTransformHmacSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + gXmlSecMSCryptoFunctions->transformHmacSha256GetKlass = xmlSecMSCryptoTransformHmacSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + gXmlSecMSCryptoFunctions->transformHmacSha384GetKlass = xmlSecMSCryptoTransformHmacSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + gXmlSecMSCryptoFunctions->transformHmacSha512GetKlass = xmlSecMSCryptoTransformHmacSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_HMAC */ + + /******************************* MD5 ********************************/ +#ifndef XMLSEC_NO_MD5 + gXmlSecMSCryptoFunctions->transformMd5GetKlass = xmlSecMSCryptoTransformMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + + /******************************* RSA ********************************/ +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + gXmlSecMSCryptoFunctions->transformRsaMd5GetKlass = xmlSecMSCryptoTransformRsaMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecMSCryptoFunctions->transformRsaSha1GetKlass = xmlSecMSCryptoTransformRsaSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + gXmlSecMSCryptoFunctions->transformRsaSha256GetKlass = xmlSecMSCryptoTransformRsaSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + gXmlSecMSCryptoFunctions->transformRsaSha384GetKlass = xmlSecMSCryptoTransformRsaSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + gXmlSecMSCryptoFunctions->transformRsaSha512GetKlass = xmlSecMSCryptoTransformRsaSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + gXmlSecMSCryptoFunctions->transformRsaPkcs1GetKlass = xmlSecMSCryptoTransformRsaPkcs1GetKlass; + gXmlSecMSCryptoFunctions->transformRsaOaepGetKlass = xmlSecMSCryptoTransformRsaOaepGetKlass; +#endif /* XMLSEC_NO_RSA */ + + /******************************* SHA ********************************/ +#ifndef XMLSEC_NO_SHA1 + gXmlSecMSCryptoFunctions->transformSha1GetKlass = xmlSecMSCryptoTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ +#ifndef XMLSEC_NO_SHA256 + gXmlSecMSCryptoFunctions->transformSha256GetKlass = xmlSecMSCryptoTransformSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ +#ifndef XMLSEC_NO_SHA384 + gXmlSecMSCryptoFunctions->transformSha384GetKlass = xmlSecMSCryptoTransformSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ +#ifndef XMLSEC_NO_SHA512 + gXmlSecMSCryptoFunctions->transformSha512GetKlass = xmlSecMSCryptoTransformSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + /******************************************************************** + * + * High level routines form xmlsec command line utility + * + ********************************************************************/ + gXmlSecMSCryptoFunctions->cryptoAppInit = xmlSecMSCryptoAppInit; + gXmlSecMSCryptoFunctions->cryptoAppShutdown = xmlSecMSCryptoAppShutdown; + gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrInit = xmlSecMSCryptoAppDefaultKeysMngrInit; + gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrAdoptKey = xmlSecMSCryptoAppDefaultKeysMngrAdoptKey; + gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrLoad = xmlSecMSCryptoAppDefaultKeysMngrLoad; + gXmlSecMSCryptoFunctions->cryptoAppDefaultKeysMngrSave = xmlSecMSCryptoAppDefaultKeysMngrSave; +#ifndef XMLSEC_NO_X509 + gXmlSecMSCryptoFunctions->cryptoAppKeysMngrCertLoad = xmlSecMSCryptoAppKeysMngrCertLoad; + gXmlSecMSCryptoFunctions->cryptoAppKeysMngrCertLoadMemory = xmlSecMSCryptoAppKeysMngrCertLoadMemory; + gXmlSecMSCryptoFunctions->cryptoAppPkcs12Load = xmlSecMSCryptoAppPkcs12Load; + gXmlSecMSCryptoFunctions->cryptoAppPkcs12LoadMemory = xmlSecMSCryptoAppPkcs12LoadMemory; + gXmlSecMSCryptoFunctions->cryptoAppKeyCertLoad = xmlSecMSCryptoAppKeyCertLoad; + gXmlSecMSCryptoFunctions->cryptoAppKeyCertLoadMemory = xmlSecMSCryptoAppKeyCertLoadMemory; +#endif /* XMLSEC_NO_X509 */ + gXmlSecMSCryptoFunctions->cryptoAppKeyLoad = xmlSecMSCryptoAppKeyLoad; + gXmlSecMSCryptoFunctions->cryptoAppKeyLoadMemory = xmlSecMSCryptoAppKeyLoadMemory; + gXmlSecMSCryptoFunctions->cryptoAppDefaultPwdCallback = (void*)xmlSecMSCryptoAppGetDefaultPwdCallback(); + + return(gXmlSecMSCryptoFunctions); +} + +/** + * xmlSecMSCryptoInit: + * + * XMLSec library specific crypto engine initialization. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoInit (void) { + /* Check loaded xmlsec library version */ + if(xmlSecCheckVersionExact() != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCheckVersionExact", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* set default errors callback for xmlsec to us */ + xmlSecErrorsSetCallback(xmlSecMSCryptoErrorsDefaultCallback); + + /* register our klasses */ + if(xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(xmlSecCryptoGetFunctions_mscrypto()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecMSCryptoShutdown: + * + * XMLSec library specific crypto engine shutdown. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoShutdown(void) { + /* TODO: if necessary, do additional shutdown here */ + return(0); +} + +/** + * xmlSecMSCryptoKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Adds MSCrypto specific key data stores in keys manager. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + +#ifndef XMLSEC_NO_X509 + /* create x509 store if needed */ + if(xmlSecKeysMngrGetDataStore(mngr, xmlSecMSCryptoX509StoreId) == NULL) { + xmlSecKeyDataStorePtr x509Store; + + x509Store = xmlSecKeyDataStoreCreate(xmlSecMSCryptoX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecMSCryptoX509StoreId"); + return(-1); + } + + ret = xmlSecKeysMngrAdoptDataStore(mngr, x509Store); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrAdoptDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataStoreDestroy(x509Store); + return(-1); + } + } +#endif /* XMLSEC_NO_X509 */ + + return(0); +} + + +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Random[] = { + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + +/** + * xmlSecMSCryptoGenerateRandom: + * @buffer: the destination buffer. + * @size: the numer of bytes to generate. + * + * Generates @size random bytes and puts result in @buffer + * (not implemented yet). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecMSCryptoGenerateRandom(xmlSecBufferPtr buffer, size_t size) { + HCRYPTPROV hProv = 0; + int ret; + + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2(size > 0, -1); + + ret = xmlSecBufferSetSize(buffer, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + hProv = xmlSecMSCryptoFindProvider(xmlSecMSCryptoProviderInfo_Random, NULL, CRYPT_VERIFYCONTEXT, FALSE); + if (0 == hProv) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if (FALSE == CryptGenRandom(hProv, (DWORD)size, xmlSecBufferGetData(buffer))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGenRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptReleaseContext(hProv,0); + return(-1); + } + + CryptReleaseContext(hProv, 0); + return(0); +} + +#define XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE 4096 + +/** + * xmlSecMSCryptoErrorsDefaultCallback: + * @file: the error location file name (__FILE__ macro). + * @line: the error location line number (__LINE__ macro). + * @func: the error location function name (__FUNCTION__ macro). + * @errorObject: the error specific error object + * @errorSubject: the error specific error subject. + * @reason: the error code. + * @msg: the additional error message. + * + * The default errors reporting callback function. + */ +void +xmlSecMSCryptoErrorsDefaultCallback(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg) { + DWORD dwError; + TCHAR errorT[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE]; + WCHAR errorW[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE]; + CHAR errorUTF8[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE]; + xmlChar buf[XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE]; + DWORD rc; + int ret; + + dwError = GetLastError(); + rc = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + dwError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + errorT, + XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, + NULL); + +#ifdef UNICODE + if(rc <= 0) { + wcscpy_s(errorT, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, L""); + } + ret = WideCharToMultiByte(CP_UTF8, 0, errorT, -1, errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, NULL, NULL); + if(ret <= 0) { + strcpy_s(errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, ""); + } +#else /* UNICODE */ + if(rc <= 0) { + strcpy_s(errorT, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, ""); + } + ret = MultiByteToWideChar(CP_ACP, 0, errorT, -1, errorW, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE); + if(ret <= 0) { + wcscpy_s(errorW, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, L""); + } + ret = WideCharToMultiByte(CP_UTF8, 0, errorW, -1, errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, NULL, NULL); + if(ret <= 0) { + strcpy_s(errorUTF8, XMLSEC_MSCRYPTO_ERROR_MSG_BUFFER_SIZE, ""); + } +#endif /* UNICODE */ + + if((msg != NULL) && ((*msg) != '\0')) { + xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "%s;last error=%d (0x%08x);last error msg=%s", msg, dwError, dwError, errorUTF8); + } else { + xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "last error=%d (0x%08x);last error msg=%s", dwError, dwError, errorUTF8); + } + xmlSecErrorsDefaultCallback(file, line, func, + errorObject, errorSubject, + reason, (char*)buf); +} + +/** + * xmlSecMSCryptoConvertUtf8ToUnicode: + * @str: the string to convert. + * + * Converts input string from UTF8 to Unicode. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +LPWSTR +xmlSecMSCryptoConvertUtf8ToUnicode(const xmlChar* str) { + LPWSTR res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + /* call MultiByteToWideChar first to get the buffer size */ + ret = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + if(ret <= 0) { + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (LPWSTR)xmlMalloc(sizeof(WCHAR) * len); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(WCHAR) * len); + return(NULL); + } + + /* convert */ + ret = MultiByteToWideChar(CP_UTF8, 0, str, -1, res, len); + if(ret <= 0) { + xmlFree(res); + return(NULL); + } + + /* done */ + return(res); +} + +/** + * xmlSecMSCryptoConvertUnicodeToUtf8: + * @str: the string to convert. + * + * Converts input string from Unicode to UTF8. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +xmlChar* +xmlSecMSCryptoConvertUnicodeToUtf8(LPCWSTR str) { + xmlChar * res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + /* call WideCharToMultiByte first to get the buffer size */ + ret = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL); + if(ret <= 0) { + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (xmlChar*)xmlMalloc(sizeof(xmlChar) * len); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(xmlChar) * len); + return(NULL); + } + + /* convert */ + ret = WideCharToMultiByte(CP_UTF8, 0, str, -1, res, len, NULL, NULL); + if(ret <= 0) { + xmlFree(res); + return(NULL); + } + + /* done */ + return(res); +} + +/** + * xmlSecMSCryptoConvertLocaleToUnicode: + * @str: the string to convert. + * + * Converts input string from current system locale to Unicode. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +LPWSTR +xmlSecMSCryptoConvertLocaleToUnicode(const char* str) { + LPWSTR res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + /* call MultiByteToWideChar first to get the buffer size */ + ret = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0); + if(ret <= 0) { + return(NULL); + } + len = ret; + + /* allocate buffer */ + res = (LPWSTR)xmlMalloc(sizeof(WCHAR) * len); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* convert */ + ret = MultiByteToWideChar(CP_ACP, 0, str, -1, res, len); + if(ret <= 0) { + xmlFree(res); + return(NULL); + } + + /* done */ + return(res); +} + +/** + * xmlSecMSCryptoConvertLocaleToUtf8: + * @str: the string to convert. + * + * Converts input string from locale to UTF8. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +xmlChar* +xmlSecMSCryptoConvertLocaleToUtf8(const char * str) { + LPWSTR strW = NULL; + xmlChar * res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + strW = xmlSecMSCryptoConvertLocaleToUnicode(str); + if(strW == NULL) { + return(NULL); + } + + /* call WideCharToMultiByte first to get the buffer size */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (xmlChar*)xmlMalloc(sizeof(xmlChar) * len); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(xmlChar) * len); + xmlFree(strW); + return(NULL); + } + + /* convert */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, res, len, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + xmlFree(res); + return(NULL); + } + + /* done */ + xmlFree(strW); + return(res); +} + +/** + * xmlSecMSCryptoConvertUtf8ToLocale: + * @str: the string to convert. + * + * Converts input string from UTF8 to locale. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +char * +xmlSecMSCryptoConvertUtf8ToLocale(const xmlChar* str) { + LPWSTR strW = NULL; + char * res = NULL; + int len; + int ret; + + xmlSecAssert2(str != NULL, NULL); + + strW = xmlSecMSCryptoConvertUtf8ToUnicode(str); + if(strW == NULL) { + return(NULL); + } + + /* call WideCharToMultiByte first to get the buffer size */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, NULL, 0, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + return(NULL); + } + len = ret + 1; + + /* allocate buffer */ + res = (char*)xmlMalloc(sizeof(char) * len); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(xmlChar) * len); + xmlFree(strW); + return(NULL); + } + + /* convert */ + ret = WideCharToMultiByte(CP_ACP, 0, strW, -1, res, len, NULL, NULL); + if(ret <= 0) { + xmlFree(strW); + xmlFree(res); + return(NULL); + } + + /* done */ + xmlFree(strW); + return(res); +} + +/** + * xmlSecMSCryptoConvertTstrToUtf8: + * @str: the string to convert. + * + * Converts input string from TSTR (locale or Unicode) to UTF8. + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +xmlChar* +xmlSecMSCryptoConvertTstrToUtf8(LPCTSTR str) { +#ifdef UNICODE + return xmlSecMSCryptoConvertUnicodeToUtf8(str); +#else /* UNICODE */ + return xmlSecMSCryptoConvertLocaleToUtf8(str); +#endif /* UNICODE */ +} + +/** + * xmlSecMSCryptoConvertUtf8ToTstr: + * @str: the string to convert. + * + * Converts input string from UTF8 to TSTR (locale or Unicode). + * + * Returns: a pointer to newly allocated string (must be freed with xmlFree) or NULL if an error occurs. + */ +LPTSTR +xmlSecMSCryptoConvertUtf8ToTstr(const xmlChar* str) { +#ifdef UNICODE + return xmlSecMSCryptoConvertUtf8ToUnicode(str); +#else /* UNICODE */ + return xmlSecMSCryptoConvertUtf8ToLocale(str); +#endif /* UNICODE */ +} + +/******************************************************************** + * + * Crypto Providers + * + ********************************************************************/ +/** + * xmlSecMSCryptoFindProvider: + * @providers: the pointer to list of providers, last provider should have NULL for name. + * @pszContainer: the container name for CryptAcquireContext call + * @dwFlags: the flags for CryptAcquireContext call + * @bUseXmlSecContainer: the flag to indicate whether we should try to use XmlSec container if default fails + * + * Finds the first provider from the list + * + * Returns: provider handle on success or NULL for error. + */ +HCRYPTPROV +xmlSecMSCryptoFindProvider(const xmlSecMSCryptoProviderInfo * providers, + LPCTSTR pszContainer, + DWORD dwFlags, + BOOL bUseXmlSecContainer) +{ + HCRYPTPROV res = 0; + DWORD dwLastError; + BOOL ret; + int ii; + + xmlSecAssert2(providers != NULL, 0); + + for(ii = 0; (res == 0) && (providers[ii].providerName != NULL) && (providers[ii].providerType != 0); ++ii) { + /* first try */ + ret = CryptAcquireContext(&res, + pszContainer, + providers[ii].providerName, + providers[ii].providerType, + dwFlags); + if((ret == TRUE) && (res != 0)) { + return (res); + } + + /* check errors */ + dwLastError = GetLastError(); + switch(dwLastError) { + case NTE_BAD_KEYSET: + /* This error can indicate that a newly installed provider + * does not have a usable key container yet. It needs to be + * created, and then we have to try again CryptAcquireContext. + * This is also referenced in + * http://www.microsoft.com/mind/0697/crypto.asp (inituser) + */ + ret = CryptAcquireContext(&res, + pszContainer, + providers[ii].providerName, + providers[ii].providerType, + CRYPT_NEWKEYSET | dwFlags); + if((ret == TRUE) && (res != 0)) { + return (res); + } + break; + + case NTE_EXISTS: + /* If we can, try our container */ + if(bUseXmlSecContainer == TRUE) { + ret = CryptAcquireContext(&res, + XMLSEC_CONTAINER_NAME, + providers[ii].providerName, + providers[ii].providerType, + CRYPT_NEWKEYSET | dwFlags); + if((ret == TRUE) && (res != 0)) { + /* ALEKSEY TODO - NEED TO DELETE ALL THE TEMP CONTEXTS ON SHUTDOWN + + CryptAcquireContext(&tmp, XMLSEC_CONTAINER_NAME, + providers[ii].providerName, + providers[ii].providerType, + CRYPT_DELETEKEYSET); + + */ + return (res); + } + } + break; + + default: + /* ignore */ + break; + } + } + + return (0); +} + + +/******************************************************************** + * + * Utils + * + ********************************************************************/ +int +ConvertEndian(const xmlSecByte * src, xmlSecByte * dst, xmlSecSize size) { + xmlSecByte * p; + + xmlSecAssert2(src != NULL, -1); + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(size > 0, -1); + + for(p = dst + size - 1; p >= dst; ++src, --p) { + (*p) = (*src); + } + + return (0); +} + +int +ConvertEndianInPlace(xmlSecByte * buf, xmlSecSize size) { + xmlSecByte * p; + xmlSecByte ch; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(size > 0, -1); + + for(p = buf + size - 1; p >= buf; ++buf, --p) { + ch = (*p); + (*p) = (*buf); + (*buf) = ch; + } + return (0); +} + + diff --git a/src/mscrypto/csp_calg.h b/src/mscrypto/csp_calg.h new file mode 100644 index 00000000..984fe347 --- /dev/null +++ b/src/mscrypto/csp_calg.h @@ -0,0 +1,105 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2005-2006 Cryptocom LTD (http://www.cryptocom.ru). + * All rights reserved. + */ +#ifndef CRYPTOCOM_CSP_CALG_H +#define CRYPTOCOM_CSP_CALG_H + +#define ALG_TYPE_GR3410 (7 << 9) + +#define ALG_SID_MAGPRO_R3410_94 64 +#define ALG_SID_MAGPRO_R3410_94_EPHEM 65 +#define ALG_SID_MAGPRO_R3410_2001 66 +#define ALG_SID_MAGPRO_R3410_2001_EPHEM 67 +#define ALG_SID_MAGPRO_28147_89 68 +#define ALG_SID_GR3411 30 +#define ALG_SID_G28147 30 + +#define ALG_SID_GR3410 30 +#define ALG_SID_DH_EX_SF 30 +#define ALG_SID_DH_EX_EPHEM 31 +#define ALG_SID_PRO_AGREEDKEY_DH 33 +#define ALG_SID_PRO_SIMMETRYKEY 34 +#define ALG_SID_GR3410EL 35 +#define ALG_SID_DH_EL_SF 36 +#define ALG_SID_DH_EL_EPHEM 37 + +/*! \defgroup CALG_MAGPRO CALG_MAGPRO + * \brief The description of CALG_MAGPRO + * + * @{ + */ + + +#define CALG_MAGPRO_SIGN_R3410_94 (ALG_CLASS_SIGNATURE | ALG_TYPE_GR3410 | ALG_SID_MAGPRO_R3410_94) + +#define CALG_MAGPRO_SIGN_R3410_2001 (ALG_CLASS_SIGNATURE | ALG_TYPE_GR3410 | ALG_SID_MAGPRO_R3410_2001) + +#define CALG_MAGPRO_DH_R3410_94 (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_MAGPRO_R3410_94) + +#define CALG_MAGPRO_DH_R3410_2001 (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_MAGPRO_R3410_2001) + +#define CALG_MAGPRO_DH_R3410_94_EPHEM (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_MAGPRO_R3410_94_EPHEM) + +#define CALG_MAGPRO_DH_R3410_2001_EPHEM (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_MAGPRO_R3410_2001_EPHEM) + +#define CALG_MAGPRO_HASH_R3411_94 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_GR3411) + +#define CALG_MAGPRO_HASH_28147_89 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MAGPRO_28147_89) + +#define CALG_MAGPRO_ENCR_28147_89 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_G28147) + +#define CALG_GR3410 (ALG_CLASS_SIGNATURE | ALG_TYPE_GR3410 | ALG_SID_GR3410) + +#define CALG_GR3410EL (ALG_CLASS_SIGNATURE | ALG_TYPE_GR3410 | ALG_SID_GR3410EL) + +#define CALG_DH_EX_SF (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EX_SF) + +#define CALG_DH_EX_EPHEM (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EX_EPHEM) + +#define CALG_DH_EL_SF (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EL_SF) + +#define CALG_DH_EL_EPHEM (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EL_EPHEM) + +/*! @} */ +/*! \defgroup PROV_TYPE PROV_TYPE + * \brief The description of PROV_MAGPRO_GOST + * + * @{ + */ +#define PROV_MAGPRO_GOST 501 +#define MAGPRO_CSP_A "MagPro CSP" +#define MAGPRO_CSP_W L"MagPro CSP" +#ifdef UNICODE +#define MAGPRO_CSP MAGPRO_CSP_W +#else +#define MAGPRO_CSP MAGPRO_CSP_A +#endif + +#define PROV_CRYPTOPRO_GOST 75 +#define CRYPTOPRO_CSP_A "CryptoPro CSP" +#define CRYPTOPRO_CSP_W L"CryptoPro CSP" +#ifdef UNICODE +#define CRYPTOPRO_CSP CRYPTOPRO_CSP_W +#else +#define CRYPTOPRO_CSP CRYPTOPRO_CSP_A +#endif + +/*! @} */ +/*! \defgroup PP_MAGPRO PP_MAGPRO + * + * @{ + */ + +#define PP_RNGTYPE 201 +#define PP_RNGSHARED 202 +#define PP_SETUP_UI 203 + +/*! @} */ + +#endif //CRYPTOCOM_CSP_CALG_H diff --git a/src/mscrypto/csp_oid.h b/src/mscrypto/csp_oid.h new file mode 100644 index 00000000..e5636741 --- /dev/null +++ b/src/mscrypto/csp_oid.h @@ -0,0 +1,114 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2005-2006 Cryptocom LTD (http://www.cryptocom.ru). + * All rights reserved. + */ +#ifndef CRYPTOCOM_OIDS_csp_H +#define CRYPTOCOM_OIDS_csp_H +/* Autogenerated from master.oid by oid2h.tcl */ + +/*! \defgroup szOID_MAGPRO szOID_MAGPRO + * \brief The OIDs supported by MagPro CSP + * + * @{ + */ + +/*! GOST 34.10-94 Diffie-Hellman algorithm Cryptocom LTD */ +#define szOID_MAGPRO_DH_R3410_94 "1.2.643.2.9.1.3.1" + +/*! GOST 34.10-2001 Diffie-Hellman algorithm Cryptocom LTD */ +#define szOID_MAGPRO_DH_R3410_2001 "1.2.643.2.9.1.3.2" + +/* */ +#define szOID_MAGPRO_DH_R3410_94_EPHEM "1.2.643.2.9.1.3.1" + +/* */ +#define szOID_MAGPRO_DH_R3410_2001_EPHEM "1.2.643.2.9.1.3.2" + +/*! GOST 34.10/11-94 digital signature algorithm Cryptocom LTD with digest */ +#define szOID_MAGPRO_SIGN_R3410_94 "1.2.643.2.9.1.3.3" + +/*! GOST 34.10-2001 digital signature algorithm with digest */ +#define szOID_MAGPRO_SIGN_R3410_2001 "1.2.643.2.9.1.3.4" + +/*! GOST 28147-89 MAC algorithm Cryptocom LTD */ +#define szOID_MAGPRO_HASH_28147_89 "1.2.643.2.9.1.4.1" + +#define szOID_MAGPRO_PUBKEY_DH_R3410_94 "1.2.643.2.9.1.5.1" + +#define szOID_MAGPRO_PUBKEY_DH_R3410_2001 "1.2.643.2.9.1.5.2" + +/*! GOST 34.10/11-94 digital signature algorithm Cryptocom LTD */ +#define szOID_MAGPRO_PUBKEY_SIGN_R3410_94 "1.2.643.2.9.1.5.3" + +/*! GOST 34.10-2001 digital signature algorithm */ +#define szOID_MAGPRO_PUBKEY_SIGN_R3410_2001 "1.2.643.2.9.1.5.4" + +/*! GOST 28147-89 encryption parameters */ +#define szOID_MAGPRO_PARAM_ENCR_28147_89 "1.2.643.2.9.1.6.1" + +/*! GOST 34.10-2001 public key parameters */ +#define szOID_MAGPRO_PARAM_PK_CC_01 "1.2.643.2.9.1.8.1" + +/*! GOST 28147-89 symmetric cipher Cryptocom LTD */ +#define szOID_MAGPRO_ENCR_28147_89 "1.2.643.2.2.21" + +/*! GOST 34.10-2001 digital signature algorithm CryptoPro LTD */ +#define szOID_MAGPRO_SIGN_R3410_2001_CP "1.2.643.2.2.3" + +/*! GOST 34.10/11-94 digital signature algorithm CryptoPro LTD */ +#define szOID_MAGPRO_SIGN_R3410_94_CP "1.2.643.2.2.4" + +/*! GOST 34.11-94 digest algorithm Cryptocom LTD */ +#define szOID_MAGPRO_HASH_R3411_94 "1.2.643.2.2.9" + +/*! GOST 34.10-2001 digital signature algorithm CryptoPro LTD public key */ +#define szOID_MAGPRO_PUBKEY_SIGN_R3410_2001_CP "1.2.643.2.2.19" + +/*! GOST 34.10/11-94 digital signature algorithm CryptoPro LTD public key */ +#define szOID_MAGPRO_PUBKEY_SIGN_R3410_94_CP "1.2.643.2.2.20" + +/*! GostR3411-94-CryptoProParamSet */ +#define szOID_MAGPRO_PARAM_HASH_3411_94 "1.2.643.2.2.30.1" + +/*! GostR3410-94-CryptoPro-A-ParamSet */ +#define szOID_MAGPRO_PARAM_PK_CC_94 "1.2.643.2.2.32.2" + + +#define szOID_CP_PARAM_R3411_94_DEF "1.2.643.2.2.30.1" +#define szOID_CP_PARAM_R3411_94_1 "1.2.643.2.2.30.2" +#define szOID_CP_PARAM_R3411_94_2 "1.2.643.2.2.30.3" +#define szOID_CP_PARAM_R3411_94_3 "1.2.643.2.2.30.4" + +#define szOID_CP_PARAM_28147_89_DEF "1.2.643.2.2.31.1" +#define szOID_CP_PARAM_28147_89_1 "1.2.643.2.2.31.2" +#define szOID_CP_PARAM_28147_89_2 "1.2.643.2.2.31.3" +#define szOID_CP_PARAM_28147_89_3 "1.2.643.2.2.31.4" +#define szOID_CP_PARAM_28147_89_4 "1.2.643.2.2.31.5" +#define szOID_CP_PARAM_28147_89_5 "1.2.643.2.2.31.6" +#define szOID_CP_PARAM_28147_89_6 "1.2.643.2.2.31.7" + +/* OID for Signature 1024*/ +#define szOID_CP_PARAM_PK_R3410_94_DEF "1.2.643.2.2.32.2" /*VerbaO*/ +#define szOID_CP_PARAM_PK_R3410_94_S1 "1.2.643.2.2.32.3" +#define szOID_CP_PARAM_PK_R3410_94_S2 "1.2.643.2.2.32.4" +#define szOID_CP_PARAM_PK_R3410_94_S3 "1.2.643.2.2.32.5" +/* OID for DH 1024*/ +#define szOID_CP_PARAM_PK_R3410_94_E1 "1.2.643.2.2.33.1" +#define szOID_CP_PARAM_PK_R3410_94_E2 "1.2.643.2.2.33.2" +#define szOID_CP_PARAM_PK_R3410_94_E3 "1.2.643.2.2.33.3" + +#define szOID_CP_PARAM_PK_R3410_2001_DEF "1.2.643.2.2.35.1" +#define szOID_CP_PARAM_PK_R3410_2001_S0 "1.2.643.2.2.35.2" +#define szOID_CP_PARAM_PK_R3410_2001_S1 "1.2.643.2.2.35.3" +#define szOID_CP_PARAM_PK_R3410_2001_E0 "1.2.643.2.2.36.0" +#define szOID_CP_PARAM_PK_R3410_2001_E1 "1.2.643.2.2.36.1" + + +/*! @} */ + +#endif diff --git a/src/mscrypto/digests.c b/src/mscrypto/digests.c new file mode 100644 index 00000000..9394afdc --- /dev/null +++ b/src/mscrypto/digests.c @@ -0,0 +1,668 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (c) 2005-2006 Cryptocom LTD (http://www.cryptocom.ru). + */ +#include "globals.h" + +#include <string.h> +#include <windows.h> +#include <wincrypt.h> +#ifndef XMLSEC_NO_GOST +#include "csp_calg.h" +#endif + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> +#include "private.h" + +#define MSCRYPTO_MAX_HASH_SIZE 256 + +typedef struct _xmlSecMSCryptoDigestCtx xmlSecMSCryptoDigestCtx, *xmlSecMSCryptoDigestCtxPtr; +struct _xmlSecMSCryptoDigestCtx { + HCRYPTPROV provider; + ALG_ID alg_id; + const xmlSecMSCryptoProviderInfo * providers; + HCRYPTHASH mscHash; + unsigned char dgst[MSCRYPTO_MAX_HASH_SIZE]; + size_t dgstSize; /* dgst size in bytes */ +}; + +/****************************************************************************** + * + * MSCrypto Digest transforms + * + * xmlSecMSCryptoDigestCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecMSCryptoDigestSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoDigestCtx)) +#define xmlSecMSCryptoDigestGetCtx(transform) \ + ((xmlSecMSCryptoDigestCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + + +static int xmlSecMSCryptoDigestInitialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoDigestFinalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoDigestVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoDigestExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoDigestCheckId (xmlSecTransformPtr transform); + + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Sha1[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { MS_DEF_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Sha2[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { NULL, 0 } +}; + +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Md5[] = { + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { MS_DEF_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + +#ifndef XMLSEC_NO_GOST +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Gost[] = { + { MAGPRO_CSP, PROV_MAGPRO_GOST }, + { CRYPTOPRO_CSP, PROV_CRYPTOPRO_GOST }, + { NULL, 0 } +}; +#endif /*ndef XMLSEC_NO_GOST*/ + +static int +xmlSecMSCryptoDigestCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformMd5Id)) { + return(1); + } +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha256Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha384Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha512Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_GOST + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGostR3411_94Id)) { + return(1); + } +#endif /* XMLSEC_NO_GOST*/ + + return(0); +} + +static int +xmlSecMSCryptoDigestInitialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoDigestCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoDigestSize), -1); + + ctx = xmlSecMSCryptoDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecMSCryptoDigestCtx)); + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformMd5Id)) { + ctx->alg_id = CALG_MD5; + ctx->providers = xmlSecMSCryptoProviderInfo_Md5; + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha1Id)) { + ctx->alg_id = CALG_SHA1; + ctx->providers = xmlSecMSCryptoProviderInfo_Sha1; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha256Id)) { + ctx->alg_id = CALG_SHA_256; + ctx->providers = xmlSecMSCryptoProviderInfo_Sha2; + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha384Id)) { + ctx->alg_id = CALG_SHA_384; + ctx->providers = xmlSecMSCryptoProviderInfo_Sha2; + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha512Id)) { + ctx->alg_id = CALG_SHA_512; + ctx->providers = xmlSecMSCryptoProviderInfo_Sha2; + } else +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_GOST + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGostR3411_94Id)) { + ctx->alg_id = CALG_MAGPRO_HASH_R3411_94; + ctx->providers = xmlSecMSCryptoProviderInfo_Gost; + } else +#endif /* XMLSEC_NO_GOST*/ + + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->provider = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(ctx->provider == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void xmlSecMSCryptoDigestFinalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoDigestCtxPtr ctx; + + xmlSecAssert(xmlSecMSCryptoDigestCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoDigestSize)); + + ctx = xmlSecMSCryptoDigestGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->mscHash != 0) { + CryptDestroyHash(ctx->mscHash); + } + if(ctx->provider != 0) { + CryptReleaseContext(ctx->provider, 0); + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoDigestCtx)); +} + +static int +xmlSecMSCryptoDigestVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoDigestCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoDigestSize), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->dgstSize > 0, -1); + + if(dataSize != ctx->dgstSize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "data_size=%d;dgst_size=%d", + dataSize, ctx->dgstSize); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + if(memcmp(ctx->dgst, data, ctx->dgstSize) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "data and digest do not match"); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + transform->status = xmlSecTransformStatusOk; + return(0); +} + +static int +xmlSecMSCryptoDigestExecute(xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoDigestCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecMSCryptoDigestCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoDigestSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + xmlSecAssert2(in != NULL, -1); + + out = &(transform->outBuf); + xmlSecAssert2(out != NULL, -1); + + ctx = xmlSecMSCryptoDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + ret = CryptCreateHash(ctx->provider, + ctx->alg_id, + 0, + 0, + &(ctx->mscHash)); + + if((ret == 0) || (ctx->mscHash == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptCreateHash", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + transform->status = xmlSecTransformStatusWorking; + } + + if (transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { + ret = CryptHashData(ctx->mscHash, + xmlSecBufferGetData(in), + inSize, + 0); + + if(ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptHashData", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", inSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + } + if(last) { + /* TODO: make a MSCrypto compatible assert here */ + /* xmlSecAssert2((xmlSecSize)EVP_MD_size(ctx->digest) <= sizeof(ctx->dgst), -1); */ + DWORD retLen; + retLen = MSCRYPTO_MAX_HASH_SIZE; + + ret = CryptGetHashParam(ctx->mscHash, + HP_HASHVAL, + ctx->dgst, + &retLen, + 0); + + if (ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptGetHashParam(HP_HASHVAL)", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", MSCRYPTO_MAX_HASH_SIZE); + return(-1); + } + + ctx->dgstSize = (size_t)retLen; + + xmlSecAssert2(ctx->dgstSize > 0, -1); + + /* copy result to output */ + if(transform->operation == xmlSecTransformOperationSign) { + ret = xmlSecBufferAppend(out, ctx->dgst, ctx->dgstSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ctx->dgstSize); + return(-1); + } + } + transform->status = xmlSecTransformStatusFinished; + } + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} + + +#ifndef XMLSEC_NO_MD5 +/****************************************************************************** + * + * MD5 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoDigestSize, /* size_t objSize */ + + xmlSecNameMd5, /* const xmlChar* name; */ + xmlSecHrefMd5, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + xmlSecMSCryptoDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformMd5GetKlass: + * + * SHA-1 digest transform klass. + * + * Returns: pointer to SHA-1 digest transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformMd5GetKlass(void) { + return(&xmlSecMSCryptoMd5Klass); +} +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 +/****************************************************************************** + * + * SHA1 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoDigestSize, /* size_t objSize */ + + xmlSecNameSha1, /* const xmlChar* name; */ + xmlSecHrefSha1, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + xmlSecMSCryptoDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformSha1GetKlass: + * + * SHA-1 digest transform klass. + * + * Returns: pointer to SHA-1 digest transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformSha1GetKlass(void) { + return(&xmlSecMSCryptoSha1Klass); +} +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 +/****************************************************************************** + * + * SHA256 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoDigestSize, /* size_t objSize */ + + xmlSecNameSha256, /* const xmlChar* name; */ + xmlSecHrefSha256, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + xmlSecMSCryptoDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformSha256GetKlass: + * + * SHA-256 digest transform klass. + * + * Returns: pointer to SHA-256 digest transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformSha256GetKlass(void) { + return(&xmlSecMSCryptoSha256Klass); +} +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/****************************************************************************** + * + * SHA384 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoDigestSize, /* size_t objSize */ + + xmlSecNameSha384, /* const xmlChar* name; */ + xmlSecHrefSha384, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + xmlSecMSCryptoDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformSha384GetKlass: + * + * SHA-384 digest transform klass. + * + * Returns: pointer to SHA-384 digest transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformSha384GetKlass(void) { + return(&xmlSecMSCryptoSha384Klass); +} +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/****************************************************************************** + * + * SHA512 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoDigestSize, /* size_t objSize */ + + xmlSecNameSha512, /* const xmlChar* name; */ + xmlSecHrefSha512, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + xmlSecMSCryptoDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformSha512GetKlass: + * + * SHA-512 digest transform klass. + * + * Returns: pointer to SHA-512 digest transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformSha512GetKlass(void) { + return(&xmlSecMSCryptoSha512Klass); +} +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_GOST +/****************************************************************************** + * + * GOSTR3411_94 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoGostR3411_94Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* size_t klassSize */ + xmlSecMSCryptoDigestSize, /* size_t objSize */ + + xmlSecNameGostR3411_94, /* const xmlChar* name; */ + xmlSecHrefGostR3411_94, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + xmlSecMSCryptoDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformGostR3411_94GetKlass: + * + * GOSTR3411_94 digest transform klass. + * + * Returns: pointer to GOSTR3411_94 digest transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformGostR3411_94GetKlass(void) { + return(&xmlSecMSCryptoGostR3411_94Klass); +} +#endif /* XMLSEC_NO_GOST*/ + diff --git a/src/mscrypto/globals.h b/src/mscrypto/globals.h new file mode 100644 index 00000000..2b88d5dd --- /dev/null +++ b/src/mscrypto/globals.h @@ -0,0 +1,39 @@ +/* + * XML Security Library + * + * THIS IS A PRIVATE XMLSEC HEADER FILE + * DON'T USE IT IN YOUR APPLICATION + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + */ +#ifndef __XMLSEC_GLOBALS_H__ +#define __XMLSEC_GLOBALS_H__ + +/** + * Use autoconf defines if present. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#define IN_XMLSEC_CRYPTO +#define XMLSEC_PRIVATE + +/* OpenSSL 0.9.6 and 0.9.7 do not have SHA 224/256/384/512 */ +#if defined(XMLSEC_OPENSSL_096) || defined(XMLSEC_OPENSSL_097) +#define XMLSEC_NO_SHA224 1 +#define XMLSEC_NO_SHA256 1 +#define XMLSEC_NO_SHA384 1 +#define XMLSEC_NO_SHA512 1 +#endif /* defined(XMLSEC_OPENSSL_096) || defined(XMLSEC_OPENSSL_097) */ + +/* OpenSSL 0.9.6 does not have AES */ +#if defined(XMLSEC_OPENSSL_096) +#define XMLSEC_NO_AES 1 +#endif /* XMLSEC_OPENSSL_096 */ + + +#endif /* ! __XMLSEC_GLOBALS_H__ */ diff --git a/src/mscrypto/hmac.c b/src/mscrypto/hmac.c new file mode 100644 index 00000000..e8709838 --- /dev/null +++ b/src/mscrypto/hmac.c @@ -0,0 +1,963 @@ +/** + * + * XMLSec library + * + * HMAC Algorithm support (http://www.w3.org/TR/xmldsig-core/#sec-HMAC): + * The HMAC algorithm (RFC2104 [HMAC]) takes the truncation length in bits + * as a parameter; if the parameter is not specified then all the bits of the + * hash are output. An example of an HMAC SignatureMethod element: + * <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"> + * <HMACOutputLength>128</HMACOutputLength> + * </SignatureMethod> + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#ifndef XMLSEC_NO_HMAC +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/base64.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> +#include "private.h" + +/* sizes in bits */ +#define XMLSEC_MSCRYPTO_MIN_HMAC_SIZE 80 +#define XMLSEC_MSCRYPTO_MAX_HMAC_SIZE 256 + +/************************************************************************** + * + * Configuration + * + *****************************************************************************/ +static int g_xmlsec_mscrypto_hmac_min_length = XMLSEC_MSCRYPTO_MIN_HMAC_SIZE; + +/** + * xmlSecMSCryptoHmacGetMinOutputLength: + * + * Gets the value of min HMAC length. + * + * Returns: the min HMAC output length + */ +int xmlSecMSCryptoHmacGetMinOutputLength(void) +{ + return g_xmlsec_mscrypto_hmac_min_length; +} + +/** + * xmlSecMSCryptoHmacSetMinOutputLength: + * @min_length: the new min length + * + * Sets the min HMAC output length + */ +void xmlSecMSCryptoHmacSetMinOutputLength(int min_length) +{ + g_xmlsec_mscrypto_hmac_min_length = min_length; +} + +/****************************************************************************** + * + * Internal MSCrypto HMAC CTX + * + *****************************************************************************/ +typedef struct _xmlSecMSCryptoHmacCtx xmlSecMSCryptoHmacCtx, *xmlSecMSCryptoHmacCtxPtr; +struct _xmlSecMSCryptoHmacCtx { + HCRYPTPROV provider; + HCRYPTKEY cryptKey; + HCRYPTKEY pubPrivKey; + ALG_ID alg_id; + const xmlSecMSCryptoProviderInfo * providers; + HCRYPTHASH mscHash; + unsigned char dgst[XMLSEC_MSCRYPTO_MAX_HMAC_SIZE]; + size_t dgstSize; /* dgst size in bytes */ + int ctxInitialized; +}; + +/****************************************************************************** + * + * HMAC transforms + * + * xmlSecMSCryptoHmacCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecMSCryptoHmacGetCtx(transform) \ + ((xmlSecMSCryptoHmacCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecMSCryptoHmacSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoHmacCtx)) + +static int xmlSecMSCryptoHmacCheckId (xmlSecTransformPtr transform); +static int xmlSecMSCryptoHmacInitialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoHmacFinalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoHmacNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoHmacSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoHmacSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoHmacVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoHmacExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Hmac[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { MS_DEF_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + +static int +xmlSecMSCryptoHmacCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha1Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha256Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha384Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha512Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacMd5Id)) { + return(1); + } else +#endif /* XMLSEC_NO_MD5 */ + + /* not found */ + { + return(0); + } + + return(0); +} + +static int +xmlSecMSCryptoHmacInitialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoHmacCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize), -1); + + ctx = xmlSecMSCryptoHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecMSCryptoHmacCtx)); + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha1Id)) { + ctx->alg_id = CALG_SHA1; + ctx->providers = xmlSecMSCryptoProviderInfo_Hmac; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha256Id)) { + ctx->alg_id = CALG_SHA_256; + ctx->providers = xmlSecMSCryptoProviderInfo_Hmac; + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha384Id)) { + ctx->alg_id = CALG_SHA_384; + ctx->providers = xmlSecMSCryptoProviderInfo_Hmac; + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacSha512Id)) { + ctx->alg_id = CALG_SHA_512; + ctx->providers = xmlSecMSCryptoProviderInfo_Hmac; + } else +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformHmacMd5Id)) { + ctx->alg_id = CALG_MD5; + ctx->providers = xmlSecMSCryptoProviderInfo_Hmac; + } else +#endif /* XMLSEC_NO_MD5 */ + + /* not found */ + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->provider = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(ctx->provider == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* Create dummy key to be able to import plain session keys */ + if (!xmlSecMSCryptoCreatePrivateExponentOneKey(ctx->provider, &(ctx->pubPrivKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoCreatePrivateExponentOneKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + return(0); +} + +static void +xmlSecMSCryptoHmacFinalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoHmacCtxPtr ctx; + + xmlSecAssert(xmlSecMSCryptoHmacCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize)); + + ctx = xmlSecMSCryptoHmacGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->mscHash != 0) { + CryptDestroyHash(ctx->mscHash); + } + if (ctx->cryptKey) { + CryptDestroyKey(ctx->cryptKey); + } + if (ctx->pubPrivKey) { + CryptDestroyKey(ctx->pubPrivKey); + } + if(ctx->provider != 0) { + CryptReleaseContext(ctx->provider, 0); + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoHmacCtx)); +} + +static int +xmlSecMSCryptoHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoHmacCtxPtr ctx; + xmlNodePtr cur; + + xmlSecAssert2(xmlSecMSCryptoHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize), -1); + xmlSecAssert2(node!= NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + cur = xmlSecGetNextElementNode(node->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHMACOutputLength, xmlSecDSigNs)) { + xmlChar *content; + + content = xmlNodeGetContent(cur); + if(content != NULL) { + ctx->dgstSize = atoi((char*)content); + xmlFree(content); + } + + /* Ensure that HMAC length is greater than min specified. + Otherwise, an attacker can set this length to 0 or very + small value + */ + if((int)ctx->dgstSize < xmlSecMSCryptoHmacGetMinOutputLength()) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "HMAC output length is too small"); + return(-1); + } + + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static int +xmlSecMSCryptoHmacSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecMSCryptoHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecMSCryptoKeyDataHmacId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationSign) { + keyReq->keyUsage = xmlSecKeyUsageSign; + } else { + keyReq->keyUsage = xmlSecKeyUsageVerify; + } + + return(0); +} + +static int +xmlSecMSCryptoHmacSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoHmacCtxPtr ctx; + xmlSecKeyDataPtr value; + xmlSecBufferPtr buffer; + HMAC_INFO hmacInfo; + int ret; + + xmlSecAssert2(xmlSecMSCryptoHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecMSCryptoHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + xmlSecAssert2(ctx->provider != 0, -1); + xmlSecAssert2(ctx->pubPrivKey != 0, -1); + xmlSecAssert2(ctx->cryptKey == 0, -1); + xmlSecAssert2(ctx->mscHash == 0, -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(xmlSecKeyDataCheckId(value, xmlSecMSCryptoKeyDataHmacId), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(value); + xmlSecAssert2(buffer != NULL, -1); + + if(xmlSecBufferGetSize(buffer) == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "keySize=0"); + return(-1); + } + + xmlSecAssert2(xmlSecBufferGetData(buffer) != NULL, -1); + + /* Import this key and get an HCRYPTKEY handle. + * + * HACK!!! HACK!!! HACK!!! + * + * Using CALG_RC2 instead of CALG_HMAC for the key algorithm so we don't want to check key length + */ + if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->provider, + ctx->pubPrivKey, + CALG_RC2, + xmlSecBufferGetData(buffer), + xmlSecBufferGetSize(buffer), + FALSE, + &(ctx->cryptKey) + ) || (ctx->cryptKey == 0)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* create hash */ + ret = CryptCreateHash(ctx->provider, + CALG_HMAC, + ctx->cryptKey, + 0, + &(ctx->mscHash)); + if((ret == 0) || (ctx->mscHash == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptCreateHash", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* set parameters */ + memset(&hmacInfo, 0, sizeof(hmacInfo)); + hmacInfo.HashAlgid = ctx->alg_id; + ret = CryptSetHashParam(ctx->mscHash, HP_HMAC_INFO, (BYTE*)&hmacInfo, 0); + if(ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptSetHashParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* done */ + ctx->ctxInitialized = 1; + return(0); +} + +static int +xmlSecMSCryptoHmacVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + static xmlSecByte last_byte_masks[] = + { 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; + + xmlSecMSCryptoHmacCtxPtr ctx; + xmlSecByte mask; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->dgstSize > 0, -1); + + /* compare the digest size in bytes */ + if(dataSize != ((ctx->dgstSize + 7) / 8)){ + /* NO COMMIT */ + xmlChar* a; + mask = last_byte_masks[ctx->dgstSize % 8]; + ctx->dgst[dataSize - 1] &= mask; + a = xmlSecBase64Encode(ctx->dgst, (ctx->dgstSize + 7) / 8, -1); + fprintf(stderr, "%s\n", a); + xmlFree(a); + + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "data=%d;dgst=%d", + dataSize, ((ctx->dgstSize + 7) / 8)); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + /* we check the last byte separatelly */ + xmlSecAssert2(dataSize > 0, -1); + mask = last_byte_masks[ctx->dgstSize % 8]; + if((ctx->dgst[dataSize - 1] & mask) != (data[dataSize - 1] & mask)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_DATA_NOT_MATCH, + "data and digest do not match (last byte)"); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + /* now check the rest of the digest */ + if((dataSize > 1) && (memcmp(ctx->dgst, data, dataSize - 1) != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_DATA_NOT_MATCH, + "data and digest do not match"); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + transform->status = xmlSecTransformStatusOk; + return(0); +} + +static int +xmlSecMSCryptoHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoHmacCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoHmacSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecMSCryptoHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + + if(transform->status == xmlSecTransformStatusNone) { + /* we should be already initialized when we set key */ + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { + ret = CryptHashData(ctx->mscHash, + xmlSecBufferGetData(in), + inSize, + 0); + + if(ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptHashData", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", inSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + } + + if(last) { + /* TODO: make a MSCrypto compatible assert here */ + /* xmlSecAssert2((xmlSecSize)EVP_MD_size(ctx->digest) <= sizeof(ctx->dgst), -1); */ + DWORD retLen; + retLen = XMLSEC_MSCRYPTO_MAX_HMAC_SIZE; + + ret = CryptGetHashParam(ctx->mscHash, + HP_HASHVAL, + ctx->dgst, + &retLen, + 0); + + if (ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptGetHashParam", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + xmlSecAssert2(retLen > 0, -1); + + /* check/set the result digest size */ + if(ctx->dgstSize == 0) { + ctx->dgstSize = retLen * 8; /* no dgst size specified, use all we have */ + } else if(ctx->dgstSize <= 8 * retLen) { + retLen = ((ctx->dgstSize + 7) / 8); /* we need to truncate result digest */ + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "result-bits=%d;required-bits=%d", + 8 * retLen, ctx->dgstSize); + return(-1); + } + + /* copy result to output */ + if(transform->operation == xmlSecTransformOperationSign) { + ret = xmlSecBufferAppend(out, ctx->dgst, retLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ctx->dgstSize); + return(-1); + } + } + transform->status = xmlSecTransformStatusFinished; + } + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} + +#ifndef XMLSEC_NO_MD5 +/****************************************************************************** + * + * HMAC MD5 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacMd5, /* const xmlChar* name; */ + xmlSecHrefHmacMd5, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacMd5GetKlass: + * + * The HMAC-MD5 transform klass. + * + * Returns: the HMAC-MD5 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacMd5GetKlass(void) { + return(&xmlSecMSCryptoHmacMd5Klass); +} + +#endif /* XMLSEC_NO_MD5 */ + + +#ifndef XMLSEC_NO_RIPEMD160 +/****************************************************************************** + * + * HMAC RIPEMD160 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacRipemd160Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacRipemd160, /* const xmlChar* name; */ + xmlSecHrefHmacRipemd160, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacRipemd160GetKlass: + * + * The HMAC-RIPEMD160 transform klass. + * + * Returns: the HMAC-RIPEMD160 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacRipemd160GetKlass(void) { + return(&xmlSecMSCryptoHmacRipemd160Klass); +} +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 +/****************************************************************************** + * + * HMAC SHA1 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha1, /* const xmlChar* name; */ + xmlSecHrefHmacSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacSha1GetKlass: + * + * The HMAC-SHA1 transform klass. + * + * Returns: the HMAC-SHA1 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacSha1GetKlass(void) { + return(&xmlSecMSCryptoHmacSha1Klass); +} + +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 +/****************************************************************************** + * + * HMAC SHA224 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacSha224Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha224, /* const xmlChar* name; */ + xmlSecHrefHmacSha224, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacSha224GetKlass: + * + * The HMAC-SHA224 transform klass. + * + * Returns: the HMAC-SHA224 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacSha224GetKlass(void) { + return(&xmlSecMSCryptoHmacSha224Klass); +} + +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 +/****************************************************************************** + * + * HMAC SHA256 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha256, /* const xmlChar* name; */ + xmlSecHrefHmacSha256, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacSha256GetKlass: + * + * The HMAC-SHA256 transform klass. + * + * Returns: the HMAC-SHA256 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacSha256GetKlass(void) { + return(&xmlSecMSCryptoHmacSha256Klass); +} + +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/****************************************************************************** + * + * HMAC SHA384 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha384, /* const xmlChar* name; */ + xmlSecHrefHmacSha384, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacSha384GetKlass: + * + * The HMAC-SHA384 transform klass. + * + * Returns: the HMAC-SHA384 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacSha384GetKlass(void) { + return(&xmlSecMSCryptoHmacSha384Klass); +} + +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/****************************************************************************** + * + * HMAC SHA512 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoHmacSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha512, /* const xmlChar* name; */ + xmlSecHrefHmacSha512, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformHmacSha512GetKlass: + * + * The HMAC-SHA512 transform klass. + * + * Returns: the HMAC-SHA512 transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformHmacSha512GetKlass(void) { + return(&xmlSecMSCryptoHmacSha512Klass); +} + +#endif /* XMLSEC_NO_SHA512 */ + + +#endif /* XMLSEC_NO_HMAC */ + diff --git a/src/mscrypto/keysstore.c b/src/mscrypto/keysstore.c new file mode 100644 index 00000000..33f0cd27 --- /dev/null +++ b/src/mscrypto/keysstore.c @@ -0,0 +1,620 @@ +/** + * XMLSec library + * + * MSCrypto keys store that uses Simple Keys Store under the hood. Uses the + * MS Certificate store as a backing store for the finding keys, but the + * MS Certificate store not written to by the keys store. + * So, if store->findkey is done and the key is not found in the simple + * keys store, the MS Certificate store is looked up. + * Thus, the MS Certificate store can be used to pre-load keys and becomes + * an alternate source of keys for xmlsec + * + * This is free software; see Copyright file in the source + * distribution for precise wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/base64.h> +#include <xmlsec/errors.h> +#include <xmlsec/xmltree.h> + +#include <xmlsec/keysmngr.h> + +#include <xmlsec/mscrypto/app.h> +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/keysstore.h> +#include <xmlsec/mscrypto/x509.h> +#include <xmlsec/mscrypto/certkeys.h> +#include "private.h" + +#define XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME_A "MY" +#define XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME_W L"MY" +#ifdef UNICODE +#define XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME_W +#else /* UNICODE */ +#define XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME_A +#endif /* UNICODE */ + +/**************************************************************************** + * + * MSCrypto Keys Store. Uses Simple Keys Store under the hood + * + * Simple Keys Store ptr is located after xmlSecKeyStore + * + ***************************************************************************/ +#define xmlSecMSCryptoKeysStoreSize \ + (sizeof(xmlSecKeyStore) + sizeof(xmlSecKeyStorePtr)) + +#define xmlSecMSCryptoKeysStoreGetSS(store) \ + ((xmlSecKeyStoreCheckSize((store), xmlSecMSCryptoKeysStoreSize)) ? \ + (xmlSecKeyStorePtr*)(((xmlSecByte*)(store)) + sizeof(xmlSecKeyStore)) : \ + (xmlSecKeyStorePtr*)NULL) + +static int xmlSecMSCryptoKeysStoreInitialize (xmlSecKeyStorePtr store); +static void xmlSecMSCryptoKeysStoreFinalize (xmlSecKeyStorePtr store); +static xmlSecKeyPtr xmlSecMSCryptoKeysStoreFindKey (xmlSecKeyStorePtr store, + const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyStoreKlass xmlSecMSCryptoKeysStoreKlass = { + sizeof(xmlSecKeyStoreKlass), + xmlSecMSCryptoKeysStoreSize, + + /* data */ + BAD_CAST "MSCrypto-keys-store", /* const xmlChar* name; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeysStoreInitialize, /* xmlSecKeyStoreInitializeMethod initialize; */ + xmlSecMSCryptoKeysStoreFinalize, /* xmlSecKeyStoreFinalizeMethod finalize; */ + xmlSecMSCryptoKeysStoreFindKey, /* xmlSecKeyStoreFindKeyMethod findKey; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoKeysStoreGetKlass: + * + * The MSCrypto list based keys store klass. + * + * Returns: MSCrypto list based keys store klass. + */ +xmlSecKeyStoreId +xmlSecMSCryptoKeysStoreGetKlass(void) { + return(&xmlSecMSCryptoKeysStoreKlass); +} + +/** + * xmlSecMSCryptoKeysStoreAdoptKey: + * @store: the pointer to MSCrypto keys store. + * @key: the pointer to key. + * + * Adds @key to the @store. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeysStoreAdoptKey(xmlSecKeyStorePtr store, xmlSecKeyPtr key) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId), -1); + xmlSecAssert2((key != NULL), -1); + + ss = xmlSecMSCryptoKeysStoreGetSS(store); + xmlSecAssert2(((ss != NULL) && (*ss != NULL) && + (xmlSecKeyStoreCheckId(*ss, xmlSecSimpleKeysStoreId))), -1); + + return (xmlSecSimpleKeysStoreAdoptKey(*ss, key)); +} + +/** + * xmlSecMSCryptoKeysStoreLoad: + * @store: the pointer to MSCrypto keys store. + * @uri: the filename. + * @keysMngr: the pointer to associated keys manager. + * + * Reads keys from an XML file. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeysStoreLoad(xmlSecKeyStorePtr store, const char *uri, + xmlSecKeysMngrPtr keysMngr) { + xmlDocPtr doc; + xmlNodePtr root; + xmlNodePtr cur; + xmlSecKeyPtr key; + xmlSecKeyInfoCtx keyInfoCtx; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId), -1); + xmlSecAssert2((uri != NULL), -1); + + doc = xmlParseFile(uri); + if(doc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlParseFile", + XMLSEC_ERRORS_R_XML_FAILED, + "uri=%s", + xmlSecErrorsSafeString(uri)); + return(-1); + } + + root = xmlDocGetRootElement(doc); + if(!xmlSecCheckNodeName(root, BAD_CAST "Keys", xmlSecNs)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + xmlSecErrorsSafeString(xmlSecNodeGetName(root)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected-node=<xmlsec:Keys>"); + xmlFreeDoc(doc); + return(-1); + } + + cur = xmlSecGetNextElementNode(root->children); + while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs)) { + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected-node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyInfo)); + xmlFreeDoc(doc); + return(-1); + } + + ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx, NULL); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + xmlFreeDoc(doc); + return(-1); + } + + keyInfoCtx.mode = xmlSecKeyInfoModeRead; + keyInfoCtx.keysMngr = keysMngr; + keyInfoCtx.flags = XMLSEC_KEYINFO_FLAGS_DONT_STOP_ON_KEY_FOUND | + XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS; + keyInfoCtx.keyReq.keyId = xmlSecKeyDataIdUnknown; + keyInfoCtx.keyReq.keyType = xmlSecKeyDataTypeAny; + keyInfoCtx.keyReq.keyUsage= xmlSecKeyDataUsageAny; + + ret = xmlSecKeyInfoNodeRead(cur, key, &keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecKeyInfoNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyInfoCtxFinalize(&keyInfoCtx); + xmlSecKeyDestroy(key); + xmlFreeDoc(doc); + return(-1); + } + xmlSecKeyInfoCtxFinalize(&keyInfoCtx); + + if(xmlSecKeyIsValid(key)) { + ret = xmlSecMSCryptoKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecMSCryptoKeysStoreAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + xmlFreeDoc(doc); + return(-1); + } + } else { + /* we have an unknown key in our file, just ignore it */ + xmlSecKeyDestroy(key); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(doc); + return(-1); + } + + xmlFreeDoc(doc); + return(0); +} + +/** + * xmlSecMSCryptoKeysStoreSave: + * @store: the pointer to MSCrypto keys store. + * @filename: the filename. + * @type: the saved keys type (public, private, ...). + * + * Writes keys from @store to an XML file. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeysStoreSave(xmlSecKeyStorePtr store, const char *filename, xmlSecKeyDataType type) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId), -1); + xmlSecAssert2((filename != NULL), -1); + + ss = xmlSecMSCryptoKeysStoreGetSS(store); + xmlSecAssert2(((ss != NULL) && (*ss != NULL) && + (xmlSecKeyStoreCheckId(*ss, xmlSecSimpleKeysStoreId))), -1); + + return (xmlSecSimpleKeysStoreSave(*ss, filename, type)); +} + +static int +xmlSecMSCryptoKeysStoreInitialize(xmlSecKeyStorePtr store) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId), -1); + + ss = xmlSecMSCryptoKeysStoreGetSS(store); + xmlSecAssert2((*ss == NULL), -1); + + *ss = xmlSecKeyStoreCreate(xmlSecSimpleKeysStoreId); + if(*ss == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecSimpleKeysStoreId"); + return(-1); + } + + return(0); +} + +static void +xmlSecMSCryptoKeysStoreFinalize(xmlSecKeyStorePtr store) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId)); + + ss = xmlSecMSCryptoKeysStoreGetSS(store); + xmlSecAssert((ss != NULL) && (*ss != NULL)); + + xmlSecKeyStoreDestroy(*ss); +} + +static PCCERT_CONTEXT +xmlSecMSCryptoKeysStoreFindCert(xmlSecKeyStorePtr store, const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + LPCTSTR storeName; + HCERTSTORE hStoreHandle = NULL; + PCCERT_CONTEXT pCertContext = NULL; + LPTSTR wcName = NULL; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId), NULL); + xmlSecAssert2(name != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + storeName = xmlSecMSCryptoAppGetCertStoreName(); + if(storeName == NULL) { + storeName = XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME; + } + + hStoreHandle = CertOpenSystemStore(0, storeName); + if (NULL == hStoreHandle) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertOpenSystemStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "storeName=%s", + xmlSecErrorsSafeString(storeName)); + return(NULL); + } + + /* convert name to unicode */ + wcName = xmlSecMSCryptoConvertUtf8ToTstr(name); + if(wcName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecMSCryptoConvertUtf8ToUnicode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "wcName"); + CertCloseStore(hStoreHandle, 0); + return(NULL); + } + + /* first attempt: try to find the cert with a full blown subject dn */ + if(NULL == pCertContext) { + pCertContext = xmlSecMSCryptoX509FindCertBySubject( + hStoreHandle, + wcName, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING); + } + + /* + * Try ro find certificate with name="Friendly Name" + */ + if (NULL == pCertContext) { + DWORD dwPropSize; + PBYTE pbFriendlyName; + PCCERT_CONTEXT pCertCtxIter = NULL; + + + while (pCertCtxIter = CertEnumCertificatesInStore(hStoreHandle, pCertCtxIter)) { + if (TRUE != CertGetCertificateContextProperty(pCertCtxIter, + CERT_FRIENDLY_NAME_PROP_ID, + NULL, + &dwPropSize)) { + continue; + } + + pbFriendlyName = xmlMalloc(dwPropSize); + if(pbFriendlyName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(wcName); + CertCloseStore(hStoreHandle, 0); + return(NULL); + } + + if (TRUE != CertGetCertificateContextProperty(pCertCtxIter, + CERT_FRIENDLY_NAME_PROP_ID, + pbFriendlyName, + &dwPropSize)) { + xmlFree(pbFriendlyName); + continue; + } + + /* Compare FriendlyName to name */ + if (!lstrcmp(wcName, (LPCTSTR)pbFriendlyName)) { + pCertContext = pCertCtxIter; + xmlFree(pbFriendlyName); + break; + } + xmlFree(pbFriendlyName); + } + } + + /* We don't give up easily, now try to find cert with part of the name + */ + if (NULL == pCertContext) { + pCertContext = CertFindCertificateInStore( + hStoreHandle, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_STR, + wcName, + NULL); + } + + + /* We could do the following here: + * It would be nice if we could locate the cert with issuer name and + * serial number, the given keyname can be something like this: + * 'serial=1234567;issuer=CN=ikke, C=NL' + * to be implemented by the first person who reads this, and thinks it's + * a good idea :) WK + */ + + /* OK, I give up, I'm gone :( */ + + /* aleksey todo: is it a right idea to close store if we have a handle to + * a cert in this store? */ + xmlFree(wcName); + CertCloseStore(hStoreHandle, 0); + return(pCertContext); +} + + +static xmlSecKeyPtr +xmlSecMSCryptoKeysStoreFindKey(xmlSecKeyStorePtr store, const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyStorePtr* ss; + xmlSecKeyPtr key = NULL; + xmlSecKeyReqPtr keyReq = NULL; + PCCERT_CONTEXT pCertContext = NULL; + PCCERT_CONTEXT pCertContext2 = NULL; + xmlSecKeyDataPtr data = NULL; + xmlSecKeyDataPtr x509Data = NULL; + xmlSecKeyPtr res = NULL; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecMSCryptoKeysStoreId), NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ss = xmlSecMSCryptoKeysStoreGetSS(store); + xmlSecAssert2(((ss != NULL) && (*ss != NULL)), NULL); + + /* first try to find key in the simple keys store */ + key = xmlSecKeyStoreFindKey(*ss, name, keyInfoCtx); + if (key != NULL) { + return (key); + } + + /* Next try to find the key in the MS Certificate store, and construct an xmlSecKey. + * we must have a name to lookup keys in the certificate store. + */ + if (name == NULL) { + goto done; + } + + /* what type of key are we looking for? + * WK: For now, we'll look only for public/private keys using the + * name as a cert nickname. Then the name is regarded as the subject + * dn of the certificate to be searched for. + */ + keyReq = &(keyInfoCtx->keyReq); + if (keyReq->keyType & (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate)) { + pCertContext = xmlSecMSCryptoKeysStoreFindCert(store, name, keyInfoCtx); + if(pCertContext == NULL) { + goto done; + } + + /* set cert in x509 data */ + x509Data = xmlSecKeyDataCreate(xmlSecMSCryptoKeyDataX509Id); + if(x509Data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + pCertContext2 = CertDuplicateCertificateContext(pCertContext); + if (NULL == pCertContext2) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(x509Data, pCertContext2); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + pCertContext2 = NULL; + + pCertContext2 = CertDuplicateCertificateContext(pCertContext); + if (NULL == pCertContext2) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecMSCryptoKeyDataX509AdoptKeyCert(x509Data, pCertContext2); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + pCertContext2 = NULL; + + /* set cert in key data */ + data = xmlSecMSCryptoCertAdopt(pCertContext, keyReq->keyType); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoCertAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + pCertContext = NULL; + + /* create key and add key data and x509 data to it */ + key = xmlSecKeyCreate(); + if (key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecKeySetValue(key, data); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data))); + goto done; + } + data = NULL; + + ret = xmlSecKeyAdoptData(key, x509Data); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyAdoptData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + x509Data = NULL; + + /* Set the name of the key to the given name */ + ret = xmlSecKeySetName(key, name); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecKeySetName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* now that we have a key, make sure it is valid and let the simple + * store adopt it */ + if (xmlSecKeyIsValid(key)) { + res = key; + key = NULL; + } + } + +done: + if (NULL != pCertContext) { + CertFreeCertificateContext(pCertContext); + } + if (NULL != pCertContext2) { + CertFreeCertificateContext(pCertContext2); + } + if (data != NULL) { + xmlSecKeyDataDestroy(data); + } + if (x509Data != NULL) { + xmlSecKeyDataDestroy(x509Data); + } + if (key != NULL) { + xmlSecKeyDestroy(key); + } + + return (res); +} diff --git a/src/mscrypto/kt_rsa.c b/src/mscrypto/kt_rsa.c new file mode 100644 index 00000000..9b4908fa --- /dev/null +++ b/src/mscrypto/kt_rsa.c @@ -0,0 +1,631 @@ +/** + * + * XMLSec library + * + * RSA Algorithms support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + */ +#include "globals.h" + +#ifndef XMLSEC_NO_RSA + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/strings.h> +#include <xmlsec/errors.h> +#include <xmlsec/keyinfo.h> + +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/certkeys.h> +#include "private.h" + +/************************************************************************** + * + * Internal MSCRYPTO RSA PKCS1 CTX + * + *************************************************************************/ +typedef struct _xmlSecMSCryptoRsaPkcs1OaepCtx xmlSecMSCryptoRsaPkcs1OaepCtx, + *xmlSecMSCryptoRsaPkcs1OaepCtxPtr; +struct _xmlSecMSCryptoRsaPkcs1OaepCtx { + DWORD dwFlags; + xmlSecKeyDataPtr data; + xmlSecBuffer oaepParams; +}; + +/********************************************************************* + * + * RSA PKCS1 key transport transform + * + * xmlSecMSCryptoRsaPkcs1OaepCtx is located after xmlSecTransform + * + ********************************************************************/ +#define xmlSecMSCryptoRsaPkcs1OaepCtx \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoRsaPkcs1OaepCtx)) +#define xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform) \ + ((xmlSecMSCryptoRsaPkcs1OaepCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecMSCryptoRsaPkcs1OaepCheckId (xmlSecTransformPtr transform); +static int xmlSecMSCryptoRsaPkcs1OaepInitialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoRsaPkcs1OaepFinalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoRsaPkcs1OaepSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoRsaPkcs1OaepSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoRsaPkcs1OaepExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoRsaPkcs1OaepProcess (xmlSecTransformPtr transform, + xmlSecTransformCtxPtr transformCtx); + + +static int +xmlSecMSCryptoRsaPkcs1OaepCheckId(xmlSecTransformPtr transform) { + + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id)) { + return(1); + } else + + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaOaepId)) { + return(1); + } else + + /* not found */ + { + return(0); + } + + /* just in case */ + return(0); +} + +static int +xmlSecMSCryptoRsaPkcs1OaepInitialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx), -1); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize */ + memset(ctx, 0, sizeof(xmlSecMSCryptoRsaPkcs1OaepCtx)); + + ret = xmlSecBufferInitialize(&(ctx->oaepParams), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id)) { + ctx->dwFlags = 0; + } else + + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaOaepId)) { + ctx->dwFlags = CRYPT_OAEP; + } else + + /* not found */ + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* done */ + return(0); +} + +static void +xmlSecMSCryptoRsaPkcs1OaepFinalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + + xmlSecAssert(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx)); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (ctx->data != NULL) { + xmlSecKeyDataDestroy(ctx->data); + ctx->data = NULL; + } + + xmlSecBufferFinalize(&(ctx->oaepParams)); + memset(ctx, 0, sizeof(xmlSecMSCryptoRsaPkcs1OaepCtx)); +} + +static int +xmlSecMSCryptoRsaPkcs1OaepSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecMSCryptoKeyDataRsaId; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyType = xmlSecKeyDataTypePublic; + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyType = xmlSecKeyDataTypePrivate; + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + return(0); +} + +static int +xmlSecMSCryptoRsaPkcs1OaepSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataRsaId), -1); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->data == NULL, -1); + + ctx->data = xmlSecKeyDataDuplicate(xmlSecKeyGetValue(key)); + if(ctx->data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKeyDataDuplicate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecMSCryptoRsaPkcs1OaepExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + ret = xmlSecMSCryptoRsaPkcs1OaepProcess(transform, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoRsaPkcs1OaepProcess", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusFinished; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + +static int +xmlSecMSCryptoRsaPkcs1OaepProcess(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + xmlSecSize keySize; + int ret; + HCRYPTKEY hKey = 0; + DWORD dwInLen; + DWORD dwBufLen; + DWORD dwOutLen; + xmlSecByte * outBuf; + xmlSecByte * inBuf; + int i; + + xmlSecAssert2(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->data != NULL, -1); + + keySize = xmlSecKeyDataGetSize(ctx->data) / 8; + xmlSecAssert2(keySize > 0, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + xmlSecAssert2(outSize == 0, -1); + + /* the encoded size is equal to the keys size so we could not + * process more than that */ + if((transform->operation == xmlSecTransformOperationEncrypt) && (inSize >= keySize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "%d when expected less than %d", inSize, keySize); + return(-1); + } else if((transform->operation == xmlSecTransformOperationDecrypt) && (inSize != keySize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "%d when expected %d", inSize, keySize); + return(-1); + } + + outSize = keySize; + ret = xmlSecBufferSetMaxSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + if(inSize > outSize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "inSize=%d;outSize=%d", + inSize, outSize); + return(-1); + } + + ret = xmlSecBufferSetData(out, xmlSecBufferGetData(in), inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + dwInLen = inSize; + dwBufLen = outSize; + if (0 == (hKey = xmlSecMSCryptoKeyDataGetKey(ctx->data, xmlSecKeyDataTypePublic))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataGetKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + + outBuf = xmlSecBufferGetData(out); + xmlSecAssert2(outBuf != NULL, -1); + + /* set OAEP parameter for the key + * + * aleksey: I don't understand how this would work in multi-threaded + * environment or when key can be re-used multiple times + */ + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaOaepId) && xmlSecBufferGetSize(&(ctx->oaepParams)) > 0) { + CRYPT_DATA_BLOB oaepParams; + + memset(&oaepParams, 0, sizeof(oaepParams)); + oaepParams.pbData = xmlSecBufferGetData(&(ctx->oaepParams)); + oaepParams.cbData = xmlSecBufferGetSize(&(ctx->oaepParams)); + + if (!CryptSetKeyParam(hKey, KP_OAEP_PARAMS, (const BYTE*)&oaepParams, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + } + + /* encrypt */ + if (!CryptEncrypt(hKey, 0, TRUE, ctx->dwFlags, outBuf, &dwInLen, dwBufLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + + /* The output of CryptEncrypt is in little-endian format, so we have to convert to + * big-endian first. + */ + ConvertEndianInPlace(outBuf, outSize); + } else { + dwOutLen = inSize; + + /* The input of CryptDecrypt is expected to be little-endian, + * so we have to convert from big-endian to little endian. + */ + inBuf = xmlSecBufferGetData(in); + outBuf = xmlSecBufferGetData(out); + ConvertEndian(inBuf, outBuf, inSize); + + if (0 == (hKey = xmlSecMSCryptoKeyDataGetDecryptKey(ctx->data))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataGetKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + + /* set OAEP parameter for the key + * + * aleksey: I don't understand how this would work in multi-threaded + * environment or when key can be re-used multiple times + */ + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaOaepId) && xmlSecBufferGetSize(&(ctx->oaepParams)) > 0) { + CRYPT_DATA_BLOB oaepParams; + + memset(&oaepParams, 0, sizeof(oaepParams)); + oaepParams.pbData = xmlSecBufferGetData(&(ctx->oaepParams)); + oaepParams.cbData = xmlSecBufferGetSize(&(ctx->oaepParams)); + + if (!CryptSetKeyParam(hKey, KP_OAEP_PARAMS, (const BYTE*)&oaepParams, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + } + + /* decrypt */ + if (!CryptDecrypt(hKey, 0, TRUE, ctx->dwFlags, outBuf, &dwOutLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptDecrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + outSize = dwOutLen; + } + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + return(0); +} + + +/********************************************************************** + * + * RSA/PKCS1 transform + * + **********************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoRsaPkcs1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoRsaPkcs1OaepCtx, /* xmlSecSize objSize */ + + xmlSecNameRsaPkcs1, /* const xmlChar* name; */ + xmlSecHrefRsaPkcs1, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoRsaPkcs1OaepInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoRsaPkcs1OaepFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoRsaPkcs1OaepSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoRsaPkcs1OaepSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoRsaPkcs1OaepExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + + +/** + * xmlSecMSCryptoTransformRsaPkcs1GetKlass: + * + * The RSA-PKCS1 key transport transform klass. + * + * Returns: RSA-PKCS1 key transport transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaPkcs1GetKlass(void) { + return(&xmlSecMSCryptoRsaPkcs1Klass); +} + + + +/********************************************************************** + * + * RSA/OAEP transform + * + **********************************************************************/ +static int xmlSecMSCryptoRsaOaepNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecMSCryptoRsaOaepKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoRsaPkcs1OaepCtx, /* xmlSecSize objSize */ + + xmlSecNameRsaOaep, /* const xmlChar* name; */ + xmlSecHrefRsaOaep, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoRsaPkcs1OaepInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoRsaPkcs1OaepFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecMSCryptoRsaOaepNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoRsaPkcs1OaepSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoRsaPkcs1OaepSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoRsaPkcs1OaepExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + + +/** + * xmlSecMSCryptoTransformRsaOaepGetKlass: + * + * The RSA-OAEP key transport transform klass. + * + * Returns: RSA-OAEP key transport transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaOaepGetKlass(void) { + return(&xmlSecMSCryptoRsaOaepKlass); +} + +static int +xmlSecMSCryptoRsaOaepNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoRsaPkcs1OaepCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecMSCryptoRsaPkcs1OaepCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1OaepCtx), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1OaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecBufferGetSize(&(ctx->oaepParams)) == 0, -1); + + cur = xmlSecGetNextElementNode(node->children); + while(cur != NULL) { + if(xmlSecCheckNodeName(cur, xmlSecNodeRsaOAEPparams, xmlSecEncNs)) { + ret = xmlSecBufferBase64NodeContentRead(&(ctx->oaepParams), cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferBase64NodeContentRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else if(xmlSecCheckNodeName(cur, xmlSecNodeDigestMethod, xmlSecDSigNs)) { + xmlChar* algorithm; + + /* Algorithm attribute is required */ + algorithm = xmlGetProp(cur, xmlSecAttrAlgorithm); + if(algorithm == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + /* for now we support only sha1 */ + if(xmlStrcmp(algorithm, xmlSecHrefSha1) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(algorithm), + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + "digest algorithm is not supported for rsa/oaep"); + xmlFree(algorithm); + return(-1); + } + xmlFree(algorithm); + } else { + /* not found */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* next node */ + cur = xmlSecGetNextElementNode(cur->next); + } + + return(0); +} + +#endif /* XMLSEC_NO_RSA */ + diff --git a/src/mscrypto/kw_aes.c b/src/mscrypto/kw_aes.c new file mode 100644 index 00000000..14e96d5a --- /dev/null +++ b/src/mscrypto/kw_aes.c @@ -0,0 +1,662 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> + +#include "../kw_aes_des.h" +#include "private.h" + + +#ifndef XMLSEC_NO_AES + +/********************************************************************* + * + * AES KW implementation + * + *********************************************************************/ +static int xmlSecMSCryptoKWAesBlockEncrypt (const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize, + void * cb_ctx); +static int xmlSecMSCryptoKWAesBlockDecrypt (const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize, + void * cb_ctx); + +/* klass for KW AES operation */ +static xmlSecKWAesKlass xmlSecMSCryptoKWAesKlass = { + /* callbacks */ + xmlSecMSCryptoKWAesBlockEncrypt, /* xmlSecKWAesBlockEncryptMethod encrypt; */ + xmlSecMSCryptoKWAesBlockDecrypt, /* xmlSecKWAesBlockDecryptMethod decrypt; */ + + /* for the future */ + NULL, /* void* reserved0; */ + NULL /* void* reserved1; */ +}; + +/************************************************************************** + * + * Internal MSCrypto KW AES cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecMSCryptoKWAesCtx xmlSecMSCryptoKWAesCtx, + *xmlSecMSCryptoKWAesCtxPtr; +struct _xmlSecMSCryptoKWAesCtx { + ALG_ID algorithmIdentifier; + const xmlSecMSCryptoProviderInfo * providers; + xmlSecKeyDataId keyId; + xmlSecSize keySize; + + HCRYPTPROV cryptProvider; + HCRYPTKEY pubPrivKey; + xmlSecBuffer keyBuffer; +}; + +/****************************************************************************** + * + * KW AES transforms + * + * xmlSecMSCryptoKWAesCtx block is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecMSCryptoKWAesSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoKWAesCtx)) +#define xmlSecMSCryptoKWAesGetCtx(transform) \ + ((xmlSecMSCryptoKWAesCtxPtr)(((unsigned char*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecMSCryptoKWAesInitialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoKWAesFinalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoKWAesSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoKWAesSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoKWAesExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoKWAesCheckId (xmlSecTransformPtr transform); + + + + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Aes[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { NULL, 0 } +}; + +static int +xmlSecMSCryptoKWAesCheckId(xmlSecTransformPtr transform) { + + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWAes128Id) || + xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWAes192Id) || + xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWAes256Id)) { + + return(1); + } + + return(0); +} + +static int +xmlSecMSCryptoKWAesInitialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoKWAesCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecMSCryptoKWAesCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWAesSize), -1); + + ctx = xmlSecMSCryptoKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKWAesCtx)); + + if(transform->id == xmlSecMSCryptoTransformKWAes128Id) { + ctx->algorithmIdentifier = CALG_AES_128; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Aes; + ctx->keySize = XMLSEC_KW_AES128_KEY_SIZE; + } else if(transform->id == xmlSecMSCryptoTransformKWAes192Id) { + ctx->algorithmIdentifier = CALG_AES_192; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Aes; + ctx->keySize = XMLSEC_KW_AES192_KEY_SIZE; + } else if(transform->id == xmlSecMSCryptoTransformKWAes256Id) { + ctx->algorithmIdentifier = CALG_AES_256; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providers = xmlSecMSCryptoProviderInfo_Aes; + ctx->keySize = XMLSEC_KW_AES256_KEY_SIZE; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&ctx->keyBuffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* find provider */ + ctx->cryptProvider = xmlSecMSCryptoFindProvider(ctx->providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(ctx->cryptProvider == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoFindProvider", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + /* Create dummy key to be able to import plain session keys */ + if (!xmlSecMSCryptoCreatePrivateExponentOneKey(ctx->cryptProvider, &(ctx->pubPrivKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoCreatePrivateExponentOneKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + return(0); +} + +static void +xmlSecMSCryptoKWAesFinalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoKWAesCtxPtr ctx; + + xmlSecAssert(xmlSecMSCryptoKWAesCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWAesSize)); + + ctx = xmlSecMSCryptoKWAesGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (ctx->pubPrivKey) { + CryptDestroyKey(ctx->pubPrivKey); + } + if (ctx->cryptProvider) { + CryptReleaseContext(ctx->cryptProvider, 0); + } + + xmlSecBufferFinalize(&ctx->keyBuffer); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKWAesCtx)); +} + +static int +xmlSecMSCryptoKWAesSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecMSCryptoKWAesCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWAesSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecMSCryptoKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cryptProvider != 0, -1); + + keyReq->keyId = ctx->keyId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + + keyReq->keyBitsSize = 8 * ctx->keySize; + return(0); +} + + + +static int +xmlSecMSCryptoKWAesSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoKWAesCtxPtr ctx; + xmlSecBufferPtr buffer; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecMSCryptoKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWAesSize), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataAesId), -1); + + ctx = xmlSecMSCryptoKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + if(keySize < ctx->keySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "key=%d;expected=%d", + keySize, ctx->keySize); + return(-1); + } + + ret = xmlSecBufferSetData(&(ctx->keyBuffer), + xmlSecBufferGetData(buffer), + ctx->keySize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "expected-size=%d", + ctx->keySize); + return(-1); + } + + return(0); +} + +static int +xmlSecMSCryptoKWAesExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoKWAesCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + int ret; + + xmlSecAssert2(xmlSecMSCryptoKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWAesSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + xmlSecAssert2(outSize == 0, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + if((inSize % 8) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d(not 8 bytes aligned)", inSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + /* the encoded key might be 8 bytes longer plus 8 bytes just in case */ + outSize = inSize + XMLSEC_KW_AES_MAGIC_BLOCK_SIZE + + XMLSEC_KW_AES_BLOCK_SIZE; + } else { + outSize = inSize + XMLSEC_KW_AES_BLOCK_SIZE; + } + + ret = xmlSecBufferSetMaxSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "outSize=%d", outSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + ret = xmlSecKWAesEncode(&xmlSecMSCryptoKWAesKlass, ctx, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWAesEncode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecKWAesDecode(&xmlSecMSCryptoKWAesKlass, ctx, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWAesEncode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "outSize=%d", outSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "inSize%d", inSize); + return(-1); + } + + transform->status = xmlSecTransformStatusFinished; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + + +/********************************************************************* + * + * AES KW implementation + * + ********************************************************************/ +static int +xmlSecMSCryptoKWAesBlockEncrypt(const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize, + void * context) { + xmlSecMSCryptoKWAesCtxPtr ctx = (xmlSecMSCryptoKWAesCtxPtr)context; + HCRYPTKEY cryptKey = 0; + DWORD dwCLen; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize >= XMLSEC_KW_AES_BLOCK_SIZE, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pubPrivKey != 0, -1); + xmlSecAssert2(xmlSecBufferGetSize(&ctx->keyBuffer) == ctx->keySize, -1); + + /* Import this key and get an HCRYPTKEY handle, we do it again and again + to ensure we don't go into CBC mode */ + if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->cryptProvider, + ctx->pubPrivKey, + ctx->algorithmIdentifier, + xmlSecBufferGetData(&ctx->keyBuffer), + xmlSecBufferGetSize(&ctx->keyBuffer), + TRUE, + &cryptKey)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(cryptKey != 0, -1); + + /* Set process last block to false, since we handle padding ourselves, and MSCrypto padding + * can be skipped. I hope this will work .... */ + if(out != in) { + memcpy(out, in, inSize); + } + dwCLen = inSize; + if(!CryptEncrypt(cryptKey, 0, FALSE, 0, out, &dwCLen, outSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* cleanup */ + CryptDestroyKey(cryptKey); + return(dwCLen); +} + +static int +xmlSecMSCryptoKWAesBlockDecrypt(const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize, + void * context) { + xmlSecMSCryptoKWAesCtxPtr ctx = (xmlSecMSCryptoKWAesCtxPtr)context; + HCRYPTKEY cryptKey = 0; + DWORD dwCLen; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize >= XMLSEC_KW_AES_BLOCK_SIZE, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pubPrivKey != 0, -1); + xmlSecAssert2(xmlSecBufferGetSize(&ctx->keyBuffer) == ctx->keySize, -1); + + /* Import this key and get an HCRYPTKEY handle, we do it again and again + to ensure we don't go into CBC mode */ + if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->cryptProvider, + ctx->pubPrivKey, + ctx->algorithmIdentifier, + xmlSecBufferGetData(&ctx->keyBuffer), + xmlSecBufferGetSize(&ctx->keyBuffer), + TRUE, + &cryptKey)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(cryptKey != 0, -1); + + /* Set process last block to false, since we handle padding ourselves, and MSCrypto padding + * can be skipped. I hope this will work .... */ + if(out != in) { + memcpy(out, in, inSize); + } + dwCLen = inSize; + if(!CryptDecrypt(cryptKey, 0, FALSE, 0, out, &dwCLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* cleanup */ + CryptDestroyKey(cryptKey); + return(dwCLen); +} + +/********************************************************************* + * + * AES KW cipher transforms + * + ********************************************************************/ + +/* + * The AES-128 kew wrapper transform klass. + */ +static xmlSecTransformKlass xmlSecMSCryptoKWAes128Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes128, /* const xmlChar* name; */ + xmlSecHrefKWAes128, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformKWAes128GetKlass: + * + * The AES-128 kew wrapper transform klass. + * + * Returns: AES-128 kew wrapper transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformKWAes128GetKlass(void) { + return(&xmlSecMSCryptoKWAes128Klass); +} + + +/* + * The AES-192 kew wrapper transform klass. + */ +static xmlSecTransformKlass xmlSecMSCryptoKWAes192Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes192, /* const xmlChar* name; */ + xmlSecHrefKWAes192, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformKWAes192GetKlass: + * + * The AES-192 kew wrapper transform klass. + * + * Returns: AES-192 kew wrapper transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformKWAes192GetKlass(void) { + return(&xmlSecMSCryptoKWAes192Klass); +} + +/* + * The AES-256 kew wrapper transform klass. + */ +static xmlSecTransformKlass xmlSecMSCryptoKWAes256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes256, /* const xmlChar* name; */ + xmlSecHrefKWAes256, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformKWAes256GetKlass: + * + * The AES-256 kew wrapper transform klass. + * + * Returns: AES-256 kew wrapper transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformKWAes256GetKlass(void) { + return(&xmlSecMSCryptoKWAes256Klass); +} + +#endif /* XMLSEC_NO_AES */ diff --git a/src/mscrypto/kw_des.c b/src/mscrypto/kw_des.c new file mode 100644 index 00000000..6ef356d4 --- /dev/null +++ b/src/mscrypto/kw_des.c @@ -0,0 +1,730 @@ +/** + * + * XMLSec library + * + * DES Algorithm support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#ifndef XMLSEC_NO_DES +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> + +#include "../kw_aes_des.h" +#include "private.h" + + +/********************************************************************* + * + * DES KW implementation + * + *********************************************************************/ +static int xmlSecMSCryptoKWDes3GenerateRandom (void * context, + xmlSecByte * out, + xmlSecSize outSize); +static int xmlSecMSCryptoKWDes3Sha1 (void * context, + const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize); +static int xmlSecMSCryptoKWDes3BlockEncrypt (void * context, + const xmlSecByte * iv, + xmlSecSize ivSize, + const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize); +static int xmlSecMSCryptoKWDes3BlockDecrypt (void * context, + const xmlSecByte * iv, + xmlSecSize ivSize, + const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize); + +static xmlSecKWDes3Klass xmlSecMSCryptoKWDes3ImplKlass = { + /* callbacks */ + xmlSecMSCryptoKWDes3GenerateRandom, /* xmlSecKWDes3GenerateRandomMethod generateRandom; */ + xmlSecMSCryptoKWDes3Sha1, /* xmlSecKWDes3Sha1Method sha1; */ + xmlSecMSCryptoKWDes3BlockEncrypt, /* xmlSecKWDes3BlockEncryptMethod encrypt; */ + xmlSecMSCryptoKWDes3BlockDecrypt, /* xmlSecKWDes3BlockDecryptMethod decrypt; */ + + /* for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/********************************************************************* + * + * Triple DES Key Wrap transform + * + * key (xmlSecBuffer) is located after xmlSecTransform structure + * + ********************************************************************/ +typedef struct _xmlSecMSCryptoKWDes3Ctx xmlSecMSCryptoKWDes3Ctx, + *xmlSecMSCryptoKWDes3CtxPtr; +struct _xmlSecMSCryptoKWDes3Ctx { + ALG_ID desAlgorithmIdentifier; + const xmlSecMSCryptoProviderInfo * desProviders; + ALG_ID sha1AlgorithmIdentifier; + const xmlSecMSCryptoProviderInfo * sha1Providers; + xmlSecKeyDataId keyId; + xmlSecSize keySize; + + HCRYPTPROV desCryptProvider; + HCRYPTPROV sha1CryptProvider; + HCRYPTKEY pubPrivKey; + xmlSecBuffer keyBuffer; +}; +#define xmlSecMSCryptoKWDes3Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoKWDes3Ctx)) +#define xmlSecMSCryptoKWDes3GetCtx(transform) \ + ((xmlSecMSCryptoKWDes3CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecMSCryptoKWDes3Initialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoKWDes3Finalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoKWDes3SetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoKWDes3SetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoKWDes3Execute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static xmlSecTransformKlass xmlSecMSCryptoKWDes3Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoKWDes3Size, /* xmlSecSize objSize */ + + xmlSecNameKWDes3, /* const xmlChar* name; */ + xmlSecHrefKWDes3, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoKWDes3Initialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoKWDes3Finalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoKWDes3SetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoKWDes3SetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoKWDes3Execute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformKWDes3GetKlass: + * + * The Triple DES key wrapper transform klass. + * + * Returns: Triple DES key wrapper transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformKWDes3GetKlass(void) { + return(&xmlSecMSCryptoKWDes3Klass); +} + +/* Ordered list of providers to search for algorithm implementation using + * xmlSecMSCryptoFindProvider() function + * + * MUST END with { NULL, 0 } !!! + */ +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Des[] = { + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; +static xmlSecMSCryptoProviderInfo xmlSecMSCryptoProviderInfo_Sha1[] = { + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV, PROV_RSA_AES}, + { XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE, PROV_RSA_AES }, + { MS_STRONG_PROV, PROV_RSA_FULL }, + { MS_ENHANCED_PROV, PROV_RSA_FULL }, + { MS_DEF_PROV, PROV_RSA_FULL }, + { NULL, 0 } +}; + + +static int +xmlSecMSCryptoKWDes3Initialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoKWDes3CtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWDes3Id), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWDes3Size), -1); + + ctx = xmlSecMSCryptoKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKWDes3Ctx)); + + if(transform->id == xmlSecMSCryptoTransformKWDes3Id) { + ctx->desAlgorithmIdentifier = CALG_3DES; + ctx->desProviders = xmlSecMSCryptoProviderInfo_Des; + ctx->sha1AlgorithmIdentifier = CALG_SHA1; + ctx->sha1Providers = xmlSecMSCryptoProviderInfo_Sha1; + ctx->keyId = xmlSecMSCryptoKeyDataDesId; + ctx->keySize = XMLSEC_KW_DES3_KEY_LENGTH; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&(ctx->keyBuffer), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* find providers */ + ctx->desCryptProvider = xmlSecMSCryptoFindProvider(ctx->desProviders, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(ctx->desCryptProvider == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoFindProvider(des)", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + ctx->sha1CryptProvider = xmlSecMSCryptoFindProvider(ctx->sha1Providers, NULL, CRYPT_VERIFYCONTEXT, TRUE); + if(ctx->sha1CryptProvider == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoFindProvider(sha1)", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + /* Create dummy key to be able to import plain session keys */ + if (!xmlSecMSCryptoCreatePrivateExponentOneKey(ctx->desCryptProvider, &(ctx->pubPrivKey))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoCreatePrivateExponentOneKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + return(0); +} + +static void +xmlSecMSCryptoKWDes3Finalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoKWDes3CtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWDes3Id)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWDes3Size)); + + ctx = xmlSecMSCryptoKWDes3GetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (ctx->pubPrivKey) { + CryptDestroyKey(ctx->pubPrivKey); + } + if (ctx->desCryptProvider) { + CryptReleaseContext(ctx->desCryptProvider, 0); + } + if (ctx->sha1CryptProvider) { + CryptReleaseContext(ctx->sha1CryptProvider, 0); + } + + xmlSecBufferFinalize(&ctx->keyBuffer); + + memset(ctx, 0, sizeof(xmlSecMSCryptoKWDes3Ctx)); +} + +static int +xmlSecMSCryptoKWDes3SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecMSCryptoKWDes3CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWDes3Size), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecMSCryptoKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecMSCryptoKeyDataDesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage= xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage= xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * XMLSEC_KW_DES3_KEY_LENGTH; + return(0); +} + +static int +xmlSecMSCryptoKWDes3SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoKWDes3CtxPtr ctx; + xmlSecBufferPtr buffer; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWDes3Size), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataDesId), -1); + + ctx = xmlSecMSCryptoKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + if(keySize < XMLSEC_KW_DES3_KEY_LENGTH) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "key length %d is not enough (%d expected)", + keySize, XMLSEC_KW_DES3_KEY_LENGTH); + return(-1); + } + + ret = xmlSecBufferSetData(&(ctx->keyBuffer), xmlSecBufferGetData(buffer), XMLSEC_KW_DES3_KEY_LENGTH); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", XMLSEC_KW_DES3_KEY_LENGTH); + return(-1); + } + + return(0); +} + +static int +xmlSecMSCryptoKWDes3Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoKWDes3CtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize, keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoKWDes3Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keySize = xmlSecBufferGetSize(&(ctx->keyBuffer)); + xmlSecAssert2(keySize == XMLSEC_KW_DES3_KEY_LENGTH, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + xmlSecAssert2(outSize == 0, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + if((inSize % XMLSEC_KW_DES3_BLOCK_LENGTH) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "%d bytes - not %d bytes aligned", + inSize, XMLSEC_KW_DES3_BLOCK_LENGTH); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + /* the encoded key might be 16 bytes longer plus one block just in case */ + outSize = inSize + XMLSEC_KW_DES3_IV_LENGTH + + XMLSEC_KW_DES3_BLOCK_LENGTH + + XMLSEC_KW_DES3_BLOCK_LENGTH; + } else { + /* just in case, add a block */ + outSize = inSize + XMLSEC_KW_DES3_BLOCK_LENGTH; + } + + ret = xmlSecBufferSetMaxSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + ret = xmlSecKWDes3Encode(&xmlSecMSCryptoKWDes3ImplKlass, ctx, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWDes3Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "key=%d,in=%d,out=%d", + keySize, inSize, outSize); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecKWDes3Decode(&xmlSecMSCryptoKWDes3ImplKlass, ctx, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWDes3Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "key=%d,in=%d,out=%d", + keySize, inSize, outSize); + return(-1); + } + outSize = ret; + } + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + transform->status = xmlSecTransformStatusFinished; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + +/********************************************************************* + * + * DES KW implementation + * + *********************************************************************/ +static int +xmlSecMSCryptoKWDes3Sha1(void * context, + const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecMSCryptoKWDes3CtxPtr ctx = (xmlSecMSCryptoKWDes3CtxPtr)context; + HCRYPTHASH mscHash = 0; + DWORD retLen; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->sha1CryptProvider != 0, -1); + xmlSecAssert2(ctx->sha1AlgorithmIdentifier != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize > 0, -1); + + /* create */ + ret = CryptCreateHash(ctx->sha1CryptProvider, + ctx->sha1AlgorithmIdentifier, + 0, + 0, + &mscHash); + if((ret == 0) || (mscHash == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptCreateHash", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* hash */ + ret = CryptHashData(mscHash, + in, + inSize, + 0); + if(ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptHashData", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", inSize); + CryptDestroyHash(mscHash); + return(-1); + } + + /* get results */ + retLen = outSize; + ret = CryptGetHashParam(mscHash, + HP_HASHVAL, + out, + &retLen, + 0); + if (ret == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetHashParam(HP_HASHVAL)", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + CryptDestroyHash(mscHash); + return(-1); + } + + /* done */ + CryptDestroyHash(mscHash); + return(retLen); +} + +static int +xmlSecMSCryptoKWDes3GenerateRandom(void * context, + xmlSecByte * out, xmlSecSize outSize) +{ + xmlSecMSCryptoKWDes3CtxPtr ctx = (xmlSecMSCryptoKWDes3CtxPtr)context; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->desCryptProvider != 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize > 0, -1); + + if(!CryptGenRandom(ctx->desCryptProvider, outSize, out)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGenRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "len=%d", outSize); + return(-1); + } + + return((int)outSize); +} + +static int +xmlSecMSCryptoKWDes3BlockEncrypt(void * context, + const xmlSecByte * iv, xmlSecSize ivSize, + const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecMSCryptoKWDes3CtxPtr ctx = (xmlSecMSCryptoKWDes3CtxPtr)context; + DWORD dwBlockLen, dwBlockLenLen, dwCLen; + HCRYPTKEY cryptKey = 0; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecBufferGetData(&(ctx->keyBuffer)) != NULL, -1); + xmlSecAssert2(xmlSecBufferGetSize(&(ctx->keyBuffer)) >= XMLSEC_KW_DES3_KEY_LENGTH, -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize >= XMLSEC_KW_DES3_IV_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + /* Import this key and get an HCRYPTKEY handle, we do it again and again + to ensure we don't go into CBC mode */ + if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->desCryptProvider, + ctx->pubPrivKey, + ctx->desAlgorithmIdentifier, + xmlSecBufferGetData(&ctx->keyBuffer), + xmlSecBufferGetSize(&ctx->keyBuffer), + TRUE, + &cryptKey)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(cryptKey != 0, -1); + + /* iv len == block len */ + dwBlockLenLen = sizeof(DWORD); + if (!CryptGetKeyParam(cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* set IV */ + if((ivSize < dwBlockLen / 8) || (!CryptSetKeyParam(cryptKey, KP_IV, iv, 0))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ivSize=%d, dwBlockLen=%d", + ivSize, dwBlockLen / 8); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* Set process last block to false, since we handle padding ourselves, and MSCrypto padding + * can be skipped. I hope this will work .... */ + if(out != in) { + memcpy(out, in, inSize); + } + dwCLen = inSize; + if(!CryptEncrypt(cryptKey, 0, FALSE, 0, out, &dwCLen, outSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* cleanup */ + CryptDestroyKey(cryptKey); + return(dwCLen); +} + +static int +xmlSecMSCryptoKWDes3BlockDecrypt(void * context, + const xmlSecByte * iv, xmlSecSize ivSize, + const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecMSCryptoKWDes3CtxPtr ctx = (xmlSecMSCryptoKWDes3CtxPtr)context; + DWORD dwBlockLen, dwBlockLenLen, dwCLen; + HCRYPTKEY cryptKey = 0; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecBufferGetData(&(ctx->keyBuffer)) != NULL, -1); + xmlSecAssert2(xmlSecBufferGetSize(&(ctx->keyBuffer)) >= XMLSEC_KW_DES3_KEY_LENGTH, -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize >= XMLSEC_KW_DES3_IV_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + /* Import this key and get an HCRYPTKEY handle, we do it again and again + to ensure we don't go into CBC mode */ + if (!xmlSecMSCryptoImportPlainSessionBlob(ctx->desCryptProvider, + ctx->pubPrivKey, + ctx->desAlgorithmIdentifier, + xmlSecBufferGetData(&ctx->keyBuffer), + xmlSecBufferGetSize(&ctx->keyBuffer), + TRUE, + &cryptKey)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(cryptKey != 0, -1); + + /* iv len == block len */ + dwBlockLenLen = sizeof(DWORD); + if (!CryptGetKeyParam(cryptKey, KP_BLOCKLEN, (BYTE *)&dwBlockLen, &dwBlockLenLen, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* set IV */ + if((ivSize < dwBlockLen / 8) || (!CryptSetKeyParam(cryptKey, KP_IV, iv, 0))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptSetKeyParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ivSize=%d, dwBlockLen=%d", + ivSize, dwBlockLen / 8); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* Set process last block to false, since we handle padding ourselves, and MSCrypto padding + * can be skipped. I hope this will work .... */ + if(out != in) { + memcpy(out, in, inSize); + } + dwCLen = inSize; + if(!CryptDecrypt(cryptKey, 0, FALSE, 0, out, &dwCLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptEncrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CryptDestroyKey(cryptKey); + return(-1); + } + + /* cleanup */ + CryptDestroyKey(cryptKey); + return(dwCLen); +} + + +#endif /* XMLSEC_NO_DES */ + diff --git a/src/mscrypto/mingw-crypt32.def b/src/mscrypto/mingw-crypt32.def new file mode 100644 index 00000000..4ba99b2f --- /dev/null +++ b/src/mscrypto/mingw-crypt32.def @@ -0,0 +1,36 @@ +IMPORTS + CertAddCertificateContextToStore@16 = crypt32.CertAddCertificateContextToStore + CertAddCRLContextToStore@16 = crypt32.CertAddCRLContextToStore + CertAddStoreToCollection@16 = crypt32.CertAddStoreToCollection + CertCloseStore@8 = crypt32.CertCloseStore + CertCompareCertificateName@12 = crypt32.CertCompareCertificateName + CertCreateCertificateContext@12 = crypt32.CertCreateCertificateContext + CertCreateCRLContext@12 = crypt32.CertCreateCRLContext + CertDuplicateCertificateContext@4 = crypt32.CertDuplicateCertificateContext + CertDuplicateCRLContext@4 = crypt32.CertDuplicateCRLContext + CertEnumCertificatesInStore@8 = crypt32.CertEnumCertificatesInStore + CertEnumCRLsInStore@8 = crypt32.CertEnumCRLsInStore + CertFindCertificateInCRL@20 = crypt32.CertFindCertificateInCRL + CertFindCertificateInStore@24 = crypt32.CertFindCertificateInStore + CertFindExtension@12 = crypt32.CertFindExtension + CertFreeCertificateChain@4 = crypt32.CertFreeCertificateChain + CertFreeCertificateContext@4 = crypt32.CertFreeCertificateContext + CertFreeCRLContext@4 = crypt32.CertFreeCRLContext + CertGetCertificateChain@32 = crypt32.CertGetCertificateChain + CertGetCertificateContextProperty@16 = crypt32.CertGetCertificateContextProperty + CertGetNameStringA@24 = crypt32.CertGetNameStringA + CertGetNameStringW@24 = crypt32.CertGetNameStringW + CertGetPublicKeyLength@8 = crypt32.CertGetPublicKeyLength + CertNameToStrA@20 = crypt32.CertNameToStrA + CertNameToStrW@20 = crypt32.CertNameToStrW + CertOpenStore@20 = crypt32.CertOpenStore + CertOpenSystemStoreA@8 = crypt32.CertOpenSystemStoreA + CertOpenSystemStoreW@8 = crypt32.CertOpenSystemStoreW + CertStrToNameA@28 = crypt32.CertStrToNameA + CertStrToNameW@28 = crypt32.CertStrToNameW + CertVerifySubjectCertificateContext@12 = crypt32.CertVerifySubjectCertificateContext + CryptAcquireCertificatePrivateKey@24 = crypt32.CryptAcquireCertificatePrivateKey + CryptImportPublicKeyInfo@16 = crypt32.CryptImportPublicKeyInfo + PFXImportCertStore@12 = crypt32.PFXImportCertStore + PFXIsPFXBlob@4 = crypt32.PFXIsPFXBlob + PFXVerifyPassword@12 = crypt32.PFXVerifyPassword diff --git a/src/mscrypto/private.h b/src/mscrypto/private.h new file mode 100644 index 00000000..11479bff --- /dev/null +++ b/src/mscrypto/private.h @@ -0,0 +1,130 @@ +/** + * XMLSec library + * + * THIS IS A PRIVATE XMLSEC HEADER FILE + * DON'T USE IT IN YOUR APPLICATION + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2010 Aleksey Sanin, All rights reserved. + */ +#ifndef __XMLSEC_MSCRYPTO_PRIVATE_H__ +#define __XMLSEC_MSCRYPTO_PRIVATE_H__ + +#ifndef XMLSEC_PRIVATE +#error "private.h file contains private xmlsec definitions and should not be used outside xmlsec or xmlsec-<crypto> libraries" +#endif /* XMLSEC_PRIVATE */ + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/******************************************************************** + * + * Utils + * + ********************************************************************/ +int ConvertEndian (const xmlSecByte * src, + xmlSecByte * dst, + xmlSecSize size); +int ConvertEndianInPlace (xmlSecByte * buf, + xmlSecSize size); + +/******************************************************************** + * + * Crypto Providers + * + ********************************************************************/ + +/* We need to redefine both to ensure that we can pick the right one at runtime (instead of compile time) */ +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE_A "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE_W L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" +#ifdef UNICODE +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE_W +#else +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_PROTOTYPE_A +#endif + +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_A "Microsoft Enhanced RSA and AES Cryptographic Provider" +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_W L"Microsoft Enhanced RSA and AES Cryptographic Provider" +#ifdef UNICODE +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_W +#else +#define XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV XMLSEC_CRYPTO_MS_ENH_RSA_AES_PROV_A +#endif + +/** + * xmlSecMSCryptoProviderInfo: + * + * Contains information for looking up provider from MS Crypto. + */ +typedef struct _xmlSecMSCryptoProviderInfo { + LPCTSTR providerName; + DWORD providerType; +} xmlSecMSCryptoProviderInfo; + +HCRYPTPROV xmlSecMSCryptoFindProvider (const xmlSecMSCryptoProviderInfo * providers, + LPCTSTR pszContainer, + DWORD dwFlags, + BOOL bUseXmlSecContainer); + + +/****************************************************************************** + * + * SymKey Util functions + * + * Low level helper routines for importing plain text keys in MS HKEY handle, + * since MSCrypto API does not support import of plain text (session) keys + * just like that. These functions are based upon MS kb article #228786 + * and "Base Provider Key BLOBs" article for priv key blob format. + * + ******************************************************************************/ +BOOL xmlSecMSCryptoCreatePrivateExponentOneKey (HCRYPTPROV hProv, + HCRYPTKEY *hPrivateKey); + +BOOL xmlSecMSCryptoImportPlainSessionBlob (HCRYPTPROV hProv, + HCRYPTKEY hPrivateKey, + ALG_ID dwAlgId, + LPBYTE pbKeyMaterial, + DWORD dwKeyMaterial, + BOOL bCheckKeyLength, + HCRYPTKEY *hSessionKey); + +/****************************************************************************** + * + * X509 Util functions + * + ******************************************************************************/ +#ifndef XMLSEC_NO_X509 +PCCERT_CONTEXT xmlSecMSCryptoX509FindCertBySubject (HCERTSTORE store, + const LPTSTR wcSubject, + DWORD dwCertEncodingType); + +PCCERT_CONTEXT xmlSecMSCryptoX509StoreFindCert (xmlSecKeyDataStorePtr store, + xmlChar *subjectName, + xmlChar *issuerName, + xmlChar *issuerSerial, + xmlChar *ski, + xmlSecKeyInfoCtx* keyInfoCtx); + +xmlChar * xmlSecMSCryptoX509GetNameString (PCCERT_CONTEXT pCertContext, + DWORD dwType, + DWORD dwFlags, + void *pvTypePara); + +PCCERT_CONTEXT xmlSecMSCryptoX509StoreVerify (xmlSecKeyDataStorePtr store, + HCERTSTORE certs, + xmlSecKeyInfoCtx* keyInfoCtx); + +#endif /* XMLSEC_NO_X509 */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __XMLSEC_MSCRYPTO_PRIVATE_H__ */ diff --git a/src/mscrypto/signatures.c b/src/mscrypto/signatures.c new file mode 100644 index 00000000..2c51f09a --- /dev/null +++ b/src/mscrypto/signatures.c @@ -0,0 +1,960 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2005-2006 Cryptocom LTD (http://www.cryptocom.ru). + */ +#include "globals.h" + +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> +#ifndef XMLSEC_NO_GOST +#include "csp_calg.h" +#endif + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/symbols.h> +#include <xmlsec/mscrypto/certkeys.h> +#include <xmlsec/mscrypto/x509.h> +#include "private.h" + + +/************************************************************************** + * + * Internal MSCrypto signatures ctx + * + *****************************************************************************/ +typedef struct _xmlSecMSCryptoSignatureCtx xmlSecMSCryptoSignatureCtx, + *xmlSecMSCryptoSignatureCtxPtr; +struct _xmlSecMSCryptoSignatureCtx { + xmlSecKeyDataPtr data; + ALG_ID alg_id; + HCRYPTHASH mscHash; + ALG_ID digestAlgId; + xmlSecKeyDataId keyId; +}; + +/****************************************************************************** + * + * Signature transforms + * + * xmlSecMSCryptoSignatureCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecMSCryptoSignatureSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoSignatureCtx)) +#define xmlSecMSCryptoSignatureGetCtx(transform) \ + ((xmlSecMSCryptoSignatureCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecMSCryptoSignatureCheckId (xmlSecTransformPtr transform); +static int xmlSecMSCryptoSignatureInitialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoSignatureFinalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoSignatureSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoSignatureSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoSignatureVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoSignatureExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + + +static int xmlSecMSCryptoSignatureCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_DSA + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) { + return(1); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha384Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha512Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_GOST + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + return(1); + } else +#endif /* XMLSEC_NO_GOST*/ + + + /* not found */ + { + return(0); + } + + return(0); +} + +static int xmlSecMSCryptoSignatureInitialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoSignatureCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoSignatureCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoSignatureSize), -1); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoSignatureCtx)); + + +#ifndef XMLSEC_NO_DSA + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) { + ctx->digestAlgId = CALG_SHA1; + ctx->keyId = xmlSecMSCryptoKeyDataDsaId; + } else +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) { + ctx->digestAlgId = CALG_MD5; + ctx->keyId = xmlSecMSCryptoKeyDataRsaId; + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + ctx->digestAlgId = CALG_SHA1; + ctx->keyId = xmlSecMSCryptoKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) { + ctx->digestAlgId = CALG_SHA_256; + ctx->keyId = xmlSecMSCryptoKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha384Id)) { + ctx->digestAlgId = CALG_SHA_384; + ctx->keyId = xmlSecMSCryptoKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha512Id)) { + ctx->digestAlgId = CALG_SHA_512; + ctx->keyId = xmlSecMSCryptoKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_GOST + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + ctx->digestAlgId = CALG_MAGPRO_HASH_R3411_94; + ctx->keyId = xmlSecMSCryptoKeyDataGost2001Id; + } else +#endif /* XMLSEC_NO_GOST*/ + + /* not found */ + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void xmlSecMSCryptoSignatureFinalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoSignatureCtxPtr ctx; + + xmlSecAssert(xmlSecMSCryptoSignatureCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoSignatureSize)); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (ctx->mscHash) { + CryptDestroyHash(ctx->mscHash); + } + + if (ctx->data != NULL) { + xmlSecKeyDataDestroy(ctx->data); + ctx->data = NULL; + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoSignatureCtx)); +} + +static int xmlSecMSCryptoSignatureSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoSignatureCtxPtr ctx; + xmlSecKeyDataPtr value; + + xmlSecAssert2(xmlSecMSCryptoSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoSignatureSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestAlgId != 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(value != NULL, -1); + + ctx->data = xmlSecKeyDataDuplicate(value); + if(ctx->data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKeyDataDuplicate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int xmlSecMSCryptoSignatureSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecMSCryptoSignatureCtxPtr ctx; + + xmlSecAssert2(xmlSecMSCryptoSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoSignatureSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + + keyReq->keyId = ctx->keyId; + if(transform->operation == xmlSecTransformOperationSign) { + keyReq->keyType = xmlSecKeyDataTypePrivate; + keyReq->keyUsage = xmlSecKeyUsageSign; + } else { + keyReq->keyType = xmlSecKeyDataTypePublic; + keyReq->keyUsage = xmlSecKeyUsageVerify; + } + return(0); +} + +static int xmlSecMSCryptoSignatureVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoSignatureCtxPtr ctx; + xmlSecBuffer tmp; + xmlSecByte *tmpBuf; + HCRYPTKEY hKey; + DWORD dwError; + int ret; + + xmlSecAssert2(xmlSecMSCryptoSignatureCheckId(transform), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoSignatureSize), -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize > 0, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + ret = xmlSecBufferInitialize(&tmp, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "dataSize=%d", dataSize); + return(-1); + } + + tmpBuf = xmlSecBufferGetData(&tmp); + xmlSecAssert2(tmpBuf != NULL, -1); + + /* Reverse the sig - Windows stores integers as octet streams in little endian + * order. The I2OSP algorithm used by XMLDSig to store integers is big endian */ +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) { + ConvertEndian(data, tmpBuf, dataSize); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + ConvertEndian(data, tmpBuf, dataSize); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) { + ConvertEndian(data, tmpBuf, dataSize); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha384Id)) { + ConvertEndian(data, tmpBuf, dataSize); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha512Id)) { + ConvertEndian(data, tmpBuf, dataSize); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id) && (dataSize == 40)) { + ConvertEndian(data, tmpBuf, 20); + ConvertEndian(data + 20, tmpBuf + 20, 20); + } else +#endif /*endif XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + ConvertEndian(data, tmpBuf, dataSize); + } else +#endif /* XMLSEC_NO_GOST*/ + + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "Invalid algo"); + xmlSecBufferFinalize(&tmp); + return(-1); + } + + hKey = xmlSecMSCryptoKeyDataGetKey(ctx->data, xmlSecKeyDataTypePublic); + if (hKey == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoKeyDataGetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&tmp); + return(-1); + } + if (!CryptVerifySignature(ctx->mscHash, + tmpBuf, + dataSize, + hKey, + NULL, + 0)) { + dwError = GetLastError(); + if (NTE_BAD_SIGNATURE == dwError) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptVerifySignature", + XMLSEC_ERRORS_R_DATA_NOT_MATCH, + "signature do not match"); + transform->status = xmlSecTransformStatusFail; + xmlSecBufferFinalize(&tmp); + return(0); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptVerifySignature", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&tmp); + return (-1); + } + } + xmlSecBufferFinalize(&tmp); + transform->status = xmlSecTransformStatusOk; + return(0); +} + + + +static int +xmlSecMSCryptoSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoSignatureCtxPtr ctx; + HCRYPTPROV hProv; + DWORD dwKeySpec; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + int ret; + DWORD dwSigLen; + BYTE *tmpBuf, *outBuf; + + xmlSecAssert2(xmlSecMSCryptoSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoSignatureSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + ctx = xmlSecMSCryptoSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestAlgId != 0, -1); + + if(transform->status == xmlSecTransformStatusNone) { + xmlSecAssert2(outSize == 0, -1); + + if (0 == (hProv = xmlSecMSCryptoKeyDataGetMSCryptoProvider(ctx->data))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoKeyDataGetMSCryptoProvider", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + + if (!CryptCreateHash(hProv, ctx->digestAlgId, 0, 0, &(ctx->mscHash))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptCreateHash", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (inSize > 0)) { + xmlSecAssert2(outSize == 0, -1); + + if (!CryptHashData(ctx->mscHash, xmlSecBufferGetData(in), inSize, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptHashData", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + xmlSecBuffer tmp; + + xmlSecAssert2(outSize == 0, -1); + + if(transform->operation == xmlSecTransformOperationSign) { + dwKeySpec = xmlSecMSCryptoKeyDataGetMSCryptoKeySpec(ctx->data); + if (!CryptSignHash(ctx->mscHash, dwKeySpec, NULL, 0, NULL, &dwSigLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptSignHash", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = (xmlSecSize)dwSigLen; + + ret = xmlSecBufferInitialize(&tmp, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + tmpBuf = xmlSecBufferGetData(&tmp); + xmlSecAssert2(tmpBuf != NULL, -1); + + if (!CryptSignHash(ctx->mscHash, dwKeySpec, NULL, 0, tmpBuf, &dwSigLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptSignHash", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&tmp); + return(-1); + } + outSize = (xmlSecSize)dwSigLen; + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + xmlSecBufferFinalize(&tmp); + return(-1); + } + outBuf = xmlSecBufferGetData(out); + xmlSecAssert2(outBuf != NULL, -1); + + /* Reverse the sig - Windows stores integers as octet streams in little endian + * order. The I2OSP algorithm used by XMLDSig to store integers is big endian */ +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaMd5Id)) { + ConvertEndian(tmpBuf, outBuf, outSize); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + ConvertEndian(tmpBuf, outBuf, outSize); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha256Id)) { + ConvertEndian(tmpBuf, outBuf, outSize); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha384Id)) { + ConvertEndian(tmpBuf, outBuf, outSize); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha512Id)) { + ConvertEndian(tmpBuf, outBuf, outSize); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA*/ + +#ifndef XMLSEC_NO_DSA + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id) && (outSize == 40)) { + ConvertEndian(tmpBuf, outBuf, 20); + ConvertEndian(tmpBuf + 20, outBuf + 20, 20); + } else +#endif /* XMLSEC_NO_DSA*/ + +#ifndef XMLSEC_NO_GOST + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + ConvertEndian(tmpBuf, outBuf, outSize); + } else +#endif /* XMLSEC_NO_GOST*/ + + { + /* We shouldn't get at this place */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "Invalid algo"); + xmlSecBufferFinalize(&tmp); + return(-1); + } + xmlSecBufferFinalize(&tmp); + } + transform->status = xmlSecTransformStatusFinished; + } + + if((transform->status == xmlSecTransformStatusWorking) || (transform->status == xmlSecTransformStatusFinished)) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} + + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 +/**************************************************************************** + * + * RSA-MD5 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoRsaMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaMd5, /* const xmlChar* name; */ + xmlSecHrefRsaMd5, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformRsaMd5GetKlass: + * + * The RSA-MD5 signature transform klass. + * + * Returns: RSA-MD5 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaMd5GetKlass(void) { + return(&xmlSecMSCryptoRsaMd5Klass); +} +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 +/**************************************************************************** + * + * RSA-SHA1 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoRsaSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha1, /* const xmlChar* name; */ + xmlSecHrefRsaSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformRsaSha1GetKlass: + * + * The RSA-SHA1 signature transform klass. + * + * Returns: RSA-SHA1 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaSha1GetKlass(void) { + return(&xmlSecMSCryptoRsaSha1Klass); +} +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 +/**************************************************************************** + * + * RSA-SHA256 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoRsaSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha256, /* const xmlChar* name; */ + xmlSecHrefRsaSha256, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformRsaSha256GetKlass: + * + * The RSA-SHA256 signature transform klass. + * + * Returns: RSA-SHA256 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaSha256GetKlass(void) { + return(&xmlSecMSCryptoRsaSha256Klass); +} +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/**************************************************************************** + * + * RSA-SHA384 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoRsaSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha384, /* const xmlChar* name; */ + xmlSecHrefRsaSha384, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformRsaSha384GetKlass: + * + * The RSA-SHA384 signature transform klass. + * + * Returns: RSA-SHA384 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaSha384GetKlass(void) { + return(&xmlSecMSCryptoRsaSha384Klass); +} +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/**************************************************************************** + * + * RSA-SHA2512 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecMSCryptoRsaSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha512, /* const xmlChar* name; */ + xmlSecHrefRsaSha512, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformRsaSha512GetKlass: + * + * The RSA-SHA512 signature transform klass. + * + * Returns: RSA-SHA512 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformRsaSha512GetKlass(void) { + return(&xmlSecMSCryptoRsaSha512Klass); +} +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA +/**************************************************************************** + * + * DSA-SHA1 signature transform + * + ***************************************************************************/ + +static xmlSecTransformKlass xmlSecMSCryptoDsaSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameDsaSha1, /* const xmlChar* name; */ + xmlSecHrefDsaSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformDsaSha1GetKlass: + * + * The DSA-SHA1 signature transform klass. + * + * Returns: DSA-SHA1 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformDsaSha1GetKlass(void) { + return(&xmlSecMSCryptoDsaSha1Klass); +} + +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST +/**************************************************************************** + * + * GOST2001-GOSTR3411_94 signature transform + * + ***************************************************************************/ + +static xmlSecTransformKlass xmlSecMSCryptoGost2001GostR3411_94Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameGost2001GostR3411_94, /* const xmlChar* name; */ + xmlSecHrefGost2001GostR3411_94, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecMSCryptoSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecMSCryptoSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecMSCryptoSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoTransformGost2001GostR3411_94GetKlass: + * + * The GOST2001-GOSTR3411_94 signature transform klass. + * + * Returns: GOST2001-GOSTR3411_94 signature transform klass. + */ +xmlSecTransformId +xmlSecMSCryptoTransformGost2001GostR3411_94GetKlass(void) { + return(&xmlSecMSCryptoGost2001GostR3411_94Klass); +} + +#endif /* XMLSEC_NO_GOST*/ + diff --git a/src/mscrypto/symkeys.c b/src/mscrypto/symkeys.c new file mode 100644 index 00000000..658a6d49 --- /dev/null +++ b/src/mscrypto/symkeys.c @@ -0,0 +1,824 @@ +/** + * + * XMLSec library + * + * DES Algorithm support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> +#include "private.h" + +/***************************************************************************** + * + * Symmetic (binary) keys - just a wrapper for xmlSecKeyDataBinary + * + ****************************************************************************/ +static int xmlSecMSCryptoSymKeyDataInitialize (xmlSecKeyDataPtr data); +static int xmlSecMSCryptoSymKeyDataDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecMSCryptoSymKeyDataFinalize (xmlSecKeyDataPtr data); +static int xmlSecMSCryptoSymKeyDataXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoSymKeyDataXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoSymKeyDataBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const unsigned char* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoSymKeyDataBinWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + unsigned char** buf, + xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoSymKeyDataGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoSymKeyDataGetType(xmlSecKeyDataPtr data); +static xmlSecSize xmlSecMSCryptoSymKeyDataGetSize (xmlSecKeyDataPtr data); +static void xmlSecMSCryptoSymKeyDataDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoSymKeyDataDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); +static int xmlSecMSCryptoSymKeyDataKlassCheck (xmlSecKeyDataKlass* klass); + +/* + * GENERIC HELPER FUNCTIONS + */ + +#define xmlSecMSCryptoSymKeyDataCheckId(data) \ + (xmlSecKeyDataIsValid((data)) && \ + xmlSecMSCryptoSymKeyDataKlassCheck((data)->id)) + +static int +xmlSecMSCryptoSymKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataCheckId(data), -1); + + return(xmlSecKeyDataBinaryValueInitialize(data)); +} + +static int +xmlSecMSCryptoSymKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataCheckId(dst), -1); + xmlSecAssert2(xmlSecMSCryptoSymKeyDataCheckId(src), -1); + xmlSecAssert2(dst->id == src->id, -1); + + return(xmlSecKeyDataBinaryValueDuplicate(dst, src)); +} + +static void +xmlSecMSCryptoSymKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecMSCryptoSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueFinalize(data); +} + +static int +xmlSecMSCryptoSymKeyDataXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlRead(id, key, node, keyInfoCtx)); +} + +static int +xmlSecMSCryptoSymKeyDataXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlWrite(id, key, node, keyInfoCtx)); +} + +static int +xmlSecMSCryptoSymKeyDataBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const unsigned char* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinRead(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecMSCryptoSymKeyDataBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + unsigned char** buf, xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinWrite(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecMSCryptoSymKeyDataGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecMSCryptoSymKeyDataCheckId(data), -1); + xmlSecAssert2(sizeBits > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecMSCryptoGenerateRandom(buffer, (sizeBits + 7) / 8)); +} + +static xmlSecKeyDataType +xmlSecMSCryptoSymKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecMSCryptoSymKeyDataCheckId(data), xmlSecKeyDataTypeUnknown); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, xmlSecKeyDataTypeUnknown); + + return((xmlSecBufferGetSize(buffer) > 0) ? xmlSecKeyDataTypeSymmetric : xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecMSCryptoSymKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataCheckId(data), 0); + + return(xmlSecKeyDataBinaryValueGetSize(data)); +} + +static void +xmlSecMSCryptoSymKeyDataDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecMSCryptoSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugDump(data, output); +} + +static void +xmlSecMSCryptoSymKeyDataDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecMSCryptoSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugXmlDump(data, output); +} + +static int +xmlSecMSCryptoSymKeyDataKlassCheck(xmlSecKeyDataKlass* klass) { + +#ifndef XMLSEC_NO_DES + if(klass == xmlSecMSCryptoKeyDataDesId) { + return(1); + } else +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(klass == xmlSecMSCryptoKeyDataAesId) { + return(1); + } else +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_HMAC + if(klass == xmlSecMSCryptoKeyDataHmacId) { + return(1); + } else +#endif /* XMLSEC_NO_HMAC */ + + { + return(0); + } + + return(0); +} + + +/****************************************************************************** + * + * Utils + * + * Low level helper routines for importing plain text keys in MS HKEY handle, + * since MSCrypto API does not support import of plain text (session) keys + * just like that. These functions are based upon MS kb article #228786 + * and "Base Provider Key BLOBs" article for priv key blob format. + * + ******************************************************************************/ +BOOL +xmlSecMSCryptoCreatePrivateExponentOneKey(HCRYPTPROV hProv, HCRYPTKEY *hPrivateKey) +{ + HCRYPTKEY hKey = 0; + LPBYTE keyBlob = NULL; + DWORD keyBlobLen; + PUBLICKEYSTRUC* pubKeyStruc; + RSAPUBKEY* rsaPubKey; + DWORD bitLen; + BYTE *ptr; + int n; + BOOL res = FALSE; + + xmlSecAssert2(hProv != 0, FALSE); + xmlSecAssert2(hPrivateKey != NULL, FALSE); + + /* just in case */ + *hPrivateKey = 0; + + /* Generate the private key */ + if(!CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_EXPORTABLE, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGenKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* Export the private key, we'll convert it to a private exponent of one key */ + if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, NULL, &keyBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen); + if(keyBlob == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + if(!CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, keyBlob, &keyBlobLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + CryptDestroyKey(hKey); + hKey = 0; + + /* Get the bit length of the key */ + if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "len=%ld", keyBlobLen); + goto done; + } + pubKeyStruc = (PUBLICKEYSTRUC*)keyBlob; + if(pubKeyStruc->bVersion != 0x02) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bVersion=%d", pubKeyStruc->bVersion); + goto done; + } + if(pubKeyStruc->bType != PRIVATEKEYBLOB) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "pubKeyStruc->bType=%d", (int)pubKeyStruc->bType); + goto done; + } + + /* aleksey: don't ask me why it is RSAPUBKEY, just don't ask */ + rsaPubKey = (RSAPUBKEY*)(keyBlob + sizeof(PUBLICKEYSTRUC)); + + /* check that we have RSA private key */ + if(rsaPubKey->magic != 0x32415352) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "rsaPubKey->magic=0x%08lx", rsaPubKey->magic); + goto done; + } + bitLen = rsaPubKey->bitlen; + + /* Modify the Exponent in Key BLOB format Key BLOB format is documented in SDK */ + rsaPubKey->pubexp = 1; + + /* Private-key BLOBs, type PRIVATEKEYBLOB, are used to store private keys outside a CSP. + * Base provider private-key BLOBs have the following format: + * + * PUBLICKEYSTRUC publickeystruc ; + * RSAPUBKEY rsapubkey; + * BYTE modulus[rsapubkey.bitlen/8]; 1/8 + * BYTE prime1[rsapubkey.bitlen/16]; 1/16 + * BYTE prime2[rsapubkey.bitlen/16]; 1/16 + * BYTE exponent1[rsapubkey.bitlen/16]; 1/16 + * BYTE exponent2[rsapubkey.bitlen/16]; 1/16 + * BYTE coefficient[rsapubkey.bitlen/16]; 1/16 + * BYTE privateExponent[rsapubkey.bitlen/8]; 1/8 + */ + if(keyBlobLen < sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY) + bitLen / 2 + bitLen / 16) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptExportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "len=%ld", keyBlobLen); + goto done; + } + ptr = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(RSAPUBKEY)); + + /* Skip modulus, prime1, prime2 */ + ptr += bitLen / 8; + ptr += bitLen / 16; + ptr += bitLen / 16; + + /* Convert exponent1 to 1 */ + for (n = 0; n < (bitLen / 16); n++) { + if (n == 0) ptr[n] = 1; + else ptr[n] = 0; + } + ptr += bitLen / 16; + + /* Convert exponent2 to 1 */ + for (n = 0; n < (bitLen / 16); n++) { + if (n == 0) ptr[n] = 1; + else ptr[n] = 0; + } + ptr += bitLen / 16; + + /* Skip coefficient */ + ptr += bitLen / 16; + + /* Convert privateExponent to 1 */ + for (n = 0; n < (bitLen / 16); n++) { + if (n == 0) ptr[n] = 1; + else ptr[n] = 0; + } + + /* Import the exponent-of-one private key. */ + if (!CryptImportKey(hProv, keyBlob, keyBlobLen, 0, 0, &hKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptImportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + (*hPrivateKey) = hKey; + hKey = 0; + res = TRUE; + +done: + if(keyBlob != NULL) { + xmlFree(keyBlob); + } + if (hKey != 0) { + CryptDestroyKey(hKey); + } + + return res; +} + +BOOL +xmlSecMSCryptoImportPlainSessionBlob(HCRYPTPROV hProv, HCRYPTKEY hPrivateKey, + ALG_ID dwAlgId, LPBYTE pbKeyMaterial, + DWORD dwKeyMaterial, BOOL bCheckKeyLength, + HCRYPTKEY *hSessionKey) { + ALG_ID dwPrivKeyAlg; + LPBYTE keyBlob = NULL; + DWORD keyBlobLen, rndBlobSize, dwSize, n; + PUBLICKEYSTRUC* pubKeyStruc; + ALG_ID* algId; + DWORD dwPublicKeySize; + DWORD dwProvSessionKeySize = 0; + LPBYTE pbPtr; + DWORD dwFlags; + PROV_ENUMALGS_EX ProvEnum; + HCRYPTKEY hTempKey = 0; + BOOL fFound; + BOOL res = FALSE; + + xmlSecAssert2(hProv != 0, FALSE); + xmlSecAssert2(hPrivateKey != 0, FALSE); + xmlSecAssert2(pbKeyMaterial != NULL, FALSE); + xmlSecAssert2(dwKeyMaterial > 0, FALSE); + xmlSecAssert2(hSessionKey != NULL, FALSE); + + /* Double check to see if this provider supports this algorithm and key size */ + fFound = FALSE; + dwFlags = CRYPT_FIRST; + dwSize = sizeof(ProvEnum); + while(CryptGetProvParam(hProv, PP_ENUMALGS_EX, (LPBYTE)&ProvEnum, &dwSize, dwFlags)) { + if (ProvEnum.aiAlgid == dwAlgId) { + fFound = TRUE; + break; + } + dwSize = sizeof(ProvEnum); + dwFlags = 0; + } + if(!fFound) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetProvParam", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "algId=%d is not supported", dwAlgId); + goto done; + } + + if(bCheckKeyLength) { + /* We have to get the key size(including padding) from an HCRYPTKEY handle. + * PP_ENUMALGS_EX contains the key size without the padding so we can't use it. + */ + if(!CryptGenKey(hProv, dwAlgId, 0, &hTempKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGenKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "algId=%d", dwAlgId); + goto done; + } + + dwSize = sizeof(DWORD); + if(!CryptGetKeyParam(hTempKey, KP_KEYLEN, (LPBYTE)&dwProvSessionKeySize, &dwSize, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetKeyParam(KP_KEYLEN)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "algId=%d", dwAlgId); + goto done; + } + CryptDestroyKey(hTempKey); + hTempKey = 0; + + /* yell if key is too big */ + if ((dwKeyMaterial * 8) > dwProvSessionKeySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "dwKeyMaterial=%ld;dwProvSessionKeySize=%ld", + dwKeyMaterial, dwProvSessionKeySize); + goto done; + } + } else { + dwProvSessionKeySize = dwKeyMaterial * 8; + } + + /* Get private key's algorithm */ + dwSize = sizeof(ALG_ID); + if(!CryptGetKeyParam(hPrivateKey, KP_ALGID, (LPBYTE)&dwPrivKeyAlg, &dwSize, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetKeyParam(KP_ALGID)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "algId=%d", dwAlgId); + goto done; + } + + /* Get private key's length in bits */ + dwSize = sizeof(DWORD); + if(!CryptGetKeyParam(hPrivateKey, KP_KEYLEN, (LPBYTE)&dwPublicKeySize, &dwSize, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGetKeyParam(KP_KEYLEN)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "algId=%d", dwAlgId); + goto done; + } + + /* 3 is for the first reserved byte after the key material and the 2 reserved bytes at the end. */ + if(dwPublicKeySize / 8 < dwKeyMaterial + 3) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "dwKeyMaterial=%ld;dwPublicKeySize=%ld", + dwKeyMaterial, dwPublicKeySize); + goto done; + } + rndBlobSize = dwPublicKeySize / 8 - (dwKeyMaterial + 3); + + /* Simple key BLOBs, type SIMPLEBLOB, are used to store and transport session keys outside a CSP. + * Base provider simple-key BLOBs are always encrypted with a key exchange public key. The pbData + * member of the SIMPLEBLOB is a sequence of bytes in the following format: + * + * PUBLICKEYSTRUC publickeystruc ; + * ALG_ID algid; + * BYTE encryptedkey[rsapubkey.bitlen/8]; + */ + + /* calculate Simple blob's length */ + keyBlobLen = sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID) + (dwPublicKeySize / 8); + + /* allocate simple blob buffer */ + keyBlob = (LPBYTE)xmlMalloc(sizeof(BYTE) * keyBlobLen); + if(keyBlob == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + memset(keyBlob, 0, keyBlobLen); + + /* initialize PUBLICKEYSTRUC */ + pubKeyStruc = (PUBLICKEYSTRUC*)(keyBlob); + pubKeyStruc->bType = SIMPLEBLOB; + pubKeyStruc->bVersion = 0x02; + pubKeyStruc->reserved = 0; + pubKeyStruc->aiKeyAlg = dwAlgId; + + /* Copy private key algorithm to buffer */ + algId = (ALG_ID*)(keyBlob + sizeof(PUBLICKEYSTRUC)); + (*algId) = dwPrivKeyAlg; + + /* Place the key material in reverse order */ + pbPtr = (BYTE*)(keyBlob + sizeof(PUBLICKEYSTRUC) + sizeof(ALG_ID)); + for (n = 0; n < dwKeyMaterial; n++) { + pbPtr[n] = pbKeyMaterial[dwKeyMaterial - n - 1]; + } + pbPtr += dwKeyMaterial; + + /* skip reserved byte */ + pbPtr += 1; + + /* Generate random data for the rest of the buffer */ + if((rndBlobSize > 0) && !CryptGenRandom(hProv, rndBlobSize, pbPtr)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptGenRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "rndBlobSize=%ld", rndBlobSize); + goto done; + } + /* aleksey: why are we doing this? */ + for (n = 0; n < rndBlobSize; n++) { + if (pbPtr[n] == 0) pbPtr[n] = 1; + } + + /* set magic number at the end */ + keyBlob[keyBlobLen - 2] = 2; + + if(!CryptImportKey(hProv, keyBlob , keyBlobLen, hPrivateKey, CRYPT_EXPORTABLE, hSessionKey)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptImportKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "algId=%d", dwAlgId); + goto done; + } + + /* success */ + res = TRUE; + +done: + if(hTempKey != 0) { + CryptDestroyKey(hTempKey); + } + if(keyBlob != NULL) { + xmlFree(keyBlob); + } + return(res); +} + +#ifndef XMLSEC_NO_AES +/************************************************************************** + * + * <xmlsec:AESKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataAesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameAESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefAESKeyValue, /* const xmlChar* href; */ + xmlSecNodeAESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecMSCryptoSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecMSCryptoSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoKeyDataAesGetKlass: + * + * The AES key data klass. + * + * Returns: AES key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataAesGetKlass(void) { + return(&xmlSecMSCryptoKeyDataAesKlass); +} + +/** + * xmlSecMSCryptoKeyDataAesSet: + * @data: the pointer to AES key data. + * @buf: the pointer to key value. + * @bufSize: the key value size (in bytes). + * + * Sets the value of AES key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeyDataAesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataAesId), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES +/************************************************************************** + * + * <xmlsec:DESKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataDesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameDESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDESKeyValue, /* const xmlChar* href; */ + xmlSecNodeDESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecMSCryptoSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecMSCryptoSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoKeyDataDesGetKlass: + * + * The DES key data klass. + * + * Returns: DES key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataDesGetKlass(void) { + return(&xmlSecMSCryptoKeyDataDesKlass); +} +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_HMAC +/************************************************************************** + * + * <xmlsec:HMACKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataHmacKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameHMACKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefHMACKeyValue, /* const xmlChar* href; */ + xmlSecNodeHMACKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecMSCryptoSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecMSCryptoSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecMSCryptoSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecMSCryptoSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoKeyDataHmacGetKlass: + * + * The HMAC key data klass. + * + * Returns: HMAC key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataHmacGetKlass(void) { + return(&xmlSecMSCryptoKeyDataHmacKlass); +} + +/** + * xmlSecMSCryptoKeyDataHmacSet: + * @data: the pointer to HMAC key data. + * @buf: the pointer to key value. + * @bufSize: the key value size (in bytes). + * + * Sets the value of HMAC key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeyDataHmacSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataHmacId), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} + + +#endif /* XMLSEC_NO_HMAC */ + + + diff --git a/src/mscrypto/x509.c b/src/mscrypto/x509.c new file mode 100644 index 00000000..5ae025f6 --- /dev/null +++ b/src/mscrypto/x509.c @@ -0,0 +1,2281 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ + +#include "globals.h" + +#ifndef XMLSEC_NO_X509 + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <time.h> + +#include <windows.h> +#include <wincrypt.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/x509.h> +#include <xmlsec/base64.h> +#include <xmlsec/bn.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/x509.h> +#include <xmlsec/mscrypto/certkeys.h> +#include "private.h" + + +/************************************************************************* + * + * X509 utility functions + * + ************************************************************************/ +static int xmlSecMSCryptoX509DataNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509CertificateNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509CertificateNodeWrite (PCCERT_CONTEXT cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509SubjectNameNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509SubjectNameNodeWrite (PCCERT_CONTEXT cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509IssuerSerialNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509IssuerSerialNodeWrite (PCCERT_CONTEXT cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509SKINodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509SKINodeWrite (PCCERT_CONTEXT cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509CRLNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoX509CRLNodeWrite (PCCRL_CONTEXT crl, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, + xmlSecKeyPtr key, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static PCCERT_CONTEXT xmlSecMSCryptoX509CertDerRead (const xmlSecByte* buf, + xmlSecSize size); +static PCCERT_CONTEXT xmlSecMSCryptoX509CertBase64DerRead (xmlChar* buf); +static xmlChar* xmlSecMSCryptoX509CertBase64DerWrite (PCCERT_CONTEXT cert, + int base64LineWrap); +static PCCRL_CONTEXT xmlSecMSCryptoX509CrlDerRead (xmlSecByte* buf, + xmlSecSize size, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static PCCRL_CONTEXT xmlSecMSCryptoX509CrlBase64DerRead (xmlChar* buf, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static xmlChar* xmlSecMSCryptoX509CrlBase64DerWrite (PCCRL_CONTEXT crl, + int base64LineWrap); +static xmlChar* xmlSecMSCryptoX509NameWrite(PCERT_NAME_BLOB nm); +static int xmlSecMSCryptoASN1IntegerWrite (xmlNodePtr node, + PCRYPT_INTEGER_BLOB num); +static xmlChar* xmlSecMSCryptoX509SKIWrite (PCCERT_CONTEXT cert); +static void xmlSecMSCryptoX509CertDebugDump (PCCERT_CONTEXT cert, + FILE* output); +static void xmlSecMSCryptoX509CertDebugXmlDump (PCCERT_CONTEXT cert, + FILE* output); +static int xmlSecMSCryptoX509CertGetTime (FILETIME t, + time_t* res); + +/************************************************************************* + * + * Internal MSCrypto X509 data CTX + * + ************************************************************************/ +typedef struct _xmlSecMSCryptoX509DataCtx xmlSecMSCryptoX509DataCtx, + *xmlSecMSCryptoX509DataCtxPtr; + +struct _xmlSecMSCryptoX509DataCtx { + PCCERT_CONTEXT keyCert; + + HCERTSTORE hMemStore; + unsigned int numCerts; + unsigned int numCrls; +}; + +/************************************************************************** + * + * <dsig:X509Data> processing + * + * + * The X509Data Element (http://www.w3.org/TR/xmldsig-core/#sec-X509Data) + * + * An X509Data element within KeyInfo contains one or more identifiers of keys + * or X509 certificates (or certificates' identifiers or a revocation list). + * The content of X509Data is: + * + * 1. At least one element, from the following set of element types; any of these may appear together or more than once iff (if and only if) each instance describes or is related to the same certificate: + * 2. + * * The X509IssuerSerial element, which contains an X.509 issuer + * distinguished name/serial number pair that SHOULD be compliant + * with RFC2253 [LDAP-DN], + * * The X509SubjectName element, which contains an X.509 subject + * distinguished name that SHOULD be compliant with RFC2253 [LDAP-DN], + * * The X509SKI element, which contains the base64 encoded plain (i.e. + * non-DER-encoded) value of a X509 V.3 SubjectKeyIdentifier extension. + * * The X509Certificate element, which contains a base64-encoded [X509v3] + * certificate, and + * * Elements from an external namespace which accompanies/complements any + * of the elements above. + * * The X509CRL element, which contains a base64-encoded certificate + * revocation list (CRL) [X509v3]. + * + * Any X509IssuerSerial, X509SKI, and X509SubjectName elements that appear + * MUST refer to the certificate or certificates containing the validation key. + * All such elements that refer to a particular individual certificate MUST be + * grouped inside a single X509Data element and if the certificate to which + * they refer appears, it MUST also be in that X509Data element. + * + * Any X509IssuerSerial, X509SKI, and X509SubjectName elements that relate to + * the same key but different certificates MUST be grouped within a single + * KeyInfo but MAY occur in multiple X509Data elements. + * + * All certificates appearing in an X509Data element MUST relate to the + * validation key by either containing it or being part of a certification + * chain that terminates in a certificate containing the validation key. + * + * No ordering is implied by the above constraints. + * + * Note, there is no direct provision for a PKCS#7 encoded "bag" of + * certificates or CRLs. However, a set of certificates and CRLs can occur + * within an X509Data element and multiple X509Data elements can occur in a + * KeyInfo. Whenever multiple certificates occur in an X509Data element, at + * least one such certificate must contain the public key which verifies the + * signature. + * + * Schema Definition + * + * <element name="X509Data" type="ds:X509DataType"/> + * <complexType name="X509DataType"> + * <sequence maxOccurs="unbounded"> + * <choice> + * <element name="X509IssuerSerial" type="ds:X509IssuerSerialType"/> + * <element name="X509SKI" type="base64Binary"/> + * <element name="X509SubjectName" type="string"/> + * <element name="X509Certificate" type="base64Binary"/> + * <element name="X509CRL" type="base64Binary"/> + * <any namespace="##other" processContents="lax"/> + * </choice> + * </sequence> + * </complexType> + * <complexType name="X509IssuerSerialType"> + * <sequence> + * <element name="X509IssuerName" type="string"/> + * <element name="X509SerialNumber" type="integer"/> + * </sequence> + * </complexType> + * + * DTD + * + * <!ELEMENT X509Data ((X509IssuerSerial | X509SKI | X509SubjectName | + * X509Certificate | X509CRL)+ %X509.ANY;)> + * <!ELEMENT X509IssuerSerial (X509IssuerName, X509SerialNumber) > + * <!ELEMENT X509IssuerName (#PCDATA) > + * <!ELEMENT X509SubjectName (#PCDATA) > + * <!ELEMENT X509SerialNumber (#PCDATA) > + * <!ELEMENT X509SKI (#PCDATA) > + * <!ELEMENT X509Certificate (#PCDATA) > + * <!ELEMENT X509CRL (#PCDATA) > + * + * ----------------------------------------------------------------------- + * + * xmlSecMSCryptoX509DataCtx is located after xmlSecTransform + * + *************************************************************************/ +#define xmlSecMSCryptoX509DataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecMSCryptoX509DataCtx)) +#define xmlSecMSCryptoX509DataGetCtx(data) \ + ((xmlSecMSCryptoX509DataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + +static int xmlSecMSCryptoKeyDataX509Initialize (xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataX509Duplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecMSCryptoKeyDataX509Finalize (xmlSecKeyDataPtr data); +static int xmlSecMSCryptoKeyDataX509XmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoKeyDataX509XmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static xmlSecKeyDataType xmlSecMSCryptoKeyDataX509GetType (xmlSecKeyDataPtr data); +static const xmlChar* xmlSecMSCryptoKeyDataX509GetIdentifier (xmlSecKeyDataPtr data); + +static void xmlSecMSCryptoKeyDataX509DebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoKeyDataX509DebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + + + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataX509Klass = { + sizeof(xmlSecKeyDataKlass), + xmlSecMSCryptoX509DataSize, + + /* data */ + xmlSecNameX509Data, + xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefX509Data, /* const xmlChar* href; */ + xmlSecNodeX509Data, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecMSCryptoKeyDataX509Initialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecMSCryptoKeyDataX509Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecMSCryptoKeyDataX509Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecMSCryptoKeyDataX509GetType, /* xmlSecKeyDataGetTypeMethod getType; */ + NULL, /* xmlSecKeyDataGetSizeMethod getSize; */ + xmlSecMSCryptoKeyDataX509GetIdentifier, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecMSCryptoKeyDataX509XmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecMSCryptoKeyDataX509XmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecMSCryptoKeyDataX509DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecMSCryptoKeyDataX509DebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoKeyDataX509GetKlass: + * + * The MSCrypto X509 key data klass (http://www.w3.org/TR/xmldsig-core/#sec-X509Data). + * + * Returns: the X509 data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataX509GetKlass(void) { + return(&xmlSecMSCryptoKeyDataX509Klass); +} + +/** + * xmlSecMSCryptoKeyDataX509GetKeyCert: + * @data: the pointer to X509 key data. + * + * Gets the certificate from which the key was extracted. + * + * Returns: the key's certificate or NULL if key data was not used for key + * extraction or an error occurs. + */ +PCCERT_CONTEXT +xmlSecMSCryptoKeyDataX509GetKeyCert(xmlSecKeyDataPtr data) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), NULL); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + + return(ctx->keyCert); +} + +/** + * xmlSecMSCryptoKeyDataX509AdoptKeyCert: + * @data: the pointer to X509 key data. + * @cert: the pointer to MSCRYPTO X509 certificate. + * + * Sets the key's certificate in @data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeyDataX509AdoptKeyCert(xmlSecKeyDataPtr data, PCCERT_CONTEXT cert) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->keyCert != NULL) { + CertFreeCertificateContext(ctx->keyCert); + ctx->keyCert = 0; + } + ctx->keyCert = cert; + + return(0); +} + +/** + * xmlSecMSCryptoKeyDataX509AdoptCert: + * @data: the pointer to X509 key data. + * @cert: the pointer to MSCRYPTO X509 certificate. + * + * Adds certificate to the X509 key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeyDataX509AdoptCert(xmlSecKeyDataPtr data, PCCERT_CONTEXT cert) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->hMemStore != 0, -1); + + if (!CertAddCertificateContextToStore(ctx->hMemStore, cert, CERT_STORE_ADD_ALWAYS, NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CertAddCertificateContextToStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + CertFreeCertificateContext(cert); + ctx->numCerts++; + + return(0); +} + +/** + * xmlSecMSCryptoKeyDataX509GetCert: + * @data: the pointer to X509 key data. + * @pos: the desired certificate position. + * + * Gets a certificate from X509 key data. + * + * Returns: the pointer to certificate or NULL if @pos is larger than the + * number of certificates in @data or an error occurs. + */ +PCCERT_CONTEXT +xmlSecMSCryptoKeyDataX509GetCert(xmlSecKeyDataPtr data, xmlSecSize pos) { + xmlSecMSCryptoX509DataCtxPtr ctx; + PCCERT_CONTEXT pCert = NULL; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), NULL); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->hMemStore != 0, NULL); + xmlSecAssert2(ctx->numCerts > pos, NULL); + + while ((pCert = CertEnumCertificatesInStore(ctx->hMemStore, pCert)) && (pos > 0)) { + pos--; + } + + return(pCert); +} + +/** + * xmlSecMSCryptoKeyDataX509GetCertsSize: + * @data: the pointer to X509 key data. + * + * Gets the number of certificates in @data. + * + * Returns: te number of certificates in @data. + */ +xmlSecSize +xmlSecMSCryptoKeyDataX509GetCertsSize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), 0); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(ctx->numCerts); +} + +/** + * xmlSecMSCryptoKeyDataX509AdoptCrl: + * @data: the pointer to X509 key data. + * @crl: the pointer to MSCrypto X509 CRL. + * + * Adds CRL to the X509 key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoKeyDataX509AdoptCrl(xmlSecKeyDataPtr data, PCCRL_CONTEXT crl) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(crl != 0, -1); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->hMemStore != 0, -1); + + if (!CertAddCRLContextToStore(ctx->hMemStore, crl, CERT_STORE_ADD_ALWAYS, NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CertAddCRLContextToStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ctx->numCrls++; + + return(0); +} + +/** + * xmlSecMSCryptoKeyDataX509GetCrl: + * @data: the pointer to X509 key data. + * @pos: the desired CRL position. + * + * Gets a CRL from X509 key data. + * + * Returns: the pointer to CRL or NULL if @pos is larger than the + * number of CRLs in @data or an error occurs. + */ +PCCRL_CONTEXT +xmlSecMSCryptoKeyDataX509GetCrl(xmlSecKeyDataPtr data, xmlSecSize pos) { + xmlSecMSCryptoX509DataCtxPtr ctx; + PCCRL_CONTEXT pCRL = NULL; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), NULL); + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->hMemStore != 0, NULL); + xmlSecAssert2(ctx->numCrls > pos, NULL); + + while ((pCRL = CertEnumCRLsInStore(ctx->hMemStore, pCRL)) && (pos > 0)) { + pos--; + } + + return(pCRL); +} + +/** + * xmlSecMSCryptoKeyDataX509GetCrlsSize: + * @data: the pointer to X509 key data. + * + * Gets the number of CRLs in @data. + * + * Returns: te number of CRLs in @data. + */ +xmlSecSize +xmlSecMSCryptoKeyDataX509GetCrlsSize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), 0); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(ctx->numCrls); +} + +static int +xmlSecMSCryptoKeyDataX509Initialize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoX509DataCtx)); + + ctx->hMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY, + 0, + 0, + CERT_STORE_CREATE_NEW_FLAG, + NULL); + if (ctx->hMemStore == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecMSCryptoKeyDataX509Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + PCCERT_CONTEXT certSrc, certDst; + PCCRL_CONTEXT crlSrc, crlDst; + xmlSecSize size, pos; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecMSCryptoKeyDataX509Id), -1); + + /* copy certsList */ + size = xmlSecMSCryptoKeyDataX509GetCertsSize(src); + for(pos = 0; pos < size; ++pos) { + /* TBD: function below does linear scan, eliminate loop within + * loop + */ + certSrc = xmlSecMSCryptoKeyDataX509GetCert(src, pos); + if(certSrc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)), + "xmlSecMSCryptoKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + certDst = CertDuplicateCertificateContext(certSrc); + if(certDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(dst, certDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(certDst); + return(-1); + } + } + + /* copy crls */ + size = xmlSecMSCryptoKeyDataX509GetCrlsSize(src); + for(pos = 0; pos < size; ++pos) { + crlSrc = xmlSecMSCryptoKeyDataX509GetCrl(src, pos); + if(crlSrc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)), + "xmlSecMSCryptoKeyDataX509GetCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + crlDst = CertDuplicateCRLContext(crlSrc); + if(crlDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "CertDuplicateCRLContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCrl(dst, crlDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataX509AdoptCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCRLContext(crlDst); + return(-1); + } + } + + /* copy key cert if exist */ + certSrc = xmlSecMSCryptoKeyDataX509GetKeyCert(src); + if(certSrc != NULL) { + certDst = CertDuplicateCertificateContext(certSrc); + if(certDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ret = xmlSecMSCryptoKeyDataX509AdoptKeyCert(dst, certDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecMSCryptoKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(certDst); + return(-1); + } + } + return(0); +} + +static void +xmlSecMSCryptoKeyDataX509Finalize(xmlSecKeyDataPtr data) { + xmlSecMSCryptoX509DataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id)); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert(ctx != NULL); + + if(ctx->keyCert != NULL) { + CertFreeCertificateContext(ctx->keyCert); + ctx->keyCert = NULL; + } + + if (ctx->hMemStore != 0) { + if (!CertCloseStore(ctx->hMemStore, CERT_CLOSE_STORE_FORCE_FLAG)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertCloseStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return; + } + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoX509DataCtx)); +} + +static int +xmlSecMSCryptoKeyDataX509XmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataX509Id, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + data = xmlSecKeyEnsureData(key, id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecMSCryptoX509DataNodeRead(data, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoX509DataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) == 0) { + ret = xmlSecMSCryptoKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataX509VerifyAndExtractKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +static int +xmlSecMSCryptoKeyDataX509XmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + PCCERT_CONTEXT cert; + PCCRL_CONTEXT crl; + xmlSecSize size, pos; + int content = 0; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataX509Id, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + content = xmlSecX509DataGetNodeContent (node, 1, keyInfoCtx); + if (content < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecX509DataGetNodeContent", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "content=%d", content); + return(-1); + } else if(content == 0) { + /* by default we are writing certificates and crls */ + content = XMLSEC_X509DATA_DEFAULT; + } + + /* get x509 data */ + data = xmlSecKeyGetData(key, id); + if(data == NULL) { + /* no x509 data in the key */ + return(0); + } + + /* write certs */ + size = xmlSecMSCryptoKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecMSCryptoKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + if((content & XMLSEC_X509DATA_CERTIFICATE_NODE) != 0) { + ret = xmlSecMSCryptoX509CertificateNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoX509CertificateNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_SUBJECTNAME_NODE) != 0) { + ret = xmlSecMSCryptoX509SubjectNameNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoX509SubjectNameNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_ISSUERSERIAL_NODE) != 0) { + ret = xmlSecMSCryptoX509IssuerSerialNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoX509IssuerSerialNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_SKI_NODE) != 0) { + ret = xmlSecMSCryptoX509SKINodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoX509SKINodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + } + + /* write crls if needed */ + if((content & XMLSEC_X509DATA_CRL_NODE) != 0) { + size = xmlSecMSCryptoKeyDataX509GetCrlsSize(data); + for(pos = 0; pos < size; ++pos) { + crl = xmlSecMSCryptoKeyDataX509GetCrl(data, pos); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataX509GetCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + ret = xmlSecMSCryptoX509CRLNodeWrite(crl, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoX509CRLNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + } + + return(0); +} + +static xmlSecKeyDataType +xmlSecMSCryptoKeyDataX509GetType(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), xmlSecKeyDataTypeUnknown); + + /* TODO: return verified/not verified status */ + return(xmlSecKeyDataTypeUnknown); +} + +static const xmlChar* +xmlSecMSCryptoKeyDataX509GetIdentifier(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), NULL); + + /* TODO */ + return(NULL); +} + +static void +xmlSecMSCryptoKeyDataX509DebugDump(xmlSecKeyDataPtr data, FILE* output) { + PCCERT_CONTEXT cert; + xmlSecSize size, pos; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== X509 Data:\n"); + cert = xmlSecMSCryptoKeyDataX509GetKeyCert(data); + if(cert != NULL) { + fprintf(output, "==== Key Certificate:\n"); + xmlSecMSCryptoX509CertDebugDump(cert, output); + } + + size = xmlSecMSCryptoKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecMSCryptoKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return; + } + fprintf(output, "==== Certificate:\n"); + xmlSecMSCryptoX509CertDebugDump(cert, output); + } + + /* we don't print out crls */ +} + +static void +xmlSecMSCryptoKeyDataX509DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + PCCERT_CONTEXT cert; + xmlSecSize size, pos; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "<X509Data>\n"); + cert = xmlSecMSCryptoKeyDataX509GetKeyCert(data); + if(cert != NULL) { + fprintf(output, "<KeyCertificate>\n"); + xmlSecMSCryptoX509CertDebugXmlDump(cert, output); + fprintf(output, "</KeyCertificate>\n"); + } + + size = xmlSecMSCryptoKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecMSCryptoKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return; + } + fprintf(output, "<Certificate>\n"); + xmlSecMSCryptoX509CertDebugXmlDump(cert, output); + fprintf(output, "</Certificate>\n"); + } + + /* we don't print out crls */ + fprintf(output, "</X509Data>\n"); +} + +static int +xmlSecMSCryptoX509DataNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + for(cur = xmlSecGetNextElementNode(node->children); + cur != NULL; + cur = xmlSecGetNextElementNode(cur->next)) { + + ret = 0; + if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) { + ret = xmlSecMSCryptoX509CertificateNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) { + ret = xmlSecMSCryptoX509SubjectNameNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) { + ret = xmlSecMSCryptoX509IssuerSerialNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) { + ret = xmlSecMSCryptoX509SKINodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) { + ret = xmlSecMSCryptoX509CRLNodeRead(data, cur, keyInfoCtx); + } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CHILD) != 0) { + /* laxi schema validation: ignore unknown nodes */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "read node failed"); + return(-1); + } + } + return(0); +} + +static int +xmlSecMSCryptoX509CertificateNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar *content; + PCCERT_CONTEXT cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + content = xmlNodeGetContent(node); + if((content == NULL) || (xmlSecIsEmptyString(content) == 1)) { + if(content != NULL) { + xmlFree(content); + } + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); + } + + cert = xmlSecMSCryptoX509CertBase64DerRead(content); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoX509CertBase64DerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(cert); + xmlFree(content); + return(-1); + } + + xmlFree(content); + return(0); +} + +static int +xmlSecMSCryptoX509CertificateNodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar* buf; + xmlNodePtr cur; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + /* set base64 lines size from context */ + buf = xmlSecMSCryptoX509CertBase64DerWrite(cert, keyInfoCtx->base64LineSize); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509CertBase64DerWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecAddChild(node, xmlSecNodeX509Certificate, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509Certificate)); + xmlFree(buf); + return(-1); + } + + /* todo: add \n around base64 data - from context */ + /* todo: add errors check */ + xmlNodeSetContent(cur, xmlSecStringCR); + xmlNodeSetContent(cur, buf); + xmlFree(buf); + return(0); +} + +static int +xmlSecMSCryptoX509SubjectNameNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlChar* subject; + PCCERT_CONTEXT cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCryptoX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + subject = xmlNodeGetContent(node); + if((subject == NULL) || (xmlSecIsEmptyString(subject) == 1)) { + if(subject != NULL) { + xmlFree(subject); + } + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); + } + + cert = xmlSecMSCryptoX509StoreFindCert(x509Store, subject, NULL, NULL, NULL, keyInfoCtx); + if(cert == NULL){ + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + NULL, + XMLSEC_ERRORS_R_CERT_NOT_FOUND, + "subject=%s", + xmlSecErrorsSafeString(subject)); + xmlFree(subject); + return(-1); + } + xmlFree(subject); + return(0); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(cert); + xmlFree(subject); + return(-1); + } + + xmlFree(subject); + return(0); +} + +static int +xmlSecMSCryptoX509SubjectNameNodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlChar* buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + buf = xmlSecMSCryptoX509NameWrite(&(cert->pCertInfo->Subject)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509NameWrite(&(cert->pCertInfo->Subject))", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecAddChild(node, xmlSecNodeX509SubjectName, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SubjectName)); + xmlFree(buf); + return(-1); + } + xmlSecNodeEncodeAndSetContent(cur, buf); + xmlFree(buf); + return(0); +} + +static int +xmlSecMSCryptoX509IssuerSerialNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlNodePtr cur; + xmlChar *issuerName; + xmlChar *issuerSerial; + PCCERT_CONTEXT cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCryptoX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecGetNextElementNode(node->children); + if(cur == NULL) { + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeX509IssuerName), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + return(0); + } + + /* the first is required node X509IssuerName */ + if(!xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeX509IssuerName), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + issuerName = xmlNodeGetContent(cur); + if(issuerName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509IssuerName)); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is required node X509SerialNumber */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber)); + xmlFree(issuerName); + return(-1); + } + issuerSerial = xmlNodeGetContent(cur); + if(issuerSerial == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + xmlFree(issuerName); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(issuerSerial); + xmlFree(issuerName); + return(-1); + } + + cert = xmlSecMSCryptoX509StoreFindCert(x509Store, NULL, issuerName, issuerSerial, NULL, keyInfoCtx); + if(cert == NULL){ + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + NULL, + XMLSEC_ERRORS_R_CERT_NOT_FOUND, + "issuerName=%s;issuerSerial=%s", + xmlSecErrorsSafeString(issuerName), + xmlSecErrorsSafeString(issuerSerial)); + xmlFree(issuerSerial); + xmlFree(issuerName); + return(-1); + } + + xmlFree(issuerSerial); + xmlFree(issuerName); + return(0); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(cert); + xmlFree(issuerSerial); + xmlFree(issuerName); + return(-1); + } + + xmlFree(issuerSerial); + xmlFree(issuerName); + return(0); +} + +static int +xmlSecMSCryptoX509IssuerSerialNodeWrite(PCCERT_CONTEXT cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlNodePtr cur; + xmlNodePtr issuerNameNode; + xmlNodePtr issuerNumberNode; + xmlChar* buf; + int ret; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* create xml nodes */ + cur = xmlSecAddChild(node, xmlSecNodeX509IssuerSerial, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial)); + return(-1); + } + + issuerNameNode = xmlSecAddChild(cur, xmlSecNodeX509IssuerName, xmlSecDSigNs); + if(issuerNameNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509IssuerName)); + return(-1); + } + + issuerNumberNode = xmlSecAddChild(cur, xmlSecNodeX509SerialNumber, xmlSecDSigNs); + if(issuerNumberNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber)); + return(-1); + } + + /* write data */ + buf = xmlSecMSCryptoX509NameWrite(&(cert->pCertInfo->Issuer)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509NameWrite(&(cert->pCertInfo->Issuer))", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecNodeEncodeAndSetContent(issuerNameNode, buf); + xmlFree(buf); + + ret = xmlSecMSCryptoASN1IntegerWrite(issuerNumberNode, &(cert->pCertInfo->SerialNumber)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoASN1IntegerWrite(&(cert->serialNumber))", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static int +xmlSecMSCryptoX509SKINodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlChar* ski; + PCCERT_CONTEXT cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCryptoX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ski = xmlNodeGetContent(node); + if((ski == NULL) || (xmlSecIsEmptyString(ski) == 1)) { + if(ski != NULL) { + xmlFree(ski); + } + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SKI)); + return(-1); + } + return(0); + } + + cert = xmlSecMSCryptoX509StoreFindCert(x509Store, NULL, NULL, NULL, ski, keyInfoCtx); + if(cert == NULL){ + xmlFree(ski); + + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_UNKNOWN_CERT) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + NULL, + XMLSEC_ERRORS_R_CERT_NOT_FOUND, + "ski=%s", + xmlSecErrorsSafeString(ski)); + return(-1); + } + return(0); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(cert); + xmlFree(ski); + return(-1); + } + + xmlFree(ski); + return(0); +} + +static int +xmlSecMSCryptoX509SKINodeWrite(PCCERT_CONTEXT cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlChar *buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + buf = xmlSecMSCryptoX509SKIWrite(cert); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509SKIWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecAddChild(node, xmlSecNodeX509SKI, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "new_node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SKI)); + xmlFree(buf); + return(-1); + } + xmlSecNodeEncodeAndSetContent(cur, buf); + xmlFree(buf); + + return(0); +} + +static int +xmlSecMSCryptoX509CRLNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar *content; + PCCRL_CONTEXT crl; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + content = xmlNodeGetContent(node); + if((content == NULL) || (xmlSecIsEmptyString(content) == 1)) { + if(content != NULL) { + xmlFree(content); + } + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_EMPTY_NODE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); + } + + crl = xmlSecMSCryptoX509CrlBase64DerRead(content, keyInfoCtx); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoX509CrlBase64DerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + if (0 != xmlSecMSCryptoKeyDataX509AdoptCrl(data, crl)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataX509AdoptCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + CertFreeCRLContext(crl); + return(-1); + } + + xmlFree(content); + return(0); +} + +static int +xmlSecMSCryptoX509CRLNodeWrite(PCCRL_CONTEXT crl, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar* buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(crl != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + /* set base64 lines size from context */ + buf = xmlSecMSCryptoX509CrlBase64DerWrite(crl, keyInfoCtx->base64LineSize); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509CrlBase64DerWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecAddChild(node, xmlSecNodeX509CRL, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "new_node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509CRL)); + xmlFree(buf); + return(-1); + } + /* todo: add \n around base64 data - from context */ + /* todo: add errors check */ + xmlNodeSetContent(cur, xmlSecStringCR); + xmlNodeSetContent(cur, buf); + xmlFree(buf); + + return(0); +} + + +static int +xmlSecMSCryptoKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, xmlSecKeyPtr key, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecMSCryptoX509DataCtxPtr ctx; + xmlSecKeyDataStorePtr x509Store; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataX509Id), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + ctx = xmlSecMSCryptoX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->hMemStore != 0, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecMSCryptoX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((ctx->keyCert == NULL) && (xmlSecKeyGetValue(key) == NULL)) { + PCCERT_CONTEXT cert; + + cert = xmlSecMSCryptoX509StoreVerify(x509Store, ctx->hMemStore, keyInfoCtx); + if(cert != NULL) { + xmlSecKeyDataPtr keyValue = NULL; + PCCERT_CONTEXT pCert = NULL; + + ctx->keyCert = CertDuplicateCertificateContext(cert); + if(ctx->keyCert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* search key according to KeyReq */ + pCert = CertDuplicateCertificateContext( ctx->keyCert ) ; + if( pCert == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CertDuplicateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + + if( ( keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate ) == xmlSecKeyDataTypePrivate ) { + keyValue = xmlSecMSCryptoCertAdopt( pCert, xmlSecKeyDataTypePrivate ) ; + if(keyValue == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoCertAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext( pCert ) ; + return(-1); + } + pCert = NULL ; + } else if( ( keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePublic ) == xmlSecKeyDataTypePublic ) { + keyValue = xmlSecMSCryptoCertAdopt( pCert, xmlSecKeyDataTypePublic ) ; + if(keyValue == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoCertAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext( pCert ) ; + return(-1); + } + pCert = NULL ; + } + + /* verify that the key matches our expectations */ + if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), keyValue) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeyReqMatchKeyValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(keyValue); + return(-1); + } + + ret = xmlSecKeySetValue(key, keyValue); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(keyValue); + return(-1); + } + + ret = xmlSecMSCryptoX509CertGetTime(ctx->keyCert->pCertInfo->NotBefore, &(key->notValidBefore)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoX509CertGetTime", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "notValidBefore"); + return(-1); + } + + ret = xmlSecMSCryptoX509CertGetTime(ctx->keyCert->pCertInfo->NotAfter, &(key->notValidAfter)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoX509CertGetTime", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "notValidAfter"); + return(-1); + } + } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_STOP_ON_INVALID_CERT) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + NULL, + XMLSEC_ERRORS_R_CERT_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +static int +xmlSecMSCryptoX509CertGetTime(FILETIME t, time_t* res) { + LONGLONG result; + + xmlSecAssert2(res != NULL, -1); + + result = t.dwHighDateTime; + result = (result) << 32; + result |= t.dwLowDateTime; + result /= 10000; /* Convert from 100 nano-sec periods to seconds. */ +#if defined(__MINGW32__) + result -= 11644473600000ULL; /* Convert from Windows epoch to Unix epoch */ +#else + result -= 11644473600000; /* Convert from Windows epoch to Unix epoch */ +#endif + + (*res) = (time_t)result; + + return(0); +} + +static PCCERT_CONTEXT +xmlSecMSCryptoX509CertBase64DerRead(xmlChar* buf) { + int ret; + + xmlSecAssert2(buf != NULL, NULL); + + /* usual trick with base64 decoding "in-place" */ + ret = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecMSCryptoX509CertDerRead((xmlSecByte*)buf, ret)); +} + + +static PCCERT_CONTEXT +xmlSecMSCryptoX509CertDerRead(const xmlSecByte* buf, xmlSecSize size) { + PCCERT_CONTEXT cert; + + xmlSecAssert2(buf != NULL, NULL); + xmlSecAssert2(size > 0, NULL); + + cert = CertCreateCertificateContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, size); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertCreateCertificateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(cert); +} + +static xmlChar* +xmlSecMSCryptoX509CertBase64DerWrite(PCCERT_CONTEXT cert, int base64LineWrap) { + xmlChar *res = NULL; + xmlSecByte *p = NULL; + long size; + + xmlSecAssert2(cert != NULL, NULL); + + p = cert->pbCertEncoded; + size = cert->cbCertEncoded; + if((size <= 0) || (p == NULL)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cert->pbCertEncoded", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecBase64Encode(p, size, base64LineWrap); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(res); +} + +static PCCRL_CONTEXT +xmlSecMSCryptoX509CrlBase64DerRead(xmlChar* buf, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + int ret; + + xmlSecAssert2(buf != NULL, NULL); + + /* usual trick with base64 decoding "in-place" */ + ret = xmlSecBase64Decode(buf, (xmlSecByte*)buf, xmlStrlen(buf)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecMSCryptoX509CrlDerRead((xmlSecByte*)buf, ret, keyInfoCtx)); +} + + +static PCCRL_CONTEXT +xmlSecMSCryptoX509CrlDerRead(xmlSecByte* buf, xmlSecSize size, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + PCCRL_CONTEXT crl = NULL; + + xmlSecAssert2(buf != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + xmlSecAssert2(size > 0, NULL); + + crl = CertCreateCRLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, buf, size); + + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertCreateCRLContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(crl); + } + +static xmlChar* +xmlSecMSCryptoX509CrlBase64DerWrite(PCCRL_CONTEXT crl, int base64LineWrap) { + xmlChar *res = NULL; + xmlSecByte *p = NULL; + long size; + + xmlSecAssert2(crl != NULL, NULL); + + p = crl->pbCrlEncoded; + size = crl->cbCrlEncoded; + if((size <= 0) || (p == NULL)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "crl->pbCrlEncoded", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecBase64Encode(p, size, base64LineWrap); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(res); +} + +static xmlChar* +xmlSecMSCryptoX509NameWrite(PCERT_NAME_BLOB nm) { + LPTSTR resT = NULL; + xmlChar *res = NULL; + DWORD csz; + + + xmlSecAssert2(nm->pbData != NULL, NULL); + xmlSecAssert2(nm->cbData > 0, NULL); + + csz = CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, nm, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, NULL, 0); + if(csz <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertNameToStr", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + resT = (LPTSTR)xmlMalloc(sizeof(TCHAR) * (csz + 1)); + if (NULL == resT) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(WCHAR) * (csz + 1)); + return (NULL); + } + + csz = CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, nm, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, resT, csz + 1); + if (csz <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertNameToStr", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(resT); + return(NULL); + } + + res = xmlSecMSCryptoConvertTstrToUtf8(resT); + if (NULL == res) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoConvertTstrToUtf8", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(resT); + return(NULL); + } + + return(res); +} + + + +static int +xmlSecMSCryptoASN1IntegerWrite(xmlNodePtr node, PCRYPT_INTEGER_BLOB num) { + xmlSecBn bn; + int ret; + + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(num != NULL, -1); + + ret = xmlSecBnInitialize(&bn, num->cbData + 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%ld", num->cbData + 1); + return(-1); + } + + ret = xmlSecBnSetData(&bn, num->pbData, num->cbData); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBnFinalize(&bn); + return(-1); + } + + /* I have no clue why at a sudden a swap is needed to + * convert from lsb... This code is purely based upon + * trial and error :( WK + */ + ret = xmlSecBnSetNodeValue(&bn, node, xmlSecBnDec, 1, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnSetNodeValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBnFinalize(&bn); + return(-1); + } + + xmlSecBnFinalize(&bn); + return(0); +} + +static xmlChar* +xmlSecMSCryptoX509SKIWrite(PCCERT_CONTEXT cert) { + xmlChar *res = NULL; + DWORD dwSize; + BYTE *bSKI = NULL; + PCERT_EXTENSION pCertExt; + + xmlSecAssert2(cert != NULL, NULL); + + /* First check if the SKI extension actually exists, otherwise we get a SHA1 hash o fthe key/cert */ + pCertExt = CertFindExtension(szOID_SUBJECT_KEY_IDENTIFIER, cert->pCertInfo->cExtension, cert->pCertInfo->rgExtension); + if (pCertExt == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertFindExtension", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + if (!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, NULL, &dwSize) || dwSize < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertGetCertificateContextProperty", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + bSKI = xmlMalloc(dwSize); + if (NULL == bSKI) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + if (!CertGetCertificateContextProperty(cert, CERT_KEY_IDENTIFIER_PROP_ID, bSKI, &dwSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertGetCertificateContextProperty", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(bSKI); + return (NULL); + } + + if (NULL == bSKI) { + return(NULL); + } + + res = xmlSecBase64Encode(bSKI, dwSize, 0); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(bSKI); + return(NULL); + } + xmlFree(bSKI); + + return(res); +} + + +static void +xmlSecMSCryptoX509CertDebugDump(PCCERT_CONTEXT cert, FILE* output) { + PCRYPT_INTEGER_BLOB sn; + unsigned int i; + xmlChar * subject = NULL; + xmlChar * issuer = NULL; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "=== X509 Certificate\n"); + + /* subject */ + subject = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL); + if(subject == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoX509GetNameString", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "subject"); + goto done; + } + fprintf(output, "==== Subject Name: %s\n", subject); + + /* issuer */ + issuer = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, CERT_NAME_ISSUER_FLAG, NULL); + if(issuer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoX509GetNameString", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "issuer"); + goto done; + } + fprintf(output, "==== Issuer Name: %s\n", issuer); + + /* serial number */ + sn = &(cert->pCertInfo->SerialNumber); + for (i = 0; i < sn->cbData; i++) { + if (i != sn->cbData - 1) { + fprintf(output, "%02x:", sn->pbData[i]); + } else { + fprintf(output, "%02x", sn->pbData[i]); + } + } + fprintf(output, "\n"); + +done: + if (subject) xmlFree(subject); + if (issuer) xmlFree(issuer); +} + + +static void +xmlSecMSCryptoX509CertDebugXmlDump(PCCERT_CONTEXT cert, FILE* output) { + PCRYPT_INTEGER_BLOB sn; + unsigned int i; + xmlChar * subject = NULL; + xmlChar * issuer = NULL; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + /* subject */ + subject = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL); + if(subject == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoX509GetNameString", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "subject"); + goto done; + } + fprintf(output, "<SubjectName>"); + xmlSecPrintXmlString(output, BAD_CAST subject); + fprintf(output, "</SubjectName>\n"); + + /* issuer */ + issuer = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, CERT_NAME_ISSUER_FLAG, NULL); + if(issuer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoX509GetNameString", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "issuer"); + goto done; + } + fprintf(output, "<IssuerName>"); + xmlSecPrintXmlString(output, BAD_CAST issuer); + fprintf(output, "</IssuerName>\n"); + + /* serial */ + fprintf(output, "<SerialNumber>"); + sn = &(cert->pCertInfo->SerialNumber); + for (i = 0; i < sn->cbData; i++) { + if (i != sn->cbData - 1) { + fprintf(output, "%02x:", sn->pbData[i]); + } else { + fprintf(output, "%02x", sn->pbData[i]); + } + } + fprintf(output, "</SerialNumber>\n"); + +done: + xmlFree(subject); + xmlFree(issuer); +} + + +/************************************************************************** + * + * Raw X509 Certificate processing + * + * + *************************************************************************/ +static int xmlSecMSCryptoKeyDataRawX509CertBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const xmlSecByte* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyDataKlass xmlSecMSCryptoKeyDataRawX509CertKlass = { + sizeof(xmlSecKeyDataKlass), + sizeof(xmlSecKeyData), + + /* data */ + xmlSecNameRawX509Cert, + xmlSecKeyDataUsageRetrievalMethodNodeBin, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefRawX509Cert, /* const xmlChar* href; */ + NULL, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + NULL, /* xmlSecKeyDataInitializeMethod initialize; */ + NULL, /* xmlSecKeyDataDuplicateMethod duplicate; */ + NULL, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + NULL, /* xmlSecKeyDataGetTypeMethod getType; */ + NULL, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + NULL, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + NULL, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecMSCryptoKeyDataRawX509CertBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecMSCryptoKeyDataRawX509CertGetKlass: + * + * The raw X509 certificates key data klass. + * + * Returns: raw X509 certificates key data klass. + */ +xmlSecKeyDataId +xmlSecMSCryptoKeyDataRawX509CertGetKlass(void) { + return(&xmlSecMSCryptoKeyDataRawX509CertKlass); +} + +static int +xmlSecMSCryptoKeyDataRawX509CertBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + PCCERT_CONTEXT cert; + int ret; + + xmlSecAssert2(id == xmlSecMSCryptoKeyDataRawX509CertId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + cert = xmlSecMSCryptoX509CertDerRead(buf, bufSize); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509CertDerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + data = xmlSecKeyEnsureData(key, xmlSecMSCryptoKeyDataX509Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(cert); + return(-1); + } + + ret = xmlSecMSCryptoKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertFreeCertificateContext(cert); + return(-1); + } + + ret = xmlSecMSCryptoKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecMSCryptoKeyDataX509VerifyAndExtractKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +#endif /* XMLSEC_NO_X509 */ diff --git a/src/mscrypto/x509vfy.c b/src/mscrypto/x509vfy.c new file mode 100644 index 00000000..cf317877 --- /dev/null +++ b/src/mscrypto/x509vfy.c @@ -0,0 +1,1406 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2003 Cordys R&D BV, All rights reserved. + * Copyright (C) 2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_X509 + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/base64.h> +#include <xmlsec/bn.h> +#include <xmlsec/errors.h> + +#include <xmlsec/mscrypto/crypto.h> +#include <xmlsec/mscrypto/x509.h> +#include "private.h" + +/************************************************************************** + * + * Internal MSCRYPTO X509 store CTX + * + *************************************************************************/ +typedef struct _xmlSecMSCryptoX509StoreCtx xmlSecMSCryptoX509StoreCtx, + *xmlSecMSCryptoX509StoreCtxPtr; +struct _xmlSecMSCryptoX509StoreCtx { + HCERTSTORE trusted; + HCERTSTORE untrusted; + int dont_use_system_trusted_certs; +}; + +/**************************************************************************** + * + * xmlSecMSCryptoKeyDataStoreX509Id: + * + * xmlSecMSCryptoX509StoreCtx is located after xmlSecTransform + * + ***************************************************************************/ +#define xmlSecMSCryptoX509StoreGetCtx(store) \ + ((xmlSecMSCryptoX509StoreCtxPtr)(((xmlSecByte*)(store)) + \ + sizeof(xmlSecKeyDataStoreKlass))) +#define xmlSecMSCryptoX509StoreSize \ + (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecMSCryptoX509StoreCtx)) + +static int xmlSecMSCryptoX509StoreInitialize (xmlSecKeyDataStorePtr store); +static void xmlSecMSCryptoX509StoreFinalize (xmlSecKeyDataStorePtr store); + +static xmlSecKeyDataStoreKlass xmlSecMSCryptoX509StoreKlass = { + sizeof(xmlSecKeyDataStoreKlass), + xmlSecMSCryptoX509StoreSize, + + /* data */ + xmlSecNameX509Store, /* const xmlChar* name; */ + + /* constructors/destructor */ + xmlSecMSCryptoX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */ + xmlSecMSCryptoX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static PCCERT_CONTEXT xmlSecMSCryptoX509FindCert(HCERTSTORE store, + const xmlChar *subjectName, + const xmlChar *issuerName, + const xmlChar *issuerSerial, + const xmlChar *ski); + + +/** + * xmlSecMSCryptoX509StoreGetKlass: + * + * The MSCrypto X509 certificates key data store klass. + * + * Returns: pointer to MSCrypto X509 certificates key data store klass. + */ +xmlSecKeyDataStoreId +xmlSecMSCryptoX509StoreGetKlass(void) { + return(&xmlSecMSCryptoX509StoreKlass); +} + +/** + * xmlSecMSCryptoX509StoreFindCert: + * @store: the pointer to X509 key data store klass. + * @subjectName: the desired certificate name. + * @issuerName: the desired certificate issuer name. + * @issuerSerial: the desired certificate issuer serial number. + * @ski: the desired certificate SKI. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Searches @store for a certificate that matches given criteria. + * + * Returns: pointer to found certificate or NULL if certificate is not found + * or an error occurs. + */ +PCCERT_CONTEXT +xmlSecMSCryptoX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName, + xmlChar *issuerName, xmlChar *issuerSerial, + xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + PCCERT_CONTEXT pCert = NULL; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, NULL); + + /* search untrusted certs store */ + if((ctx->untrusted != NULL) && (pCert == NULL)) { + pCert = xmlSecMSCryptoX509FindCert(ctx->untrusted, subjectName, issuerName, issuerSerial, ski); + } + + /* search untrusted certs store */ + if((ctx->trusted != NULL) && (pCert == NULL)) { + pCert = xmlSecMSCryptoX509FindCert(ctx->trusted, subjectName, issuerName, issuerSerial, ski); + } + + return pCert; +} + + +static void +xmlSecMSCryptoUnixTimeToFileTime(time_t t, LPFILETIME pft) { + /* Note that LONGLONG is a 64-bit value */ + LONGLONG ll; + + xmlSecAssert(pft != NULL); + +#if defined( __MINGW32__) + ll = Int32x32To64(t, 10000000) + 116444736000000000ULL; +#else + ll = Int32x32To64(t, 10000000) + 116444736000000000; +#endif + pft->dwLowDateTime = (DWORD)ll; + pft->dwHighDateTime = ll >> 32; +} + +static BOOL +xmlSecMSCrypoVerifyCertTime(PCCERT_CONTEXT pCert, LPFILETIME pft) { + xmlSecAssert2(pCert != NULL, FALSE); + xmlSecAssert2(pCert->pCertInfo != NULL, FALSE); + xmlSecAssert2(pft != NULL, FALSE); + + if(1 == CompareFileTime(&(pCert->pCertInfo->NotBefore), pft)) { + return (FALSE); + } + if(-1 == CompareFileTime(&(pCert->pCertInfo->NotAfter), pft)) { + return (FALSE); + } + + return (TRUE); +} + +static BOOL +xmlSecMSCryptoCheckRevocation(HCERTSTORE hStore, PCCERT_CONTEXT pCert) { + PCCRL_CONTEXT pCrl = NULL; + PCRL_ENTRY pCrlEntry = NULL; + + xmlSecAssert2(pCert != NULL, FALSE); + xmlSecAssert2(hStore != NULL, FALSE); + + while((pCrl = CertEnumCRLsInStore(hStore, pCrl)) != NULL) { + if (CertFindCertificateInCRL(pCert, pCrl, 0, NULL, &pCrlEntry) && (pCrlEntry != NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertFindCertificateInCRL", + XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, + "cert found in crl list"); + return(FALSE); + } + } + + return(TRUE); +} + +static void +xmlSecMSCryptoX509StoreCertError(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, DWORD flags) { + xmlChar * subject = NULL; + DWORD dwSize; + + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId)); + xmlSecAssert(cert != NULL); + xmlSecAssert(flags != 0); + + /* get certs subject */ + subject = xmlSecMSCryptoX509GetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL); + if(subject == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoX509GetNameString", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return; + } + + /* print error */ + if (flags & CERT_STORE_SIGNATURE_FLAG) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + xmlSecErrorsSafeString(subject), + XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, + "signature"); + } else if (flags & CERT_STORE_TIME_VALIDITY_FLAG) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + xmlSecErrorsSafeString(subject), + XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, + XMLSEC_ERRORS_NO_MESSAGE); + } else if (flags & CERT_STORE_REVOCATION_FLAG) { + if (flags & CERT_STORE_NO_CRL_FLAG) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + xmlSecErrorsSafeString(subject), + XMLSEC_ERRORS_R_CERT_REVOKED, + "no crl"); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + xmlSecErrorsSafeString(subject), + XMLSEC_ERRORS_R_CERT_REVOKED, + XMLSEC_ERRORS_NO_MESSAGE); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + xmlSecErrorsSafeString(subject), + XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + } + + xmlFree(subject); +} + +/** + * xmlSecBuildChainUsingWinapi: + * @cert: the certificate we check + * @pfTime: pointer to FILETIME that we are interested in + * @store_untrusted: untrusted certificates added via API + * @store_doc: untrusted certificates/CRLs extracted from a document + * + * Builds certificates chain using Windows API. + * + * Returns: TRUE on success or FALSE otherwise. + */ +static BOOL +xmlSecBuildChainUsingWinapi (PCCERT_CONTEXT cert, LPFILETIME pfTime, + HCERTSTORE store_untrusted, HCERTSTORE store_doc) +{ + PCCERT_CHAIN_CONTEXT pChainContext = NULL; + CERT_CHAIN_PARA chainPara; + BOOL rc = FALSE; + HCERTSTORE store_add = NULL; + + /* Initialize data structures. */ + + memset(&chainPara, 0, sizeof(CERT_CHAIN_PARA)); + chainPara.cbSize = sizeof(CERT_CHAIN_PARA); + + /* Create additional store for CertGetCertificateChain() */ + store_add = CertOpenStore(CERT_STORE_PROV_COLLECTION, 0, 0, 0, NULL); + if (!store_add) { + xmlSecError(XMLSEC_ERRORS_HERE, + "chain additional collection store", + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + if (!CertAddStoreToCollection(store_add, store_doc, 0, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + "adding document store", + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + if (!CertAddStoreToCollection(store_add, store_untrusted, 0, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + "adding untrusted store", + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + + /* Build a chain using CertGetCertificateChain + and the certificate retrieved. */ + if(!CertGetCertificateChain( + NULL, /* use the default chain engine */ + cert, + pfTime, + store_add, + &chainPara, + CERT_CHAIN_REVOCATION_CHECK_CHAIN, + NULL, + &pChainContext)) + { + xmlSecError(XMLSEC_ERRORS_HERE, + "building certificate chain, checking root", + "CertGetCertificateChain", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_REVOCATION_STATUS_UNKNOWN) { + CertFreeCertificateChain(pChainContext); pChainContext = NULL; + if(!CertGetCertificateChain( + NULL, /* use the default chain engine */ + cert, + pfTime, + store_add, + &chainPara, + CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, + NULL, + &pChainContext)) + { + xmlSecError(XMLSEC_ERRORS_HERE, + "building certificate chain, excluding root", + "CertGetCertificateChain", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto end; + } + } + + if (pChainContext->TrustStatus.dwErrorStatus == CERT_TRUST_NO_ERROR) + rc = TRUE; + +end: + if (pChainContext) CertFreeCertificateChain(pChainContext); + if (store_add) CertCloseStore(store_add, 0); + return (rc); +} + +/** + * xmlSecMSCryptoBuildCertChainManually: + * @cert: the certificate we check + * @pfTime: pointer to FILETIME that we are interested in + * @store_trusted: trusted certificates added via API + * @store_untrusted: untrusted certificates added via API + * @certs: untrusted certificates/CRLs extracted from a document + * @store: pointer to store klass passed to error functions + * + * Builds certificates chain manually. + * + * Returns: TRUE on success or FALSE otherwise. + */ +static BOOL +xmlSecMSCryptoBuildCertChainManually (PCCERT_CONTEXT cert, LPFILETIME pfTime, + HCERTSTORE store_trusted, HCERTSTORE store_untrusted, HCERTSTORE certs, + xmlSecKeyDataStorePtr store) { + PCCERT_CONTEXT issuerCert = NULL; + DWORD flags; + + if (!xmlSecMSCrypoVerifyCertTime(cert, pfTime)) { + xmlSecMSCryptoX509StoreCertError(store, cert, CERT_STORE_TIME_VALIDITY_FLAG); + return(FALSE); + } + + if (!xmlSecMSCryptoCheckRevocation(certs, cert)) { + return(FALSE); + } + + /* + * Try to find the cert in the trusted cert store. We will trust + * the certificate in the trusted store. + */ + issuerCert = CertFindCertificateInStore(store_trusted, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &(cert->pCertInfo->Subject), + NULL); + if( issuerCert != NULL) { + /* We have found the trusted cert, so return true */ + /* todo: do we want to verify the trusted cert's revocation? we must, I think */ + CertFreeCertificateContext( issuerCert ) ; + return( TRUE ) ; + } + + /* Check whether the certificate is self signed certificate */ + if(CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &(cert->pCertInfo->Subject), &(cert->pCertInfo->Issuer))) { + return(FALSE); + } + + /* try to find issuer cert in the trusted cert in the store */ + issuerCert = CertFindCertificateInStore(store_trusted, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &(cert->pCertInfo->Issuer), + NULL); + if(issuerCert != NULL) { + flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG; + if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) { + xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags); + CertFreeCertificateContext(issuerCert); + return(FALSE); + } + /* todo: do we want to verify the trusted cert? we must check + * revocation, I think */ + CertFreeCertificateContext(issuerCert); + return(TRUE); + } + + /* try the untrusted certs in the chain */ + issuerCert = CertFindCertificateInStore(certs, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &(cert->pCertInfo->Issuer), + NULL); + if(issuerCert != NULL) { + flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG; + if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) { + xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags); + CertFreeCertificateContext(issuerCert); + return(FALSE); + } + if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) { + xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags); + CertFreeCertificateContext(issuerCert); + return(FALSE); + } + CertFreeCertificateContext(issuerCert); + return(TRUE); + } + + /* try the untrusted certs in the store */ + issuerCert = CertFindCertificateInStore(store_untrusted, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &(cert->pCertInfo->Issuer), + NULL); + if(issuerCert != NULL) { + flags = CERT_STORE_REVOCATION_FLAG | CERT_STORE_SIGNATURE_FLAG; + if(!CertVerifySubjectCertificateContext(cert, issuerCert, &flags)) { + xmlSecMSCryptoX509StoreCertError(store, issuerCert, flags); + CertFreeCertificateContext(issuerCert); + return(FALSE); + } + if(!xmlSecMSCryptoBuildCertChainManually(issuerCert, pfTime, store_trusted, store_untrusted, certs, store)) { + CertFreeCertificateContext(issuerCert); + return(FALSE); + } + CertFreeCertificateContext(issuerCert); + return(TRUE); + } + + return(FALSE); +} + +static BOOL +xmlSecMSCryptoX509StoreConstructCertsChain(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT cert, HCERTSTORE certs, + xmlSecKeyInfoCtx* keyInfoCtx) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + PCCERT_CONTEXT tempCert = NULL; + FILETIME fTime; + BOOL res = FALSE; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), FALSE); + xmlSecAssert2(cert != NULL, FALSE); + xmlSecAssert2(cert->pCertInfo != NULL, FALSE); + xmlSecAssert2(certs != NULL, FALSE); + xmlSecAssert2(keyInfoCtx != NULL, FALSE); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, FALSE); + xmlSecAssert2(ctx->trusted != NULL, FALSE); + xmlSecAssert2(ctx->untrusted != NULL, FALSE); + + if(keyInfoCtx->certsVerificationTime > 0) { + /* convert the time to FILETIME */ + xmlSecMSCryptoUnixTimeToFileTime(keyInfoCtx->certsVerificationTime, &fTime); + } else { + /* Defaults to current time */ + GetSystemTimeAsFileTime(&fTime); + } + + /* try the certificates in the keys manager */ + if(!res) { + tempCert = CertEnumCertificatesInStore(ctx->trusted, NULL); + if(tempCert) { + CertFreeCertificateContext(tempCert); + res = xmlSecMSCryptoBuildCertChainManually(cert, &fTime, ctx->trusted, ctx->untrusted, certs, store); + } + } + + /* try the certificates in the system */ + if(!res && !ctx->dont_use_system_trusted_certs) { + res = xmlSecBuildChainUsingWinapi(cert, &fTime, ctx->untrusted, certs); + } + + /* done */ + return res; +} + +/** + * xmlSecMSCryptoX509StoreVerify: + * @store: the pointer to X509 certificate context store klass. + * @certs: the untrusted certificates stack. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Verifies @certs list. + * + * Returns: pointer to the first verified certificate from @certs. + */ +PCCERT_CONTEXT +xmlSecMSCryptoX509StoreVerify(xmlSecKeyDataStorePtr store, HCERTSTORE certs, + xmlSecKeyInfoCtx* keyInfoCtx) { + PCCERT_CONTEXT cert = NULL; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), NULL); + xmlSecAssert2(certs != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + while((cert = CertEnumCertificatesInStore(certs, cert)) != NULL){ + PCCERT_CONTEXT nextCert = NULL; + unsigned char selected = 1; + + xmlSecAssert2(cert->pCertInfo != NULL, NULL); + + /* if cert is the issuer of any other cert in the list, then it is + * to be skipped except a case of a celf-signed cert*/ + do { + nextCert = CertFindCertificateInStore(certs, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_ISSUER_NAME, + &(cert->pCertInfo->Subject), + nextCert); + if((nextCert != NULL) && !CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + &(nextCert->pCertInfo->Subject), &(nextCert->pCertInfo->Issuer))) { + selected = 0; + } + } while((selected == 1) && (nextCert != NULL)); + if(nextCert != NULL) { + CertFreeCertificateContext(nextCert); + } + + if((selected == 1) && xmlSecMSCryptoX509StoreConstructCertsChain(store, cert, certs, keyInfoCtx)) { + return(cert); + } + } + + return (NULL); +} + +/** + * xmlSecMSCryptoX509StoreAdoptCert: + * @store: the pointer to X509 key data store klass. + * @cert: the pointer to PCCERT_CONTEXT X509 certificate. + * @type: the certificate type (trusted/untrusted). + * + * Adds trusted (root) or untrusted certificate to the store. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoX509StoreAdoptCert(xmlSecKeyDataStorePtr store, PCCERT_CONTEXT pCert, xmlSecKeyDataType type) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + HCERTSTORE certStore; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1); + xmlSecAssert2(pCert != NULL, -1); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->trusted != NULL, -1); + xmlSecAssert2(ctx->untrusted != NULL, -1); + + if(type == xmlSecKeyDataTypeTrusted) { + certStore = ctx->trusted; + } else if(type == xmlSecKeyDataTypeNone) { + certStore = ctx->untrusted; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "type=%d", type); + return(-1); + } + + /* TODO: The context to be added here is not duplicated first, + * hopefully this will not lead to errors when closing teh store + * and freeing the mem for all the context in the store. + */ + xmlSecAssert2(certStore != NULL, -1); + if (!CertAddCertificateContextToStore(certStore, pCert, CERT_STORE_ADD_ALWAYS, NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertAddCertificateContextToStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + + +/** + * xmlSecMSCryptoX509StoreAdoptKeyStore: + * @store: the pointer to X509 key data store klass. + * @keyStore: the pointer to keys store. + * + * Adds @keyStore to the list of key stores. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoX509StoreAdoptKeyStore (xmlSecKeyDataStorePtr store, HCERTSTORE keyStore) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1); + xmlSecAssert2( keyStore != NULL, -1); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->trusted != NULL, -1); + + if(!CertAddStoreToCollection ( ctx->trusted , keyStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 2)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoX509StoreAdoptTrustedStore: + * @store: the pointer to X509 key data store klass. + * @trustedStore: the pointer to certs store. + * + * Adds @trustedStore to the list of trusted certs stores. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoX509StoreAdoptTrustedStore (xmlSecKeyDataStorePtr store, HCERTSTORE trustedStore) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1); + xmlSecAssert2( trustedStore != NULL, -1); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->trusted != NULL, -1); + + if( !CertAddStoreToCollection ( ctx->trusted , trustedStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 3 ) ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoX509StoreAdoptUntrustedStore: + * @store: the pointer to X509 key data store klass. + * @untrustedStore: the pointer to certs store. + * + * Adds @trustedStore to the list of un-trusted certs stores. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecMSCryptoX509StoreAdoptUntrustedStore (xmlSecKeyDataStorePtr store, HCERTSTORE untrustedStore) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1); + xmlSecAssert2( untrustedStore != NULL, -1); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->untrusted != NULL, -1); + + if( !CertAddStoreToCollection ( ctx->untrusted , untrustedStore , CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG , 2 ) ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecMSCryptoX509StoreEnableSystemTrustedCerts: + * @store: the pointer to X509 key data store klass. + * @val: the enable/disable flag + * + * Enables/disables the system trusted certs. + */ +void +xmlSecMSCryptoX509StoreEnableSystemTrustedCerts (xmlSecKeyDataStorePtr store, int val) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId)); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert(ctx != NULL); + xmlSecAssert(ctx->untrusted != NULL); + + /* it is other way around to make default value 0 mimic old behaiviour */ + ctx->dont_use_system_trusted_certs = !val; +} + +static int +xmlSecMSCryptoX509StoreInitialize(xmlSecKeyDataStorePtr store) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + HCERTSTORE hTrustedMemStore ; + HCERTSTORE hUntrustedMemStore ; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId), -1); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoX509StoreCtx)); + + /* create trusted certs store collection */ + ctx->trusted = CertOpenStore(CERT_STORE_PROV_COLLECTION, + 0, + 0, + 0, + NULL); + if(ctx->trusted == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* create trusted certs store */ + hTrustedMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_STORE_CREATE_NEW_FLAG, + NULL); + if(hTrustedMemStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG); + ctx->trusted = NULL ; + return(-1); + } + + /* add the memory trusted certs store to trusted certs store collection */ + if( !CertAddStoreToCollection( ctx->trusted, hTrustedMemStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1 ) ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG); + CertCloseStore(hTrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG); + ctx->trusted = NULL ; + return(-1); + } + CertCloseStore(hTrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG); + + /* create untrusted certs store collection */ + ctx->untrusted = CertOpenStore(CERT_STORE_PROV_COLLECTION, + 0, + 0, + 0, + NULL); + if(ctx->untrusted == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG); + ctx->trusted = NULL ; + return(-1); + } + + /* create untrusted certs store */ + hUntrustedMemStore = CertOpenStore(CERT_STORE_PROV_MEMORY, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_STORE_CREATE_NEW_FLAG, + NULL); + if(hUntrustedMemStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertOpenStore", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG); + CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG); + ctx->trusted = NULL ; + ctx->untrusted = NULL ; + return(-1); + } + + /* add the memory trusted certs store to untrusted certs store collection */ + if( !CertAddStoreToCollection( ctx->untrusted, hUntrustedMemStore, CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG, 1 ) ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CertAddStoreToCollection", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG); + CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG); + CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG); + ctx->trusted = NULL ; + ctx->untrusted = NULL ; + return(-1); + } + CertCloseStore(hUntrustedMemStore, CERT_CLOSE_STORE_CHECK_FLAG); + + return(0); +} + +static void +xmlSecMSCryptoX509StoreFinalize(xmlSecKeyDataStorePtr store) { + xmlSecMSCryptoX509StoreCtxPtr ctx; + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId)); + + ctx = xmlSecMSCryptoX509StoreGetCtx(store); + xmlSecAssert(ctx != NULL); + + if (ctx->trusted) { + CertCloseStore(ctx->trusted, CERT_CLOSE_STORE_FORCE_FLAG); + } + if (ctx->untrusted) { + CertCloseStore(ctx->untrusted, CERT_CLOSE_STORE_FORCE_FLAG); + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoX509StoreCtx)); +} + + +/***************************************************************************** + * + * Low-level x509 functions + * + *****************************************************************************/ +/** + * xmlSecMSCryptoCertStrToName: + * @dwCertEncodingType: the encoding used. + * @pszX500: the string to convert. + * @dwStrType: the string type. + * @len: the result len. + * + * Converts input string to name by calling @CertStrToName function. + * + * Returns: a pointer to newly allocated string or NULL if an error occurs. + */ +static BYTE* +xmlSecMSCryptoCertStrToName(DWORD dwCertEncodingType, LPTSTR pszX500, DWORD dwStrType, DWORD* len) { + BYTE* str = NULL; + LPCTSTR ppszError = NULL; + + xmlSecAssert2(pszX500 != NULL, NULL); + xmlSecAssert2(len != NULL, NULL); + + if (!CertStrToName(dwCertEncodingType, pszX500, dwStrType, + NULL, NULL, len, &ppszError)) { + /* this might not be an error, string might just not exist */ + DWORD dw = GetLastError(); + return(NULL); + } + + str = (BYTE *)xmlMalloc(sizeof(TCHAR) * ((*len) + 1)); + if(str == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "len=%ld", (*len)); + return(NULL); + } + memset(str, 0, (*len) + 1); + + if (!CertStrToName(dwCertEncodingType, pszX500, dwStrType, + NULL, str, len, NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertStrToName", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(NULL); + } + + return(str); +} + + +/** + * xmlSecMSCryptoX509FindCertBySubject: + * @store: the pointer to certs store + * @wcSubject: the cert subject (Unicode) + * @dwCertEncodingType: the cert encoding type + * + * Searches for a cert with given @subject in the @store + * + * Returns: cert handle on success or NULL otherwise + */ +PCCERT_CONTEXT +xmlSecMSCryptoX509FindCertBySubject(HCERTSTORE store, const LPTSTR wcSubject, DWORD dwCertEncodingType) { + PCCERT_CONTEXT res = NULL; + CERT_NAME_BLOB cnb; + BYTE* bdata; + DWORD len; + + xmlSecAssert2(store != NULL, NULL); + xmlSecAssert2(wcSubject != NULL, NULL); + + /* CASE 1: UTF8, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } + + /* CASE 2: UTF8, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } + + /* CASE 3: UNICODE, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } + + /* CASE 4: UNICODE, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcSubject, + CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + cnb.cbData = len; + cnb.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } + + + /* done */ + return (res); +} + +/** + * xmlSecMSCryptoX509FindCertByIssuer: + * @store: the pointer to certs store + * @wcIssuer: the cert issuer (Unicode) + * @issuerSerialBn: the cert issuer serial + * @dwCertEncodingType: the cert encoding type + * + * Searches for a cert with given @subject in the @store + * + * Returns: cert handle on success or NULL otherwise + */ +static PCCERT_CONTEXT +xmlSecMSCryptoX509FindCertByIssuer(HCERTSTORE store, const LPTSTR wcIssuer, + xmlSecBnPtr issuerSerialBn, DWORD dwCertEncodingType) { + + PCCERT_CONTEXT res = NULL; + CERT_INFO certInfo; + BYTE* bdata; + DWORD len; + + + xmlSecAssert2(store != NULL, NULL); + xmlSecAssert2(wcIssuer != NULL, NULL); + xmlSecAssert2(issuerSerialBn != NULL, NULL); + + certInfo.SerialNumber.cbData = xmlSecBnGetSize(issuerSerialBn); + certInfo.SerialNumber.pbData = xmlSecBnGetData(issuerSerialBn); + + + /* CASE 1: UTF8, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + /* CASE 2: UTF8, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + /* CASE 3: UNICODE, DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + /* CASE 4: UNICODE, REVERSE DN */ + if (NULL == res) { + bdata = xmlSecMSCryptoCertStrToName(dwCertEncodingType, + wcIssuer, + CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + certInfo.Issuer.cbData = len; + certInfo.Issuer.pbData = bdata; + + res = CertFindCertificateInStore(store, + dwCertEncodingType, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL); + xmlFree(bdata); + } + } + + + /* done */ + return (res); +} + +static LPTSTR +xmlSecMSCryptoX509GetCertName(const xmlChar * name) { + xmlChar *name2 = NULL; + xmlChar *p = NULL; + LPTSTR res = NULL; + + xmlSecAssert2(name != 0, NULL); + + /* MSCrypto doesn't support "emailAddress" attribute (see NSS as well). + * This code is not bullet proof and may produce incorrect results if someone has + * "emailAddress=" string in one of the fields, but it is best I can suggest to fix + * this problem. + */ + name2 = xmlStrdup(name); + if(name2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "xmlStrlen(name)=%d", + xmlStrlen(name)); + return(NULL); + } + while( (p = (xmlChar*)xmlStrstr(name2, BAD_CAST "emailAddress=")) != NULL) { + memcpy(p, " E=", 13); + } + + /* get name */ + res = xmlSecMSCryptoConvertUtf8ToTstr(name2); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoConvertUtf8ToTstr", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* done */ + return(res); +} + +static PCCERT_CONTEXT +xmlSecMSCryptoX509FindCert(HCERTSTORE store, + const xmlChar *subjectName, + const xmlChar *issuerName, + const xmlChar *issuerSerial, + const xmlChar *ski) { + PCCERT_CONTEXT pCert = NULL; + int ret; + + xmlSecAssert2(store != 0, NULL); + + if((pCert == NULL) && (NULL != subjectName)) { + LPTSTR wcSubjectName = NULL; + + /* get unicode subject name */ + wcSubjectName = xmlSecMSCryptoX509GetCertName(subjectName); + if(wcSubjectName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509GetCertName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "wcSubjectName"); + return(NULL); + } + + /* search */ + pCert = xmlSecMSCryptoX509FindCertBySubject(store, + wcSubjectName, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING); + + + /* cleanup */ + xmlFree(wcSubjectName); + } + + if((pCert == NULL) && (NULL != issuerName) && (NULL != issuerSerial)) { + xmlSecBn issuerSerialBn; + LPTSTR wcIssuerName = NULL; + + /* get serial number */ + ret = xmlSecBnInitialize(&issuerSerialBn, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecBnFromDecString(&issuerSerialBn, issuerSerial); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBnFinalize(&issuerSerialBn); + return(NULL); + } + + /* I have no clue why at a sudden a swap is needed to + * convert from lsb... This code is purely based upon + * trial and error :( WK + */ + ret = xmlSecBnReverse(&issuerSerialBn); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBnFinalize(&issuerSerialBn); + return(NULL); + } + + /* get issuer name */ + wcIssuerName = xmlSecMSCryptoX509GetCertName(issuerName); + if(wcIssuerName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoX509GetCertName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "wcIssuerName"); + xmlSecBnFinalize(&issuerSerialBn); + return(NULL); + } + + /* search */ + pCert = xmlSecMSCryptoX509FindCertByIssuer(store, + wcIssuerName, + &issuerSerialBn, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING); + + xmlFree(wcIssuerName); + + /* cleanup */ + xmlSecBnFinalize(&issuerSerialBn); + } + + if((pCert == NULL) && (ski != NULL)) { + CRYPT_HASH_BLOB blob; + xmlChar* binSki; + int binSkiLen; + + binSki = xmlStrdup(ski); + if(binSki == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + /* trick: base64 decode "in place" */ + binSkiLen = xmlSecBase64Decode(binSki, (xmlSecByte*)binSki, xmlStrlen(binSki)); + if(binSkiLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ski=%s", + xmlSecErrorsSafeString(ski)); + xmlFree(binSki); + return(NULL); + } + + blob.pbData = binSki; + blob.cbData = binSkiLen; + pCert = CertFindCertificateInStore(store, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + 0, + CERT_FIND_KEY_IDENTIFIER, + &blob, + NULL); + xmlFree(binSki); + } + + return(pCert); +} + + +/** + * xmlSecMSCryptoX509GetNameString: + * @pCertContext: the pointer to cert + * @dwType: the type (see CertGetNameString description in MSDN) + * @dwFlags: the flags (see CertGetNameString description in MSDN) + * @pvTypePara: the type parameter (see CertGetNameString description in MSDN) + * + * Gets the name string for certificate (see CertGetNameString description in MSDN). + * + * Returns: name string (should be freed with xmlFree) or NULL if failed. + */ +xmlChar * +xmlSecMSCryptoX509GetNameString(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, void *pvTypePara) { + LPTSTR name = NULL; + xmlChar * res = NULL; + DWORD dwSize; + + xmlSecAssert2(pCertContext != NULL, NULL); + + /* get size first */ + dwSize = CertGetNameString(pCertContext, dwType, dwFlags, pvTypePara, NULL, 0); + if(dwSize <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + "CertGetNameString", + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + /* allocate buffer */ + name = (LPTSTR)xmlMalloc(sizeof(TCHAR) * (dwSize + 1)); + if(name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + /* actually get the name */ + dwSize = CertGetNameString(pCertContext, dwType, dwFlags, pvTypePara, name, dwSize); + if(dwSize <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + "CertGetNameString", + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(name); + return (NULL); + } + + res = xmlSecMSCryptoConvertTstrToUtf8(name); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecMSCryptoConvertTstrToUtf8", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(name); + return (NULL); + } + /* done */ + xmlFree(name); + return (res); +} + +#endif /* XMLSEC_NO_X509 */ + + diff --git a/src/mscrypto/xmlsec-mingw.h b/src/mscrypto/xmlsec-mingw.h new file mode 100644 index 00000000..ef5d2ae4 --- /dev/null +++ b/src/mscrypto/xmlsec-mingw.h @@ -0,0 +1,210 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2007,2010 Roumen Petrov. + */ + +#ifndef __XMLSEC_MSCRYPTO_XMLSEC_MINGW_H__ +#define __XMLSEC_MSCRYPTO_XMLSEC_MINGW_H__ + +#ifndef XMLSEC_PRIVATE +#error "xmlsec-mingw.h file contains private xmlsec definitions for mingw build and should not be used outside xmlsec or xmlsec-<crypto> libraries" +#endif /* XMLSEC_PRIVATE */ + + +/*defines*/ + +#ifndef ALG_SID_HMAC +# define ALG_SID_HMAC 9 +#endif + +#ifndef ALG_SID_SHA_256 +# define ALG_SID_SHA_256 12 +#endif + +#ifndef ALG_SID_SHA_384 +# define ALG_SID_SHA_384 13 +#endif + +#ifndef ALG_SID_SHA_512 +# define ALG_SID_SHA_512 14 +#endif + +#ifndef CALG_HMAC +# define CALG_HMAC (ALG_CLASS_HASH|ALG_TYPE_ANY|ALG_SID_HMAC) +#endif + +#ifndef CALG_SHA_256 +# define CALG_SHA_256 (ALG_CLASS_HASH|ALG_TYPE_ANY|ALG_SID_SHA_256) +#endif + +#ifndef CALG_SHA_384 +# define CALG_SHA_384 (ALG_CLASS_HASH|ALG_TYPE_ANY|ALG_SID_SHA_384) +#endif + +#ifndef CALG_SHA_512 +# define CALG_SHA_512 (ALG_CLASS_HASH|ALG_TYPE_ANY|ALG_SID_SHA_512) +#endif + + +#ifndef KP_OAEP_PARAMS +# define KP_OAEP_PARAMS 36 +#endif + + +#ifndef CERT_CLOSE_STORE_FORCE_FLAG +# define CERT_CLOSE_STORE_FORCE_FLAG 1 +#endif + +#ifndef CERT_CLOSE_STORE_CHECK_FLAG +# define CERT_CLOSE_STORE_CHECK_FLAG 2 +#endif + + +#ifndef CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG +# define CERT_PHYSICAL_STORE_ADD_ENABLE_FLAG 1 +#endif + + +#ifndef CERT_STORE_ADD_ALWAYS +# define CERT_STORE_ADD_ALWAYS 4 +#endif + +#ifndef CERT_STORE_CREATE_NEW_FLAG +# define CERT_STORE_CREATE_NEW_FLAG (2<<12) +#endif + +#ifndef CERT_STORE_SIGNATURE_FLAG +# define CERT_STORE_SIGNATURE_FLAG 1 +#endif + +#ifndef CERT_STORE_TIME_VALIDITY_FLAG +# define CERT_STORE_TIME_VALIDITY_FLAG 2 +#endif + +#ifndef CERT_STORE_REVOCATION_FLAG +# define CERT_STORE_REVOCATION_FLAG 4 +#endif + +#ifndef CERT_STORE_NO_CRL_FLAG +# define CERT_STORE_NO_CRL_FLAG (1<<16) +#endif + + +#ifndef CERT_STORE_PROV_COLLECTION +# define CERT_STORE_PROV_COLLECTION ((LPCSTR) 11) +#endif + +#ifndef CERT_STORE_PROV_MEMORY +# define CERT_STORE_PROV_MEMORY ((LPCSTR) 2) +#endif + + +#ifndef CERT_KEY_SPEC_PROP_ID +# define CERT_KEY_SPEC_PROP_ID 6 +#endif + +#ifndef CERT_FRIENDLY_NAME_PROP_ID +# define CERT_FRIENDLY_NAME_PROP_ID 11 +#endif + +#ifndef CERT_KEY_IDENTIFIER_PROP_ID +# define CERT_KEY_IDENTIFIER_PROP_ID 20 +#endif + + +#ifndef CERT_NAME_ISSUER_FLAG +# define CERT_NAME_ISSUER_FLAG 1 +#endif + +#ifndef CERT_NAME_RDN_TYPE +# define CERT_NAME_RDN_TYPE 2 +#endif + +#ifndef CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG +# define CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG (4<<16) +#endif + + +#ifndef CERT_CHAIN_REVOCATION_CHECK_CHAIN +# define CERT_CHAIN_REVOCATION_CHECK_CHAIN (2<<28) +#endif + +#ifndef CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT +# define CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT (4<<28) +#endif + + +#ifndef szOID_SUBJECT_KEY_IDENTIFIER +# define szOID_SUBJECT_KEY_IDENTIFIER "2.5.29.14" +#endif + + +#ifndef CRYPT_ACQUIRE_COMPARE_KEY_FLAG +# define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 4 +#endif + + +/*structures/types*/ +typedef struct _PUBKEY { + DWORD magic; + DWORD bitlen; +} DSSPUBKEY; + +typedef struct _DSSSEED { + DWORD counter; + BYTE seed[20]; +} DSSSEED; + + +typedef struct _PROV_ENUMALGS_EX { + ALG_ID aiAlgid; + DWORD dwDefaultLen; + DWORD dwMinLen; + DWORD dwMaxLen; + DWORD dwProtocols; + DWORD dwNameLen; + CHAR szName[20]; + DWORD dwLongNameLen; + CHAR szLongName[40]; +} PROV_ENUMALGS_EX; + + +/*methods(functions)*/ +DWORD WINAPI CertGetPublicKeyLength(DWORD,PCERT_PUBLIC_KEY_INFO); + +BOOL WINAPI CertStrToNameA(DWORD,LPCSTR,DWORD,void*,BYTE*,DWORD*,LPCSTR*); +BOOL WINAPI CertStrToNameW(DWORD,LPCWSTR,DWORD,void*,BYTE*,DWORD*,LPCWSTR*); +#ifdef UNICODE +#define CertStrToName CertStrToNameW +#else +#define CertStrToName CertStrToNameA +#endif + + +BOOL WINAPI CertCompareCertificateName(DWORD,PCERT_NAME_BLOB,PCERT_NAME_BLOB); + +BOOL WINAPI CertAddStoreToCollection(HCERTSTORE,HCERTSTORE,DWORD,DWORD); + +PCCERT_CONTEXT WINAPI CertCreateCertificateContext(DWORD,const BYTE*,DWORD); +BOOL WINAPI CertGetCertificateContextProperty(PCCERT_CONTEXT,DWORD,void*,DWORD*); +BOOL WINAPI CertVerifySubjectCertificateContext(PCCERT_CONTEXT,PCCERT_CONTEXT,DWORD*); + +BOOL WINAPI CertAddCRLContextToStore(HCERTSTORE,PCCRL_CONTEXT,DWORD,PCCRL_CONTEXT*); +PCCRL_CONTEXT WINAPI CertDuplicateCRLContext(PCCRL_CONTEXT); +BOOL WINAPI CertFreeCRLContext(PCCRL_CONTEXT); + +BOOL WINAPI CertFindCertificateInCRL(PCCERT_CONTEXT,PCCRL_CONTEXT,DWORD,void*,PCRL_ENTRY*); +PCCRL_CONTEXT WINAPI CertEnumCRLsInStore(HCERTSTORE,PCCRL_CONTEXT); + +PCCRL_CONTEXT WINAPI CertCreateCRLContext(DWORD,const BYTE*,DWORD); + +BOOL WINAPI CryptAcquireCertificatePrivateKey(PCCERT_CONTEXT,DWORD,void*,HCRYPTPROV*,DWORD*,BOOL*); +BOOL WINAPI CryptDuplicateKey(HCRYPTKEY,DWORD*,DWORD,HCRYPTKEY*); +BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV,DWORD,PCERT_PUBLIC_KEY_INFO,HCRYPTKEY*); + + +#endif /*ndef __XMLSEC_MSCRYPTO_XMLSEC_MINGW_H__*/ |