diff options
Diffstat (limited to 'src')
103 files changed, 78646 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..e28bb5ed --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,69 @@ +NULL = + +SUBDIRS = . $(XMLSEC_CRYPTO_LIST) + +INCLUDES = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(XMLSEC_DL_INCLUDES) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +EXTRA_DIST = \ + globals.h \ + skeleton \ + mscrypto \ + $(XMLSEC_CRYPTO_DISABLED_LIST) \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1.la \ + $(NULL) + +libxmlsec1_la_SOURCES = \ + $(LTDL_SOURCE_FILES) \ + app.c \ + base64.c \ + bn.c \ + buffer.c \ + c14n.c \ + dl.c \ + enveloped.c \ + errors.c \ + io.c \ + keyinfo.c \ + keys.c \ + keysdata.c \ + keysmngr.c \ + list.c \ + membuf.c \ + nodeset.c \ + parser.c \ + soap.c \ + strings.c \ + templates.c \ + transforms.c \ + x509.c \ + xkms.c \ + xmldsig.c \ + xmlenc.c \ + xmlsec.c \ + xmltree.c \ + xpath.c \ + xslt.c \ + $(NULL) + +libxmlsec1_la_LIBADD = \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(XMLSEC_DL_LIBS) \ + $(NULL) + +libxmlsec1_la_LDFLAGS = \ + @XMLSEC_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) + diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 00000000..56fb659d --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,863 @@ +# Makefile.in generated by automake 1.11 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@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +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 = +libxmlsec1_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) +am__objects_1 = +am_libxmlsec1_la_OBJECTS = app.lo base64.lo bn.lo buffer.lo c14n.lo \ + dl.lo enveloped.lo errors.lo io.lo keyinfo.lo keys.lo \ + keysdata.lo keysmngr.lo list.lo membuf.lo nodeset.lo parser.lo \ + soap.lo strings.lo templates.lo transforms.lo x509.lo xkms.lo \ + xmldsig.lo xmlenc.lo xmlsec.lo xmltree.lo xpath.lo xslt.lo \ + $(am__objects_1) +libxmlsec1_la_OBJECTS = $(am_libxmlsec1_la_OBJECTS) +libxmlsec1_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libxmlsec1_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_la_SOURCES) +DIST_SOURCES = $(libxmlsec1_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +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@ +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@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_ENABLED = @PKG_CONFIG_ENABLED@ +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_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_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 = +SUBDIRS = . $(XMLSEC_CRYPTO_LIST) +INCLUDES = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(XMLSEC_DL_INCLUDES) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +EXTRA_DIST = \ + globals.h \ + skeleton \ + mscrypto \ + $(XMLSEC_CRYPTO_DISABLED_LIST) \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1.la \ + $(NULL) + +libxmlsec1_la_SOURCES = \ + $(LTDL_SOURCE_FILES) \ + app.c \ + base64.c \ + bn.c \ + buffer.c \ + c14n.c \ + dl.c \ + enveloped.c \ + errors.c \ + io.c \ + keyinfo.c \ + keys.c \ + keysdata.c \ + keysmngr.c \ + list.c \ + membuf.c \ + nodeset.c \ + parser.c \ + soap.c \ + strings.c \ + templates.c \ + transforms.c \ + x509.c \ + xkms.c \ + xmldsig.c \ + xmlenc.c \ + xmlsec.c \ + xmltree.c \ + xpath.c \ + xslt.c \ + $(NULL) + +libxmlsec1_la_LIBADD = \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(XMLSEC_DL_LIBS) \ + $(NULL) + +libxmlsec1_la_LDFLAGS = \ + @XMLSEC_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) + +all: all-recursive + +.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/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/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.la: $(libxmlsec1_la_OBJECTS) $(libxmlsec1_la_DEPENDENCIES) + $(libxmlsec1_la_LINK) -rpath $(libdir) $(libxmlsec1_la_OBJECTS) $(libxmlsec1_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/app.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bn.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/c14n.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/enveloped.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyinfo.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keysdata.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keysmngr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/membuf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nodeset.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parser.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/soap.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strings.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/templates.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transforms.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x509.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xkms.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmldsig.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlenc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmlsec.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xmltree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xpath.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xslt.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 $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +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: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + 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: ctags-recursive $(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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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-recursive + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags ctags-recursive \ + 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 installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive 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/app.c b/src/app.c new file mode 100644 index 00000000..ca09f62c --- /dev/null +++ b/src/app.c @@ -0,0 +1,1498 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/app.h> +#include <xmlsec/list.h> +#include <xmlsec/keysdata.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/private.h> +#include <xmlsec/errors.h> + + +/****************************************************************************** + * + * Crypto Init/shutdown + * + *****************************************************************************/ +/** + * xmlSecCryptoInit: + * + * XMLSec library specific crypto engine initialization. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoInit(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoInit == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoInit", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoInit()); +} + +/** + * xmlSecCryptoShutdown: + * + * XMLSec library specific crypto engine shutdown. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoShutdown(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoShutdown == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoShutdown", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoShutdown()); +} + +/** + * xmlSecCryptoKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Adds crypto specific key data stores in keys manager. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoKeysMngrInit(xmlSecKeysMngrPtr mngr) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoKeysMngrInit == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoKeysMngrInit", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoKeysMngrInit(mngr)); +} + +/****************************************************************************** + * + * Key data ids + * + *****************************************************************************/ +/** + * xmlSecKeyDataAesGetKlass: + * + * The AES key data klass. + * + * Returns: AES key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the AES key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataAesGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataAesGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataAesId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataAesGetKlass()); +} + +/** + * xmlSecKeyDataDesGetKlass: + * + * The DES key data klass. + * + * Returns: DES key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the DES key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataDesGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataDesGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataDesId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataDesGetKlass()); +} + +/** + * xmlSecKeyDataDsaGetKlass: + * + * The DSA key data klass. + * + * Returns: DSA key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the DSA key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataDsaGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataDsaGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataDsaId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataDsaGetKlass()); +} + +/** + * xmlSecKeyDataGost2001GetKlass: + * + * The GOST2001 key data klass. + * + * Returns: GOST2001 key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the GOST2001 key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataGost2001GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataGost2001GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataGost2001Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataGost2001GetKlass()); +} + +/** + * xmlSecKeyDataHmacGetKlass: + * + * The HMAC key data klass. + * + * Returns: HMAC key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the HMAC key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataHmacGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataHmacGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataHmacId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataHmacGetKlass()); +} + +/** + * xmlSecKeyDataRsaGetKlass: + * + * The RSA key data klass. + * + * Returns: RSA key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the RSA key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataRsaGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataRsaGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataRsaId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataRsaGetKlass()); +} + +/** + * xmlSecKeyDataX509GetKlass: + * + * The X509 key data klass. + * + * Returns: X509 key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the X509 key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataX509GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataX509GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataX509Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataX509GetKlass()); +} + +/** + * xmlSecKeyDataRawX509CertGetKlass: + * + * The raw X509 cert key data klass. + * + * Returns: raw x509 cert key data klass or NULL if an error occurs + * (xmlsec-crypto library is not loaded or the raw X509 cert key data + * klass is not implemented). + */ +xmlSecKeyDataId +xmlSecKeyDataRawX509CertGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->keyDataRawX509CertGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "keyDataRawX509CertId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyDataIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->keyDataRawX509CertGetKlass()); +} + +/****************************************************************************** + * + * Key data store ids + * + *****************************************************************************/ +/** + * xmlSecX509StoreGetKlass: + * + * The X509 certificates key data store klass. + * + * Returns: pointer to X509 certificates key data store klass or NULL if + * an error occurs (xmlsec-crypto library is not loaded or the raw X509 + * cert key data klass is not implemented). + */ +xmlSecKeyDataStoreId +xmlSecX509StoreGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->x509StoreGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "x509StoreId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecKeyStoreIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->x509StoreGetKlass()); +} + +/****************************************************************************** + * + * Crypto transforms ids + * + *****************************************************************************/ +/** + * xmlSecTransformAes128CbcGetKlass: + * + * AES 128 CBC encryption transform klass. + * + * Returns: pointer to AES 128 CBC encryption transform or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformAes128CbcGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformAes128CbcGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformAes128CbcId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformAes128CbcGetKlass()); +} + +/** + * xmlSecTransformAes192CbcGetKlass: + * + * AES 192 CBC encryption transform klass. + * + * Returns: pointer to AES 192 CBC encryption transform or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformAes192CbcGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformAes192CbcGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformAes192CbcId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformAes192CbcGetKlass()); +} + +/** + * xmlSecTransformAes256CbcGetKlass: + * + * AES 256 CBC encryption transform klass. + * + * Returns: pointer to AES 256 CBC encryption transform or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformAes256CbcGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformAes256CbcGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformAes256CbcId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformAes256CbcGetKlass()); +} + +/** + * xmlSecTransformKWAes128GetKlass: + * + * The AES-128 kew wrapper transform klass. + * + * Returns: AES-128 kew wrapper transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformKWAes128GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformKWAes128GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformKWAes128Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformKWAes128GetKlass()); +} + +/** + * xmlSecTransformKWAes192GetKlass: + * + * The AES-192 kew wrapper transform klass. + * + * Returns: AES-192 kew wrapper transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformKWAes192GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformKWAes192GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformKWAes192Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformKWAes192GetKlass()); +} + +/** + * xmlSecTransformKWAes256GetKlass: + * + * The AES-256 kew wrapper transform klass. + * + * Returns: AES-256 kew wrapper transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformKWAes256GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformKWAes256GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformKWAes256Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformKWAes256GetKlass()); +} + +/** + * xmlSecTransformDes3CbcGetKlass: + * + * Triple DES CBC encryption transform klass. + * + * Returns: pointer to Triple DES encryption transform or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformDes3CbcGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformDes3CbcGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformDes3CbcId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformDes3CbcGetKlass()); +} + +/** + * xmlSecTransformKWDes3GetKlass: + * + * The Triple DES key wrapper transform klass. + * + * Returns: Triple DES key wrapper transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformKWDes3GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformKWDes3GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformKWDes3Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformKWDes3GetKlass()); +} + +/** + * xmlSecTransformDsaSha1GetKlass: + * + * The DSA-SHA1 signature transform klass. + * + * Returns: DSA-SHA1 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformDsaSha1GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformDsaSha1GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformDsaSha1Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformDsaSha1GetKlass()); +} + +/** + * xmlSecTransformGost2001GostR3411_94GetKlass: + * + * The GOST2001-GOSTR3411_94 signature transform klass. + * + * Returns: GOST2001-GOSTR3411_94 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformGost2001GostR3411_94GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformGost2001GostR3411_94GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformGost2001GostR3411_94Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformGost2001GostR3411_94GetKlass()); +} + +/** + * xmlSecTransformHmacMd5GetKlass: + * + * The HMAC-MD5 transform klass. + * + * Returns: the HMAC-MD5 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacMd5GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacMd5GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacMd5Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacMd5GetKlass()); +} + +/** + * xmlSecTransformHmacRipemd160GetKlass: + * + * The HMAC-RIPEMD160 transform klass. + * + * Returns: the HMAC-RIPEMD160 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacRipemd160GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacRipemd160GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacRipemd160Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacRipemd160GetKlass()); +} + +/** + * xmlSecTransformHmacSha1GetKlass: + * + * The HMAC-SHA1 transform klass. + * + * Returns: the HMAC-SHA1 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacSha1GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacSha1GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacSha1Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacSha1GetKlass()); +} + +/** + * xmlSecTransformHmacSha224GetKlass: + * + * The HMAC-SHA224 transform klass. + * + * Returns: the HMAC-SHA224 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacSha224GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacSha224GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacSha224Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacSha224GetKlass()); +} + +/** + * xmlSecTransformHmacSha256GetKlass: + * + * The HMAC-SHA256 transform klass. + * + * Returns: the HMAC-SHA256 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacSha256GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacSha256GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacSha256Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacSha256GetKlass()); +} + +/** + * xmlSecTransformHmacSha384GetKlass: + * + * The HMAC-SHA384 transform klass. + * + * Returns: the HMAC-SHA384 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacSha384GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacSha384GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacSha384Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacSha384GetKlass()); +} + +/** + * xmlSecTransformHmacSha512GetKlass: + * + * The HMAC-SHA512 transform klass. + * + * Returns: the HMAC-SHA512 transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformHmacSha512GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformHmacSha512GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformHmacSha512Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformHmacSha512GetKlass()); +} + +/** + * xmlSecTransformMd5GetKlass: + * + * MD5 digest transform klass. + * + * Returns: pointer to MD5 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformMd5GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformMd5GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformMd5Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformMd5GetKlass()); +} + +/** + * xmlSecTransformRipemd160GetKlass: + * + * RIPEMD-160 digest transform klass. + * + * Returns: pointer to RIPEMD-160 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRipemd160GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRipemd160GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRipemd160Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRipemd160GetKlass()); +} + +/** + * xmlSecTransformRsaMd5GetKlass: + * + * The RSA-MD5 signature transform klass. + * + * Returns: RSA-MD5 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaMd5GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaMd5GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaMd5Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaMd5GetKlass()); +} + +/** + * xmlSecTransformRsaRipemd160GetKlass: + * + * The RSA-RIPEMD160 signature transform klass. + * + * Returns: RSA-RIPEMD160 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaRipemd160GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaRipemd160GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaRipemd160Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaRipemd160GetKlass()); +} + +/** + * xmlSecTransformRsaSha1GetKlass: + * + * The RSA-SHA1 signature transform klass. + * + * Returns: RSA-SHA1 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaSha1GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaSha1GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaSha1Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaSha1GetKlass()); +} + +/** + * xmlSecTransformRsaSha224GetKlass: + * + * The RSA-SHA224 signature transform klass. + * + * Returns: RSA-SHA224 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaSha224GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaSha224GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaSha224Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaSha224GetKlass()); +} + +/** + * xmlSecTransformRsaSha256GetKlass: + * + * The RSA-SHA256 signature transform klass. + * + * Returns: RSA-SHA256 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaSha256GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaSha256GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaSha256Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaSha256GetKlass()); +} + +/** + * xmlSecTransformRsaSha384GetKlass: + * + * The RSA-SHA384 signature transform klass. + * + * Returns: RSA-SHA384 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaSha384GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaSha384GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaSha384Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaSha384GetKlass()); +} + +/** + * xmlSecTransformRsaSha512GetKlass: + * + * The RSA-SHA512 signature transform klass. + * + * Returns: RSA-SHA512 signature transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaSha512GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaSha512GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaSha512Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaSha512GetKlass()); +} + +/** + * xmlSecTransformRsaPkcs1GetKlass: + * + * The RSA-PKCS1 key transport transform klass. + * + * Returns: RSA-PKCS1 key transport transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaPkcs1GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaPkcs1GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaPkcs1Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaPkcs1GetKlass()); +} + +/** + * xmlSecTransformRsaOaepGetKlass: + * + * The RSA-OAEP key transport transform klass. + * + * Returns: RSA-OAEP key transport transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformRsaOaepGetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformRsaOaepGetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformRsaOaepId", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformRsaOaepGetKlass()); +} + +/** + * xmlSecTransformGostR3411_94GetKlass: + * + * GOSTR3411_94 digest transform klass. + * + * Returns: pointer to GOSTR3411_94 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformGostR3411_94GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformGostR3411_94GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformGostR3411_94Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformGostR3411_94GetKlass()); +} + + +/** + * xmlSecTransformSha1GetKlass: + * + * SHA-1 digest transform klass. + * + * Returns: pointer to SHA-1 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformSha1GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformSha1GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformSha1Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformSha1GetKlass()); +} + +/** + * xmlSecTransformSha224GetKlass: + * + * SHA224 digest transform klass. + * + * Returns: pointer to SHA224 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformSha224GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformSha224GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformSha224Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformSha224GetKlass()); +} + +/** + * xmlSecTransformSha256GetKlass: + * + * SHA256 digest transform klass. + * + * Returns: pointer to SHA256 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformSha256GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformSha256GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformSha256Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformSha256GetKlass()); +} + +/** + * xmlSecTransformSha384GetKlass: + * + * SHA384 digest transform klass. + * + * Returns: pointer to SHA384 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformSha384GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformSha384GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformSha384Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformSha384GetKlass()); +} + +/** + * xmlSecTransformSha512GetKlass: + * + * SHA512 digest transform klass. + * + * Returns: pointer to SHA512 digest transform klass or NULL if an error + * occurs (the xmlsec-crypto library is not loaded or this transform is not + * implemented). + */ +xmlSecTransformId +xmlSecTransformSha512GetKlass(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->transformSha512GetKlass == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "transformSha512Id", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecTransformIdUnknown); + } + + return(xmlSecCryptoDLGetFunctions()->transformSha512GetKlass()); +} + +/****************************************************************************** + * + * High level routines form xmlsec command line utility + * + *****************************************************************************/ +/** + * xmlSecCryptoAppInit: + * @config: the path to crypto library configuration. + * + * 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 +xmlSecCryptoAppInit(const char* config) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppInit == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppInit", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppInit(config)); +} + + +/** + * xmlSecCryptoAppShutdown: + * + * 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 +xmlSecCryptoAppShutdown(void) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppShutdown == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppShutdown", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppShutdown()); +} + +/** + * xmlSecCryptoAppDefaultKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Initializes @mngr with simple keys store #xmlSecSimpleKeysStoreId + * and a default crypto key data stores. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrInit == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppDefaultKeysMngrInit", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrInit(mngr)); +} + +/** + * xmlSecCryptoAppDefaultKeysMngrAdoptKey: + * @mngr: the pointer to keys manager. + * @key: the pointer to key. + * + * Adds @key to the keys manager @mngr created with #xmlSecCryptoAppDefaultKeysMngrInit + * function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr mngr, xmlSecKeyPtr key) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrAdoptKey == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppDefaultKeysMngrAdoptKey", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrAdoptKey(mngr, key)); +} + +/** + * xmlSecCryptoAppDefaultKeysMngrLoad: + * @mngr: the pointer to keys manager. + * @uri: the uri. + * + * Loads XML keys file from @uri to the keys manager @mngr created + * with #xmlSecCryptoAppDefaultKeysMngrInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoAppDefaultKeysMngrLoad(xmlSecKeysMngrPtr mngr, const char* uri) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrLoad == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppDefaultKeysMngrLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrLoad(mngr, uri)); +} + +/** + * xmlSecCryptoAppDefaultKeysMngrSave: + * @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 +xmlSecCryptoAppDefaultKeysMngrSave(xmlSecKeysMngrPtr mngr, const char* filename, + xmlSecKeyDataType type) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrSave == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppDefaultKeysMngrSave", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppDefaultKeysMngrSave(mngr, filename, type)); +} + +/** + * xmlSecCryptoAppKeysMngrCertLoad: + * @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. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, + xmlSecKeyDataFormat format, xmlSecKeyDataType type) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppKeysMngrCertLoad == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppKeysMngrCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppKeysMngrCertLoad(mngr, filename, format, type)); +} + +/** + * xmlSecCryptoAppKeysMngrCertLoadMemory: + * @mngr: the keys manager. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * @type: the flag that indicates is the certificate trusted or not. + * + * Reads cert from binary buffer @data and adds to the list of trusted or known + * untrusted certs in @store. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppKeysMngrCertLoadMemory == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppKeysMngrCertLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppKeysMngrCertLoadMemory(mngr, data, dataSize, format, type)); +} + +/** + * xmlSecCryptoAppKeyLoad: + * @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 +xmlSecCryptoAppKeyLoad(const char *filename, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppKeyLoad == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppKeyLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppKeyLoad(filename, format, pwd, pwdCallback, pwdCallbackCtx)); +} + +/** + * xmlSecCryptoAppKeyLoadMemory: + * @data: the binary key data. + * @dataSize: the size of binary key. + * @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 memory buffer. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecCryptoAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppKeyLoadMemory == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppKeyLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppKeyLoadMemory(data, dataSize, format, pwd, pwdCallback, pwdCallbackCtx)); +} + +/** + * xmlSecCryptoAppPkcs12Load: + * @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. + * For uniformity, call xmlSecCryptoAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecCryptoAppPkcs12Load(const char* filename, const char* pwd, void* pwdCallback, + void* pwdCallbackCtx) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppPkcs12Load == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppPkcs12Load", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppPkcs12Load(filename, pwd, pwdCallback, pwdCallbackCtx)); +} + +/** + * xmlSecCryptoAppPkcs12LoadMemory: + * @data: the PKCS12 binary data. + * @dataSize: the PKCS12 binary data size. + * @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 data in memory buffer. + * For uniformity, call xmlSecCryptoAppKeyLoadMemory instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecCryptoAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, + const char *pwd, void* pwdCallback, + void* pwdCallbackCtx) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppPkcs12LoadMemory == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppPkcs12LoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppPkcs12LoadMemory(data, dataSize, pwd, pwdCallback, pwdCallbackCtx)); +} + +/** + * xmlSecCryptoAppKeyCertLoad: + * @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 +xmlSecCryptoAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, xmlSecKeyDataFormat format) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppKeyCertLoad == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppKeyCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppKeyCertLoad(key, filename, format)); +} + +/** + * xmlSecCryptoAppKeyCertLoadMemory: + * @key: the pointer to key. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * + * Reads the certificate from memory buffer and adds it to key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecCryptoAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format) { + if((xmlSecCryptoDLGetFunctions() == NULL) || (xmlSecCryptoDLGetFunctions()->cryptoAppKeyCertLoadMemory == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cryptoAppKeyCertLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppKeyCertLoadMemory(key, data, dataSize, format)); +} + +/** + * xmlSecCryptoAppGetDefaultPwdCallback: + * + * Gets default password callback. + * + * Returns: default password callback. + */ +void* +xmlSecCryptoAppGetDefaultPwdCallback(void) { + if(xmlSecCryptoDLGetFunctions() == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecCryptoDLGetFunctions()->cryptoAppDefaultPwdCallback); +} + +#endif /* XMLSEC_NO_CRYPTO_DYNAMIC_LOADING */ + diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 00000000..73b9e504 --- /dev/null +++ b/src/base64.c @@ -0,0 +1,1034 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Base64 encode/decode transform and utility functions. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/base64.h> +#include <xmlsec/errors.h> + +/* + * the table to map numbers to base64 + */ +static const xmlSecByte base64[] = +{ +/* 0 1 2 3 4 5 6 7 */ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', /* 0 */ + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 1 */ + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', /* 2 */ + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', /* 3 */ + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', /* 4 */ + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', /* 5 */ + 'w', 'x', 'y', 'z', '0', '1', '2', '3', /* 6 */ + '4', '5', '6', '7', '8', '9', '+', '/' /* 7 */ +}; + + +/* few macros to simplify the code */ +#define xmlSecBase64Encode1(a) (((a) >> 2) & 0x3F) +#define xmlSecBase64Encode2(a, b) ((((a) << 4) & 0x30) + (((b) >> 4) & 0x0F)) +#define xmlSecBase64Encode3(b, c) ((((b) << 2) & 0x3c) + (((c) >> 6) & 0x03)) +#define xmlSecBase64Encode4(c) ((c) & 0x3F) + +#define xmlSecBase64Decode1(a, b) (((a) << 2) | (((b) & 0x3F) >> 4)) +#define xmlSecBase64Decode2(b, c) (((b) << 4) | (((c) & 0x3F) >> 2)) +#define xmlSecBase64Decode3(c, d) (((c) << 6) | ((d) & 0x3F)) + +#define xmlSecIsBase64Char(ch) ((((ch) >= 'A') && ((ch) <= 'Z')) || \ + (((ch) >= 'a') && ((ch) <= 'z')) || \ + (((ch) >= '0') && ((ch) <= '9')) || \ + ((ch) == '+') || ((ch) == '/')) +#define xmlSecIsBase64Space(ch) (((ch) == ' ') || ((ch) == '\t') || \ + ((ch) == '\x0d') || ((ch) == '\x0a')) + + + +/*********************************************************************** + * + * Base64 Context + * + ***********************************************************************/ +typedef enum { + xmlSecBase64StatusConsumeAndNext = 0, + xmlSecBase64StatusConsumeAndRepeat, + xmlSecBase64StatusNext, + xmlSecBase64StatusDone, + xmlSecBase64StatusFailed +} xmlSecBase64Status; + +struct _xmlSecBase64Ctx { + int encode; + int inByte; + int inPos; + xmlSecSize linePos; + xmlSecSize columns; + int finished; +}; + +static xmlSecBase64Status xmlSecBase64CtxEncodeByte (xmlSecBase64CtxPtr ctx, + xmlSecByte inByte, + xmlSecByte* outByte); +static xmlSecBase64Status xmlSecBase64CtxEncodeByteFinal (xmlSecBase64CtxPtr ctx, + xmlSecByte* outByte); +static xmlSecBase64Status xmlSecBase64CtxDecodeByte (xmlSecBase64CtxPtr ctx, + xmlSecByte inByte, + xmlSecByte* outByte); +static int xmlSecBase64CtxEncode (xmlSecBase64CtxPtr ctx, + const xmlSecByte* inBuf, + xmlSecSize inBufSize, + xmlSecSize* inBufResSize, + xmlSecByte* outBuf, + xmlSecSize outBufSize, + xmlSecSize* outBufResSize); +static int xmlSecBase64CtxEncodeFinal (xmlSecBase64CtxPtr ctx, + xmlSecByte* outBuf, + xmlSecSize outBufSize, + xmlSecSize* outBufResSize); +static int xmlSecBase64CtxDecode (xmlSecBase64CtxPtr ctx, + const xmlSecByte* inBuf, + xmlSecSize inBufSize, + xmlSecSize* inBufResSize, + xmlSecByte* outBuf, + xmlSecSize outBufSize, + xmlSecSize* outBufResSize); +static int xmlSecBase64CtxDecodeIsFinished (xmlSecBase64CtxPtr ctx); + + +static int g_xmlsec_base64_default_line_size = XMLSEC_BASE64_LINESIZE; + +/** + * xmlSecBase64GetDefaultLineSize: + * + * Gets the current default line size. + * + * Returns: the current default line size. + */ +int +xmlSecBase64GetDefaultLineSize(void) +{ + return g_xmlsec_base64_default_line_size; +} + +/** + * xmlSecBase64SetDefaultLineSize: + * @columns: number of columns + * + * Sets the current default line size. + */ +void +xmlSecBase64SetDefaultLineSize(int columns) +{ + g_xmlsec_base64_default_line_size = columns; +} + +/** + * xmlSecBase64CtxCreate: + * @encode: the encode/decode flag (1 - encode, 0 - decode) + * @columns: the max line length. + * + * Allocates and initializes new base64 context. + * + * Returns: a pointer to newly created #xmlSecBase64Ctx structure + * or NULL if an error occurs. + */ +xmlSecBase64CtxPtr +xmlSecBase64CtxCreate(int encode, int columns) { + xmlSecBase64CtxPtr ctx; + int ret; + + /* + * Allocate a new xmlSecBase64CtxPtr and fill the fields. + */ + ctx = (xmlSecBase64CtxPtr) xmlMalloc(sizeof(xmlSecBase64Ctx)); + if (ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecBase64Ctx)=%d", + sizeof(xmlSecBase64Ctx)); + return(NULL); + } + + ret = xmlSecBase64CtxInitialize(ctx, encode, columns); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBase64CtxDestroy(ctx); + return(NULL); + } + return(ctx); +} + +/** + * xmlSecBase64CtxDestroy: + * @ctx: the pointer to #xmlSecBase64Ctx structure. + * + * Destroys base64 context. + */ +void +xmlSecBase64CtxDestroy(xmlSecBase64CtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + xmlSecBase64CtxFinalize(ctx); + xmlFree(ctx); +} + +/** + * xmlSecBase64CtxInitialize: + * @ctx: the pointer to #xmlSecBase64Ctx structure, + * @encode: the encode/decode flag (1 - encode, 0 - decode) + * @columns: the max line length. + * + * Initializes new base64 context. + * + * Returns: 0 on success and a negative value otherwise. + */ +int +xmlSecBase64CtxInitialize(xmlSecBase64CtxPtr ctx, int encode, int columns) { + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecBase64Ctx)); + + ctx->encode = encode; + ctx->columns = columns; + return(0); +} + +/** + * xmlSecBase64CtxFinalize: + * @ctx: the pointer to #xmlSecBase64Ctx structure, + * + * Frees all the resources allocated by @ctx. + */ +void +xmlSecBase64CtxFinalize(xmlSecBase64CtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + memset(ctx, 0, sizeof(xmlSecBase64Ctx)); +} + +/** + * xmlSecBase64CtxUpdate: + * @ctx: the pointer to #xmlSecBase64Ctx structure + * @in: the input buffer + * @inSize: the input buffer size + * @out: the output buffer + * @outSize: the output buffer size + * + * Encodes or decodes the next piece of data from input buffer. + * + * Returns: the number of bytes written to output buffer or + * -1 if an error occurs. + */ +int +xmlSecBase64CtxUpdate(xmlSecBase64CtxPtr ctx, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + xmlSecSize inResSize = 0, outResSize = 0; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + + if(ctx->encode != 0) { + ret = xmlSecBase64CtxEncode(ctx, in, inSize, &inResSize, + out, outSize, &outResSize); + if((ret < 0) || (inResSize != inSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxEncode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + ret = xmlSecBase64CtxDecode(ctx, in, inSize, &inResSize, + out, outSize, &outResSize); + if((ret < 0) || (inResSize != inSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxDecode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(outResSize); +} + +/** + * xmlSecBase64CtxFinal: + * @ctx: the pointer to #xmlSecBase64Ctx structure + * @out: the output buffer + * @outSize: the output buffer size + * + * Encodes or decodes the last piece of data stored in the context + * and finalizes the result. + * + * Returns: the number of bytes written to output buffer or + * -1 if an error occurs. + */ +int +xmlSecBase64CtxFinal(xmlSecBase64CtxPtr ctx, + xmlSecByte *out, xmlSecSize outSize) { + xmlSecSize outResSize = 0; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize > 0, -1); + + if(ctx->encode != 0) { + ret = xmlSecBase64CtxEncodeFinal(ctx, out, outSize, &outResSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxEncodeFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "outSize=%d", outSize); + return(-1); + } + } else { + if(!xmlSecBase64CtxDecodeIsFinished(ctx)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxIsFinished", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* add \0 */ + if((outResSize + 1) < outSize) { + out[outResSize] = '\0'; + } + return(outResSize); +} + +static xmlSecBase64Status +xmlSecBase64CtxEncodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) { + xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed); + xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed); + + if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) { + (*outByte) = '\n'; + ctx->linePos = 0; + return(xmlSecBase64StatusConsumeAndRepeat); + } else if(ctx->inPos == 0) { + /* we just started new block */ + (*outByte) = base64[xmlSecBase64Encode1(inByte)]; + ctx->inByte = inByte; + ++ctx->linePos; + ++ctx->inPos; + return(xmlSecBase64StatusConsumeAndNext); + } else if(ctx->inPos == 1) { + (*outByte) = base64[xmlSecBase64Encode2(ctx->inByte, inByte)]; + ctx->inByte = inByte; + ++ctx->linePos; + ++ctx->inPos; + return(xmlSecBase64StatusConsumeAndNext); + } else if(ctx->inPos == 2) { + (*outByte) = base64[xmlSecBase64Encode3(ctx->inByte, inByte)]; + ctx->inByte = inByte; + ++ctx->linePos; + ++ctx->inPos; + return(xmlSecBase64StatusConsumeAndRepeat); + } else if(ctx->inPos == 3) { + (*outByte) = base64[xmlSecBase64Encode4(ctx->inByte)]; + ++ctx->linePos; + ctx->inByte = 0; + ctx->inPos = 0; + return(xmlSecBase64StatusConsumeAndNext); + } + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "ctx->inPos=%d", ctx->inPos); + return(xmlSecBase64StatusFailed); +} + +static xmlSecBase64Status +xmlSecBase64CtxEncodeByteFinal(xmlSecBase64CtxPtr ctx, xmlSecByte* outByte) { + xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed); + xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed); + + if(ctx->inPos == 0) { + return(xmlSecBase64StatusDone); + } else if((ctx->columns > 0) && (ctx->linePos >= ctx->columns)) { + (*outByte) = '\n'; + ctx->linePos = 0; + return(xmlSecBase64StatusConsumeAndRepeat); + } else if(ctx->finished == 0) { + ctx->finished = 1; + return(xmlSecBase64CtxEncodeByte(ctx, 0, outByte)); + } else if(ctx->inPos < 3) { + (*outByte) = '='; + ++ctx->inPos; + ++ctx->linePos; + return(xmlSecBase64StatusConsumeAndRepeat); + } else if(ctx->inPos == 3) { + (*outByte) = '='; + ++ctx->linePos; + ctx->inPos = 0; + return(xmlSecBase64StatusConsumeAndRepeat); + } + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "ctx->inPos=%d", ctx->inPos); + return(xmlSecBase64StatusFailed); +} + +static xmlSecBase64Status +xmlSecBase64CtxDecodeByte(xmlSecBase64CtxPtr ctx, xmlSecByte inByte, xmlSecByte* outByte) { + xmlSecAssert2(ctx != NULL, xmlSecBase64StatusFailed); + xmlSecAssert2(outByte != NULL, xmlSecBase64StatusFailed); + + if((ctx->finished != 0) && (ctx->inPos == 0)) { + return(xmlSecBase64StatusDone); + } if(inByte == '=') { + ctx->finished = 1; + if(ctx->inPos < 2) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "ctx->inPos=%d", ctx->inPos); + return(xmlSecBase64StatusFailed); + } else if(ctx->inPos == 2) { + ++ctx->inPos; + return(xmlSecBase64StatusNext); + } else if(ctx->inPos == 3) { + ctx->inPos = 0; + return(xmlSecBase64StatusNext); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "ctx->inPos=%d", ctx->inPos); + return(xmlSecBase64StatusFailed); + } + } else if(xmlSecIsBase64Space(inByte)) { + return(xmlSecBase64StatusNext); + } else if(!xmlSecIsBase64Char(inByte) || (ctx->finished != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "inByte=0x%02x", inByte); + return(xmlSecBase64StatusFailed); + } + + /* convert from character to position in base64 array */ + if((inByte >= 'A') && (inByte <= 'Z')) { + inByte = (inByte - 'A'); + } else if((inByte >= 'a') && (inByte <= 'z')) { + inByte = 26 + (inByte - 'a'); + } else if((inByte >= '0') && (inByte <= '9')) { + inByte = 52 + (inByte - '0'); + } else if(inByte == '+') { + inByte = 62; + } else if(inByte == '/') { + inByte = 63; + } + + if(ctx->inPos == 0) { + ctx->inByte = inByte; + ++ctx->inPos; + return(xmlSecBase64StatusNext); + } else if(ctx->inPos == 1) { + (*outByte) = xmlSecBase64Decode1(ctx->inByte, inByte); + ctx->inByte = inByte; + ++ctx->inPos; + return(xmlSecBase64StatusConsumeAndNext); + } else if(ctx->inPos == 2) { + (*outByte) = xmlSecBase64Decode2(ctx->inByte, inByte); + ctx->inByte = inByte; + ++ctx->inPos; + return(xmlSecBase64StatusConsumeAndNext); + } else if(ctx->inPos == 3) { + (*outByte) = xmlSecBase64Decode3(ctx->inByte, inByte); + ctx->inByte = 0; + ctx->inPos = 0; + return(xmlSecBase64StatusConsumeAndNext); + } + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "ctx->inPos=%d", ctx->inPos); + return(xmlSecBase64StatusFailed); +} + + +static int +xmlSecBase64CtxEncode(xmlSecBase64CtxPtr ctx, + const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize, + xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) { + xmlSecBase64Status status = xmlSecBase64StatusNext; + xmlSecSize inPos, outPos; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(inBuf != NULL, -1); + xmlSecAssert2(inBufResSize != NULL, -1); + xmlSecAssert2(outBuf != NULL, -1); + xmlSecAssert2(outBufResSize != NULL, -1); + + /* encode */ + for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize); ) { + status = xmlSecBase64CtxEncodeByte(ctx, inBuf[inPos], &(outBuf[outPos])); + switch(status) { + case xmlSecBase64StatusConsumeAndNext: + ++inPos; + ++outPos; + break; + case xmlSecBase64StatusConsumeAndRepeat: + ++outPos; + break; + case xmlSecBase64StatusNext: + case xmlSecBase64StatusDone: + case xmlSecBase64StatusFailed: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxEncodeByte", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "status=%d", status); + return(-1); + } + } + + (*inBufResSize) = inPos; + (*outBufResSize) = outPos; + + return(0); +} + +static int +xmlSecBase64CtxEncodeFinal(xmlSecBase64CtxPtr ctx, + xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) { + xmlSecBase64Status status = xmlSecBase64StatusNext; + xmlSecSize outPos; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(outBuf != NULL, -1); + xmlSecAssert2(outBufResSize != NULL, -1); + + /* encode final bytes */ + for(outPos = 0; (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) { + status = xmlSecBase64CtxEncodeByteFinal(ctx, &(outBuf[outPos])); + switch(status) { + case xmlSecBase64StatusConsumeAndNext: + case xmlSecBase64StatusConsumeAndRepeat: + ++outPos; + break; + case xmlSecBase64StatusDone: + break; + case xmlSecBase64StatusNext: + case xmlSecBase64StatusFailed: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxEncodeByteFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "status=%d", status); + return(-1); + } + } + + if(status != xmlSecBase64StatusDone) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "outBufSize=%d", outBufSize); + return(-1); + } + if(outPos < outBufSize) { + outBuf[outPos] = '\0'; /* just in case */ + } + + (*outBufResSize) = outPos; + return(0); +} + + +static int +xmlSecBase64CtxDecode(xmlSecBase64CtxPtr ctx, + const xmlSecByte* inBuf, xmlSecSize inBufSize, xmlSecSize* inBufResSize, + xmlSecByte* outBuf, xmlSecSize outBufSize, xmlSecSize* outBufResSize) { + xmlSecBase64Status status = xmlSecBase64StatusNext; + xmlSecSize inPos, outPos; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(inBuf != NULL, -1); + xmlSecAssert2(inBufResSize != NULL, -1); + xmlSecAssert2(outBuf != NULL, -1); + xmlSecAssert2(outBufResSize != NULL, -1); + + /* decode */ + for(inPos = outPos = 0; (inPos < inBufSize) && (outPos < outBufSize) && (status != xmlSecBase64StatusDone); ) { + status = xmlSecBase64CtxDecodeByte(ctx, inBuf[inPos], &(outBuf[outPos])); + switch(status) { + case xmlSecBase64StatusConsumeAndNext: + ++inPos; + ++outPos; + break; + case xmlSecBase64StatusConsumeAndRepeat: + ++outPos; + break; + case xmlSecBase64StatusNext: + ++inPos; + break; + case xmlSecBase64StatusDone: + break; + case xmlSecBase64StatusFailed: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxDecodeByte", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "status=%d", status); + return(-1); + } + } + + /* skip spaces at the end */ + while((inPos < inBufSize) && xmlSecIsBase64Space(inBuf[inPos])) { + ++inPos; + } + + (*inBufResSize) = inPos; + (*outBufResSize) = outPos; + + return(0); +} + +static int +xmlSecBase64CtxDecodeIsFinished(xmlSecBase64CtxPtr ctx) { + xmlSecAssert2(ctx != NULL, -1); + + return((ctx->inPos == 0) ? 1 : 0); +} + +/** + * xmlSecBase64Encode: + * @buf: the input buffer. + * @len: the input buffer size. + * @columns: the output max line length (if 0 then no line breaks + * would be inserted) + * + * Encodes the data from input buffer and allocates the string for the result. + * The caller is responsible for freeing returned buffer using + * xmlFree() function. + * + * Returns: newly allocated string with base64 encoded data + * or NULL if an error occurs. + */ +xmlChar* +xmlSecBase64Encode(const xmlSecByte *buf, xmlSecSize len, int columns) { + xmlSecBase64Ctx ctx; + xmlChar *ptr; + xmlSecSize size; + int size_update, size_final; + int ret; + + xmlSecAssert2(buf != NULL, NULL); + + ret = xmlSecBase64CtxInitialize(&ctx, 1, columns); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* create result buffer */ + size = (4 * len) / 3 + 4; + if(columns > 0) { + size += (size / columns) + 4; + } + ptr = (xmlChar*) xmlMalloc(size); + if(ptr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", size); + xmlSecBase64CtxFinalize(&ctx); + return(NULL); + } + + ret = xmlSecBase64CtxUpdate(&ctx, buf, len, (xmlSecByte*)ptr, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "len=%d", len); + xmlFree(ptr); + xmlSecBase64CtxFinalize(&ctx); + return(NULL); + } + size_update = ret; + + ret = xmlSecBase64CtxFinal(&ctx, ((xmlSecByte*)ptr) + size_update, size - size_update); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(ptr); + xmlSecBase64CtxFinalize(&ctx); + return(NULL); + } + size_final = ret; + ptr[size_update + size_final] = '\0'; + + xmlSecBase64CtxFinalize(&ctx); + return(ptr); +} + +/** + * xmlSecBase64Decode: + * @str: the input buffer with base64 encoded string + * @buf: the output buffer + * @len: the output buffer size + * + * Decodes input base64 encoded string and puts result into + * the output buffer. + * + * Returns: the number of bytes written to the output buffer or + * a negative value if an error occurs + */ +int +xmlSecBase64Decode(const xmlChar* str, xmlSecByte *buf, xmlSecSize len) { + xmlSecBase64Ctx ctx; + int size_update; + int size_final; + int ret; + + xmlSecAssert2(str != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + + ret = xmlSecBase64CtxInitialize(&ctx, 0, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBase64CtxUpdate(&ctx, (const xmlSecByte*)str, xmlStrlen(str), buf, len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBase64CtxFinalize(&ctx); + return(-1); + } + + size_update = ret; + ret = xmlSecBase64CtxFinal(&ctx, buf + size_update, len - size_update); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64CtxFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBase64CtxFinalize(&ctx); + return(-1); + } + size_final = ret; + + xmlSecBase64CtxFinalize(&ctx); + return(size_update + size_final); +} + +/************************************************************** + * + * Base64 Transform + * + * xmlSecBase64Ctx is located after xmlSecTransform + * + **************************************************************/ +#define xmlSecBase64Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecBase64Ctx)) +#define xmlSecBase64GetCtx(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecBase64Size)) ? \ + (xmlSecBase64CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \ + (xmlSecBase64CtxPtr)NULL) + +static int xmlSecBase64Initialize (xmlSecTransformPtr transform); +static void xmlSecBase64Finalize (xmlSecTransformPtr transform); +static int xmlSecBase64Execute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecBase64Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecBase64Size, /* xmlSecSize objSize */ + + xmlSecNameBase64, /* const xmlChar* name; */ + xmlSecHrefBase64, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecAlgorithmUsage usage; */ + + xmlSecBase64Initialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecBase64Finalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecBase64Execute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformBase64GetKlass: + * + * The Base64 transform klass (http://www.w3.org/TR/xmldsig-core/#sec-Base-64). + * The normative specification for base64 decoding transforms is RFC 2045 + * (http://www.ietf.org/rfc/rfc2045.txt). The base64 Transform element has + * no content. The input is decoded by the algorithms. This transform is + * useful if an application needs to sign the raw data associated with + * the encoded content of an element. + * + * Returns: base64 transform id. + */ +xmlSecTransformId +xmlSecTransformBase64GetKlass(void) { + return(&xmlSecBase64Klass); +} + +/** + * xmlSecTransformBase64SetLineSize: + * @transform: the pointer to BASE64 encode transform. + * @lineSize: the new max line size. + * + * Sets the max line size to @lineSize. + */ +void +xmlSecTransformBase64SetLineSize(xmlSecTransformPtr transform, xmlSecSize lineSize) { + xmlSecBase64CtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id)); + + ctx = xmlSecBase64GetCtx(transform); + xmlSecAssert(ctx != NULL); + + ctx->columns = lineSize; +} + +static int +xmlSecBase64Initialize(xmlSecTransformPtr transform) { + xmlSecBase64CtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1); + + ctx = xmlSecBase64GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + transform->operation = xmlSecTransformOperationDecode; + ret = xmlSecBase64CtxInitialize(ctx, 0, xmlSecBase64GetDefaultLineSize()); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBase64CtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecBase64Finalize(xmlSecTransformPtr transform) { + xmlSecBase64CtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id)); + + ctx = xmlSecBase64GetCtx(transform); + xmlSecAssert(ctx != NULL); + + xmlSecBase64CtxFinalize(ctx); +} + +static int +xmlSecBase64Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecBase64CtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize, outLen; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformBase64Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncode) || (transform->operation == xmlSecTransformOperationDecode), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecBase64GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + if(transform->status == xmlSecTransformStatusNone) { + ctx->encode = (transform->operation == xmlSecTransformOperationEncode) ? 1 : 0; + transform->status = xmlSecTransformStatusWorking; + } + + switch(transform->status) { + case xmlSecTransformStatusWorking: + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + if(inSize > 0) { + if(ctx->encode != 0) { + outLen = 4 * inSize / 3 + 8; + if(ctx->columns > 0) { + outLen += inSize / ctx->columns + 4; + } + } else { + outLen = 3 * inSize / 4 + 8; + } + ret = xmlSecBufferSetMaxSize(out, outSize + outLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen); + return(-1); + } + + /* encode/decode the next chunk */ + ret = xmlSecBase64CtxUpdate(ctx, xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out) + outSize, + outLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBase64CtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outLen = ret; + + /* set correct size */ + ret = xmlSecBufferSetSize(out, outSize + outLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen); + return(-1); + } + + /* remove chunk from input */ + 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) { + outSize = xmlSecBufferGetSize(out); + + ret = xmlSecBufferSetMaxSize(out, outSize + 16); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + 16); + return(-1); + } + + /* add from ctx buffer */ + ret = xmlSecBase64CtxFinal(ctx, xmlSecBufferGetData(out) + outSize, 16); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBase64CtxFinal", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outLen = ret; + + /* set correct size */ + ret = xmlSecBufferSetSize(out, outSize + outLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen); + return(-1); + } + transform->status = xmlSecTransformStatusFinished; + } + break; + case xmlSecTransformStatusFinished: + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + + diff --git a/src/bn.c b/src/bn.c new file mode 100644 index 00000000..5a26de28 --- /dev/null +++ b/src/bn.c @@ -0,0 +1,1060 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Big Numbers. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyrigth (C) 2003 Cordys R&D BV, All rights reserved. + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/base64.h> +#include <xmlsec/bn.h> +#include <xmlsec/errors.h> + +/* table for converting hex digits back to bytes */ +static const int xmlSecBnLookupTable[] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static const char xmlSecBnRevLookupTable[] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + +/***************************************************************************** + * + * xmlSecBn + * + ****************************************************************************/ +/** + * xmlSecBnCreate: + * @size: the initial allocated BN size. + * + * Creates a new BN object. Caller is responsible for destroying it + * by calling @xmlSecBnDestroy function. + * + * Returns: the newly BN or a NULL if an error occurs. + */ +xmlSecBnPtr +xmlSecBnCreate(xmlSecSize size) { + return(xmlSecBufferCreate(size)); +} + +/** + * xmlSecBnDestroy: + * @bn: the pointer to BN. + * + * Destroys @bn object created with @xmlSecBnCreate function. + */ +void +xmlSecBnDestroy(xmlSecBnPtr bn) { + xmlSecBufferDestroy(bn); +} + +/** + * xmlSecBnInitialize: + * @bn: the pointer to BN. + * @size: the initial allocated BN size. + * + * Initializes a BN object. Caller is responsible for destroying it + * by calling @xmlSecBnFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnInitialize(xmlSecBnPtr bn, xmlSecSize size) { + return(xmlSecBufferInitialize(bn, size)); +} + +/** + * xmlSecBnFinalize: + * @bn: the pointer to BN. + * + * Destroys @bn object created with @xmlSecBnInitialize function. + */ +void +xmlSecBnFinalize(xmlSecBnPtr bn) { + xmlSecBufferFinalize(bn); +} + +/** + * xmlSecBnGetData: + * @bn: the pointer to BN. + * + * Gets pointer to the binary @bn representation. + * + * Returns: pointer to binary BN data or NULL if an error occurs. + */ +xmlSecByte* +xmlSecBnGetData(xmlSecBnPtr bn) { + return(xmlSecBufferGetData(bn)); +} + +/** + * xmlSecBnSetData: + * @bn: the pointer to BN. + * @data: the pointer to new BN binary data. + * @size: the size of new BN data. + * + * Sets the value of @bn to @data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnSetData(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize size) { + return(xmlSecBufferSetData(bn, data, size)); +} + +/** + * xmlSecBnGetSize: + * @bn: the pointer to BN. + * + * Gets the size of binary data in @bn. + * + * Returns: the size of binary data. + */ +xmlSecSize +xmlSecBnGetSize(xmlSecBnPtr bn) { + return(xmlSecBufferGetSize(bn)); +} + +/** + * xmlSecBnZero: + * @bn: the pointer to BN. + * + * Sets the value of @bn to zero. + */ +void +xmlSecBnZero(xmlSecBnPtr bn) { + xmlSecBufferEmpty(bn); +} + +/** + * xmlSecBnFromString: + * @bn: the pointer to BN. + * @str: the string with BN. + * @base: the base for @str. + * + * Reads @bn from string @str assuming it has base @base. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnFromString(xmlSecBnPtr bn, const xmlChar* str, xmlSecSize base) { + xmlSecSize i, len, size; + xmlSecByte ch; + xmlSecByte* data; + int positive; + int nn; + int ret; + + xmlSecAssert2(bn != NULL, -1); + xmlSecAssert2(str != NULL, -1); + xmlSecAssert2(base > 1, -1); + xmlSecAssert2(base <= sizeof(xmlSecBnRevLookupTable), -1); + + /* trivial case */ + len = xmlStrlen(str); + if(len == 0) { + return(0); + } + + /* The result size could not exceed the input string length + * because each char fits inside a byte in all cases :) + * In truth, it would be likely less than 1/2 input string length + * because each byte is represented by 2 chars. If needed, + * buffer size would be increased by Mul/Add functions. + * Finally, we can add one byte for 00 or 10 prefix. + */ + ret = xmlSecBufferSetMaxSize(bn, xmlSecBufferGetSize(bn) + len / 2 + 1 + 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnRevLookupTable", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", len / 2 + 1); + return (-1); + } + + /* figure out if it is positive or negative number */ + positive = 1; + i = 0; + while(i < len) { + ch = str[i++]; + + /* skip spaces */ + if(isspace(ch)) { + continue; + } + + /* check if it is + or - */ + if(ch == '+') { + positive = 1; + break; + } else if(ch == '-') { + positive = 0; + break; + } + + /* otherwise, it must be start of the number */ + nn = xmlSecBnLookupTable[ch]; + if((nn >= 0) && ((xmlSecSize)nn < base)) { + xmlSecAssert2(i > 0, -1); + + /* no sign, positive by default */ + positive = 1; + --i; /* make sure that we will look at this character in next loop */ + break; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "char=%c;base=%d", + ch, base); + return (-1); + } + } + + /* now parse the number itself */ + while(i < len) { + ch = str[i++]; + if(isspace(ch)) { + continue; + } + + xmlSecAssert2(ch <= sizeof(xmlSecBnLookupTable), -1); + nn = xmlSecBnLookupTable[ch]; + if((nn < 0) || ((xmlSecSize)nn > base)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "char=%c;base=%d", + ch, base); + return (-1); + } + + ret = xmlSecBnMul(bn, base); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnMul", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "base=%d", base); + return (-1); + } + + ret = xmlSecBnAdd(bn, nn); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "base=%d", base); + return (-1); +} + } + + /* check if we need to add 00 prefix, do this for empty bn too */ + data = xmlSecBufferGetData(bn); + size = xmlSecBufferGetSize(bn); + if(((size > 0) && (data[0] > 127)) || (size == 0)) { + ch = 0; + ret = xmlSecBufferPrepend(bn, &ch, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "base=%d", base); + return (-1); + } + } + + /* do 2's compliment and add 1 to represent negative value */ + if(positive == 0) { + data = xmlSecBufferGetData(bn); + size = xmlSecBufferGetSize(bn); + for(i = 0; i < size; ++i) { + data[i] ^= 0xFF; + } + + ret = xmlSecBnAdd(bn, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "base=%d", base); + return (-1); + } + } + + return(0); +} + +/** + * xmlSecBnToString: + * @bn: the pointer to BN. + * @base: the base for returned string. + * + * Writes @bn to string with base @base. Caller is responsible for + * freeing returned string with @xmlFree. + * + * Returns: the string represenataion if BN or a NULL if an error occurs. + */ +xmlChar* +xmlSecBnToString(xmlSecBnPtr bn, xmlSecSize base) { + xmlSecBn bn2; + int positive = 1; + xmlChar* res; + xmlSecSize i, len, size; + xmlSecByte* data; + int ret; + int nn; + xmlChar ch; + + xmlSecAssert2(bn != NULL, NULL); + xmlSecAssert2(base > 1, NULL); + xmlSecAssert2(base <= sizeof(xmlSecBnRevLookupTable), NULL); + + + /* copy bn */ + data = xmlSecBufferGetData(bn); + size = xmlSecBufferGetSize(bn); + ret = xmlSecBnInitialize(&bn2, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return (NULL); + } + + ret = xmlSecBnSetData(&bn2, data, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlSecBnFinalize(&bn2); + return (NULL); + } + + /* check if it is a negative number or not */ + data = xmlSecBufferGetData(&bn2); + size = xmlSecBufferGetSize(&bn2); + if((size > 0) && (data[0] > 127)) { + /* subtract 1 and do 2's compliment */ + ret = xmlSecBnAdd(&bn2, -1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlSecBnFinalize(&bn2); + return (NULL); + } + for(i = 0; i < size; ++i) { + data[i] ^= 0xFF; + } + + positive = 0; + } else { + positive = 1; + } + + /* Result string len is + * len = log base (256) * <bn size> + * Since the smallest base == 2 then we can get away with + * len = 8 * <bn size> + */ + len = 8 * size + 1 + 1; + res = (xmlChar*)xmlMalloc(len + 1); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "len=%d", len); + xmlSecBnFinalize(&bn2); + return (NULL); + } + memset(res, 0, len + 1); + + for(i = 0; (xmlSecBufferGetSize(&bn2) > 0) && (i < len); i++) { + if(xmlSecBnDiv(&bn2, base, &nn) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnDiv", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "base=%d", base); + xmlFree(res); + xmlSecBnFinalize(&bn2); + return (NULL); + } + xmlSecAssert2((size_t)nn < sizeof(xmlSecBnRevLookupTable), NULL); + res[i] = xmlSecBnRevLookupTable[nn]; + } + xmlSecAssert2(i < len, NULL); + + /* we might have '0' at the beggining, remove it but keep one zero */ + for(len = i; (len > 1) && (res[len - 1] == '0'); len--); + res[len] = '\0'; + + /* add "-" for negative numbers */ + if(positive == 0) { + res[len] = '-'; + res[++len] = '\0'; + } + + /* swap the string because we wrote it in reverse order */ + for(i = 0; i < len / 2; i++) { + ch = res[i]; + res[i] = res[len - i - 1]; + res[len - i - 1] = ch; + } + + xmlSecBnFinalize(&bn2); + return(res); +} + +/** + * xmlSecBnFromHexString: + * @bn: the pointer to BN. + * @str: the string with BN. + * + * Reads @bn from hex string @str. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnFromHexString(xmlSecBnPtr bn, const xmlChar* str) { + return(xmlSecBnFromString(bn, str, 16)); +} + +/** + * xmlSecBnToHexString: + * @bn: the pointer to BN. + * + * Writes @bn to hex string. Caller is responsible for + * freeing returned string with @xmlFree. + * + * Returns: the string represenataion if BN or a NULL if an error occurs. + */ +xmlChar* +xmlSecBnToHexString(xmlSecBnPtr bn) { + return(xmlSecBnToString(bn, 16)); +} + +/** + * xmlSecBnFromDecString: + * @bn: the pointer to BN. + * @str: the string with BN. + * + * Reads @bn from decimal string @str. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnFromDecString(xmlSecBnPtr bn, const xmlChar* str) { + return(xmlSecBnFromString(bn, str, 10)); +} + +/** + * xmlSecBnToDecString: + * @bn: the pointer to BN. + * + * Writes @bn to decimal string. Caller is responsible for + * freeing returned string with @xmlFree. + * + * Returns: the string represenataion if BN or a NULL if an error occurs. + */ +xmlChar* +xmlSecBnToDecString(xmlSecBnPtr bn) { + return(xmlSecBnToString(bn, 10)); +} + +/** + * xmlSecBnMul: + * @bn: the pointer to BN. + * @multiplier: the multiplier. + * + * Multiplies @bn with @multiplier. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnMul(xmlSecBnPtr bn, int multiplier) { + xmlSecByte* data; + int over; + xmlSecSize i; + xmlSecByte ch; + int ret; + + xmlSecAssert2(bn != NULL, -1); + xmlSecAssert2(multiplier > 0, -1); + + if(multiplier == 1) { + return(0); + } + + data = xmlSecBufferGetData(bn); + i = xmlSecBufferGetSize(bn); + over = 0; + while(i > 0) { + xmlSecAssert2(data != NULL, -1); + + over = over + multiplier * data[--i]; + data[i] = over % 256; + over = over / 256; + } + + while(over > 0) { + ch = over % 256; + over = over / 256; + + ret = xmlSecBufferPrepend(bn, &ch, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=1"); + return (-1); + } + } + + return(0); +} + +/** + * xmlSecBnDiv: + * @bn: the pointer to BN. + * @divider: the divider + * @mod: the pointer for modulus result. + * + * Divides @bn by @divider and places modulus into @mod. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnDiv(xmlSecBnPtr bn, int divider, int* mod) { + int over; + xmlSecSize i, size; + xmlSecByte* data; + int ret; + + xmlSecAssert2(bn != NULL, -1); + xmlSecAssert2(divider > 0, -1); + xmlSecAssert2(mod != NULL, -1); + + if(divider == 1) { + return(0); + } + + data = xmlSecBufferGetData(bn); + size = xmlSecBufferGetSize(bn); + for(over = 0, i = 0; i < size; i++) { + xmlSecAssert2(data != NULL, -1); + + over = over * 256 + data[i]; + data[i] = over / divider; + over = over % divider; + } + (*mod) = over; + + /* remove leading zeros */ + for(i = 0; i < size; i++) { + xmlSecAssert2(data != NULL, -1); + + if(data[i] != 0) { + break; + } + } + if(i > 0) { + ret = xmlSecBufferRemoveHead(bn, i); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", i); + return (-1); + } + } + return(0); +} + +/** + * xmlSecBnAdd: + * @bn: the pointer to BN. + * @delta: the delta. + * + * Adds @delta to @bn. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnAdd(xmlSecBnPtr bn, int delta) { + int over, tmp; + xmlSecByte* data; + xmlSecSize i; + xmlSecByte ch; + int ret; + + xmlSecAssert2(bn != NULL, -1); + + if(delta == 0) { + return(0); + } + + data = xmlSecBufferGetData(bn); + if(delta > 0) { + for(over = delta, i = xmlSecBufferGetSize(bn); (i > 0) && (over > 0) ;) { + xmlSecAssert2(data != NULL, -1); + + tmp = data[--i]; + over += tmp; + data[i] = over % 256; + over = over / 256; + } + + while(over > 0) { + ch = over % 256; + over = over / 256; + + ret = xmlSecBufferPrepend(bn, &ch, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=1"); + return (-1); + } + } + } else { + for(over = -delta, i = xmlSecBufferGetSize(bn); (i > 0) && (over > 0);) { + xmlSecAssert2(data != NULL, -1); + + tmp = data[--i]; + if(tmp < over) { + data[i] = 0; + over = (over - tmp) / 256; + } else { + data[i] = tmp - over; + over = 0; + } + } + } + return(0); +} + +/** + * xmlSecBnReverse: + * @bn: the pointer to BN. + * + * Reverses bytes order in @bn. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBnReverse(xmlSecBnPtr bn) { + xmlSecByte* data; + xmlSecSize i, j, size; + xmlSecByte ch; + + xmlSecAssert2(bn != NULL, -1); + + data = xmlSecBufferGetData(bn); + size = xmlSecBufferGetSize(bn); + for(i = 0, j = size - 1; i < size / 2; ++i, --j) { + xmlSecAssert2(data != NULL, -1); + + ch = data[i]; + data[i] = data[j]; + data[j] = ch; + } + + return(0); +} + +/** + * xmlSecBnCompare: + * @bn: the pointer to BN. + * @data: the data to compare BN to. + * @dataSize: the @data size. + * + * Compares the @bn with @data. + * + * Returns: 0 if data is equal, negative value if @bn is less or positive value if @bn + * is greater than @data. + */ +int +xmlSecBnCompare(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize dataSize) { + xmlSecByte* bnData; + xmlSecSize bnSize; + + xmlSecAssert2(bn != NULL, -1); + + bnData = xmlSecBnGetData(bn); + bnSize = xmlSecBnGetSize(bn); + + /* skip zeros in the beggining */ + while((dataSize > 0) && (data != 0) && (data[0] == 0)) { + ++data; + --dataSize; + } + while((bnSize > 0) && (bnData != 0) && (bnData[0] == 0)) { + ++bnData; + --bnSize; + } + + if(((bnData == NULL) || (bnSize == 0)) && ((data == NULL) || (dataSize == 0))) { + return(0); + } else if((bnData == NULL) || (bnSize == 0)) { + return(-1); + } else if((data == NULL) || (dataSize == 0)) { + return(1); + } else if(bnSize < dataSize) { + return(-1); + } else if(bnSize > dataSize) { + return(-1); + } + + xmlSecAssert2(bnData != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(bnSize == dataSize, -1); + + return(memcmp(bnData, data, dataSize)); +} + +/** + * xmlSecBnCompareReverse: + * @bn: the pointer to BN. + * @data: the data to compare BN to. + * @dataSize: the @data size. + * + * Compares the @bn with reverse @data. + * + * Returns: 0 if data is equal, negative value if @bn is less or positive value if @bn + * is greater than @data. + */ +int +xmlSecBnCompareReverse(xmlSecBnPtr bn, const xmlSecByte* data, xmlSecSize dataSize) { + xmlSecByte* bnData; + xmlSecSize bnSize; + xmlSecSize i, j; + + xmlSecAssert2(bn != NULL, -1); + + bnData = xmlSecBnGetData(bn); + bnSize = xmlSecBnGetSize(bn); + + /* skip zeros in the beggining */ + while((dataSize > 0) && (data != 0) && (data[dataSize - 1] == 0)) { + --dataSize; + } + while((bnSize > 0) && (bnData != 0) && (bnData[0] == 0)) { + ++bnData; + --bnSize; + } + + if(((bnData == NULL) || (bnSize == 0)) && ((data == NULL) || (dataSize == 0))) { + return(0); + } else if((bnData == NULL) || (bnSize == 0)) { + return(-1); + } else if((data == NULL) || (dataSize == 0)) { + return(1); + } else if(bnSize < dataSize) { + return(-1); + } else if(bnSize > dataSize) { + return(-1); + } + + xmlSecAssert2(bnData != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(bnSize == dataSize, -1); + for(i = 0, j = dataSize - 1; i < dataSize; ++i, --j) { + if(bnData[i] < data[j]) { + return(-1); + } else if(data[j] < bnData[i]) { + return(1); + } + } + + return(0); +} + +/** + * xmlSecBnGetNodeValue: + * @bn: the pointer to BN. + * @cur: the poitner to an XML node. + * @format: the BN format. + * @reverse: if set then reverse read buffer after reading. + * + * Converts the node content from @format to @bn. + * + * Returns: 0 on success and a negative values if an error occurs. + */ +int +xmlSecBnGetNodeValue(xmlSecBnPtr bn, xmlNodePtr cur, xmlSecBnFormat format, int reverse) { + xmlChar* content; + int ret; + + xmlSecAssert2(bn != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + + switch(format) { + case xmlSecBnBase64: + ret = xmlSecBufferBase64NodeContentRead(bn, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferBase64NodeContentRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + break; + case xmlSecBnHex: + content = xmlNodeGetContent(cur); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNodeGetContent", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ret = xmlSecBnFromHexString(bn, content); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnFromHexString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + xmlFree(content); + break; + case xmlSecBnDec: + content = xmlNodeGetContent(cur); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNodeGetContent", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ret = xmlSecBnFromDecString(bn, content); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnFromDecString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + xmlFree(content); + break; + } + + if(reverse != 0) { + ret = xmlSecBnReverse(bn); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +/** + * xmlSecBnSetNodeValue: + * @bn: the pointer to BN. + * @cur: the poitner to an XML node. + * @format: the BN format. + * @reverse: the flag that indicates whether to reverse the buffer before writing. + * @addLineBreaks: the flag; it is equal to 1 then linebreaks will be added before and after new buffer content. + * + * Converts the @bn and sets it to node content. + * + * Returns: 0 on success and a negative values if an error occurs. + */ +int +xmlSecBnSetNodeValue(xmlSecBnPtr bn, xmlNodePtr cur, xmlSecBnFormat format, int reverse, int addLineBreaks) { + xmlChar* content; + int ret; + + xmlSecAssert2(bn != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + + if(reverse != 0) { + ret = xmlSecBnReverse(bn); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(addLineBreaks) { + xmlNodeAddContent(cur, xmlSecStringCR); + } + + switch(format) { + case xmlSecBnBase64: + ret = xmlSecBufferBase64NodeContentWrite(bn, cur, xmlSecBase64GetDefaultLineSize()); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferBase64NodeContentWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + break; + case xmlSecBnHex: + content = xmlSecBnToHexString(bn); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnToHexString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + xmlNodeSetContent(cur, content); + xmlFree(content); + break; + case xmlSecBnDec: + content = xmlSecBnToDecString(bn); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnToDecString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + xmlNodeSetContent(cur, content); + xmlFree(content); + break; + } + + if(addLineBreaks) { + xmlNodeAddContent(cur, xmlSecStringCR); + } + + return(0); +} + +/** + * xmlSecBnBlobSetNodeValue: + * @data: the pointer to BN blob. + * @dataSize: the size of BN blob. + * @cur: the poitner to an XML node. + * @format: the BN format. + * @reverse: the flag that indicates whether to reverse the buffer before writing. + * @addLineBreaks: if the flag is equal to 1 then + * linebreaks will be added before and after + * new buffer content. + * + * Converts the @blob and sets it to node content. + * + * Returns: 0 on success and a negative values if an error occurs. + */ +int +xmlSecBnBlobSetNodeValue(const xmlSecByte* data, xmlSecSize dataSize, + xmlNodePtr cur, xmlSecBnFormat format, int reverse, + int addLineBreaks) { + xmlSecBn bn; + int ret; + + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + + ret = xmlSecBnInitialize(&bn, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBnSetData(&bn, data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBnSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBnFinalize(&bn); + return(-1); + } + + ret = xmlSecBnSetNodeValue(&bn, cur, format, reverse, addLineBreaks); + 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); +} + + diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 00000000..c13fe44f --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,674 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Memory buffer. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/base64.h> +#include <xmlsec/buffer.h> +#include <xmlsec/errors.h> + +/***************************************************************************** + * + * xmlSecBuffer + * + ****************************************************************************/ +static xmlSecAllocMode gAllocMode = xmlSecAllocModeDouble; +static xmlSecSize gInitialSize = 1024; + +/** + * xmlSecBufferSetDefaultAllocMode: + * @defAllocMode: the new default buffer allocation mode. + * @defInitialSize: the new default buffer minimal intial size. + * + * Sets new global default allocation mode and minimal intial size. + */ +void +xmlSecBufferSetDefaultAllocMode(xmlSecAllocMode defAllocMode, xmlSecSize defInitialSize) { + xmlSecAssert(defInitialSize > 0); + + gAllocMode = defAllocMode; + gInitialSize = defInitialSize; +} + +/** + * xmlSecBufferCreate: + * @size: the intial size. + * + * Allocates and initalizes new memory buffer with given size. + * Caller is responsible for calling #xmlSecBufferDestroy function + * to free the buffer. + * + * Returns: pointer to newly allocated buffer or NULL if an error occurs. + */ +xmlSecBufferPtr +xmlSecBufferCreate(xmlSecSize size) { + xmlSecBufferPtr buf; + int ret; + + buf = (xmlSecBufferPtr)xmlMalloc(sizeof(xmlSecBuffer)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecBuffer)=%d", sizeof(xmlSecBuffer)); + return(NULL); + } + + ret = xmlSecBufferInitialize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlSecBufferDestroy(buf); + return(NULL); + } + return(buf); +} + +/** + * xmlSecBufferDestroy: + * @buf: the pointer to buffer object. + * + * Desrtoys buffer object created with #xmlSecBufferCreate function. + */ +void +xmlSecBufferDestroy(xmlSecBufferPtr buf) { + xmlSecAssert(buf != NULL); + + xmlSecBufferFinalize(buf); + xmlFree(buf); +} + +/** + * xmlSecBufferInitialize: + * @buf: the pointer to buffer object. + * @size: the initial buffer size. + * + * Initializes buffer object @buf. Caller is responsible for calling + * #xmlSecBufferFinalize function to free allocated resources. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferInitialize(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecAssert2(buf != NULL, -1); + + buf->data = NULL; + buf->size = buf->maxSize = 0; + buf->allocMode = gAllocMode; + + return(xmlSecBufferSetMaxSize(buf, size)); +} + +/** + * xmlSecBufferFinalize: + * @buf: the pointer to buffer object. + * + * Frees allocated resource for a buffer intialized with #xmlSecBufferInitialize + * function. + */ +void +xmlSecBufferFinalize(xmlSecBufferPtr buf) { + xmlSecAssert(buf != NULL); + + xmlSecBufferEmpty(buf); + if(buf->data != 0) { + xmlFree(buf->data); + } + buf->data = NULL; + buf->size = buf->maxSize = 0; +} + +/** + * xmlSecBufferEmpty: + * @buf: the pointer to buffer object. + * + * Empties the buffer. + */ +void +xmlSecBufferEmpty(xmlSecBufferPtr buf) { + xmlSecAssert(buf != NULL); + + if(buf->data != 0) { + xmlSecAssert(buf->maxSize > 0); + + memset(buf->data, 0, buf->maxSize); + } + buf->size = 0; +} + +/** + * xmlSecBufferGetData: + * @buf: the pointer to buffer object. + * + * Gets pointer to buffer's data. + * + * Returns: pointer to buffer's data. + */ +xmlSecByte* +xmlSecBufferGetData(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, NULL); + + return(buf->data); +} + +/** + * xmlSecBufferSetData: + * @buf: the pointer to buffer object. + * @data: the data. + * @size: the data size. + * + * Sets the value of the buffer to @data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferSetData(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + xmlSecBufferEmpty(buf); + if(size > 0) { + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + memcpy(buf->data, data, size); + } + + buf->size = size; + return(0); +} + +/** + * xmlSecBufferGetSize: + * @buf: the pointer to buffer object. + * + * Gets the current buffer data size. + * + * Returns: the current data size. + */ +xmlSecSize +xmlSecBufferGetSize(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, 0); + + return(buf->size); +} + +/** + * xmlSecBufferSetSize: + * @buf: the pointer to buffer object. + * @size: the new data size. + * + * Sets new buffer data size. If necessary, buffer grows to + * have at least @size bytes. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferSetSize(xmlSecBufferPtr buf, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + + buf->size = size; + return(0); +} + +/** + * xmlSecBufferGetMaxSize: + * @buf: the pointer to buffer object. + * + * Gets the maximum (allocated) buffer size. + * + * Returns: the maximum (allocated) buffer size. + */ +xmlSecSize +xmlSecBufferGetMaxSize(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, 0); + + return(buf->maxSize); +} + +/** + * xmlSecBufferSetMaxSize: + * @buf: the pointer to buffer object. + * @size: the new maximum size. + * + * Sets new buffer maximum size. If necessary, buffer grows to + * have at least @size bytes. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferSetMaxSize(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecByte* newData; + xmlSecSize newSize = 0; + + xmlSecAssert2(buf != NULL, -1); + if(size <= buf->maxSize) { + return(0); + } + + switch(buf->allocMode) { + case xmlSecAllocModeExact: + newSize = size + 8; + break; + case xmlSecAllocModeDouble: + newSize = 2 * size + 32; + break; + } + + if(newSize < gInitialSize) { + newSize = gInitialSize; + } + + + if(buf->data != NULL) { + newData = (xmlSecByte*)xmlRealloc(buf->data, newSize); + } else { + newData = (xmlSecByte*)xmlMalloc(newSize); + } + if(newData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", newSize); + return(-1); + } + + buf->data = newData; + buf->maxSize = newSize; + + if(buf->size < buf->maxSize) { + xmlSecAssert2(buf->data != NULL, -1); + memset(buf->data + buf->size, 0, buf->maxSize - buf->size); + } + + return(0); +} + +/** + * xmlSecBufferAppend: + * @buf: the pointer to buffer object. + * @data: the data. + * @size: the data size. + * + * Appends the @data after the current data stored in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferAppend(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + if(size > 0) { + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, buf->size + size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", buf->size + size); + return(-1); + } + + memcpy(buf->data + buf->size, data, size); + buf->size += size; + } + + return(0); +} + +/** + * xmlSecBufferPrepend: + * @buf: the pointer to buffer object. + * @data: the data. + * @size: the data size. + * + * Prepends the @data before the current data stored in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferPrepend(xmlSecBufferPtr buf, const xmlSecByte* data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + + if(size > 0) { + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferSetMaxSize(buf, buf->size + size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", buf->size + size); + return(-1); + } + + memmove(buf->data + size, buf->data, buf->size); + memcpy(buf->data, data, size); + buf->size += size; + } + + return(0); +} + +/** + * xmlSecBufferRemoveHead: + * @buf: the pointer to buffer object. + * @size: the number of bytes to be removed. + * + * Removes @size bytes from the beginning of the current buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferRemoveHead(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecAssert2(buf != NULL, -1); + + if(size < buf->size) { + xmlSecAssert2(buf->data != NULL, -1); + + buf->size -= size; + memmove(buf->data, buf->data + size, buf->size); + } else { + buf->size = 0; + } + if(buf->size < buf->maxSize) { + xmlSecAssert2(buf->data != NULL, -1); + memset(buf->data + buf->size, 0, buf->maxSize - buf->size); + } + return(0); +} + +/** + * xmlSecBufferRemoveTail: + * @buf: the pointer to buffer object. + * @size: the number of bytes to be removed. + * + * Removes @size bytes from the end of current buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferRemoveTail(xmlSecBufferPtr buf, xmlSecSize size) { + xmlSecAssert2(buf != NULL, -1); + + if(size < buf->size) { + buf->size -= size; + } else { + buf->size = 0; + } + if(buf->size < buf->maxSize) { + xmlSecAssert2(buf->data != NULL, -1); + memset(buf->data + buf->size, 0, buf->maxSize - buf->size); + } + return(0); +} + +/** + * xmlSecBufferReadFile: + * @buf: the pointer to buffer object. + * @filename: the filename. + * + * Reads the content of the file @filename in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferReadFile(xmlSecBufferPtr buf, const char* filename) { + xmlSecByte buffer[1024]; + FILE* f; + int ret, len; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + + f = fopen(filename, "rb"); + if(f == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "fopen", + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + return(-1); + } + + while(1) { + len = fread(buffer, 1, sizeof(buffer), f); + if(len == 0) { + break; + }else if(len < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "fread", + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + fclose(f); + return(-1); + } + + ret = xmlSecBufferAppend(buf, buffer, len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", + len); + fclose(f); + return(-1); + } + } + + fclose(f); + return(0); +} + +/** + * xmlSecBufferBase64NodeContentRead: + * @buf: the pointer to buffer object. + * @node: the pointer to node. + * + * Reads the content of the @node, base64 decodes it and stores the + * result in the buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferBase64NodeContentRead(xmlSecBufferPtr buf, xmlNodePtr node) { + xmlChar* content; + xmlSecSize size; + int ret; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + content = xmlNodeGetContent(node); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* base64 decode size is less than input size */ + ret = xmlSecBufferSetMaxSize(buf, xmlStrlen(content)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + ret = xmlSecBase64Decode(content, xmlSecBufferGetData(buf), xmlSecBufferGetMaxSize(buf)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + size = ret; + + ret = xmlSecBufferSetSize(buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlFree(content); + return(-1); + } + xmlFree(content); + + return(0); +} + +/** + * xmlSecBufferBase64NodeContentWrite: + * @buf: the pointer to buffer object. + * @node: the pointer to a node. + * @columns: the max line size fro base64 encoded data. + * + * Sets the content of the @node to the base64 encoded buffer data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecBufferBase64NodeContentWrite(xmlSecBufferPtr buf, xmlNodePtr node, int columns) { + xmlChar* content; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + content = xmlSecBase64Encode(xmlSecBufferGetData(buf), xmlSecBufferGetSize(buf), columns); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlNodeAddContent(node, content); + xmlFree(content); + + return(0); +} + +/************************************************************************ + * + * IO buffer + * + ************************************************************************/ +static int xmlSecBufferIOWrite (xmlSecBufferPtr buf, + const xmlSecByte *data, + xmlSecSize size); +static int xmlSecBufferIOClose (xmlSecBufferPtr buf); + +/** + * xmlSecBufferCreateOutputBuffer: + * @buf: the pointer to buffer. + * + * Creates new LibXML output buffer to store data in the @buf. Caller is + * responsible for destroying @buf when processing is done. + * + * Returns: pointer to newly allocated output buffer or NULL if an error + * occurs. + */ +xmlOutputBufferPtr +xmlSecBufferCreateOutputBuffer(xmlSecBufferPtr buf) { + return(xmlOutputBufferCreateIO((xmlOutputWriteCallback)xmlSecBufferIOWrite, + (xmlOutputCloseCallback)xmlSecBufferIOClose, + buf, + NULL)); +} + +static int +xmlSecBufferIOWrite(xmlSecBufferPtr buf, const xmlSecByte *data, xmlSecSize size) { + int ret; + + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(data != NULL, -1); + + ret = xmlSecBufferAppend(buf, data, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + return(size); +} + +static int +xmlSecBufferIOClose(xmlSecBufferPtr buf) { + xmlSecAssert2(buf != NULL, -1); + + /* just do nothing */ + return(0); +} diff --git a/src/c14n.c b/src/c14n.c new file mode 100644 index 00000000..384e2d86 --- /dev/null +++ b/src/c14n.c @@ -0,0 +1,801 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Canonicalization transforms. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/c14n.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/list.h> +#include <xmlsec/transforms.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/errors.h> + +/****************************************************************************** + * + * C14N transforms + * + * Inclusive namespaces list for ExclC14N (xmlSecStringList) is located + * after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecTransformC14NSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecPtrList)) +#define xmlSecTransformC14NGetNsList(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecTransformC14NSize)) ? \ + (xmlSecPtrListPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \ + (xmlSecPtrListPtr)NULL) + +#define xmlSecTransformC14NCheckId(transform) \ + (xmlSecTransformInclC14NCheckId((transform)) || \ + xmlSecTransformInclC14N11CheckId((transform)) || \ + xmlSecTransformExclC14NCheckId((transform)) || \ + xmlSecTransformCheckId((transform), xmlSecTransformRemoveXmlTagsC14NId)) +#define xmlSecTransformInclC14NCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecTransformInclC14NId) || \ + xmlSecTransformCheckId((transform), xmlSecTransformInclC14NWithCommentsId)) +#define xmlSecTransformInclC14N11CheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecTransformInclC14N11Id) || \ + xmlSecTransformCheckId((transform), xmlSecTransformInclC14N11WithCommentsId)) +#define xmlSecTransformExclC14NCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecTransformExclC14NId) || \ + xmlSecTransformCheckId((transform), xmlSecTransformExclC14NWithCommentsId) ) + + +static int xmlSecTransformC14NInitialize (xmlSecTransformPtr transform); +static void xmlSecTransformC14NFinalize (xmlSecTransformPtr transform); +static int xmlSecTransformC14NNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecTransformC14NPushXml (xmlSecTransformPtr transform, + xmlSecNodeSetPtr nodes, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecTransformC14NPopBin (xmlSecTransformPtr transform, + xmlSecByte* data, + xmlSecSize maxDataSize, + xmlSecSize* dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecTransformC14NExecute (xmlSecTransformId id, + xmlSecNodeSetPtr nodes, + xmlChar** nsList, + xmlOutputBufferPtr buf); +static int +xmlSecTransformC14NInitialize(xmlSecTransformPtr transform) { + xmlSecPtrListPtr nsList; + int ret; + + xmlSecAssert2(xmlSecTransformC14NCheckId(transform), -1); + + nsList = xmlSecTransformC14NGetNsList(transform); + xmlSecAssert2(nsList != NULL, -1); + + ret = xmlSecPtrListInitialize(nsList, xmlSecStringListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecTransformC14NFinalize(xmlSecTransformPtr transform) { + xmlSecPtrListPtr nsList; + + xmlSecAssert(xmlSecTransformC14NCheckId(transform)); + + nsList = xmlSecTransformC14NGetNsList(transform); + xmlSecAssert(xmlSecPtrListCheckId(nsList, xmlSecStringListId)); + + xmlSecPtrListFinalize(nsList); +} + +static int +xmlSecTransformC14NNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecPtrListPtr nsList; + xmlNodePtr cur; + xmlChar *list; + xmlChar *p, *n, *tmp; + int ret; + + /* we have something to read only for exclusive c14n transforms */ + xmlSecAssert2(xmlSecTransformExclC14NCheckId(transform), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + nsList = xmlSecTransformC14NGetNsList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(nsList, xmlSecStringListId), -1); + xmlSecAssert2(xmlSecPtrListGetSize(nsList) == 0, -1); + + /* there is only one optional node */ + cur = xmlSecGetNextElementNode(node->children); + if(cur != NULL) { + if(!xmlSecCheckNodeName(cur, xmlSecNodeInclusiveNamespaces, xmlSecNsExcC14N)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + list = xmlGetProp(cur, xmlSecAttrPrefixList); + if(list == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecAttrPrefixList), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + /* the list of namespaces is space separated */ + for(p = n = list; ((p != NULL) && ((*p) != '\0')); p = n) { + n = (xmlChar*)xmlStrchr(p, ' '); + if(n != NULL) { + *(n++) = '\0'; + } + + tmp = xmlStrdup(p); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "len=%d", xmlStrlen(p)); + xmlFree(list); + return(-1); + } + + ret = xmlSecPtrListAdd(nsList, tmp); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(tmp); + xmlFree(list); + return(-1); + } + } + xmlFree(list); + + /* add NULL at the end */ + ret = xmlSecPtrListAdd(nsList, NULL); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecGetNextElementNode(cur->next); + } + + /* check that we have nothing else */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecTransformC14NPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes, + xmlSecTransformCtxPtr transformCtx) { + xmlOutputBufferPtr buf; + xmlSecPtrListPtr nsList; + int ret; + + xmlSecAssert2(xmlSecTransformC14NCheckId(transform), -1); + xmlSecAssert2(nodes != NULL, -1); + xmlSecAssert2(nodes->doc != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + /* check/update current transform status */ + switch(transform->status) { + case xmlSecTransformStatusNone: + transform->status = xmlSecTransformStatusWorking; + break; + case xmlSecTransformStatusWorking: + case xmlSecTransformStatusFinished: + return(0); + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1); + + /* prepare output buffer: next transform or ourselves */ + if(transform->next != NULL) { + buf = xmlSecTransformCreateOutputBuffer(transform->next, transformCtx); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + buf = xmlSecBufferCreateOutputBuffer(&(transform->outBuf)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* we are using a semi-hack here: we know that xmlSecPtrList keeps + * all pointers in the big array */ + nsList = xmlSecTransformC14NGetNsList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(nsList, xmlSecStringListId), -1); + + ret = xmlSecTransformC14NExecute(transform->id, nodes, (xmlChar**)(nsList->data), buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformC14NExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlOutputBufferClose(buf); + return(-1); + } + + ret = xmlOutputBufferClose(buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusFinished; + return(0); +} + +static int +xmlSecTransformC14NPopBin(xmlSecTransformPtr transform, xmlSecByte* data, + xmlSecSize maxDataSize, xmlSecSize* dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecPtrListPtr nsList; + xmlSecBufferPtr out; + int ret; + + xmlSecAssert2(xmlSecTransformC14NCheckId(transform), -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + out = &(transform->outBuf); + if(transform->status == xmlSecTransformStatusNone) { + xmlOutputBufferPtr buf; + + xmlSecAssert2(transform->inNodes == NULL, -1); + + /* todo: isn't it an error? */ + if(transform->prev == NULL) { + (*dataSize) = 0; + transform->status = xmlSecTransformStatusFinished; + return(0); + } + + /* get xml data from previous transform */ + ret = xmlSecTransformPopXml(transform->prev, &(transform->inNodes), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformPopXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* dump everything to internal buffer */ + buf = xmlSecBufferCreateOutputBuffer(out); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* we are using a semi-hack here: we know that xmlSecPtrList keeps + * all pointers in the big array */ + nsList = xmlSecTransformC14NGetNsList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(nsList, xmlSecStringListId), -1); + + ret = xmlSecTransformC14NExecute(transform->id, transform->inNodes, (xmlChar**)(nsList->data), buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformC14NExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlOutputBufferClose(buf); + return(-1); + } + ret = xmlOutputBufferClose(buf); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize outSize; + + /* return chunk after chunk */ + outSize = xmlSecBufferGetSize(out); + if(outSize > maxDataSize) { + outSize = maxDataSize; + } + if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) { + outSize = XMLSEC_TRANSFORM_BINARY_CHUNK; + } + if(outSize > 0) { + xmlSecAssert2(xmlSecBufferGetData(&(transform->outBuf)), -1); + + memcpy(data, xmlSecBufferGetData(&(transform->outBuf)), outSize); + ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + } else if(xmlSecBufferGetSize(out) == 0) { + transform->status = xmlSecTransformStatusFinished; + } + (*dataSize) = outSize; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no output */ + xmlSecAssert2(xmlSecBufferGetSize(out) == 0, -1); + (*dataSize) = 0; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + + return(0); +} + +static int +xmlSecTransformC14NExecute(xmlSecTransformId id, xmlSecNodeSetPtr nodes, xmlChar** nsList, + xmlOutputBufferPtr buf) { + int ret; + + xmlSecAssert2(id != xmlSecTransformIdUnknown, -1); + xmlSecAssert2(nodes != NULL, -1); + xmlSecAssert2(nodes->doc != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + + /* execute c14n transform */ + if(id == xmlSecTransformInclC14NId) { + ret = xmlC14NExecute(nodes->doc, + (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, + nodes, XML_C14N_1_0, NULL, 0, buf); + } else if(id == xmlSecTransformInclC14NWithCommentsId) { + ret = xmlC14NExecute(nodes->doc, + (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, + nodes, XML_C14N_1_0, NULL, 1, buf); + } else if(id == xmlSecTransformInclC14N11Id) { + ret = xmlC14NExecute(nodes->doc, + (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, + nodes, XML_C14N_1_1, NULL, 0, buf); + } else if(id == xmlSecTransformInclC14N11WithCommentsId) { + ret = xmlC14NExecute(nodes->doc, + (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, + nodes, XML_C14N_1_1, NULL, 1, buf); + } else if(id == xmlSecTransformExclC14NId) { + ret = xmlC14NExecute(nodes->doc, + (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, + nodes, XML_C14N_EXCLUSIVE_1_0, nsList, 0, buf); + } else if(id == xmlSecTransformExclC14NWithCommentsId) { + ret = xmlC14NExecute(nodes->doc, + (xmlC14NIsVisibleCallback)xmlSecNodeSetContains, + nodes, XML_C14N_EXCLUSIVE_1_0, nsList, 1, buf); + } else if(id == xmlSecTransformRemoveXmlTagsC14NId) { + ret = xmlSecNodeSetDumpTextNodes(nodes, buf); + } else { + /* shoudn't be possible to come here, actually */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)), + "xmlC14NExecute", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/*************************************************************************** + * + * C14N + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformInclC14NKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + xmlSecNameC14N, /* const xmlChar* name; */ + xmlSecHrefC14N, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformInclC14NGetKlass: + * + * Inclusive (regular) canonicalization that omits comments transform klass + * (http://www.w3.org/TR/xmldsig-core/#sec-c14nAlg and + * http://www.w3.org/TR/2001/REC-xml-c14n-20010315). + * + * Returns: c14n transform id. + */ +xmlSecTransformId +xmlSecTransformInclC14NGetKlass(void) { + return(&xmlSecTransformInclC14NKlass); +} + +/*************************************************************************** + * + * C14N With Comments + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformInclC14NWithCommentsKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + /* same as xmlSecTransformId */ + xmlSecNameC14NWithComments, /* const xmlChar* name; */ + xmlSecHrefC14NWithComments, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod read; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformInclC14NWithCommentsGetKlass: + * + * Inclusive (regular) canonicalization that includes comments transform klass + * (http://www.w3.org/TR/xmldsig-core/#sec-c14nAlg and + * http://www.w3.org/TR/2001/REC-xml-c14n-20010315). + * + * Returns: c14n with comments transform id. + */ +xmlSecTransformId +xmlSecTransformInclC14NWithCommentsGetKlass(void) { + return(&xmlSecTransformInclC14NWithCommentsKlass); +} + +/*************************************************************************** + * + * C14N v1.1 + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformInclC14N11Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + xmlSecNameC14N11, /* const xmlChar* name; */ + xmlSecHrefC14N11, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformInclC14N11GetKlass: + * + * C14N version 1.1 (http://www.w3.org/TR/xml-c14n11) + * + * Returns: c14n v1.1 transform id. + */ +xmlSecTransformId +xmlSecTransformInclC14N11GetKlass(void) { + return(&xmlSecTransformInclC14N11Klass); +} + +/*************************************************************************** + * + * C14N v1.1 With Comments + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformInclC14N11WithCommentsKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + /* same as xmlSecTransformId */ + xmlSecNameC14N11WithComments, /* const xmlChar* name; */ + xmlSecHrefC14N11WithComments, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod read; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformInclC14N11WithCommentsGetKlass: + * + * C14N version 1.1 (http://www.w3.org/TR/xml-c14n11) with comments + * + * Returns: c14n v1.1 with comments transform id. + */ +xmlSecTransformId +xmlSecTransformInclC14N11WithCommentsGetKlass(void) { + return(&xmlSecTransformInclC14N11WithCommentsKlass); +} + + +/*************************************************************************** + * + * Excl C14N + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformExclC14NKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + xmlSecNameExcC14N, /* const xmlChar* name; */ + xmlSecHrefExcC14N, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecTransformC14NNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformExclC14NGetKlass: + * + * Exclusive canoncicalization that ommits comments transform klass + * (http://www.w3.org/TR/xml-exc-c14n/). + * + * Returns: exclusive c14n transform id. + */ +xmlSecTransformId +xmlSecTransformExclC14NGetKlass(void) { + return(&xmlSecTransformExclC14NKlass); +} + +/*************************************************************************** + * + * Excl C14N With Comments + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformExclC14NWithCommentsKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + xmlSecNameExcC14NWithComments, /* const xmlChar* name; */ + xmlSecHrefExcC14NWithComments, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecTransformC14NNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformExclC14NWithCommentsGetKlass: + * + * Exclusive canoncicalization that includes comments transform klass + * (http://www.w3.org/TR/xml-exc-c14n/). + * + * Returns: exclusive c14n with comments transform id. + */ +xmlSecTransformId +xmlSecTransformExclC14NWithCommentsGetKlass(void) { + return(&xmlSecTransformExclC14NWithCommentsKlass); +} + +/*************************************************************************** + * + * Remove XML tags C14N + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecTransformRemoveXmlTagsC14NKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformC14NSize, /* xmlSecSize objSize */ + + BAD_CAST "remove-xml-tags-transform", /* const xmlChar* name; */ + NULL, /* const xmlChar* href; */ + xmlSecTransformUsageC14NMethod | xmlSecTransformUsageDSigTransform, + /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformC14NInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformC14NFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformC14NPopBin, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformC14NPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformRemoveXmlTagsC14NGetKlass: + * + * The "remove xml tags" transform klass (http://www.w3.org/TR/xmldsig-core/#sec-Base-64): + * Base64 transform requires an octet stream for input. If an XPath node-set + * (or sufficiently functional alternative) is given as input, then it is + * converted to an octet stream by performing operations logically equivalent + * to 1) applying an XPath transform with expression self::text(), then 2) + * taking the string-value of the node-set. Thus, if an XML element is + * identified by a barename XPointer in the Reference URI, and its content + * consists solely of base64 encoded character data, then this transform + * automatically strips away the start and end tags of the identified element + * and any of its descendant elements as well as any descendant comments and + * processing instructions. The output of this transform is an octet stream. + * + * Returns: "remove xml tags" transform id. + */ +xmlSecTransformId +xmlSecTransformRemoveXmlTagsC14NGetKlass(void) { + return(&xmlSecTransformRemoveXmlTagsC14NKlass); +} + diff --git a/src/dl.c b/src/dl.c new file mode 100644 index 00000000..6c0aa180 --- /dev/null +++ b/src/dl.c @@ -0,0 +1,978 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <time.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/app.h> +#include <xmlsec/list.h> +#include <xmlsec/keysdata.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/private.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/errors.h> +#include <xmlsec/dl.h> + +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING + + +#ifdef XMLSEC_DL_LIBLTDL +#include <ltdl.h> +#endif /* XMLSEC_DL_LIBLTDL */ + +#ifdef XMLSEC_DL_WIN32 +#include <windows.h> +#endif /* XMLSEC_DL_WIN32 */ + +/*********************************************************************** + * + * loaded libraries list + * + **********************************************************************/ +typedef struct _xmlSecCryptoDLLibrary xmlSecCryptoDLLibrary, + *xmlSecCryptoDLLibraryPtr; +struct _xmlSecCryptoDLLibrary { + xmlChar* name; + xmlChar* filename; + xmlChar* getFunctionsName; + xmlSecCryptoDLFunctionsPtr functions; + +#ifdef XMLSEC_DL_LIBLTDL + lt_dlhandle handle; +#endif /* XMLSEC_DL_LIBLTDL */ + +#ifdef XMLSEC_DL_WIN32 + HINSTANCE handle; +#endif /* XMLSEC_DL_WIN32 */ +}; + +static xmlSecCryptoDLLibraryPtr xmlSecCryptoDLLibraryCreate (const xmlChar* name); +static void xmlSecCryptoDLLibraryDestroy (xmlSecCryptoDLLibraryPtr lib); +static xmlSecCryptoDLLibraryPtr xmlSecCryptoDLLibraryDuplicate (xmlSecCryptoDLLibraryPtr lib); +static xmlChar* xmlSecCryptoDLLibraryConstructFilename (const xmlChar* name); +static xmlChar* xmlSecCryptoDLLibraryConstructGetFunctionsName(const xmlChar* name); + + +static xmlSecPtrListKlass xmlSecCryptoDLLibrariesListKlass = { + BAD_CAST "dl-libraries-list", + (xmlSecPtrDuplicateItemMethod)xmlSecCryptoDLLibraryDuplicate,/* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecCryptoDLLibraryDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; +static xmlSecPtrListId xmlSecCryptoDLLibrariesListGetKlass (void); +static int xmlSecCryptoDLLibrariesListFindByName (xmlSecPtrListPtr list, + const xmlChar* name); + +typedef xmlSecCryptoDLFunctionsPtr (*xmlSecCryptoGetFunctionsCallback)(void); + +static xmlSecCryptoDLLibraryPtr +xmlSecCryptoDLLibraryCreate(const xmlChar* name) { + xmlSecCryptoDLLibraryPtr lib; + xmlSecCryptoGetFunctionsCallback getFunctions; + + xmlSecAssert2(name != NULL, NULL); + + /* fprintf (stderr, "loading \"library %s\"...\n", name); */ + + /* Allocate a new xmlSecCryptoDLLibrary and fill the fields. */ + lib = (xmlSecCryptoDLLibraryPtr)xmlMalloc(sizeof(xmlSecCryptoDLLibrary)); + if(lib == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(lib)); + return(NULL); + } + memset(lib, 0, sizeof(xmlSecCryptoDLLibrary)); + + lib->name = xmlStrdup(name); + if(lib->name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlStrdup", + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + lib->filename = xmlSecCryptoDLLibraryConstructFilename(name); + if(lib->filename == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecCryptoDLLibraryConstructFilename", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + lib->getFunctionsName = xmlSecCryptoDLLibraryConstructGetFunctionsName(name); + if(lib->getFunctionsName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "xmlSecCryptoDLLibraryConstructGetFunctionsName", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + +#ifdef XMLSEC_DL_LIBLTDL + lib->handle = lt_dlopenext((char*)lib->filename); + if(lib->handle == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "lt_dlopenext", + NULL, + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s", + xmlSecErrorsSafeString(lib->filename)); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + getFunctions = (xmlSecCryptoGetFunctionsCallback)lt_dlsym(lib->handle, (char*)lib->getFunctionsName); + if(getFunctions == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "lt_dlsym", + NULL, + XMLSEC_ERRORS_R_IO_FAILED, + "function=%s", + xmlSecErrorsSafeString(lib->getFunctionsName)); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } +#endif /* XMLSEC_DL_LIBLTDL */ + +#ifdef XMLSEC_DL_WIN32 + lib->handle = LoadLibraryA((char*)lib->filename); + if(lib->handle == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "LoadLibraryA", + NULL, + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s", + xmlSecErrorsSafeString(lib->filename)); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + getFunctions = (xmlSecCryptoGetFunctionsCallback)GetProcAddress(lib->handle, (char*)lib->getFunctionsName); + if(getFunctions == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "GetProcAddressA", + NULL, + XMLSEC_ERRORS_R_IO_FAILED, + "function=%s", + xmlSecErrorsSafeString(lib->getFunctionsName)); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } +#endif /* XMLSEC_DL_WIN32 */ + + if(getFunctions == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "invalid configuration: no way to load library"); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + lib->functions = getFunctions(); + if(lib->functions == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + "getFunctions", + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + /* fprintf (stderr, "library %s loaded\n", name); */ + return(lib); +} + +static void +xmlSecCryptoDLLibraryDestroy(xmlSecCryptoDLLibraryPtr lib) { + xmlSecAssert(lib != NULL); + + /* fprintf (stderr, "unloading \"library %s\"...\n", lib->name); */ + if(lib->name != NULL) { + xmlFree(lib->name); + } + + if(lib->filename != NULL) { + xmlFree(lib->filename); + } + + if(lib->getFunctionsName != NULL) { + xmlFree(lib->getFunctionsName); + } + +#ifdef XMLSEC_DL_LIBLTDL + if(lib->handle != NULL) { + int ret; + + ret = lt_dlclose(lib->handle); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + "lt_dlclose", + NULL, + XMLSEC_ERRORS_R_IO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + } + } +#endif /* XMLSEC_DL_LIBLTDL */ + +#ifdef XMLSEC_DL_WIN32 + if(lib->handle != NULL) { + BOOL res; + + res = FreeLibrary(lib->handle); + if(!res) { + xmlSecError(XMLSEC_ERRORS_HERE, + "FreeLibrary", + NULL, + XMLSEC_ERRORS_R_IO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + } + } +#endif /* XMLSEC_DL_WIN32*/ + + memset(lib, 0, sizeof(xmlSecCryptoDLLibrary)); + xmlFree(lib); +} + +static xmlSecCryptoDLLibraryPtr +xmlSecCryptoDLLibraryDuplicate(xmlSecCryptoDLLibraryPtr lib) { + xmlSecAssert2(lib != NULL, NULL); + xmlSecAssert2(lib->name != NULL, NULL); + + return(xmlSecCryptoDLLibraryCreate(lib->name)); +} + +static xmlChar* +xmlSecCryptoDLLibraryConstructFilename(const xmlChar* name) { + static xmlChar tmpl[] = "lib%s-%s"; + xmlChar* res; + int len; + + xmlSecAssert2(name != NULL, NULL); + + /* TODO */ + len = xmlStrlen(BAD_CAST PACKAGE) + xmlStrlen(name) + xmlStrlen(tmpl) + 1; + res = (xmlChar*)xmlMalloc(len + 1); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", len + 1); + return(NULL); + } + xmlSecStrPrintf(res, len, tmpl, PACKAGE, name); + + return(res); +} + +static xmlChar* +xmlSecCryptoDLLibraryConstructGetFunctionsName(const xmlChar* name) { + static xmlChar tmpl[] = "xmlSecCryptoGetFunctions_%s"; + xmlChar* res; + int len; + + xmlSecAssert2(name != NULL, NULL); + + len = xmlStrlen(name) + xmlStrlen(tmpl) + 1; + res = (xmlChar*)xmlMalloc(len + 1); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", len + 1); + return(NULL); + } + xmlSecStrPrintf(res, len, tmpl, name); + + return(res); +} + +static xmlSecPtrListId +xmlSecCryptoDLLibrariesListGetKlass(void) { + return(&xmlSecCryptoDLLibrariesListKlass); +} + +static int +xmlSecCryptoDLLibrariesListFindByName(xmlSecPtrListPtr list, const xmlChar* name) { + xmlSecSize i, size; + xmlSecCryptoDLLibraryPtr lib; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecCryptoDLLibrariesListGetKlass()), -1); + xmlSecAssert2(name != NULL, -1); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + lib = (xmlSecCryptoDLLibraryPtr)xmlSecPtrListGetItem(list, i); + if((lib != NULL) && (lib->name != NULL) && (xmlStrcmp(lib->name, name) == 0)) { + return(i); + } + } + return(-1); +} + +/****************************************************************************** + * + * Dynamic load functions + * + *****************************************************************************/ +static xmlSecCryptoDLFunctionsPtr gXmlSecCryptoDLFunctions = NULL; +static xmlSecPtrList gXmlSecCryptoDLLibraries; + +/** + * xmlSecCryptoDLInit: + * + * Initializes dynamic loading engine. This is an internal function + * and should not be called by application directly. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecCryptoDLInit(void) { + int ret; + + ret = xmlSecPtrListInitialize(&gXmlSecCryptoDLLibraries, xmlSecCryptoDLLibrariesListGetKlass()); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListPtrInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecCryptoDLLibrariesListGetKlass"); + return(-1); + } + +#ifdef XMLSEC_DL_LIBLTDL + ret = lt_dlinit (); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "lt_dlinit", + XMLSEC_ERRORS_R_IO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#endif /* XMLSEC_DL_LIBLTDL */ + + return(0); +} + + +/** + * xmlSecCryptoDLShutdown: + * + * Shutdowns dynamic loading engine. This is an internal function + * and should not be called by application directly. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecCryptoDLShutdown(void) { + int ret; + + xmlSecPtrListFinalize(&gXmlSecCryptoDLLibraries); + +#ifdef XMLSEC_DL_LIBLTDL + ret = lt_dlexit (); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "lt_dlexit", + XMLSEC_ERRORS_R_IO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + } +#endif /* XMLSEC_DL_LIBLTDL */ + + return(0); +} + +/** + * xmlSecCryptoDLLoadLibrary: + * @crypto: the desired crypto library name ("openssl", "nss", ...). + * + * Loads the xmlsec-<crypto> library. This function is NOT thread safe, + * application MUST NOT call #xmlSecCryptoDLLoadLibrary, #xmlSecCryptoDLGetLibraryFunctions, + * and #xmlSecCryptoDLUnloadLibrary functions from multiple threads. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecCryptoDLLoadLibrary(const xmlChar* crypto) { + xmlSecCryptoDLFunctionsPtr functions; + int ret; + + xmlSecAssert2(crypto != NULL, -1); + + functions = xmlSecCryptoDLGetLibraryFunctions(crypto); + if(functions == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLGetLibraryFunctions", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecCryptoDLSetFunctions(functions); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLSetFunctions", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecCryptoDLGetLibraryFunctions: + * @crypto: the desired crypto library name ("openssl", "nss", ...). + * + * Loads the xmlsec-<crypto> library and gets global crypto functions/transforms/keys data/keys store + * table. This function is NOT thread safe, application MUST NOT call #xmlSecCryptoDLLoadLibrary, + * #xmlSecCryptoDLGetLibraryFunctions, and #xmlSecCryptoDLUnloadLibrary functions from multiple threads. + * + * Returns: the table or NULL if an error occurs. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoDLGetLibraryFunctions(const xmlChar* crypto) { + xmlSecCryptoDLLibraryPtr lib; + int pos; + int ret; + + xmlSecAssert2(crypto != NULL, NULL); + + pos = xmlSecCryptoDLLibrariesListFindByName(&gXmlSecCryptoDLLibraries, crypto); + if(pos >= 0) { + lib = (xmlSecCryptoDLLibraryPtr)xmlSecPtrListGetItem(&gXmlSecCryptoDLLibraries, pos); + xmlSecAssert2(lib != NULL, NULL); + xmlSecAssert2(lib->functions != NULL, NULL); + + return(lib->functions); + } + + lib = xmlSecCryptoDLLibraryCreate(crypto); + if(lib == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLLibraryCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "crypto=%s", + xmlSecErrorsSafeString(crypto)); + return(NULL); + } + + ret = xmlSecPtrListAdd(&gXmlSecCryptoDLLibraries, lib); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "crypto=%s", + xmlSecErrorsSafeString(crypto)); + xmlSecCryptoDLLibraryDestroy(lib); + return(NULL); + } + + return(lib->functions); +} + +/** + * xmlSecCryptoDLUnloadLibrary: + * @crypto: the desired crypto library name ("openssl", "nss", ...). + * + * Unloads the xmlsec-<crypto> library. All pointers to this library + * functions tables became invalid. This function is NOT thread safe, + * application MUST NOT call #xmlSecCryptoDLLoadLibrary, #xmlSecCryptoDLGetLibraryFunctions, + * and #xmlSecCryptoDLUnloadLibrary functions from multiple threads. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecCryptoDLUnloadLibrary(const xmlChar* crypto) { + xmlSecCryptoDLLibraryPtr lib; + int pos; + int ret; + + xmlSecAssert2(crypto != NULL, -1); + + pos = xmlSecCryptoDLLibrariesListFindByName(&gXmlSecCryptoDLLibraries, crypto); + if(pos < 0) { + /* todo: is it an error? */ + return(0); + } + + lib = (xmlSecCryptoDLLibraryPtr)xmlSecPtrListGetItem(&gXmlSecCryptoDLLibraries, pos); + if((lib != NULL) && (lib->functions == gXmlSecCryptoDLFunctions)) { + gXmlSecCryptoDLFunctions = NULL; + } + + ret = xmlSecPtrListRemove(&gXmlSecCryptoDLLibraries, pos); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListRemove", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecCryptoDLSetFunctions: + * @functions: the new table + * + * Sets global crypto functions/transforms/keys data/keys store table. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecCryptoDLSetFunctions(xmlSecCryptoDLFunctionsPtr functions) { + xmlSecAssert2(functions != NULL, -1); + + gXmlSecCryptoDLFunctions = functions; + + return(0); +} + +/** + * xmlSecCryptoDLGetFunctions: + * + * Gets global crypto functions/transforms/keys data/keys store table. + * + * Returns: the table. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoDLGetFunctions(void) { + return(gXmlSecCryptoDLFunctions); +} + +#endif /* XMLSEC_NO_CRYPTO_DYNAMIC_LOADING */ + +/** + * xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms: + * @functions: the functions table. + * + * Registers the key data and transforms klasses from @functions table in xmlsec. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(struct _xmlSecCryptoDLFunctions* functions) { + xmlSecAssert2(functions != NULL, -1); + + /** + * Register keys + */ + if((functions->keyDataAesGetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataAesGetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataAesGetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataDesGetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataDesGetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataDesGetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataDsaGetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataDsaGetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataDsaGetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataGost2001GetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataGost2001GetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataGost2001GetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataHmacGetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataHmacGetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataHmacGetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataRsaGetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataRsaGetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataRsaGetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataX509GetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataX509GetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataX509GetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if((functions->keyDataRawX509CertGetKlass != NULL) && (xmlSecKeyDataIdsRegister(functions->keyDataRawX509CertGetKlass()) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(functions->keyDataRawX509CertGetKlass())), + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + + /** + * Register transforms + */ + if((functions->transformAes128CbcGetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformAes128CbcGetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformAes128CbcGetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformAes192CbcGetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformAes192CbcGetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformAes192CbcGetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformAes256CbcGetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformAes256CbcGetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformAes256CbcGetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformKWAes128GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformKWAes128GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformKWAes128GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformKWAes192GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformKWAes192GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformKWAes192GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformKWAes256GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformKWAes256GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformKWAes256GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformDes3CbcGetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformDes3CbcGetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformDes3CbcGetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformKWDes3GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformKWDes3GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformKWDes3GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformGost2001GostR3411_94GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformGost2001GostR3411_94GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformGost2001GostR3411_94GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformDsaSha1GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformDsaSha1GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformDsaSha1GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacMd5GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacMd5GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacMd5GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacRipemd160GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacRipemd160GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacRipemd160GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacSha1GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacSha1GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacSha1GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacSha224GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacSha224GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacSha224GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacSha256GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacSha256GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacSha256GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacSha384GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacSha384GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacSha384GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformHmacSha512GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformHmacSha512GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformHmacSha512GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformMd5GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformMd5GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformMd5GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRipemd160GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRipemd160GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRipemd160GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaMd5GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaMd5GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaMd5GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaRipemd160GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaRipemd160GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaRipemd160GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaSha1GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaSha1GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaSha1GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaSha224GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaSha224GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaSha224GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaSha256GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaSha256GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaSha256GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaSha384GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaSha384GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaSha384GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaSha512GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaSha512GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaSha512GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaPkcs1GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaPkcs1GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaPkcs1GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformRsaOaepGetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformRsaOaepGetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformRsaOaepGetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformGostR3411_94GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformGostR3411_94GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformGostR3411_94GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformSha1GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformSha1GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformSha1GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformSha224GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformSha224GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformSha224GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformSha256GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformSha256GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformSha256GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformSha384GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformSha384GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformSha384GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((functions->transformSha512GetKlass != NULL) && xmlSecTransformIdsRegister(functions->transformSha512GetKlass()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(functions->transformSha512GetKlass())), + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + + diff --git a/src/enveloped.c b/src/enveloped.c new file mode 100644 index 00000000..bea30a15 --- /dev/null +++ b/src/enveloped.c @@ -0,0 +1,152 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Enveloped transform. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +/************************************************************************** + * + * Enveloped transform + * + *************************************************************************/ +static int xmlSecTransformEnvelopedExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + + +static xmlSecTransformKlass xmlSecTransformEnvelopedKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + sizeof(xmlSecTransform), /* xmlSecSize objSize */ + + xmlSecNameEnveloped, /* const xmlChar* name; */ + xmlSecHrefEnveloped, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + NULL, /* xmlSecTransformInitializeMethod initialize; */ + NULL, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + NULL, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecTransformEnvelopedExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformEnvelopedGetKlass: + * + * The enveloped transform klass (http://www.w3.org/TR/xmldsig-core/#sec-EnvelopedSignature): + * + * An enveloped signature transform T removes the whole Signature element + * containing T from the digest calculation of the Reference element + * containing T. The entire string of characters used by an XML processor + * to match the Signature with the XML production element is removed. + * The output of the transform is equivalent to the output that would + * result from replacing T with an XPath transform containing the following + * XPath parameter element: + * + * <XPath xmlns:dsig="&dsig;"> + * count(ancestor-or-self::dsig:Signature | + * here()/ancestor::dsig:Signature[1]) > + * count(ancestor-or-self::dsig:Signature)</XPath> + * + * The input and output requirements of this transform are identical to + * those of the XPath transform, but may only be applied to a node-set from + * its parent XML document. Note that it is not necessary to use an XPath + * expression evaluator to create this transform. However, this transform + * MUST produce output in exactly the same manner as the XPath transform + * parameterized by the XPath expression above. + * + * Returns: enveloped transform id. + */ +xmlSecTransformId +xmlSecTransformEnvelopedGetKlass(void) { + return(&xmlSecTransformEnvelopedKlass); +} + +static int +xmlSecTransformEnvelopedExecute(xmlSecTransformPtr transform, int last, + xmlSecTransformCtxPtr transformCtx) { + xmlNodePtr node; + xmlSecNodeSetPtr children; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformEnvelopedId), -1); + xmlSecAssert2(transform->hereNode != NULL, -1); + xmlSecAssert2(transform->outNodes == NULL, -1); + xmlSecAssert2(last != 0, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + if((transform->inNodes != NULL) && (transform->inNodes->doc != transform->hereNode->doc)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* find signature node and get all its children in the nodes set */ + node = xmlSecFindParent(transform->hereNode, xmlSecNodeSignature, xmlSecDSigNs); + if(node == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeSignature), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + children = xmlSecNodeSetGetChildren(node->doc, node, 1, 1); + if(children == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNodeSetGetChildren", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + + /* intersect <dsig:Signature/> node children with input nodes (if exist) */ + transform->outNodes = xmlSecNodeSetAdd(transform->inNodes, children, xmlSecNodeSetIntersection); + if(transform->outNodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNodeSetAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecNodeSetDestroy(children); + return(-1); + } + + return(0); +} + diff --git a/src/errors.c b/src/errors.c new file mode 100644 index 00000000..54e34e6c --- /dev/null +++ b/src/errors.c @@ -0,0 +1,242 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Error codes and error reporting functions. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <time.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/private.h> +#include <xmlsec/errors.h> + +#define XMLSEC_ERRORS_BUFFER_SIZE 1024 + +typedef struct _xmlSecErrorDescription xmlSecErrorDescription, *xmlSecErrorDescriptionPtr; +struct _xmlSecErrorDescription { + int errorCode; + const char* errorMsg; +}; + +static xmlSecErrorDescription xmlSecErrorsTable[XMLSEC_ERRORS_MAX_NUMBER + 1] = { + { XMLSEC_ERRORS_R_XMLSEC_FAILED, "xmlsec library function failed" }, + { XMLSEC_ERRORS_R_MALLOC_FAILED, "malloc function failed" }, + { XMLSEC_ERRORS_R_STRDUP_FAILED, "strdup function failed" }, + { XMLSEC_ERRORS_R_CRYPTO_FAILED, "crypto library function failed" }, + { XMLSEC_ERRORS_R_XML_FAILED, "libxml2 library function failed" }, + { XMLSEC_ERRORS_R_XSLT_FAILED, "libxslt library function failed" }, + { XMLSEC_ERRORS_R_IO_FAILED, "io function failed" }, + { XMLSEC_ERRORS_R_DISABLED, "feature is disabled" }, + { XMLSEC_ERRORS_R_NOT_IMPLEMENTED, "feature is not implemented" }, + { XMLSEC_ERRORS_R_INVALID_SIZE, "invalid size" }, + { XMLSEC_ERRORS_R_INVALID_DATA, "invalid data" }, + { XMLSEC_ERRORS_R_INVALID_RESULT, "invalid result" }, + { XMLSEC_ERRORS_R_INVALID_TYPE, "invalid type" }, + { XMLSEC_ERRORS_R_INVALID_OPERATION, "invalid operation" }, + { XMLSEC_ERRORS_R_INVALID_STATUS, "invalid status" }, + { XMLSEC_ERRORS_R_INVALID_FORMAT, "invalid format" }, + { XMLSEC_ERRORS_R_DATA_NOT_MATCH, "data do not match" }, + { XMLSEC_ERRORS_R_INVALID_NODE, "invalid node" }, + { XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, "invalid node content" }, + { XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, "invalid node attribute" }, + { XMLSEC_ERRORS_R_MISSING_NODE_ATTRIBUTE, "missing node attribute" }, + { XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, "node already present" }, + { XMLSEC_ERRORS_R_UNEXPECTED_NODE, "unexpected node" }, + { XMLSEC_ERRORS_R_NODE_NOT_FOUND, "node node found" }, + { XMLSEC_ERRORS_R_INVALID_TRANSFORM, "invalid transform" }, + { XMLSEC_ERRORS_R_INVALID_TRANSFORM_KEY, "invalid transform key" }, + { XMLSEC_ERRORS_R_INVALID_URI_TYPE, "invalid URI type" }, + { XMLSEC_ERRORS_R_TRANSFORM_SAME_DOCUMENT_REQUIRED, "same document is required for transform" }, + { XMLSEC_ERRORS_R_TRANSFORM_DISABLED, "transform is disabled" }, + { XMLSEC_ERRORS_R_INVALID_KEY_DATA, "invalid key data" }, + { XMLSEC_ERRORS_R_KEY_DATA_NOT_FOUND, "key data is not found" }, + { XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, "key data already exist" }, + { XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, "invalid key data size" }, + { XMLSEC_ERRORS_R_KEY_NOT_FOUND, "key is not found" }, + { XMLSEC_ERRORS_R_KEYDATA_DISABLED, "key data is disabled" }, + { XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL, "maximum key retrieval level" }, + { XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH,"key retrieval type mismatch" }, + { XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL, "maximum encrypted key level" }, + { XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, "certificate verification failed" }, + { XMLSEC_ERRORS_R_CERT_NOT_FOUND, "certificate is not found" }, + { XMLSEC_ERRORS_R_CERT_REVOKED, "certificate is revoked" }, + { XMLSEC_ERRORS_R_CERT_ISSUER_FAILED, "certificate issuer check failed" }, + { XMLSEC_ERRORS_R_CERT_NOT_YET_VALID, "certificate is not yet valid" }, + { XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, "certificate has expirred" }, + { XMLSEC_ERRORS_R_DSIG_NO_REFERENCES, "Reference nodes are not found" }, + { XMLSEC_ERRORS_R_DSIG_INVALID_REFERENCE, "Reference verification failed" }, + { XMLSEC_ERRORS_R_ASSERTION, "assertion" }, + { 0, NULL} +}; + +static xmlSecErrorsCallback xmlSecErrorsClbk = xmlSecErrorsDefaultCallback; +static int xmlSecPrintErrorMessages = 1; /* whether the error messages will be printed immidiatelly */ + +/** + * xmlSecErrorsInit: + * + * Initializes the errors reporting. It is called from #xmlSecInit function. + * and applications must not call this function directly. + */ +void +xmlSecErrorsInit(void) { +} + +/** + * xmlSecErrorsShutdown: + * + * Cleanups the errors reporting. It is called from #xmlSecShutdown function. + * and applications must not call this function directly. + */ +void +xmlSecErrorsShutdown(void) { +} + +/** + * xmlSecErrorsSetCallback: + * @callback: the new errors callback function. + * + * Sets the errors callback function to @callback that will be called + * every time an error occurs. + */ +void +xmlSecErrorsSetCallback(xmlSecErrorsCallback callback) { + xmlSecErrorsClbk = callback; +} + +/** + * xmlSecErrorsDefaultCallback: + * @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 error reporting callback that utilizes LibXML + * error reporting #xmlGenericError function. + */ +void +xmlSecErrorsDefaultCallback(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg) { + if(xmlSecPrintErrorMessages) { + const char* error_msg = NULL; + xmlSecSize i; + + for(i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) { + if(xmlSecErrorsGetCode(i) == reason) { + error_msg = xmlSecErrorsGetMsg(i); + break; + } + } + xmlGenericError(xmlGenericErrorContext, + "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n", + (func != NULL) ? func : "unknown", + (file != NULL) ? file : "unknown", + line, + (errorObject != NULL) ? errorObject : "unknown", + (errorSubject != NULL) ? errorSubject : "unknown", + reason, + (error_msg != NULL) ? error_msg : "", + (msg != NULL) ? msg : ""); + } +} + +/** + * xmlSecErrorsDefaultCallbackEnableOutput: + * @enabled: the flag. + * + * Enables or disables calling LibXML2 callback from the default + * errors callback. + */ +void +xmlSecErrorsDefaultCallbackEnableOutput(int enabled) { + xmlSecPrintErrorMessages = enabled; +} + +/** + * xmlSecErrorsGetCode: + * @pos: the error position. + * + * Gets the known error code at position @pos. + * + * Returns: the known error code or 0 if @pos is greater than + * total number of known error codes. + */ +int +xmlSecErrorsGetCode(xmlSecSize pos) { + /* could not use asserts here! */ + if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { + return(xmlSecErrorsTable[pos].errorCode); + } + return(0); +} + +/** + * xmlSecErrorsGetMsg: + * @pos: the error position. + * + * Gets the known error message at position @pos. + * + * Returns: the known error message or NULL if @pos is greater than + * total number of known error codes. + */ +const char* +xmlSecErrorsGetMsg(xmlSecSize pos) { + /* could not use asserts here! */ + if(pos < sizeof(xmlSecErrorsTable) / sizeof(xmlSecErrorsTable[0])) { + return(xmlSecErrorsTable[pos].errorMsg); + } + return(NULL); +} + +/** + * xmlSecError: + * @file: the error location filename (__FILE__). + * @line: the error location line number (__LINE__). + * @func: the error location function (__FUNCTIION__). + * @errorObject: the error specific error object + * @errorSubject: the error specific error subject. + * @reason: the error code. + * @msg: the error message in printf format. + * @...: the parameters for the @msg. + * + * Reports an error to the default (#xmlSecErrorsDefaultCallback) or + * application specific callback installed using #xmlSecErrorsSetCallback + * function. + */ +void +xmlSecError(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg, ...) { + + if(xmlSecErrorsClbk != NULL) { + xmlChar error_msg[XMLSEC_ERRORS_BUFFER_SIZE]; + + if(msg != NULL) { + va_list va; + + va_start(va, msg); + xmlSecStrVPrintf(error_msg, sizeof(error_msg), BAD_CAST msg, va); + error_msg[sizeof(error_msg) - 1] = '\0'; + va_end(va); + } else { + error_msg[0] = '\0'; + } + xmlSecErrorsClbk(file, line, func, errorObject, errorSubject, reason, (char*)error_msg); + } +} diff --git a/src/globals.h b/src/globals.h new file mode 100644 index 00000000..35a238cc --- /dev/null +++ b/src/globals.h @@ -0,0 +1,25 @@ +/* + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Internal header only used during the compilation, + * + * 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_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 +#define XMLSEC_PRIVATE + +#endif /* __XMLSEC_GLOBALS_H__ */ diff --git a/src/gnutls/Makefile.am b/src/gnutls/Makefile.am new file mode 100644 index 00000000..7d639a34 --- /dev/null +++ b/src/gnutls/Makefile.am @@ -0,0 +1,48 @@ +NULL = + +EXTRA_DIST = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-gnutls.la \ + $(NULL) + +libxmlsec1_gnutls_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(GNUTLS_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_gnutls_la_SOURCES =\ + app.c \ + ciphers.c \ + crypto.c \ + digests.c \ + hmac.c \ + symkeys.c \ + globals.h \ + $(NULL) + +if SHAREDLIB_HACK +libxmlsec1_gnutls_la_SOURCES += ../strings.c +endif + +libxmlsec1_gnutls_la_LIBADD = \ + ../libxmlsec1.la \ + $(GNUTLS_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_gnutls_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_gnutls_la_LDFLAGS = \ + @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) diff --git a/src/gnutls/Makefile.in b/src/gnutls/Makefile.in new file mode 100644 index 00000000..f07a4b49 --- /dev/null +++ b/src/gnutls/Makefile.in @@ -0,0 +1,706 @@ +# Makefile.in generated by automake 1.11 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/gnutls +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +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_gnutls_la_SOURCES_DIST = app.c ciphers.c crypto.c \ + digests.c hmac.c symkeys.c globals.h ../strings.c +am__objects_1 = +@SHAREDLIB_HACK_TRUE@am__objects_2 = libxmlsec1_gnutls_la-strings.lo +am_libxmlsec1_gnutls_la_OBJECTS = libxmlsec1_gnutls_la-app.lo \ + libxmlsec1_gnutls_la-ciphers.lo libxmlsec1_gnutls_la-crypto.lo \ + libxmlsec1_gnutls_la-digests.lo libxmlsec1_gnutls_la-hmac.lo \ + libxmlsec1_gnutls_la-symkeys.lo $(am__objects_1) \ + $(am__objects_2) +libxmlsec1_gnutls_la_OBJECTS = $(am_libxmlsec1_gnutls_la_OBJECTS) +libxmlsec1_gnutls_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libxmlsec1_gnutls_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_gnutls_la_SOURCES) +DIST_SOURCES = $(am__libxmlsec1_gnutls_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@ +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@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_ENABLED = @PKG_CONFIG_ENABLED@ +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_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_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 = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-gnutls.la \ + $(NULL) + +libxmlsec1_gnutls_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(GNUTLS_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_gnutls_la_SOURCES = app.c ciphers.c crypto.c digests.c \ + hmac.c symkeys.c globals.h $(NULL) $(am__append_1) +libxmlsec1_gnutls_la_LIBADD = \ + ../libxmlsec1.la \ + $(GNUTLS_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_gnutls_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_gnutls_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/gnutls/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/gnutls/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-gnutls.la: $(libxmlsec1_gnutls_la_OBJECTS) $(libxmlsec1_gnutls_la_DEPENDENCIES) + $(libxmlsec1_gnutls_la_LINK) -rpath $(libdir) $(libxmlsec1_gnutls_la_OBJECTS) $(libxmlsec1_gnutls_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-app.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-ciphers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-crypto.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-digests.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-hmac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-strings.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_gnutls_la-symkeys.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_gnutls_la-app.lo: app.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-app.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-app.Tpo -c -o libxmlsec1_gnutls_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-app.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-app.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='app.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c + +libxmlsec1_gnutls_la-ciphers.lo: ciphers.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-ciphers.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-ciphers.Tpo -c -o libxmlsec1_gnutls_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-ciphers.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-ciphers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ciphers.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c + +libxmlsec1_gnutls_la-crypto.lo: crypto.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-crypto.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-crypto.Tpo -c -o libxmlsec1_gnutls_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-crypto.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c + +libxmlsec1_gnutls_la-digests.lo: digests.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-digests.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-digests.Tpo -c -o libxmlsec1_gnutls_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-digests.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-digests.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='digests.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c + +libxmlsec1_gnutls_la-hmac.lo: hmac.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-hmac.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-hmac.Tpo -c -o libxmlsec1_gnutls_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-hmac.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hmac.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c + +libxmlsec1_gnutls_la-symkeys.lo: symkeys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-symkeys.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-symkeys.Tpo -c -o libxmlsec1_gnutls_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-symkeys.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-symkeys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='symkeys.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c + +libxmlsec1_gnutls_la-strings.lo: ../strings.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_gnutls_la-strings.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_gnutls_la-strings.Tpo -c -o libxmlsec1_gnutls_la-strings.lo `test -f '../strings.c' || echo '$(srcdir)/'`../strings.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_gnutls_la-strings.Tpo $(DEPDIR)/libxmlsec1_gnutls_la-strings.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../strings.c' object='libxmlsec1_gnutls_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_gnutls_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_gnutls_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/gnutls/README b/src/gnutls/README new file mode 100644 index 00000000..02c5fbbf --- /dev/null +++ b/src/gnutls/README @@ -0,0 +1,9 @@ +The xmlsec-gnutls implementation is really limited and is not ready +for production use. The only supported crypto transforms are: + + - HMAC + - Tripple DES + - AES [128|192|256] + - SHA1 + +
\ No newline at end of file diff --git a/src/gnutls/app.c b/src/gnutls/app.c new file mode 100644 index 00000000..54da1999 --- /dev/null +++ b/src/gnutls/app.c @@ -0,0 +1,499 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <gnutls/gnutls.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/gnutls/app.h> +#include <xmlsec/gnutls/crypto.h> + +/** + * xmlSecGnuTLSAppInit: + * @config: the path to GnuTLS configuration (unused). + * + * 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 +xmlSecGnuTLSAppInit(const char* config ATTRIBUTE_UNUSED) { + int ret; + + ret = gnutls_global_init(); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "gnutls_global_init", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + return(0); +} + +/** + * xmlSecGnuTLSAppShutdown: + * + * 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 +xmlSecGnuTLSAppShutdown(void) { + gnutls_global_deinit(); + return(0); +} + +/** + * xmlSecGnuTLSAppKeyLoad: + * @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 (not implemented yet). + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecGnuTLSAppKeyLoad(const char *filename, xmlSecKeyDataFormat format, + const char *pwd, + void* pwdCallback, + void* pwdCallbackCtx) { + xmlSecAssert2(filename != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + + if (format == xmlSecKeyDataFormatPkcs12) { + return (xmlSecGnuTLSAppPkcs12Load(filename, pwd, pwdCallback, + pwdCallbackCtx)); + } + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppKeyLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +/** + * xmlSecGnuTLSAppKeyLoadMemory: + * @data: the binary key data. + * @dataSize: the size of binary key. + * @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 memory buffer (not implemented yet). + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecGnuTLSAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format, const char *pwd, + void* pwdCallback, void* pwdCallbackCtx) { + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + if (format == xmlSecKeyDataFormatPkcs12) { + return (xmlSecGnuTLSAppPkcs12LoadMemory(data, dataSize, pwd, + pwdCallback, pwdCallbackCtx)); + } + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppKeyLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +#ifndef XMLSEC_NO_X509 +/** + * xmlSecGnuTLSAppKeyCertLoad: + * @key: the pointer to key. + * @filename: the certificate filename. + * @format: the certificate file format. + * + * Reads the certificate from $@filename and adds it to key + * (not implemented yet). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, + xmlSecKeyDataFormat format) { + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppKeyCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +/** + * xmlSecGnuTLSAppKeyCertLoadMemory: + * @key: the pointer to key. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * + * Reads the certificate from memory buffer and adds it to key (not implemented yet). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format) { + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppKeyCertLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +/** + * xmlSecGnuTLSAppPkcs12Load: + * @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 + * (not implemented yet). + * For uniformity, call xmlSecGnuTLSAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecGnuTLSAppPkcs12Load(const char *filename, + const char *pwd ATTRIBUTE_UNUSED, + void* pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + xmlSecAssert2(filename != NULL, NULL); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppPkcs12Load", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +/** + * xmlSecGnuTLSAppPkcs12LoadMemory: + * @data: the PKCS12 binary data. + * @dataSize: the PKCS12 binary data size. + * @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 data in memory buffer. + * For uniformity, call xmlSecGnuTLSAppKeyLoadMemory instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12 (not implemented yet). + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecGnuTLSAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, + const char *pwd, void* pwdCallback, + void* pwdCallbackCtx) { + xmlSecAssert2(data != NULL, NULL); + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppPkcs12LoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +/** + * xmlSecGnuTLSAppKeysMngrCertLoad: + * @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 +xmlSecGnuTLSAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, + xmlSecKeyDataFormat format, + xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppKeysMngrCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +/** + * xmlSecGnuTLSAppKeysMngrCertLoadMemory: + * @mngr: the keys manager. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * @type: the flag that indicates is the certificate trusted or not. + * + * Reads cert from binary buffer @data 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 +xmlSecGnuTLSAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSAppKeysMngrCertLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +#endif /* XMLSEC_NO_X509 */ + +/** + * xmlSecGnuTLSAppDefaultKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Initializes @mngr with simple keys store #xmlSecSimpleKeysStoreId + * and a default GnuTLS crypto key data stores. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + + /* create simple keys store if needed */ + if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) { + xmlSecKeyStorePtr keysStore; + + keysStore = xmlSecKeyStoreCreate(xmlSecSimpleKeysStoreId); + if(keysStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecSimpleKeysStoreId"); + 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 = xmlSecGnuTLSKeysMngrInit(mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGnuTLSKeysMngrInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* TODO */ + mngr->getKey = xmlSecKeysMngrGetKey; + return(0); +} + +/** + * xmlSecGnuTLSAppDefaultKeysMngrAdoptKey: + * @mngr: the pointer to keys manager. + * @key: the pointer to key. + * + * Adds @key to the keys manager @mngr created with #xmlSecGnuTLSAppDefaultKeysMngrInit + * function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSAppDefaultKeysMngrAdoptKey(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 = xmlSecSimpleKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecGnuTLSAppDefaultKeysMngrLoad: + * @mngr: the pointer to keys manager. + * @uri: the uri. + * + * Loads XML keys file from @uri to the keys manager @mngr created + * with #xmlSecGnuTLSAppDefaultKeysMngrInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSAppDefaultKeysMngrLoad(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 = xmlSecSimpleKeysStoreLoad(store, uri, mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreLoad", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", xmlSecErrorsSafeString(uri)); + return(-1); + } + + return(0); +} + +/** + * xmlSecGnuTLSAppDefaultKeysMngrSave: + * @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 +xmlSecGnuTLSAppDefaultKeysMngrSave(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 = xmlSecSimpleKeysStoreSave(store, filename, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreSave", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + return(-1); + } + + return(0); +} + +/** + * xmlSecGnuTLSAppGetDefaultPwdCallback: + * + * Gets default password callback. + * + * Returns: default password callback. + */ +void* +xmlSecGnuTLSAppGetDefaultPwdCallback(void) { + return(NULL); +} + diff --git a/src/gnutls/ciphers.c b/src/gnutls/ciphers.c new file mode 100644 index 00000000..b9421597 --- /dev/null +++ b/src/gnutls/ciphers.c @@ -0,0 +1,860 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <gnutls/gnutls.h> +#include <gcrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/gnutls/crypto.h> + +/************************************************************************** + * + * Internal GnuTLS Block cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecGnuTLSBlockCipherCtx xmlSecGnuTLSBlockCipherCtx, + *xmlSecGnuTLSBlockCipherCtxPtr; +struct _xmlSecGnuTLSBlockCipherCtx { + int cipher; + int mode; + GcryCipherHd cipherCtx; + xmlSecKeyDataId keyId; + int keyInitialized; + int ctxInitialized; +}; + +static int xmlSecGnuTLSBlockCipherCtxInit (xmlSecGnuTLSBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSBlockCipherCtxUpdate (xmlSecGnuTLSBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSBlockCipherCtxFinal (xmlSecGnuTLSBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int +xmlSecGnuTLSBlockCipherCtxInit(xmlSecGnuTLSBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int blockLen; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + /* iv len == block len */ + blockLen = gcry_cipher_get_algo_blklen(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + if(encrypt) { + xmlSecByte* iv; + xmlSecSize 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 */ + gcry_randomize(iv, blockLen, GCRY_STRONG_RANDOM); + ret = gcry_cipher_setiv(ctx->cipherCtx, iv, blockLen); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "gcry_cipher_setiv", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + } else { + /* if we don't have enough data, exit and hope that + * we'll have iv next time */ + if(xmlSecBufferGetSize(in) < (xmlSecSize)blockLen) { + return(0); + } + xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1); + + /* set iv */ + ret = gcry_cipher_setiv(ctx->cipherCtx, xmlSecBufferGetData(in), blockLen); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "gcry_cipher_setiv", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + 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 +xmlSecGnuTLSBlockCipherCtxUpdate(xmlSecGnuTLSBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + xmlSecSize inSize, inBlocks, outSize; + int blockLen; + xmlSecByte* outBuf; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = gcry_cipher_get_algo_blklen(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(inSize < (xmlSecSize)blockLen) { + return(0); + } + + if(encrypt) { + inBlocks = inSize / ((xmlSecSize)blockLen); + } else { + /* we want to have the last block in the input buffer + * for padding check */ + inBlocks = (inSize - 1) / ((xmlSecSize)blockLen); + } + inSize = inBlocks * ((xmlSecSize)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; + + if(encrypt) { + ret = gcry_cipher_encrypt(ctx->cipherCtx, outBuf, inSize + blockLen, + xmlSecBufferGetData(in), inSize); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "gcry_cipher_encrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + } else { + ret = gcry_cipher_decrypt(ctx->cipherCtx, outBuf, inSize + blockLen, + xmlSecBufferGetData(in), inSize); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "gcry_cipher_decrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + 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 +xmlSecGnuTLSBlockCipherCtxFinal(xmlSecGnuTLSBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + xmlSecSize inSize, outSize; + int blockLen, outLen = 0; + xmlSecByte* inBuf; + xmlSecByte* outBuf; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = gcry_cipher_get_algo_blklen(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(encrypt != 0) { + xmlSecAssert2(inSize < (xmlSecSize)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((xmlSecSize)blockLen > (inSize + 1)) { + gcry_randomize(inBuf + inSize, blockLen - inSize - 1, + GCRY_STRONG_RANDOM); /* as usual, we are paranoid */ + } + inBuf[blockLen - 1] = blockLen - inSize; + inSize = blockLen; + } else { + if(inSize != (xmlSecSize)blockLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "data=%d;block=%d", inSize, blockLen); + return(-1); + } + } + + /* 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; + + if(encrypt) { + ret = gcry_cipher_encrypt(ctx->cipherCtx, outBuf, inSize + blockLen, + xmlSecBufferGetData(in), inSize); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "gcry_cipher_encrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + } else { + ret = gcry_cipher_decrypt(ctx->cipherCtx, outBuf, inSize + blockLen, + xmlSecBufferGetData(in), inSize); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "gcry_cipher_decrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + 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); + } + + + /* 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 + * + * xmlSecGnuTLSBlockCipherCtx block is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecGnuTLSBlockCipherSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecGnuTLSBlockCipherCtx)) +#define xmlSecGnuTLSBlockCipherGetCtx(transform) \ + ((xmlSecGnuTLSBlockCipherCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecGnuTLSBlockCipherInitialize (xmlSecTransformPtr transform); +static void xmlSecGnuTLSBlockCipherFinalize (xmlSecTransformPtr transform); +static int xmlSecGnuTLSBlockCipherSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecGnuTLSBlockCipherSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecGnuTLSBlockCipherExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSBlockCipherCheckId (xmlSecTransformPtr transform); + + + +static int +xmlSecGnuTLSBlockCipherCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DES + if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformDes3CbcId)) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformAes128CbcId) || + xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformAes192CbcId) || + xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformAes256CbcId)) { + + return(1); + } +#endif /* XMLSEC_NO_AES */ + + return(0); +} + +static int +xmlSecGnuTLSBlockCipherInitialize(xmlSecTransformPtr transform) { + xmlSecGnuTLSBlockCipherCtxPtr ctx; +#ifndef XMLSEC_GNUTLS_OLD + gpg_err_code_t ret; +#endif /* XMLSEC_GNUTLS_OLD */ + + xmlSecAssert2(xmlSecGnuTLSBlockCipherCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSBlockCipherSize), -1); + + ctx = xmlSecGnuTLSBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecGnuTLSBlockCipherCtx)); + +#ifndef XMLSEC_NO_DES + if(transform->id == xmlSecGnuTLSTransformDes3CbcId) { + ctx->cipher = GCRY_CIPHER_3DES; + ctx->mode = GCRY_CIPHER_MODE_CBC; + ctx->keyId = xmlSecGnuTLSKeyDataDesId; + } else +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(transform->id == xmlSecGnuTLSTransformAes128CbcId) { + ctx->cipher = GCRY_CIPHER_AES128; + ctx->mode = GCRY_CIPHER_MODE_CBC; + ctx->keyId = xmlSecGnuTLSKeyDataAesId; + } else if(transform->id == xmlSecGnuTLSTransformAes192CbcId) { + ctx->cipher = GCRY_CIPHER_AES192; + ctx->mode = GCRY_CIPHER_MODE_CBC; + ctx->keyId = xmlSecGnuTLSKeyDataAesId; + } else if(transform->id == xmlSecGnuTLSTransformAes256CbcId) { + ctx->cipher = GCRY_CIPHER_AES256; + ctx->mode = GCRY_CIPHER_MODE_CBC; + ctx->keyId = xmlSecGnuTLSKeyDataAesId; + } else +#endif /* XMLSEC_NO_AES */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_GNUTLS_OLD + ret = gcry_cipher_open(&ctx->cipherCtx, ctx->cipher, ctx->mode, GCRY_CIPHER_SECURE); /* we are paranoid */ + if(ret != GPG_ERR_NO_ERROR) { +#else /* XMLSEC_GNUTLS_OLD */ + ctx->cipherCtx = gcry_cipher_open(ctx->cipher, ctx->mode, GCRY_CIPHER_SECURE); /* we are paranoid */ + if(ctx->cipherCtx == NULL) { +#endif /* XMLSEC_GNUTLS_OLD */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_cipher_open", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecGnuTLSBlockCipherFinalize(xmlSecTransformPtr transform) { + xmlSecGnuTLSBlockCipherCtxPtr ctx; + + xmlSecAssert(xmlSecGnuTLSBlockCipherCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecGnuTLSBlockCipherSize)); + + ctx = xmlSecGnuTLSBlockCipherGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->cipherCtx != NULL) { + gcry_cipher_close(ctx->cipherCtx); + } + + memset(ctx, 0, sizeof(xmlSecGnuTLSBlockCipherCtx)); +} + +static int +xmlSecGnuTLSBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecGnuTLSBlockCipherCtxPtr ctx; + + xmlSecAssert2(xmlSecGnuTLSBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSBlockCipherSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecGnuTLSBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + + keyReq->keyId = ctx->keyId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + + keyReq->keyBitsSize = 8 * gcry_cipher_get_algo_keylen(ctx->cipher); + return(0); +} + +static int +xmlSecGnuTLSBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecGnuTLSBlockCipherCtxPtr ctx; + xmlSecBufferPtr buffer; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecGnuTLSBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSBlockCipherSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecGnuTLSBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->keyInitialized == 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + keySize = gcry_cipher_get_algo_keylen(ctx->cipher); + xmlSecAssert2(keySize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + if(xmlSecBufferGetSize(buffer) < keySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "keySize=%d;expected=%d", + xmlSecBufferGetSize(buffer), keySize); + return(-1); + } + + xmlSecAssert2(xmlSecBufferGetData(buffer) != NULL, -1); + ret = gcry_cipher_setkey(ctx->cipherCtx, xmlSecBufferGetData(buffer), keySize); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_cipher_setkey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + + ctx->keyInitialized = 1; + return(0); +} + +static int +xmlSecGnuTLSBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecGnuTLSBlockCipherCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecGnuTLSBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSBlockCipherSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecGnuTLSBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + if(ctx->ctxInitialized == 0) { + ret = xmlSecGnuTLSBlockCipherCtxInit(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecGnuTLSBlockCipherCtxInit", + 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 = xmlSecGnuTLSBlockCipherCtxUpdate(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecGnuTLSBlockCipherCtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(last) { + ret = xmlSecGnuTLSBlockCipherCtxFinal(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecGnuTLSBlockCipherCtxFinal", + 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 xmlSecGnuTLSAes128CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes128Cbc, /* const xmlChar* name; */ + xmlSecHrefAes128Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecGnuTLSBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecGnuTLSBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformAes128CbcGetKlass: + * + * AES 128 CBC encryption transform klass. + * + * Returns: pointer to AES 128 CBC encryption transform. + */ +xmlSecTransformId +xmlSecGnuTLSTransformAes128CbcGetKlass(void) { + return(&xmlSecGnuTLSAes128CbcKlass); +} + +static xmlSecTransformKlass xmlSecGnuTLSAes192CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes192Cbc, /* const xmlChar* name; */ + xmlSecHrefAes192Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecGnuTLSBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecGnuTLSBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformAes192CbcGetKlass: + * + * AES 192 CBC encryption transform klass. + * + * Returns: pointer to AES 192 CBC encryption transform. + */ +xmlSecTransformId +xmlSecGnuTLSTransformAes192CbcGetKlass(void) { + return(&xmlSecGnuTLSAes192CbcKlass); +} + +static xmlSecTransformKlass xmlSecGnuTLSAes256CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes256Cbc, /* const xmlChar* name; */ + xmlSecHrefAes256Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecGnuTLSBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecGnuTLSBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformAes256CbcGetKlass: + * + * AES 256 CBC encryption transform klass. + * + * Returns: pointer to AES 256 CBC encryption transform. + */ +xmlSecTransformId +xmlSecGnuTLSTransformAes256CbcGetKlass(void) { + return(&xmlSecGnuTLSAes256CbcKlass); +} + +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES +static xmlSecTransformKlass xmlSecGnuTLSDes3CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameDes3Cbc, /* const xmlChar* name; */ + xmlSecHrefDes3Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecGnuTLSBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecGnuTLSBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformDes3CbcGetKlass: + * + * Triple DES CBC encryption transform klass. + * + * Returns: pointer to Triple DES encryption transform. + */ +xmlSecTransformId +xmlSecGnuTLSTransformDes3CbcGetKlass(void) { + return(&xmlSecGnuTLSDes3CbcKlass); +} +#endif /* XMLSEC_NO_DES */ + diff --git a/src/gnutls/crypto.c b/src/gnutls/crypto.c new file mode 100644 index 00000000..dbf69f21 --- /dev/null +++ b/src/gnutls/crypto.c @@ -0,0 +1,205 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <gnutls/gnutls.h> +#include <gcrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/dl.h> +#include <xmlsec/private.h> + +#include <xmlsec/gnutls/app.h> +#include <xmlsec/gnutls/crypto.h> + +static xmlSecCryptoDLFunctionsPtr gXmlSecGnuTLSFunctions = NULL; + +/** + * xmlSecCryptoGetFunctions_gnutls: + * + * Gets the pointer to xmlsec-gnutls functions table. + * + * Returns: the xmlsec-gnutls functions table or NULL if an error occurs. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoGetFunctions_gnutls(void) { + static xmlSecCryptoDLFunctions functions; + + if(gXmlSecGnuTLSFunctions != NULL) { + return(gXmlSecGnuTLSFunctions); + } + + memset(&functions, 0, sizeof(functions)); + gXmlSecGnuTLSFunctions = &functions; + + /** + * Crypto Init/shutdown + */ + gXmlSecGnuTLSFunctions->cryptoInit = xmlSecGnuTLSInit; + gXmlSecGnuTLSFunctions->cryptoShutdown = xmlSecGnuTLSShutdown; + gXmlSecGnuTLSFunctions->cryptoKeysMngrInit = xmlSecGnuTLSKeysMngrInit; + + /** + * Key data ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecGnuTLSFunctions->keyDataAesGetKlass = xmlSecGnuTLSKeyDataAesGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecGnuTLSFunctions->keyDataDesGetKlass = xmlSecGnuTLSKeyDataDesGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecGnuTLSFunctions->keyDataHmacGetKlass = xmlSecGnuTLSKeyDataHmacGetKlass; +#endif /* XMLSEC_NO_HMAC */ + + /** + * Key data store ids + */ + + /** + * Crypto transforms ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecGnuTLSFunctions->transformAes128CbcGetKlass = xmlSecGnuTLSTransformAes128CbcGetKlass; + gXmlSecGnuTLSFunctions->transformAes192CbcGetKlass = xmlSecGnuTLSTransformAes192CbcGetKlass; + gXmlSecGnuTLSFunctions->transformAes256CbcGetKlass = xmlSecGnuTLSTransformAes256CbcGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecGnuTLSFunctions->transformDes3CbcGetKlass = xmlSecGnuTLSTransformDes3CbcGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecGnuTLSFunctions->transformHmacSha1GetKlass = xmlSecGnuTLSTransformHmacSha1GetKlass; + gXmlSecGnuTLSFunctions->transformHmacRipemd160GetKlass = xmlSecGnuTLSTransformHmacRipemd160GetKlass; + gXmlSecGnuTLSFunctions->transformHmacMd5GetKlass = xmlSecGnuTLSTransformHmacMd5GetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecGnuTLSFunctions->transformSha1GetKlass = xmlSecGnuTLSTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + + /** + * High level routines form xmlsec command line utility + */ + gXmlSecGnuTLSFunctions->cryptoAppInit = xmlSecGnuTLSAppInit; + gXmlSecGnuTLSFunctions->cryptoAppShutdown = xmlSecGnuTLSAppShutdown; + gXmlSecGnuTLSFunctions->cryptoAppDefaultKeysMngrInit = xmlSecGnuTLSAppDefaultKeysMngrInit; + gXmlSecGnuTLSFunctions->cryptoAppDefaultKeysMngrAdoptKey = xmlSecGnuTLSAppDefaultKeysMngrAdoptKey; + gXmlSecGnuTLSFunctions->cryptoAppDefaultKeysMngrLoad = xmlSecGnuTLSAppDefaultKeysMngrLoad; + gXmlSecGnuTLSFunctions->cryptoAppDefaultKeysMngrSave = xmlSecGnuTLSAppDefaultKeysMngrSave; +#ifndef XMLSEC_NO_X509 + gXmlSecGnuTLSFunctions->cryptoAppKeysMngrCertLoad = xmlSecGnuTLSAppKeysMngrCertLoad; + gXmlSecGnuTLSFunctions->cryptoAppPkcs12Load = xmlSecGnuTLSAppPkcs12Load; + gXmlSecGnuTLSFunctions->cryptoAppKeyCertLoad = xmlSecGnuTLSAppKeyCertLoad; +#endif /* XMLSEC_NO_X509 */ + gXmlSecGnuTLSFunctions->cryptoAppKeyLoad = xmlSecGnuTLSAppKeyLoad; + gXmlSecGnuTLSFunctions->cryptoAppDefaultPwdCallback = (void*)xmlSecGnuTLSAppGetDefaultPwdCallback(); + + return(gXmlSecGnuTLSFunctions); +} + + +/** + * xmlSecGnuTLSInit: + * + * XMLSec library specific crypto engine initialization. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSInit (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); + } + + /* register our klasses */ + if(xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(xmlSecCryptoGetFunctions_gnutls()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecGnuTLSShutdown: + * + * XMLSec library specific crypto engine shutdown. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSShutdown(void) { + return(0); +} + +/** + * xmlSecGnuTLSKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Adds GnuTLS specific key data stores in keys manager. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSKeysMngrInit(xmlSecKeysMngrPtr mngr) { + xmlSecAssert2(mngr != NULL, -1); + + /* TODO: add key data stores */ + return(0); +} + +/** + * xmlSecGnuTLSGenerateRandom: + * @buffer: the destination buffer. + * @size: the numer of bytes to generate. + * + * Generates @size random bytes and puts result in @buffer. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecGnuTLSGenerateRandom(xmlSecBufferPtr buffer, xmlSecSize size) { + 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); + } + + /* get random data */ + gcry_randomize(xmlSecBufferGetData(buffer), size, GCRY_STRONG_RANDOM); + return(0); +} diff --git a/src/gnutls/digests.c b/src/gnutls/digests.c new file mode 100644 index 00000000..fb8109de --- /dev/null +++ b/src/gnutls/digests.c @@ -0,0 +1,318 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <gnutls/gnutls.h> +#include <gcrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/gnutls/app.h> +#include <xmlsec/gnutls/crypto.h> + +#define XMLSEC_GNUTLS_MAX_DIGEST_SIZE 32 + +/************************************************************************** + * + * Internal GNUTLS Digest CTX + * + *****************************************************************************/ +typedef struct _xmlSecGnuTLSDigestCtx xmlSecGnuTLSDigestCtx, *xmlSecGnuTLSDigestCtxPtr; +struct _xmlSecGnuTLSDigestCtx { + int digest; + GcryMDHd digestCtx; + xmlSecByte dgst[XMLSEC_GNUTLS_MAX_DIGEST_SIZE]; + xmlSecSize dgstSize; /* dgst size in bytes */ +}; + +/****************************************************************************** + * + * Digest transforms + * + * xmlSecGnuTLSDigestCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecGnuTLSDigestSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecGnuTLSDigestCtx)) +#define xmlSecGnuTLSDigestGetCtx(transform) \ + ((xmlSecGnuTLSDigestCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecGnuTLSDigestInitialize (xmlSecTransformPtr transform); +static void xmlSecGnuTLSDigestFinalize (xmlSecTransformPtr transform); +static int xmlSecGnuTLSDigestVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSDigestExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSDigestCheckId (xmlSecTransformPtr transform); + +static int +xmlSecGnuTLSDigestCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + + return(0); +} + +static int +xmlSecGnuTLSDigestInitialize(xmlSecTransformPtr transform) { + xmlSecGnuTLSDigestCtxPtr ctx; +#ifndef XMLSEC_GNUTLS_OLD + gpg_err_code_t ret; +#endif /* XMLSEC_GNUTLS_OLD */ + + xmlSecAssert2(xmlSecGnuTLSDigestCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSDigestSize), -1); + + ctx = xmlSecGnuTLSDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecGnuTLSDigestCtx)); + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformSha1Id)) { + ctx->digest = GCRY_MD_SHA1; + } else +#endif /* XMLSEC_NO_SHA1 */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_GNUTLS_OLD + ret = gcry_md_open(&ctx->digestCtx, ctx->digest, GCRY_MD_FLAG_SECURE); /* we are paranoid */ + if(ret != GPG_ERR_NO_ERROR) { +#else /* XMLSEC_GNUTLS_OLD */ + ctx->digestCtx = gcry_md_open(ctx->digest, GCRY_MD_FLAG_SECURE); /* we are paranoid */ + if(ctx->digestCtx == NULL) { +#endif /* XMLSEC_GNUTLS_OLD */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_md_open", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecGnuTLSDigestFinalize(xmlSecTransformPtr transform) { + xmlSecGnuTLSDigestCtxPtr ctx; + + xmlSecAssert(xmlSecGnuTLSDigestCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecGnuTLSDigestSize)); + + ctx = xmlSecGnuTLSDigestGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->digestCtx != NULL) { + gcry_md_close(ctx->digestCtx); + } + memset(ctx, 0, sizeof(xmlSecGnuTLSDigestCtx)); +} + +static int +xmlSecGnuTLSDigestVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecGnuTLSDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecGnuTLSDigestCheckId(transform), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSDigestSize), -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecGnuTLSDigestGetCtx(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_DATA, + "data and digest sizes are different (data=%d, dgst=%d)", + dataSize, ctx->dgstSize); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + if(memcmp(ctx->dgst, data, dataSize) != 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 +xmlSecGnuTLSDigestExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecGnuTLSDigestCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecGnuTLSDigestCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(transformCtx != NULL, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSDigestSize), -1); + + ctx = xmlSecGnuTLSDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digest != GCRY_MD_NONE, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { + gcry_md_write(ctx->digestCtx, xmlSecBufferGetData(in), inSize); + + 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) { + xmlSecByte* buf; + + /* get the final digest */ + gcry_md_final(ctx->digestCtx); + buf = gcry_md_read(ctx->digestCtx, ctx->digest); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_md_read", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* copy it to our internal buffer */ + ctx->dgstSize = gcry_md_get_algo_dlen(ctx->digest); + xmlSecAssert2(ctx->dgstSize > 0, -1); + xmlSecAssert2(ctx->dgstSize <= sizeof(ctx->dgst), -1); + memcpy(ctx->dgst, buf, ctx->dgstSize); + + /* and to the output if needed */ + 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(&(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_SHA1 +/****************************************************************************** + * + * SHA1 Digest transforms + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecGnuTLSSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSDigestSize, /* xmlSecSize objSize */ + + /* data */ + xmlSecNameSha1, /* const xmlChar* name; */ + xmlSecHrefSha1, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + /* methods */ + xmlSecGnuTLSDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecGnuTLSDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformSha1GetKlass: + * + * SHA-1 digest transform klass. + * + * Returns: pointer to SHA-1 digest transform klass. + */ +xmlSecTransformId +xmlSecGnuTLSTransformSha1GetKlass(void) { + return(&xmlSecGnuTLSSha1Klass); +} +#endif /* XMLSEC_NO_SHA1 */ + + diff --git a/src/gnutls/globals.h b/src/gnutls/globals.h new file mode 100644 index 00000000..272a27b8 --- /dev/null +++ b/src/gnutls/globals.h @@ -0,0 +1,24 @@ +/* + * XML Security Library + * + * globals.h: internal header only used during the compilation + * + * 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_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 + +#endif /* ! __XMLSEC_GLOBALS_H__ */ diff --git a/src/gnutls/hmac.c b/src/gnutls/hmac.c new file mode 100644 index 00000000..bc106471 --- /dev/null +++ b/src/gnutls/hmac.c @@ -0,0 +1,601 @@ +/** + * XMLSec library + * + * 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 <string.h> + +#include <gnutls/gnutls.h> +#include <gcrypt.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/gnutls/app.h> +#include <xmlsec/gnutls/crypto.h> + +/* sizes in bits */ +#define XMLSEC_GNUTLS_MIN_HMAC_SIZE 80 +#define XMLSEC_GNUTLS_MAX_HMAC_SIZE (128 * 8) + +/************************************************************************** + * + * Configuration + * + *****************************************************************************/ +static int g_xmlsec_gnutls_hmac_min_length = XMLSEC_GNUTLS_MIN_HMAC_SIZE; + +/** + * xmlSecGnuTLSHmacGetMinOutputLength: + * + * Gets the value of min HMAC length. + * + * Returns: the min HMAC output length + */ +int xmlSecGnuTLSHmacGetMinOutputLength(void) +{ + return g_xmlsec_gnutls_hmac_min_length; +} + +/** + * xmlSecGnuTLSHmacSetMinOutputLength: + * @min_length: the new min length + * + * Sets the min HMAC output length + */ +void xmlSecGnuTLSHmacSetMinOutputLength(int min_length) +{ + g_xmlsec_gnutls_hmac_min_length = min_length; +} + +/************************************************************************** + * + * Internal GNUTLS HMAC CTX + * + *****************************************************************************/ +typedef struct _xmlSecGnuTLSHmacCtx xmlSecGnuTLSHmacCtx, *xmlSecGnuTLSHmacCtxPtr; +struct _xmlSecGnuTLSHmacCtx { + int digest; + GcryMDHd digestCtx; + xmlSecByte dgst[XMLSEC_GNUTLS_MAX_HMAC_SIZE / 8]; + xmlSecSize dgstSize; /* dgst size in bits */ +}; + +/****************************************************************************** + * + * HMAC transforms + * + * xmlSecGnuTLSHmacCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecGnuTLSHmacGetCtx(transform) \ + ((xmlSecGnuTLSHmacCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecGnuTLSHmacSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecGnuTLSHmacCtx)) +#define xmlSecGnuTLSHmacCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecGnuTLSTransformHmacSha1Id) || \ + xmlSecTransformCheckId((transform), xmlSecGnuTLSTransformHmacMd5Id) || \ + xmlSecTransformCheckId((transform), xmlSecGnuTLSTransformHmacRipemd160Id)) + +static int xmlSecGnuTLSHmacInitialize (xmlSecTransformPtr transform); +static void xmlSecGnuTLSHmacFinalize (xmlSecTransformPtr transform); +static int xmlSecGnuTLSHmacNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSHmacSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecGnuTLSHmacSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecGnuTLSHmacVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecGnuTLSHmacExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static int +xmlSecGnuTLSHmacInitialize(xmlSecTransformPtr transform) { + xmlSecGnuTLSHmacCtxPtr ctx; +#ifndef XMLSEC_GNUTLS_OLD + gpg_err_code_t ret; +#endif /* XMLSEC_GNUTLS_OLD */ + + xmlSecAssert2(xmlSecGnuTLSHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize), -1); + + ctx = xmlSecGnuTLSHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecGnuTLSHmacCtx)); + if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformHmacSha1Id)) { + ctx->digest = GCRY_MD_SHA1; + } else if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformHmacMd5Id)) { + ctx->digest = GCRY_MD_MD5; + } else if(xmlSecTransformCheckId(transform, xmlSecGnuTLSTransformHmacRipemd160Id)) { + ctx->digest = GCRY_MD_RMD160; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_GNUTLS_OLD + ret = gcry_md_open(&ctx->digestCtx, ctx->digest, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); /* we are paranoid */ + if(ret != GPG_ERR_NO_ERROR) { +#else /* XMLSEC_GNUTLS_OLD */ + ctx->digestCtx = gcry_md_open(ctx->digest, GCRY_MD_FLAG_HMAC | GCRY_MD_FLAG_SECURE); /* we are paranoid */ + if(ctx->digestCtx == NULL) { +#endif /* XMLSEC_GNUTLS_OLD */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_md_open", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecGnuTLSHmacFinalize(xmlSecTransformPtr transform) { + xmlSecGnuTLSHmacCtxPtr ctx; + + xmlSecAssert(xmlSecGnuTLSHmacCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize)); + + ctx = xmlSecGnuTLSHmacGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->digestCtx != NULL) { + gcry_md_close(ctx->digestCtx); + } + memset(ctx, 0, sizeof(xmlSecGnuTLSHmacCtx)); +} + +/** + * xmlSecGnuTLSHmacNodeRead: + * + * HMAC (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> + * + * Schema Definition: + * + * <simpleType name="HMACOutputLengthType"> + * <restriction base="integer"/> + * </simpleType> + * + * DTD: + * + * <!ELEMENT HMACOutputLength (#PCDATA)> + */ +static int +xmlSecGnuTLSHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecGnuTLSHmacCtxPtr ctx; + xmlNodePtr cur; + + xmlSecAssert2(xmlSecGnuTLSHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecGnuTLSHmacGetCtx(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 lenght to 0 or very + small value + */ + if((int)ctx->dgstSize < xmlSecGnuTLSHmacGetMinOutputLength()) { + 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_INVALID_NODE, + "no nodes expected"); + return(-1); + } + return(0); +} + + +static int +xmlSecGnuTLSHmacSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecGnuTLSHmacCtxPtr ctx; + + xmlSecAssert2(xmlSecGnuTLSHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(keyReq != NULL, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize), -1); + + ctx = xmlSecGnuTLSHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecGnuTLSKeyDataHmacId; + keyReq->keyType= xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationSign) { + keyReq->keyUsage = xmlSecKeyUsageSign; + } else { + keyReq->keyUsage = xmlSecKeyUsageVerify; + } + + return(0); +} + +static int +xmlSecGnuTLSHmacSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecGnuTLSHmacCtxPtr ctx; + xmlSecKeyDataPtr value; + xmlSecBufferPtr buffer; + int ret; + + xmlSecAssert2(xmlSecGnuTLSHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecGnuTLSHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(xmlSecKeyDataCheckId(value, xmlSecGnuTLSKeyDataHmacId), -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, + "key is empty"); + return(-1); + } + + ret = gcry_md_setkey(ctx->digestCtx, xmlSecBufferGetData(buffer), + xmlSecBufferGetSize(buffer)); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_md_setkey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + return(0); +} + +static int +xmlSecGnuTLSHmacVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + static xmlSecByte last_byte_masks[] = + { 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; + + xmlSecGnuTLSHmacCtxPtr ctx; + xmlSecByte mask; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecGnuTLSHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + xmlSecAssert2(ctx->dgstSize > 0, -1); + + /* compare the digest size in bytes */ + if(dataSize != ((ctx->dgstSize + 7) / 8)){ + 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 +xmlSecGnuTLSHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecGnuTLSHmacCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecByte* dgst; + xmlSecSize dgstSize; + int ret; + + xmlSecAssert2(xmlSecGnuTLSHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecGnuTLSHmacSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecGnuTLSHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { + gcry_md_write(ctx->digestCtx, xmlSecBufferGetData(in), inSize); + + 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) { + /* get the final digest */ + gcry_md_final(ctx->digestCtx); + dgst = gcry_md_read(ctx->digestCtx, ctx->digest); + if(dgst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "gcry_md_read", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* copy it to our internal buffer */ + dgstSize = gcry_md_get_algo_dlen(ctx->digest); + xmlSecAssert2(dgstSize > 0, -1); + xmlSecAssert2(dgstSize <= sizeof(ctx->dgst), -1); + memcpy(ctx->dgst, dgst, dgstSize); + + /* check/set the result digest size */ + if(ctx->dgstSize == 0) { + ctx->dgstSize = dgstSize * 8; /* no dgst size specified, use all we have */ + } else if(ctx->dgstSize <= 8 * dgstSize) { + dgstSize = ((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 * dgstSize, ctx->dgstSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationSign) { + ret = xmlSecBufferAppend(out, ctx->dgst, dgstSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", 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(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "size=%d", transform->status); + return(-1); + } + + return(0); +} + +/** + * HMAC SHA1 + */ +static xmlSecTransformKlass xmlSecGnuTLSHmacSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha1, /* const xmlChar* name; */ + xmlSecHrefHmacSha1, /* const xmlChar *href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecGnuTLSHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecGnuTLSHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecGnuTLSHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecGnuTLSHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformHmacSha1GetKlass: + * + * The HMAC-SHA1 transform klass. + * + * Returns: the HMAC-SHA1 transform klass. + */ +xmlSecTransformId +xmlSecGnuTLSTransformHmacSha1GetKlass(void) { + return(&xmlSecGnuTLSHmacSha1Klass); +} + +/** + * HMAC Ripemd160 + */ +static xmlSecTransformKlass xmlSecGnuTLSHmacRipemd160Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacRipemd160, /* const xmlChar* name; */ + xmlSecHrefHmacRipemd160, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecGnuTLSHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecGnuTLSHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecGnuTLSHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecGnuTLSHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformHmacRipemd160GetKlass: + * + * The HMAC-RIPEMD160 transform klass. + * + * Returns: the HMAC-RIPEMD160 transform klass. + */ +xmlSecTransformId +xmlSecGnuTLSTransformHmacRipemd160GetKlass(void) { + return(&xmlSecGnuTLSHmacRipemd160Klass); +} + +/** + * HMAC Md5 + */ +static xmlSecTransformKlass xmlSecGnuTLSHmacMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecGnuTLSHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacMd5, /* const xmlChar* name; */ + xmlSecHrefHmacMd5, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecGnuTLSHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecGnuTLSHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecGnuTLSHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecGnuTLSHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecGnuTLSHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecGnuTLSHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecGnuTLSHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSTransformHmacMd5GetKlass: + * + * The HMAC-MD5 transform klass. + * + * Returns: the HMAC-MD5 transform klass. + */ +xmlSecTransformId +xmlSecGnuTLSTransformHmacMd5GetKlass(void) { + return(&xmlSecGnuTLSHmacMd5Klass); +} + + +#endif /* XMLSEC_NO_HMAC */ diff --git a/src/gnutls/symkeys.c b/src/gnutls/symkeys.c new file mode 100644 index 00000000..4a11d13a --- /dev/null +++ b/src/gnutls/symkeys.c @@ -0,0 +1,440 @@ +/** + * + * 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> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.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/gnutls/crypto.h> + +/***************************************************************************** + * + * Symmetic (binary) keys - just a wrapper for xmlSecKeyDataBinary + * + ****************************************************************************/ +static int xmlSecGnuTLSSymKeyDataInitialize (xmlSecKeyDataPtr data); +static int xmlSecGnuTLSSymKeyDataDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecGnuTLSSymKeyDataFinalize (xmlSecKeyDataPtr data); +static int xmlSecGnuTLSSymKeyDataXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecGnuTLSSymKeyDataXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecGnuTLSSymKeyDataBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const xmlSecByte* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecGnuTLSSymKeyDataBinWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlSecByte** buf, + xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecGnuTLSSymKeyDataGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecGnuTLSSymKeyDataGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecGnuTLSSymKeyDataGetSize (xmlSecKeyDataPtr data); +static void xmlSecGnuTLSSymKeyDataDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecGnuTLSSymKeyDataDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); +static int xmlSecGnuTLSSymKeyDataKlassCheck (xmlSecKeyDataKlass* klass); + +#define xmlSecGnuTLSSymKeyDataCheckId(data) \ + (xmlSecKeyDataIsValid((data)) && \ + xmlSecGnuTLSSymKeyDataKlassCheck((data)->id)) + +static int +xmlSecGnuTLSSymKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataCheckId(data), -1); + + return(xmlSecKeyDataBinaryValueInitialize(data)); +} + +static int +xmlSecGnuTLSSymKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataCheckId(dst), -1); + xmlSecAssert2(xmlSecGnuTLSSymKeyDataCheckId(src), -1); + xmlSecAssert2(dst->id == src->id, -1); + + return(xmlSecKeyDataBinaryValueDuplicate(dst, src)); +} + +static void +xmlSecGnuTLSSymKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecGnuTLSSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueFinalize(data); +} + +static int +xmlSecGnuTLSSymKeyDataXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlRead(id, key, node, keyInfoCtx)); +} + +static int +xmlSecGnuTLSSymKeyDataXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlWrite(id, key, node, keyInfoCtx)); +} + +static int +xmlSecGnuTLSSymKeyDataBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinRead(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecGnuTLSSymKeyDataBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlSecByte** buf, xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinWrite(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecGnuTLSSymKeyDataGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecGnuTLSSymKeyDataCheckId(data), -1); + xmlSecAssert2(sizeBits > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecGnuTLSGenerateRandom(buffer, (sizeBits + 7) / 8)); +} + +static xmlSecKeyDataType +xmlSecGnuTLSSymKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecGnuTLSSymKeyDataCheckId(data), xmlSecKeyDataTypeUnknown); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, xmlSecKeyDataTypeUnknown); + + return((xmlSecBufferGetSize(buffer) > 0) ? xmlSecKeyDataTypeSymmetric : xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecGnuTLSSymKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecGnuTLSSymKeyDataCheckId(data), 0); + + return(xmlSecKeyDataBinaryValueGetSize(data)); +} + +static void +xmlSecGnuTLSSymKeyDataDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecGnuTLSSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugDump(data, output); +} + +static void +xmlSecGnuTLSSymKeyDataDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecGnuTLSSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugXmlDump(data, output); +} + +static int +xmlSecGnuTLSSymKeyDataKlassCheck(xmlSecKeyDataKlass* klass) { +#ifndef XMLSEC_NO_DES + if(klass == xmlSecGnuTLSKeyDataDesId) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(klass == xmlSecGnuTLSKeyDataAesId) { + return(1); + } +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_HMAC + if(klass == xmlSecGnuTLSKeyDataHmacId) { + return(1); + } +#endif /* XMLSEC_NO_HMAC */ + + return(0); +} + +#ifndef XMLSEC_NO_AES +/************************************************************************** + * + * <xmlsec:AESKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecGnuTLSKeyDataAesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameAESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefAESKeyValue, /* const xmlChar* href; */ + xmlSecNodeAESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecGnuTLSSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecGnuTLSSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecGnuTLSSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecGnuTLSSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecGnuTLSSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecGnuTLSSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecGnuTLSSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecGnuTLSSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecGnuTLSSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecGnuTLSSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecGnuTLSSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecGnuTLSSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSKeyDataAesGetKlass: + * + * The AES key data klass. + * + * Returns: AES key data klass. + */ +xmlSecKeyDataId +xmlSecGnuTLSKeyDataAesGetKlass(void) { + return(&xmlSecGnuTLSKeyDataAesKlass); +} + +/** + * xmlSecGnuTLSKeyDataAesSet: + * @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 +xmlSecGnuTLSKeyDataAesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataAesId), -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 xmlSecGnuTLSKeyDataDesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameDESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDESKeyValue, /* const xmlChar* href; */ + xmlSecNodeDESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecGnuTLSSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecGnuTLSSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecGnuTLSSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecGnuTLSSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecGnuTLSSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecGnuTLSSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecGnuTLSSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecGnuTLSSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecGnuTLSSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecGnuTLSSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecGnuTLSSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecGnuTLSSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSKeyDataDesGetKlass: + * + * The DES key data klass. + * + * Returns: DES key data klass. + */ +xmlSecKeyDataId +xmlSecGnuTLSKeyDataDesGetKlass(void) { + return(&xmlSecGnuTLSKeyDataDesKlass); +} + +/** + * xmlSecGnuTLSKeyDataDesSet: + * @data: the pointer to DES key data. + * @buf: the pointer to key value. + * @bufSize: the key value size (in bytes). + * + * Sets the value of DES key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecGnuTLSKeyDataDesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataDesId), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} + +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_HMAC +/************************************************************************** + * + * <xmlsec:HMACKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecGnuTLSKeyDataHmacKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameHMACKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefHMACKeyValue, /* const xmlChar* href; */ + xmlSecNodeHMACKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecGnuTLSSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecGnuTLSSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecGnuTLSSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecGnuTLSSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecGnuTLSSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecGnuTLSSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecGnuTLSSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecGnuTLSSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecGnuTLSSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecGnuTLSSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecGnuTLSSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecGnuTLSSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecGnuTLSKeyDataHmacGetKlass: + * + * The HMAC key data klass. + * + * Returns: HMAC key data klass. + */ +xmlSecKeyDataId +xmlSecGnuTLSKeyDataHmacGetKlass(void) { + return(&xmlSecGnuTLSKeyDataHmacKlass); +} + +/** + * xmlSecGnuTLSKeyDataHmacSet: + * @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 +xmlSecGnuTLSKeyDataHmacSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecGnuTLSKeyDataHmacId), -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/io.c b/src/io.c new file mode 100644 index 00000000..a691f68b --- /dev/null +++ b/src/io.c @@ -0,0 +1,496 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Input uri transform and utility functions. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <libxml/uri.h> +#include <libxml/tree.h> +#include <libxml/xmlIO.h> + +#ifdef LIBXML_HTTP_ENABLED +#include <libxml/nanohttp.h> +#endif /* LIBXML_HTTP_ENABLED */ + +#ifdef LIBXML_FTP_ENABLED +#include <libxml/nanoftp.h> +#endif /* LIBXML_FTP_ENABLED */ + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keys.h> +#include <xmlsec/io.h> +#include <xmlsec/errors.h> + +/******************************************************************* + * + * Input I/O callback sets + * + ******************************************************************/ +typedef struct _xmlSecIOCallback { + xmlInputMatchCallback matchcallback; + xmlInputOpenCallback opencallback; + xmlInputReadCallback readcallback; + xmlInputCloseCallback closecallback; +} xmlSecIOCallback, *xmlSecIOCallbackPtr; + +static xmlSecIOCallbackPtr xmlSecIOCallbackCreate (xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, + xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc); +static void xmlSecIOCallbackDestroy (xmlSecIOCallbackPtr callbacks); + +static xmlSecIOCallbackPtr +xmlSecIOCallbackCreate(xmlInputMatchCallback matchFunc, xmlInputOpenCallback openFunc, + xmlInputReadCallback readFunc, xmlInputCloseCallback closeFunc) { + xmlSecIOCallbackPtr callbacks; + + xmlSecAssert2(matchFunc != NULL, NULL); + + /* Allocate a new xmlSecIOCallback and fill the fields. */ + callbacks = (xmlSecIOCallbackPtr)xmlMalloc(sizeof(xmlSecIOCallback)); + if(callbacks == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecIOCallback)=%d", + sizeof(xmlSecIOCallback)); + return(NULL); + } + memset(callbacks, 0, sizeof(xmlSecIOCallback)); + + callbacks->matchcallback = matchFunc; + callbacks->opencallback = openFunc; + callbacks->readcallback = readFunc; + callbacks->closecallback = closeFunc; + + return(callbacks); +} + +static void +xmlSecIOCallbackDestroy(xmlSecIOCallbackPtr callbacks) { + xmlSecAssert(callbacks != NULL); + + memset(callbacks, 0, sizeof(xmlSecIOCallback)); + xmlFree(callbacks); +} + +/******************************************************************* + * + * Input I/O callback list + * + ******************************************************************/ +static xmlSecPtrListKlass xmlSecIOCallbackPtrListKlass = { + BAD_CAST "io-callbacks-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecIOCallbackDestroy,/* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +#define xmlSecIOCallbackPtrListId xmlSecIOCallbackPtrListGetKlass () +static xmlSecPtrListId xmlSecIOCallbackPtrListGetKlass (void); +static xmlSecIOCallbackPtr xmlSecIOCallbackPtrListFind (xmlSecPtrListPtr list, + const char* uri); + +/** + * xmlSecIOCallbackPtrListGetKlass: + * + * The keys list klass. + * + * Returns: keys list id. + */ +static xmlSecPtrListId +xmlSecIOCallbackPtrListGetKlass(void) { + return(&xmlSecIOCallbackPtrListKlass); +} + +static xmlSecIOCallbackPtr +xmlSecIOCallbackPtrListFind(xmlSecPtrListPtr list, const char* uri) { + xmlSecIOCallbackPtr callbacks; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecIOCallbackPtrListId), NULL); + xmlSecAssert2(uri != NULL, NULL); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + callbacks = (xmlSecIOCallbackPtr)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(callbacks != NULL, NULL); + xmlSecAssert2(callbacks->matchcallback != NULL, NULL); + + if((callbacks->matchcallback(uri)) != 0) { + return(callbacks); + } + } + return(NULL); +} + +static xmlSecPtrList xmlSecAllIOCallbacks; + +/** + * xmlSecIOInit: + * + * The IO initialization (called from #xmlSecInit function). + * Applications should not call this function directly. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecIOInit(void) { + int ret; + + ret = xmlSecPtrListInitialize(&xmlSecAllIOCallbacks, xmlSecIOCallbackPtrListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListPtrInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifdef LIBXML_HTTP_ENABLED + xmlNanoHTTPInit(); +#endif /* LIBXML_HTTP_ENABLED */ + +#ifdef LIBXML_FTP_ENABLED + xmlNanoFTPInit(); +#endif /* LIBXML_FTP_ENABLED */ + + return(xmlSecIORegisterDefaultCallbacks()); +} + +/** + * xmlSecIOShutdown: + * + * The IO clenaup (called from #xmlSecShutdown function). + * Applications should not call this function directly. + */ +void +xmlSecIOShutdown(void) { + +#ifdef LIBXML_HTTP_ENABLED + xmlNanoHTTPCleanup(); +#endif /* LIBXML_HTTP_ENABLED */ + +#ifdef LIBXML_FTP_ENABLED + xmlNanoFTPCleanup(); +#endif /* LIBXML_FTP_ENABLED */ + + xmlSecPtrListFinalize(&xmlSecAllIOCallbacks); +} + +/** + * xmlSecIOCleanupCallbacks: + * + * Clears the entire input callback table. this includes the + * compiled-in I/O. + */ +void +xmlSecIOCleanupCallbacks(void) { + xmlSecPtrListEmpty(&xmlSecAllIOCallbacks); +} + +/** + * xmlSecIORegisterCallbacks: + * @matchFunc: the protocol match callback. + * @openFunc: the open stream callback. + * @readFunc: the read from stream callback. + * @closeFunc: the close stream callback. + * + * Register a new set of I/O callback for handling parser input. + * + * Returns: the 0 on success or a negative value if an error occurs. + */ +int +xmlSecIORegisterCallbacks(xmlInputMatchCallback matchFunc, + xmlInputOpenCallback openFunc, xmlInputReadCallback readFunc, + xmlInputCloseCallback closeFunc) { + xmlSecIOCallbackPtr callbacks; + int ret; + + xmlSecAssert2(matchFunc != NULL, -1); + + callbacks = xmlSecIOCallbackCreate(matchFunc, openFunc, readFunc, closeFunc); + if(callbacks == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecIOCallbackCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecPtrListAdd(&xmlSecAllIOCallbacks, callbacks); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecIOCallbackDestroy(callbacks); + return(-1); + } + return(0); +} + + +/** + * xmlSecIORegisterDefaultCallbacks: + * + * Registers the default compiled-in I/O handlers. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecIORegisterDefaultCallbacks(void) { + int ret; + +#ifdef LIBXML_HTTP_ENABLED + ret = xmlSecIORegisterCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen, + xmlIOHTTPRead, xmlIOHTTPClose); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecIORegisterCallbacks", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "http"); + return(-1); + } +#endif /* LIBXML_HTTP_ENABLED */ + +#ifdef LIBXML_FTP_ENABLED + ret = xmlSecIORegisterCallbacks(xmlIOFTPMatch, xmlIOFTPOpen, + xmlIOFTPRead, xmlIOFTPClose); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecIORegisterCallbacks", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ftp"); + return(-1); + } +#endif /* LIBXML_FTP_ENABLED */ + + ret = xmlSecIORegisterCallbacks(xmlFileMatch, xmlFileOpen, + xmlFileRead, xmlFileClose); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecIORegisterCallbacks", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "file"); + return(-1); + } + + return(0); +} + + + + +/************************************************************** + * + * Input URI Transform + * + * xmlSecInputURICtx is located after xmlSecTransform + * + **************************************************************/ +typedef struct _xmlSecInputURICtx xmlSecInputURICtx, + *xmlSecInputURICtxPtr; +struct _xmlSecInputURICtx { + xmlSecIOCallbackPtr clbks; + void* clbksCtx; +}; +#define xmlSecTransformInputUriSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecInputURICtx)) +#define xmlSecTransformInputUriGetCtx(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecTransformInputUriSize)) ? \ + (xmlSecInputURICtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \ + (xmlSecInputURICtxPtr)NULL) + +static int xmlSecTransformInputURIInitialize (xmlSecTransformPtr transform); +static void xmlSecTransformInputURIFinalize (xmlSecTransformPtr transform); +static int xmlSecTransformInputURIPopBin (xmlSecTransformPtr transform, + xmlSecByte* data, + xmlSecSize maxDataSize, + xmlSecSize* dataSize, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecTransformInputURIKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformInputUriSize, /* xmlSecSize objSize */ + + BAD_CAST "input-uri", /* const xmlChar* name; */ + NULL, /* const xmlChar* href; */ + 0, /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformInputURIInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformInputURIFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformInputURIPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformInputURIGetKlass: + * + * The input uri transform klass. Reads binary data from an uri. + * + * Returns: input URI transform id. + */ +xmlSecTransformId +xmlSecTransformInputURIGetKlass(void) { + return(&xmlSecTransformInputURIKlass); +} + +/** + * xmlSecTransformInputURIOpen: + * @transform: the pointer to IO transform. + * @uri: the URL to open. + * + * Opens the given @uri for reading. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformInputURIOpen(xmlSecTransformPtr transform, const xmlChar *uri) { + xmlSecInputURICtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId), -1); + xmlSecAssert2(uri != NULL, -1); + + ctx = xmlSecTransformInputUriGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->clbks == NULL, -1); + xmlSecAssert2(ctx->clbksCtx == NULL, -1); + + /* + * Try to find one of the input accept method accepting that scheme + * Go in reverse to give precedence to user defined handlers. + * try with an unescaped version of the uri + */ + if(ctx->clbks == NULL) { + char *unescaped; + + unescaped = xmlURIUnescapeString((char*)uri, 0, NULL); + if (unescaped != NULL) { + ctx->clbks = xmlSecIOCallbackPtrListFind(&xmlSecAllIOCallbacks, unescaped); + if(ctx->clbks != NULL) { + ctx->clbksCtx = ctx->clbks->opencallback(unescaped); + } + xmlFree(unescaped); + } + } + + /* + * If this failed try with a non-escaped uri this may be a strange + * filename + */ + if (ctx->clbks == NULL) { + ctx->clbks = xmlSecIOCallbackPtrListFind(&xmlSecAllIOCallbacks, (char*)uri); + if(ctx->clbks != NULL) { + ctx->clbksCtx = ctx->clbks->opencallback((char*)uri); + } + } + + if((ctx->clbks == NULL) || (ctx->clbksCtx == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "opencallback", + XMLSEC_ERRORS_R_IO_FAILED, + "uri=%s;errno=%d", + xmlSecErrorsSafeString(uri), + errno); + return(-1); + } + + return(0); +} + +static int +xmlSecTransformInputURIInitialize(xmlSecTransformPtr transform) { + xmlSecInputURICtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId), -1); + + ctx = xmlSecTransformInputUriGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecInputURICtx)); + return(0); +} + +static void +xmlSecTransformInputURIFinalize(xmlSecTransformPtr transform) { + xmlSecInputURICtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId)); + + ctx = xmlSecTransformInputUriGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if((ctx->clbksCtx != NULL) && (ctx->clbks != NULL) && (ctx->clbks->closecallback != NULL)) { + (ctx->clbks->closecallback)(ctx->clbksCtx); + } + memset(ctx, 0, sizeof(xmlSecInputURICtx)); +} + +static int +xmlSecTransformInputURIPopBin(xmlSecTransformPtr transform, xmlSecByte* data, + xmlSecSize maxDataSize, xmlSecSize* dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecInputURICtxPtr ctx; + + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformInputURIId), -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecTransformInputUriGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if((ctx->clbksCtx != NULL) && (ctx->clbks != NULL) && (ctx->clbks->readcallback != NULL)) { + ret = (ctx->clbks->readcallback)(ctx->clbksCtx, (char*)data, (int)maxDataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "readcallback", + XMLSEC_ERRORS_R_IO_FAILED, + "errno=%d", errno); + return(-1); + } + (*dataSize) = ret; + } else { + (*dataSize) = 0; + } + return(0); +} + diff --git a/src/keyinfo.c b/src/keyinfo.c new file mode 100644 index 00000000..6e327b2b --- /dev/null +++ b/src/keyinfo.c @@ -0,0 +1,1561 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * <dsig:KeyInfo/> element processing + * (http://www.w3.org/TR/xmlSec-core/#sec-KeyInfo: + * + * The KeyInfo Element + * + * KeyInfo is an optional element that enables the recipient(s) to obtain + * the key needed to validate the signature. KeyInfo may contain keys, + * names, certificates and other public key management information, such as + * in-band key distribution or key agreement data. + * + * Schema Definition: + * + * <element name="KeyInfo" type="ds:KeyInfoType"/> + * <complexType name="KeyInfoType" mixed="true"> + * <choice maxOccurs="unbounded"> + * <element ref="ds:KeyName"/> + * <element ref="ds:KeyValue"/> + * <element ref="ds:RetrievalMethod"/> + * <element ref="ds:X509Data"/> + * <element ref="ds:PGPData"/> + * <element ref="ds:SPKIData"/> + * <element ref="ds:MgmtData"/> + * <any processContents="lax" namespace="##other"/> + * <!-- (1,1) elements from (0,unbounded) namespaces --> + * </choice> + * <attribute name="Id" type="ID" use="optional"/> + * </complexType> + * + * DTD: + * + * <!ELEMENT KeyInfo (#PCDATA|KeyName|KeyValue|RetrievalMethod| + * X509Data|PGPData|SPKIData|MgmtData %KeyInfo.ANY;)* > + * <!ATTLIST KeyInfo Id ID #IMPLIED > + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/base64.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/xmlenc.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/errors.h> + + +/************************************************************************** + * + * Hi level functions + * + *************************************************************************/ +/** + * xmlSecKeyInfoNodeRead: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * @key: the pointer to result key object. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Parses the <dsig:KeyInfo/> element @keyInfoNode, extracts the key data + * and stores into @key. + * + * Returns: 0 on success or -1 if an error occurs. + */ +int +xmlSecKeyInfoNodeRead(xmlNodePtr keyInfoNode, xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) { + const xmlChar* nodeName; + const xmlChar* nodeNs; + xmlSecKeyDataId dataId; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(keyInfoNode != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1); + + for(cur = xmlSecGetNextElementNode(keyInfoNode->children); + (cur != NULL) && + (((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_DONT_STOP_ON_KEY_FOUND) != 0) || + (xmlSecKeyIsValid(key) == 0) || + (xmlSecKeyMatch(key, NULL, &(keyInfoCtx->keyReq)) == 0)); + cur = xmlSecGetNextElementNode(cur->next)) { + + /* find data id */ + nodeName = cur->name; + nodeNs = xmlSecGetNodeNsHref(cur); + + /* use global list only if we don't have a local one */ + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData), + nodeName, nodeNs, xmlSecKeyDataUsageKeyInfoNodeRead); + } else { + dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(), + nodeName, nodeNs, xmlSecKeyDataUsageKeyInfoNodeRead); + } + if(dataId != xmlSecKeyDataIdUnknown) { + /* read data node */ + ret = xmlSecKeyDataXmlRead(dataId, key, cur, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyDataXmlRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_UNKNOWN_CHILD) != 0) { + /* there is a laxi schema validation but application may + * desire to disable unknown nodes*/ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +/** + * xmlSecKeyInfoNodeWrite: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * @key: the pointer to key object. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Writes the @key into the <dsig:KeyInfo/> element template @keyInfoNode. + * + * Returns: 0 on success or -1 if an error occurs. + */ +int +xmlSecKeyInfoNodeWrite(xmlNodePtr keyInfoNode, xmlSecKeyPtr key, xmlSecKeyInfoCtxPtr keyInfoCtx) { + const xmlChar* nodeName; + const xmlChar* nodeNs; + xmlSecKeyDataId dataId; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(keyInfoNode != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1); + + for(cur = xmlSecGetNextElementNode(keyInfoNode->children); + cur != NULL; + cur = xmlSecGetNextElementNode(cur->next)) { + + /* find data id */ + nodeName = cur->name; + nodeNs = xmlSecGetNodeNsHref(cur); + + /* use global list only if we don't have a local one */ + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData), + nodeName, nodeNs, + xmlSecKeyDataUsageKeyInfoNodeWrite); + } else { + dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(), + nodeName, nodeNs, + xmlSecKeyDataUsageKeyInfoNodeWrite); + } + if(dataId != xmlSecKeyDataIdUnknown) { + ret = xmlSecKeyDataXmlWrite(dataId, key, cur, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyDataXmlWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_STOP_ON_UNKNOWN_CHILD) != 0) { + /* laxi schema validation but application can disable it*/ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +/************************************************************************** + * + * KeyInfo context + * + *************************************************************************/ +/** + * xmlSecKeyInfoCtxCreate: + * @keysMngr: the pointer to keys manager (may be NULL). + * + * Allocates and initializes <dsig:KeyInfo/> element processing context. + * Caller is responsible for freeing it by calling #xmlSecKeyInfoCtxDestroy + * function. + * + * Returns: pointer to newly allocated object or NULL if an error occurs. + */ +xmlSecKeyInfoCtxPtr +xmlSecKeyInfoCtxCreate(xmlSecKeysMngrPtr keysMngr) { + xmlSecKeyInfoCtxPtr keyInfoCtx; + int ret; + + /* Allocate a new xmlSecKeyInfoCtx and fill the fields. */ + keyInfoCtx = (xmlSecKeyInfoCtxPtr)xmlMalloc(sizeof(xmlSecKeyInfoCtx)); + if(keyInfoCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(xmlSecKeyInfoCtx)); + return(NULL); + } + + ret = xmlSecKeyInfoCtxInitialize(keyInfoCtx, keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyInfoCtxDestroy(keyInfoCtx); + return(NULL); + } + + return(keyInfoCtx); +} + +/** + * xmlSecKeyInfoCtxDestroy: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Destroys @keyInfoCtx object created with #xmlSecKeyInfoCtxCreate function. + */ +void +xmlSecKeyInfoCtxDestroy(xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert(keyInfoCtx != NULL); + + xmlSecKeyInfoCtxFinalize(keyInfoCtx); + xmlFree(keyInfoCtx); +} + +/** + * xmlSecKeyInfoCtxInitialize: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * @keysMngr: the pointer to keys manager (may be NULL). + * + * Initializes <dsig:KeyInfo/> element processing context. Caller is + * responsible for cleaning it up by #xmlSecKeyInfoCtxFinalize function. + * + * Returns: 0 on success and a negative value if an error occurs. + */ +int +xmlSecKeyInfoCtxInitialize(xmlSecKeyInfoCtxPtr keyInfoCtx, xmlSecKeysMngrPtr keysMngr) { + int ret; + + xmlSecAssert2(keyInfoCtx != NULL, -1); + + memset(keyInfoCtx, 0, sizeof(xmlSecKeyInfoCtx)); + keyInfoCtx->keysMngr = keysMngr; + keyInfoCtx->base64LineSize = xmlSecBase64GetDefaultLineSize(); + ret = xmlSecPtrListInitialize(&(keyInfoCtx->enabledKeyData), xmlSecKeyDataIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + keyInfoCtx->maxRetrievalMethodLevel = 1; + ret = xmlSecTransformCtxInitialize(&(keyInfoCtx->retrievalMethodCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_NO_XMLENC + keyInfoCtx->maxEncryptedKeyLevel = 1; +#endif /* XMLSEC_NO_XMLENC */ + +#ifndef XMLSEC_NO_X509 + keyInfoCtx->certsVerificationDepth= 9; +#endif /* XMLSEC_NO_X509 */ + + ret = xmlSecKeyReqInitialize(&(keyInfoCtx->keyReq)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyReqInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyInfoCtxFinalize: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Cleans up the @keyInfoCtx initialized with #xmlSecKeyInfoCtxInitialize + * function. + */ +void +xmlSecKeyInfoCtxFinalize(xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert(keyInfoCtx != NULL); + + xmlSecPtrListFinalize(&(keyInfoCtx->enabledKeyData)); + xmlSecTransformCtxFinalize(&(keyInfoCtx->retrievalMethodCtx)); + xmlSecKeyReqFinalize(&(keyInfoCtx->keyReq)); + +#ifndef XMLSEC_NO_XMLENC + if(keyInfoCtx->encCtx != NULL) { + xmlSecEncCtxDestroy(keyInfoCtx->encCtx); + } +#endif /* XMLSEC_NO_XMLENC */ + + memset(keyInfoCtx, 0, sizeof(xmlSecKeyInfoCtx)); +} + +/** + * xmlSecKeyInfoCtxReset: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Resets the @keyInfoCtx state. User settings are not changed. + */ +void +xmlSecKeyInfoCtxReset(xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert(keyInfoCtx != NULL); + + xmlSecTransformCtxReset(&(keyInfoCtx->retrievalMethodCtx)); + keyInfoCtx->curRetrievalMethodLevel = 0; + +#ifndef XMLSEC_NO_XMLENC + if(keyInfoCtx->encCtx != NULL) { + xmlSecEncCtxReset(keyInfoCtx->encCtx); + } + keyInfoCtx->curEncryptedKeyLevel = 0; +#endif /* XMLSEC_NO_XMLENC */ + + xmlSecKeyReqReset(&(keyInfoCtx->keyReq)); +} + +/** + * xmlSecKeyInfoCtxCreateEncCtx: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Creates encryption context form processing <enc:EncryptedKey/> child + * of <dsig:KeyInfo/> element. + * + * Returns: 0 on success and a negative value if an error occurs. + */ +int +xmlSecKeyInfoCtxCreateEncCtx(xmlSecKeyInfoCtxPtr keyInfoCtx) { +#ifndef XMLSEC_NO_XMLENC + xmlSecEncCtxPtr tmp; + int ret; + + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->encCtx == NULL, -1); + + /* we have to use tmp variable to avoid a recursive loop */ + tmp = xmlSecEncCtxCreate(keyInfoCtx->keysMngr); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + tmp->mode = xmlEncCtxModeEncryptedKey; + + /* copy user preferences from our current ctx */ + switch(keyInfoCtx->mode) { + case xmlSecKeyInfoModeRead: + ret = xmlSecKeyInfoCtxCopyUserPref(&(tmp->keyInfoReadCtx), keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecEncCtxDestroy(tmp); + return(-1); + } + break; + case xmlSecKeyInfoModeWrite: + ret = xmlSecKeyInfoCtxCopyUserPref(&(tmp->keyInfoWriteCtx), keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecEncCtxDestroy(tmp); + return(-1); + } + break; + } + keyInfoCtx->encCtx = tmp; + + return(0); +#else /* XMLSEC_NO_XMLENC */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xml encryption", + XMLSEC_ERRORS_R_DISABLED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +#endif /* XMLSEC_NO_XMLENC */ +} + +/** + * xmlSecKeyInfoCtxCopyUserPref: + * @dst: the pointer to destination context object. + * @src: the pointer to source context object. + * + * Copies user preferences from @src context to @dst context. + * + * Returns: 0 on success and a negative value if an error occurs. + */ +int +xmlSecKeyInfoCtxCopyUserPref(xmlSecKeyInfoCtxPtr dst, xmlSecKeyInfoCtxPtr src) { + int ret; + + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(src != NULL, -1); + + dst->userData = src->userData; + dst->flags = src->flags; + dst->flags2 = src->flags2; + dst->keysMngr = src->keysMngr; + dst->mode = src->mode; + dst->base64LineSize = src->base64LineSize; + + ret = xmlSecPtrListCopy(&(dst->enabledKeyData), &(src->enabledKeyData)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "enabledKeyData"); + return(-1); + } + + /* <dsig:RetrievalMethod/> */ + dst->maxRetrievalMethodLevel= src->maxRetrievalMethodLevel; + ret = xmlSecTransformCtxCopyUserPref(&(dst->retrievalMethodCtx), + &(src->retrievalMethodCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "enabledKeyData"); + return(-1); + } + + /* <enc:EncryptedContext /> */ +#ifndef XMLSEC_NO_XMLENC + xmlSecAssert2(dst->encCtx == NULL, -1); + if(src->encCtx != NULL) { + dst->encCtx = xmlSecEncCtxCreate(dst->keysMngr); + if(dst->encCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + dst->encCtx->mode = xmlEncCtxModeEncryptedKey; + ret = xmlSecEncCtxCopyUserPref(dst->encCtx, src->encCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + dst->maxEncryptedKeyLevel = src->maxEncryptedKeyLevel; +#endif /* XMLSEC_NO_XMLENC */ + + /* <dsig:X509Data /> */ +#ifndef XMLSEC_NO_X509 + dst->certsVerificationTime = src->certsVerificationTime; + dst->certsVerificationDepth = src->certsVerificationDepth; +#endif /* XMLSEC_NO_X509 */ + + return(0); +} + +/** + * xmlSecKeyInfoCtxDebugDump: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * @output: the output file pointer. + * + * Prints user settings and current context state to @output. + */ +void +xmlSecKeyInfoCtxDebugDump(xmlSecKeyInfoCtxPtr keyInfoCtx, FILE* output) { + xmlSecAssert(keyInfoCtx != NULL); + xmlSecAssert(output != NULL); + + switch(keyInfoCtx->mode) { + case xmlSecKeyInfoModeRead: + fprintf(output, "= KEY INFO READ CONTEXT\n"); + break; + case xmlSecKeyInfoModeWrite: + fprintf(output, "= KEY INFO WRITE CONTEXT\n"); + break; + } + + fprintf(output, "== flags: 0x%08x\n", keyInfoCtx->flags); + fprintf(output, "== flags2: 0x%08x\n", keyInfoCtx->flags2); + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + fprintf(output, "== enabled key data: "); + xmlSecKeyDataIdListDebugDump(&(keyInfoCtx->enabledKeyData), output); + } else { + fprintf(output, "== enabled key data: all\n"); + } + fprintf(output, "== RetrievalMethod level (cur/max): %d/%d\n", + keyInfoCtx->curRetrievalMethodLevel, + keyInfoCtx->maxRetrievalMethodLevel); + xmlSecTransformCtxDebugDump(&(keyInfoCtx->retrievalMethodCtx), output); + +#ifndef XMLSEC_NO_XMLENC + fprintf(output, "== EncryptedKey level (cur/max): %d/%d\n", + keyInfoCtx->curEncryptedKeyLevel, + keyInfoCtx->maxEncryptedKeyLevel); + if(keyInfoCtx->encCtx != NULL) { + xmlSecEncCtxDebugDump(keyInfoCtx->encCtx, output); + } +#endif /* XMLSEC_NO_XMLENC */ + + xmlSecKeyReqDebugDump(&(keyInfoCtx->keyReq), output); +} + +/** + * xmlSecKeyInfoCtxDebugXmlDump: + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * @output: the output file pointer. + * + * Prints user settings and current context state in XML format to @output. + */ +void +xmlSecKeyInfoCtxDebugXmlDump(xmlSecKeyInfoCtxPtr keyInfoCtx, FILE* output) { + xmlSecAssert(keyInfoCtx != NULL); + xmlSecAssert(output != NULL); + + switch(keyInfoCtx->mode) { + case xmlSecKeyInfoModeRead: + fprintf(output, "<KeyInfoReadContext>\n"); + break; + case xmlSecKeyInfoModeWrite: + fprintf(output, "<KeyInfoWriteContext>\n"); + break; + } + + fprintf(output, "<Flags>%08x</Flags>\n", keyInfoCtx->flags); + fprintf(output, "<Flags2>%08x</Flags2>\n", keyInfoCtx->flags2); + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + fprintf(output, "<EnabledKeyData>\n"); + xmlSecKeyDataIdListDebugXmlDump(&(keyInfoCtx->enabledKeyData), output); + fprintf(output, "</EnabledKeyData>\n"); + } else { + fprintf(output, "<EnabledKeyData>all</EnabledKeyData>\n"); + } + + fprintf(output, "<RetrievalMethodLevel cur=\"%d\" max=\"%d\" />\n", + keyInfoCtx->curRetrievalMethodLevel, + keyInfoCtx->maxRetrievalMethodLevel); + xmlSecTransformCtxDebugXmlDump(&(keyInfoCtx->retrievalMethodCtx), output); + +#ifndef XMLSEC_NO_XMLENC + fprintf(output, "<EncryptedKeyLevel cur=\"%d\" max=\"%d\" />\n", + keyInfoCtx->curEncryptedKeyLevel, + keyInfoCtx->maxEncryptedKeyLevel); + if(keyInfoCtx->encCtx != NULL) { + xmlSecEncCtxDebugXmlDump(keyInfoCtx->encCtx, output); + } +#endif /* XMLSEC_NO_XMLENC */ + + xmlSecKeyReqDebugXmlDump(&(keyInfoCtx->keyReq), output); + switch(keyInfoCtx->mode) { + case xmlSecKeyInfoModeRead: + fprintf(output, "</KeyInfoReadContext>\n"); + break; + case xmlSecKeyInfoModeWrite: + fprintf(output, "</KeyInfoWriteContext>\n"); + break; + } +} + +/************************************************************************** + * + * <dsig:KeyName/> processing + * + *************************************************************************/ +static int xmlSecKeyDataNameXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecKeyDataNameXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyDataKlass xmlSecKeyDataNameKlass = { + sizeof(xmlSecKeyDataKlass), + sizeof(xmlSecKeyData), + + /* data */ + xmlSecNameKeyName, + xmlSecKeyDataUsageKeyInfoNode, /* xmlSecKeyDataUsage usage; */ + NULL, /* const xmlChar* href; */ + xmlSecNodeKeyName, /* 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 */ + xmlSecKeyDataNameXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecKeyDataNameXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecKeyDataNameGetKlass: + * + * The <dsig:KeyName/> element key data klass + * (http://www.w3.org/TR/xmldsig-core/#sec-KeyName): + * + * The KeyName element contains a string value (in which white space is + * significant) which may be used by the signer to communicate a key + * identifier to the recipient. Typically, KeyName contains an identifier + * related to the key pair used to sign the message, but it may contain + * other protocol-related information that indirectly identifies a key pair. + * (Common uses of KeyName include simple string names for keys, a key index, + * a distinguished name (DN), an email address, etc.) + * + * Returns: the <dsig:KeyName/> element processing key data klass. + */ +xmlSecKeyDataId +xmlSecKeyDataNameGetKlass(void) { + return(&xmlSecKeyDataNameKlass); +} + +static int +xmlSecKeyDataNameXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + const xmlChar* oldName; + xmlChar* newName; + int ret; + + xmlSecAssert2(id == xmlSecKeyDataNameId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1); + + oldName = xmlSecKeyGetName(key); + newName = xmlNodeGetContent(node); + if(newName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + /* TODO: do we need to decode the name? */ + + /* compare name values */ + if((oldName != NULL) && !xmlStrEqual(oldName, newName)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "key name is already specified", + XMLSEC_ERRORS_R_INVALID_KEY_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(newName); + return(-1); + } + + /* try to find key in the manager */ + if((xmlSecKeyGetValue(key) == NULL) && (keyInfoCtx->keysMngr != NULL)) { + xmlSecKeyPtr tmpKey; + + tmpKey = xmlSecKeysMngrFindKey(keyInfoCtx->keysMngr, newName, keyInfoCtx); + if(tmpKey != NULL) { + /* erase any current information in the key */ + xmlSecKeyEmpty(key); + + /* TODO: since we will destroy tmpKey anyway, we can easily + * just re-assign key data values. It'll save use some memory + * malloc/free + */ + + /* and copy what we've found */ + ret = xmlSecKeyCopy(key, tmpKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(tmpKey); + xmlFree(newName); + return(-1); + } + xmlSecKeyDestroy(tmpKey); + } + } + + /* finally set key name if it is not there */ + if(xmlSecKeyGetName(key) == NULL) { + xmlSecKeySetName(key, newName); + } + xmlFree(newName); + return(0); +} + +static int +xmlSecKeyDataNameXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + const xmlChar* name; + + xmlSecAssert2(id == xmlSecKeyDataNameId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1); + + name = xmlSecKeyGetName(key); + if(name != NULL) { + xmlSecNodeEncodeAndSetContent(node, name); + } + return(0); +} + +/************************************************************************** + * + * <dsig:KeyValue/> processing + * + *************************************************************************/ +static int xmlSecKeyDataValueXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecKeyDataValueXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyDataKlass xmlSecKeyDataValueKlass = { + sizeof(xmlSecKeyDataKlass), + sizeof(xmlSecKeyData), + + /* data */ + xmlSecNameKeyValue, + xmlSecKeyDataUsageKeyInfoNode, /* xmlSecKeyDataUsage usage; */ + NULL, /* const xmlChar* href; */ + xmlSecNodeKeyValue, /* 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 */ + xmlSecKeyDataValueXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecKeyDataValueXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecKeyDataValueGetKlass: + * + * The <dsig:KeyValue/> element key data klass + * (http://www.w3.org/TR/xmldsig-core/#sec-KeyValue): + * + * The KeyValue element contains a single public key that may be useful in + * validating the signature. + * + * Returns: the <dsig:KeyValue/> element processing key data klass. + */ +xmlSecKeyDataId +xmlSecKeyDataValueGetKlass(void) { + return(&xmlSecKeyDataValueKlass); +} + +static int +xmlSecKeyDataValueXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + const xmlChar* nodeName; + const xmlChar* nodeNs; + xmlSecKeyDataId dataId; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecKeyDataValueId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1); + + cur = xmlSecGetNextElementNode(node->children); + if(cur == NULL) { + /* just an empty node */ + return(0); + } + + /* find data id */ + nodeName = cur->name; + nodeNs = xmlSecGetNodeNsHref(cur); + + /* use global list only if we don't have a local one */ + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData), + nodeName, nodeNs, xmlSecKeyDataUsageKeyValueNodeRead); + } else { + dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(), + nodeName, nodeNs, xmlSecKeyDataUsageKeyValueNodeRead); + } + if(dataId != xmlSecKeyDataIdUnknown) { + /* read data node */ + ret = xmlSecKeyDataXmlRead(dataId, key, cur, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataXmlRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + } else if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_KEYVALUE_STOP_ON_UNKNOWN_CHILD) != 0) { + /* laxi schema validation but application can disable it */ + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* <dsig:KeyValue/> might have only one node */ + 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); + return(-1); + } + + return(0); +} + +static int +xmlSecKeyDataValueXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + const xmlChar* nodeName; + const xmlChar* nodeNs; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecKeyDataValueId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1); + + if(!xmlSecKeyDataIsValid(key->value) || + !xmlSecKeyDataCheckUsage(key->value, xmlSecKeyDataUsageKeyValueNodeWrite)){ + /* nothing to write */ + return(0); + } + if((xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) && + (xmlSecKeyDataIdListFind(&(keyInfoCtx->enabledKeyData), id) != 1)) { + + /* we are not enabled to write out key data with this id */ + return(0); + } + if(xmlSecKeyReqMatchKey(&(keyInfoCtx->keyReq), key) != 1) { + /* we are not allowed to write out this key */ + return(0); + } + + nodeName = key->value->id->dataNodeName; + nodeNs = key->value->id->dataNodeNs; + xmlSecAssert2(nodeName != NULL, -1); + + /* remove all existing key value */ + xmlNodeSetContent(node, NULL); + + /* create key node */ + cur = xmlSecAddChild(node, nodeName, nodeNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + + ret = xmlSecKeyDataXmlWrite(key->value->id, key, cur, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataXmlWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + return(0); +} + +/************************************************************************** + * + * <dsig:RetrievalMethod/> processing + * + *************************************************************************/ +static int xmlSecKeyDataRetrievalMethodXmlRead(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecKeyDataRetrievalMethodXmlWrite(xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); + + + +static xmlSecKeyDataKlass xmlSecKeyDataRetrievalMethodKlass = { + sizeof(xmlSecKeyDataKlass), + sizeof(xmlSecKeyData), + + /* data */ + xmlSecNameRetrievalMethod, + xmlSecKeyDataUsageKeyInfoNode, /* xmlSecKeyDataUsage usage; */ + NULL, /* const xmlChar* href; */ + xmlSecNodeRetrievalMethod, /* 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 */ + xmlSecKeyDataRetrievalMethodXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecKeyDataRetrievalMethodXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static int xmlSecKeyDataRetrievalMethodReadXmlResult(xmlSecKeyDataId typeId, + xmlSecKeyPtr key, + const xmlChar* buffer, + xmlSecSize bufferSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +/** + * xmlSecKeyDataRetrievalMethodGetKlass: + * + * The <dsig:RetrievalMethod/> element key data klass + * (http://www.w3.org/TR/xmldsig-core/#sec-RetrievalMethod): + * A RetrievalMethod element within KeyInfo is used to convey a reference to + * KeyInfo information that is stored at another location. For example, + * several signatures in a document might use a key verified by an X.509v3 + * certificate chain appearing once in the document or remotely outside the + * document; each signature's KeyInfo can reference this chain using a single + * RetrievalMethod element instead of including the entire chain with a + * sequence of X509Certificate elements. + * + * RetrievalMethod uses the same syntax and dereferencing behavior as + * Reference's URI and The Reference Processing Model. + * + * Returns: the <dsig:RetrievalMethod/> element processing key data klass. + */ +xmlSecKeyDataId +xmlSecKeyDataRetrievalMethodGetKlass(void) { + return(&xmlSecKeyDataRetrievalMethodKlass); +} + +static int +xmlSecKeyDataRetrievalMethodXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataId dataId = xmlSecKeyDataIdUnknown; + xmlChar *retrType = NULL; + xmlChar *uri = NULL; + xmlNodePtr cur; + int res = -1; + int ret; + + xmlSecAssert2(id == xmlSecKeyDataRetrievalMethodId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->doc != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1); + + /* check retrieval level */ + if(keyInfoCtx->curRetrievalMethodLevel >= keyInfoCtx->maxRetrievalMethodLevel) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MAX_RETRIEVALS_LEVEL, + "cur=%d;max=%d", + keyInfoCtx->curRetrievalMethodLevel, + keyInfoCtx->maxRetrievalMethodLevel); + goto done; + } + ++keyInfoCtx->curRetrievalMethodLevel; + + retrType = xmlGetProp(node, xmlSecAttrType); + if(retrType != NULL) { + /* use global list only if we don't have a local one */ + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + dataId = xmlSecKeyDataIdListFindByHref(&(keyInfoCtx->enabledKeyData), + retrType, xmlSecKeyDataUsageRetrievalMethodNode); + } else { + dataId = xmlSecKeyDataIdListFindByHref(xmlSecKeyDataIdsGet(), + retrType, xmlSecKeyDataUsageRetrievalMethodNode); + } + } + + /* laxi schema validation but aplication can disable it */ + if(dataId == xmlSecKeyDataIdUnknown) { + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_RETRMETHOD_STOP_ON_UNKNOWN_HREF) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecAttrType), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "value=%s", xmlSecErrorsSafeString(retrType)); + } else { + res = 0; + } + goto done; + } + + /* destroy prev retrieval method context */ + xmlSecTransformCtxReset(&(keyInfoCtx->retrievalMethodCtx)); + + /* set start URI and check that it is enabled */ + uri = xmlGetProp(node, xmlSecAttrURI); + ret = xmlSecTransformCtxSetUri(&(keyInfoCtx->retrievalMethodCtx), uri, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecTransformCtxSetUri", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", + xmlSecErrorsSafeString(uri)); + goto done; + } + + /* the only one node is optional Transforms node */ + cur = xmlSecGetNextElementNode(node->children); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecDSigNs))) { + ret = xmlSecTransformCtxNodesListRead(&(keyInfoCtx->retrievalMethodCtx), + cur, xmlSecTransformUsageDSigTransform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecTransformCtxNodesListRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + goto done; + } + 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; + } + + /* finally get transforms results */ + ret = xmlSecTransformCtxExecute(&(keyInfoCtx->retrievalMethodCtx), node->doc); + if((ret < 0) || + (keyInfoCtx->retrievalMethodCtx.result == NULL) || + (xmlSecBufferGetData(keyInfoCtx->retrievalMethodCtx.result) == NULL)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecTransformCtxExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + + /* assume that the data is in XML if we could not find id */ + if((dataId == xmlSecKeyDataIdUnknown) || + ((dataId->usage & xmlSecKeyDataUsageRetrievalMethodNodeXml) != 0)) { + + ret = xmlSecKeyDataRetrievalMethodReadXmlResult(dataId, key, + xmlSecBufferGetData(keyInfoCtx->retrievalMethodCtx.result), + xmlSecBufferGetSize(keyInfoCtx->retrievalMethodCtx.result), + keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataRetrievalMethodReadXmlResult", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } else { + ret = xmlSecKeyDataBinRead(dataId, key, + xmlSecBufferGetData(keyInfoCtx->retrievalMethodCtx.result), + xmlSecBufferGetSize(keyInfoCtx->retrievalMethodCtx.result), + keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataBinRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + --keyInfoCtx->curRetrievalMethodLevel; + + res = 0; +done: + if(uri != NULL) { + xmlFree(uri); + } + if(retrType != NULL) { + xmlFree(retrType); + } + return(res); +} + +static int +xmlSecKeyDataRetrievalMethodXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(id == xmlSecKeyDataRetrievalMethodId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1); + + /* just do nothing */ + return(0); +} + +static int +xmlSecKeyDataRetrievalMethodReadXmlResult(xmlSecKeyDataId typeId, xmlSecKeyPtr key, + const xmlChar* buffer, xmlSecSize bufferSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlDocPtr doc; + xmlNodePtr cur; + const xmlChar* nodeName; + const xmlChar* nodeNs; + xmlSecKeyDataId dataId; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2(bufferSize > 0, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1); + + doc = xmlRecoverMemory((const char*)buffer, bufferSize); + if(doc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)), + "xmlRecoverMemory", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlDocGetRootElement(doc); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)), + "xmlDocGetRootElement", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(doc); + return(-1); + } + + nodeName = cur->name; + nodeNs = xmlSecGetNodeNsHref(cur); + + /* use global list only if we don't have a local one */ + if(xmlSecPtrListGetSize(&(keyInfoCtx->enabledKeyData)) > 0) { + dataId = xmlSecKeyDataIdListFindByNode(&(keyInfoCtx->enabledKeyData), + nodeName, nodeNs, xmlSecKeyDataUsageRetrievalMethodNodeXml); + } else { + dataId = xmlSecKeyDataIdListFindByNode(xmlSecKeyDataIdsGet(), + nodeName, nodeNs, xmlSecKeyDataUsageRetrievalMethodNodeXml); + } + if(dataId == xmlSecKeyDataIdUnknown) { + xmlFreeDoc(doc); + + /* laxi schema validation but application can disable it */ + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_KEYVALUE_STOP_ON_UNKNOWN_CHILD) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); + } else if((typeId != xmlSecKeyDataIdUnknown) && (typeId != dataId) && + ((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_RETRMETHOD_STOP_ON_MISMATCH_HREF) != 0)) { + + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)), + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + XMLSEC_ERRORS_R_MAX_RETRIEVAL_TYPE_MISMATCH, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(doc); + return(-1); + } + + /* read data node */ + ret = xmlSecKeyDataXmlRead(dataId, key, cur, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(typeId)), + "xmlSecKeyDataXmlRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + xmlFreeDoc(doc); + return(-1); + } + + xmlFreeDoc(doc); + return(0); +} + + +#ifndef XMLSEC_NO_XMLENC +/************************************************************************** + * + * <enc:EncryptedKey/> processing + * + *************************************************************************/ +static int xmlSecKeyDataEncryptedKeyXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecKeyDataEncryptedKeyXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); + + + +static xmlSecKeyDataKlass xmlSecKeyDataEncryptedKeyKlass = { + sizeof(xmlSecKeyDataKlass), + sizeof(xmlSecKeyData), + + /* data */ + xmlSecNameEncryptedKey, + xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefEncryptedKey, /* const xmlChar* href; */ + xmlSecNodeEncryptedKey, /* const xmlChar* dataNodeName; */ + xmlSecEncNs, /* 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 */ + xmlSecKeyDataEncryptedKeyXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecKeyDataEncryptedKeyXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecKeyDataEncryptedKeyGetKlass: + * + * The <enc:EncryptedKey/> element key data klass + * (http://www.w3.org/TR/xmlenc-core/#sec-EncryptedKey): + * + * The EncryptedKey element is used to transport encryption keys from + * the originator to a known recipient(s). It may be used as a stand-alone + * XML document, be placed within an application document, or appear inside + * an EncryptedData element as a child of a ds:KeyInfo element. The key value + * is always encrypted to the recipient(s). When EncryptedKey is decrypted the + * resulting octets are made available to the EncryptionMethod algorithm + * without any additional processing. + * + * Returns: the <enc:EncryptedKey/> element processing key data klass. + */ +xmlSecKeyDataId +xmlSecKeyDataEncryptedKeyGetKlass(void) { + return(&xmlSecKeyDataEncryptedKeyKlass); +} + +static int +xmlSecKeyDataEncryptedKeyXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecBufferPtr result; + int ret; + + xmlSecAssert2(id == xmlSecKeyDataEncryptedKeyId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeRead, -1); + + /* check the enc level */ + if(keyInfoCtx->curEncryptedKeyLevel >= keyInfoCtx->maxEncryptedKeyLevel) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MAX_ENCKEY_LEVEL, + "cur=%d;max=%d", + keyInfoCtx->curEncryptedKeyLevel, + keyInfoCtx->maxEncryptedKeyLevel); + return(-1); + } + ++keyInfoCtx->curEncryptedKeyLevel; + + /* init Enc context */ + if(keyInfoCtx->encCtx != NULL) { + xmlSecEncCtxReset(keyInfoCtx->encCtx); + } else { + ret = xmlSecKeyInfoCtxCreateEncCtx(keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyInfoCtxCreateEncCtx", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + xmlSecAssert2(keyInfoCtx->encCtx != NULL, -1); + + result = xmlSecEncCtxDecryptToBuffer(keyInfoCtx->encCtx, node); + if((result == NULL) || (xmlSecBufferGetData(result) == NULL)) { + /* We might have multiple EncryptedKey elements, encrypted + * for different receipints but application can enforce + * correct enc key. + */ + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_ENCKEY_DONT_STOP_ON_FAILED_DECRYPTION) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecEncCtxDecryptToBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); + } + + ret = xmlSecKeyDataBinRead(keyInfoCtx->keyReq.keyId, key, + xmlSecBufferGetData(result), + xmlSecBufferGetSize(result), + keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataBinRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + --keyInfoCtx->curEncryptedKeyLevel; + + return(0); +} + +static int +xmlSecKeyDataEncryptedKeyXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyInfoCtx keyInfoCtx2; + xmlSecByte *keyBuf = NULL; + xmlSecSize keySize = 0; + int res = -1; + int ret; + + xmlSecAssert2(id == xmlSecKeyDataEncryptedKeyId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyIsValid(key), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->mode == xmlSecKeyInfoModeWrite, -1); + + /* dump key to a binary buffer */ + ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx2, NULL); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlSecKeyInfoCtxCopyUserPref(&keyInfoCtx2, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyInfoCtxFinalize(&keyInfoCtx2); + goto done; + } + + keyInfoCtx2.keyReq.keyType = xmlSecKeyDataTypeAny; + ret = xmlSecKeyDataBinWrite(key->value->id, key, &keyBuf, &keySize, &keyInfoCtx2); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataBinWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyInfoCtxFinalize(&keyInfoCtx2); + goto done; + } + xmlSecKeyInfoCtxFinalize(&keyInfoCtx2); + + /* init Enc context */ + if(keyInfoCtx->encCtx != NULL) { + xmlSecEncCtxReset(keyInfoCtx->encCtx); + } else { + ret = xmlSecKeyInfoCtxCreateEncCtx(keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyInfoCtxCreateEncCtx", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + xmlSecAssert2(keyInfoCtx->encCtx != NULL, -1); + + ret = xmlSecEncCtxBinaryEncrypt(keyInfoCtx->encCtx, node, keyBuf, keySize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecEncCtxBinaryEncrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + res = 0; +done: + if(keyBuf != NULL) { + memset(keyBuf, 0, keySize); + xmlFree(keyBuf); keyBuf = NULL; + } + return(res); +} + +#endif /* XMLSEC_NO_XMLENC */ + diff --git a/src/keys.c b/src/keys.c new file mode 100644 index 00000000..44522aa1 --- /dev/null +++ b/src/keys.c @@ -0,0 +1,1415 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Keys. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/list.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/errors.h> + +/************************************************************************** + * + * xmlSecKeyUseWith + * + *************************************************************************/ +/** + * xmlSecKeyUseWithInitialize: + * @keyUseWith: the pointer to information about key application/user. + * + * Initializes @keyUseWith object. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyUseWithInitialize(xmlSecKeyUseWithPtr keyUseWith) { + xmlSecAssert2(keyUseWith != NULL, -1); + + memset(keyUseWith, 0, sizeof(xmlSecKeyUseWith)); + return(0); +} + +/** + * xmlSecKeyUseWithFinalize: + * @keyUseWith: the pointer to information about key application/user. + * + * Finalizes @keyUseWith object. + */ +void +xmlSecKeyUseWithFinalize(xmlSecKeyUseWithPtr keyUseWith) { + xmlSecAssert(keyUseWith != NULL); + + xmlSecKeyUseWithReset(keyUseWith); + memset(keyUseWith, 0, sizeof(xmlSecKeyUseWith)); +} + +/** + * xmlSecKeyUseWithReset: + * @keyUseWith: the pointer to information about key application/user. + * + * Resets the @keyUseWith to its state after initialization. + */ +void +xmlSecKeyUseWithReset(xmlSecKeyUseWithPtr keyUseWith) { + xmlSecAssert(keyUseWith != NULL); + + xmlSecKeyUseWithSet(keyUseWith, NULL, NULL); +} + +/** + * xmlSecKeyUseWithCopy: + * @dst: the pointer to destination object. + * @src: the pointer to source object. + * + * Copies information from @dst to @src. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyUseWithCopy(xmlSecKeyUseWithPtr dst, xmlSecKeyUseWithPtr src) { + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(src != NULL, -1); + + return(xmlSecKeyUseWithSet(dst, src->application, src->identifier)); +} + +/** + * xmlSecKeyUseWithCreate: + * @application: the application value. + * @identifier: the identifier value. + * + * Creates new xmlSecKeyUseWith object. The caller is responsible for destroying + * returned object with @xmlSecKeyUseWithDestroy function. + * + * Returns: pointer to newly created object or NULL if an error occurs. + */ +xmlSecKeyUseWithPtr +xmlSecKeyUseWithCreate(const xmlChar* application, const xmlChar* identifier) { + xmlSecKeyUseWithPtr keyUseWith; + int ret; + + /* Allocate a new xmlSecKeyUseWith and fill the fields. */ + keyUseWith = (xmlSecKeyUseWithPtr)xmlMalloc(sizeof(xmlSecKeyUseWith)); + if(keyUseWith == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecKeyUseWith)=%d", + sizeof(xmlSecKeyUseWith)); + return(NULL); + } + memset(keyUseWith, 0, sizeof(xmlSecKeyUseWith)); + + ret = xmlSecKeyUseWithInitialize(keyUseWith); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyUseWithInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyUseWithDestroy(keyUseWith); + return(NULL); + } + + ret = xmlSecKeyUseWithSet(keyUseWith, application, identifier); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyUseWithSet", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyUseWithDestroy(keyUseWith); + return(NULL); + } + + return(keyUseWith); +} + +/** + * xmlSecKeyUseWithDuplicate: + * @keyUseWith: the pointer to information about key application/user. + * + * Duplicates @keyUseWith object. The caller is responsible for destroying + * returned object with @xmlSecKeyUseWithDestroy function. + * + * Returns: pointer to newly created object or NULL if an error occurs. + */ +xmlSecKeyUseWithPtr +xmlSecKeyUseWithDuplicate(xmlSecKeyUseWithPtr keyUseWith) { + int ret; + + xmlSecKeyUseWithPtr newKeyUseWith; + + xmlSecAssert2(keyUseWith != NULL, NULL); + + newKeyUseWith = xmlSecKeyUseWithCreate(NULL, NULL); + if(newKeyUseWith == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyUseWithCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecKeyUseWithCopy(newKeyUseWith, keyUseWith); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyUseWithCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyUseWithDestroy(keyUseWith); + return(NULL); + } + + return(newKeyUseWith); +} + +/** + * xmlSecKeyUseWithDestroy: + * @keyUseWith: the pointer to information about key application/user. + * + * Destroys @keyUseWith created with @xmlSecKeyUseWithCreate or @xmlSecKeyUseWithDuplicate + * functions. + */ +void +xmlSecKeyUseWithDestroy(xmlSecKeyUseWithPtr keyUseWith) { + xmlSecAssert(keyUseWith != NULL); + + xmlSecKeyUseWithFinalize(keyUseWith); + xmlFree(keyUseWith); +} + +/** + * xmlSecKeyUseWithSet: + * @keyUseWith: the pointer to information about key application/user. + * @application: the new application value. + * @identifier: the new identifier value. + * + * Sets @application and @identifier in the @keyUseWith. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyUseWithSet(xmlSecKeyUseWithPtr keyUseWith, const xmlChar* application, const xmlChar* identifier) { + xmlSecAssert2(keyUseWith != NULL, -1); + + if(keyUseWith->application != NULL) { + xmlFree(keyUseWith->application); + keyUseWith->application = NULL; + } + if(keyUseWith->identifier != NULL) { + xmlFree(keyUseWith->identifier); + keyUseWith->identifier = NULL; + } + + if(application != NULL) { + keyUseWith->application = xmlStrdup(application); + if(keyUseWith->application == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "xmlStrlen(application)=%d", + xmlStrlen(application)); + return(-1); + } + } + if(identifier != NULL) { + keyUseWith->identifier = xmlStrdup(identifier); + if(keyUseWith->identifier == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "xmlStrlen(identifier)=%d", + xmlStrlen(identifier)); + return(-1); + } + } + + return(0); +} + +/** + * xmlSecKeyUseWithDebugDump: + * @keyUseWith: the pointer to information about key application/user. + * @output: the pointer to output FILE. + * + * Prints xmlSecKeyUseWith debug information to a file @output. + */ +void +xmlSecKeyUseWithDebugDump(xmlSecKeyUseWithPtr keyUseWith, FILE* output) { + xmlSecAssert(keyUseWith != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "=== KeyUseWith: application=\"%s\",identifier=\"%s\"\n", + (keyUseWith->application) ? keyUseWith->application : BAD_CAST "", + (keyUseWith->identifier) ? keyUseWith->identifier : BAD_CAST ""); +} + +/** + * xmlSecKeyUseWithDebugXmlDump: + * @keyUseWith: the pointer to information about key application/user. + * @output: the pointer to output FILE. + * + * Prints xmlSecKeyUseWith debug information to a file @output in XML format. + */ +void +xmlSecKeyUseWithDebugXmlDump(xmlSecKeyUseWithPtr keyUseWith, FILE* output) { + xmlSecAssert(keyUseWith != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "<KeyUseWith>\n"); + + fprintf(output, "<Application>"); + xmlSecPrintXmlString(output, keyUseWith->application); + fprintf(output, "</Application>"); + + fprintf(output, "<Identifier>"); + xmlSecPrintXmlString(output, keyUseWith->identifier); + fprintf(output, "</Identifier>"); + + fprintf(output, "</KeyUseWith>\n"); +} + +/*********************************************************************** + * + * KeyUseWith list + * + **********************************************************************/ +static xmlSecPtrListKlass xmlSecKeyUseWithPtrListKlass = { + BAD_CAST "key-use-with-list", + (xmlSecPtrDuplicateItemMethod)xmlSecKeyUseWithDuplicate, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecKeyUseWithDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecKeyUseWithDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecKeyUseWithDebugXmlDump, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecKeyUseWithPtrListGetKlass: + * + * The key data list klass. + * + * Returns: pointer to the key data list klass. + */ +xmlSecPtrListId +xmlSecKeyUseWithPtrListGetKlass(void) { + return(&xmlSecKeyUseWithPtrListKlass); +} + +/************************************************************************** + * + * xmlSecKeyReq - what key are we looking for? + * + *************************************************************************/ +/** + * xmlSecKeyReqInitialize: + * @keyReq: the pointer to key requirements object. + * + * Initialize key requirements object. Caller is responsible for + * cleaning it with #xmlSecKeyReqFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyReqInitialize(xmlSecKeyReqPtr keyReq) { + int ret; + + xmlSecAssert2(keyReq != NULL, -1); + + memset(keyReq, 0, sizeof(xmlSecKeyReq)); + + keyReq->keyUsage = xmlSecKeyUsageAny; /* by default you can do whatever you want with the key */ + ret = xmlSecPtrListInitialize(&keyReq->keyUseWithList, xmlSecKeyUseWithPtrListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + + return(0); +} + +/** + * xmlSecKeyReqFinalize: + * @keyReq: the pointer to key requirements object. + * + * Cleans the key requirements object initialized with #xmlSecKeyReqInitialize + * function. + */ +void +xmlSecKeyReqFinalize(xmlSecKeyReqPtr keyReq) { + xmlSecAssert(keyReq != NULL); + + xmlSecPtrListFinalize(&keyReq->keyUseWithList); + memset(keyReq, 0, sizeof(xmlSecKeyReq)); +} + +/** + * xmlSecKeyReqReset: + * @keyReq: the pointer to key requirements object. + * + * Resets key requirements object for new key search. + */ +void +xmlSecKeyReqReset(xmlSecKeyReqPtr keyReq) { + xmlSecAssert(keyReq != NULL); + + xmlSecPtrListEmpty(&keyReq->keyUseWithList); + keyReq->keyId = NULL; + keyReq->keyType = 0; + keyReq->keyUsage = xmlSecKeyUsageAny; + keyReq->keyBitsSize = 0; +} + +/** + * xmlSecKeyReqCopy: + * @dst: the pointer to destination object. + * @src: the pointer to source object. + * + * Copies key requirements from @src object to @dst object. + * + * Returns: 0 on success and a negative value if an error occurs. + */ +int +xmlSecKeyReqCopy(xmlSecKeyReqPtr dst, xmlSecKeyReqPtr src) { + int ret; + + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(src != NULL, -1); + + dst->keyId = src->keyId; + dst->keyType = src->keyType; + dst->keyUsage = src->keyUsage; + dst->keyBitsSize = src->keyBitsSize; + + ret = xmlSecPtrListCopy(&dst->keyUseWithList, &src->keyUseWithList); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyReqMatchKey: + * @keyReq: the pointer to key requirements object. + * @key: the pointer to key. + * + * Checks whether @key matches key requirements @keyReq. + * + * Returns: 1 if key matches requirements, 0 if not and a negative value + * if an error occurs. + */ +int +xmlSecKeyReqMatchKey(xmlSecKeyReqPtr keyReq, xmlSecKeyPtr key) { + xmlSecAssert2(keyReq != NULL, -1); + xmlSecAssert2(xmlSecKeyIsValid(key), -1); + + if((keyReq->keyType != xmlSecKeyDataTypeUnknown) && ((xmlSecKeyGetType(key) & keyReq->keyType) == 0)) { + return(0); + } + if((keyReq->keyUsage != xmlSecKeyDataUsageUnknown) && ((keyReq->keyUsage & key->usage) == 0)) { + return(0); + } + + return(xmlSecKeyReqMatchKeyValue(keyReq, xmlSecKeyGetValue(key))); +} + +/** + * xmlSecKeyReqMatchKeyValue: + * @keyReq: the pointer to key requirements. + * @value: the pointer to key value. + * + * Checks whether @keyValue matches key requirements @keyReq. + * + * Returns: 1 if key value matches requirements, 0 if not and a negative value + * if an error occurs. + */ +int +xmlSecKeyReqMatchKeyValue(xmlSecKeyReqPtr keyReq, xmlSecKeyDataPtr value) { + xmlSecAssert2(keyReq != NULL, -1); + xmlSecAssert2(value != NULL, -1); + + if((keyReq->keyId != xmlSecKeyDataIdUnknown) && + (!xmlSecKeyDataCheckId(value, keyReq->keyId))) { + + return(0); + } + if((keyReq->keyBitsSize > 0) && + (xmlSecKeyDataGetSize(value) > 0) && + (xmlSecKeyDataGetSize(value) < keyReq->keyBitsSize)) { + + return(0); + } + return(1); +} + +/** + * xmlSecKeyReqDebugDump: + * @keyReq: the pointer to key requirements object. + * @output: the pointer to output FILE. + * + * Prints debug information about @keyReq into @output. + */ +void +xmlSecKeyReqDebugDump(xmlSecKeyReqPtr keyReq, FILE* output) { + xmlSecAssert(keyReq != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "=== KeyReq:\n"); + fprintf(output, "==== keyId: %s\n", + (xmlSecKeyDataKlassGetName(keyReq->keyId)) ? + xmlSecKeyDataKlassGetName(keyReq->keyId) : + BAD_CAST "NULL"); + fprintf(output, "==== keyType: 0x%08x\n", keyReq->keyType); + fprintf(output, "==== keyUsage: 0x%08x\n", keyReq->keyUsage); + fprintf(output, "==== keyBitsSize: %d\n", keyReq->keyBitsSize); + xmlSecPtrListDebugDump(&(keyReq->keyUseWithList), output); +} + +/** + * xmlSecKeyReqDebugXmlDump: + * @keyReq: the pointer to key requirements object. + * @output: the pointer to output FILE. + * + * Prints debug information about @keyReq into @output in XML format. + */ +void +xmlSecKeyReqDebugXmlDump(xmlSecKeyReqPtr keyReq, FILE* output) { + xmlSecAssert(keyReq != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "<KeyReq>\n"); + + fprintf(output, "<KeyId>"); + xmlSecPrintXmlString(output, xmlSecKeyDataKlassGetName(keyReq->keyId)); + fprintf(output, "</KeyId>\n"); + + fprintf(output, "<KeyType>0x%08x</KeyType>\n", keyReq->keyType); + fprintf(output, "<KeyUsage>0x%08x</KeyUsage>\n", keyReq->keyUsage); + fprintf(output, "<KeyBitsSize>%d</KeyBitsSize>\n", keyReq->keyBitsSize); + xmlSecPtrListDebugXmlDump(&(keyReq->keyUseWithList), output); + fprintf(output, "</KeyReq>\n"); +} + + +/************************************************************************** + * + * xmlSecKey + * + *************************************************************************/ +/** + * xmlSecKeyCreate: + * + * Allocates and initializes new key. Caller is responsible for + * freeing returned object with #xmlSecKeyDestroy function. + * + * Returns: the pointer to newly allocated @xmlSecKey structure + * or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyCreate(void) { + xmlSecKeyPtr key; + + /* Allocate a new xmlSecKey and fill the fields. */ + key = (xmlSecKeyPtr)xmlMalloc(sizeof(xmlSecKey)); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecKey)=%d", + sizeof(xmlSecKey)); + return(NULL); + } + memset(key, 0, sizeof(xmlSecKey)); + key->usage = xmlSecKeyUsageAny; + return(key); +} + +/** + * xmlSecKeyEmpty: + * @key: the pointer to key. + * + * Clears the @key data. + */ +void +xmlSecKeyEmpty(xmlSecKeyPtr key) { + xmlSecAssert(key != NULL); + + if(key->value != NULL) { + xmlSecKeyDataDestroy(key->value); + } + if(key->name != NULL) { + xmlFree(key->name); + } + if(key->dataList != NULL) { + xmlSecPtrListDestroy(key->dataList); + } + + memset(key, 0, sizeof(xmlSecKey)); +} + +/** + * xmlSecKeyDestroy: + * @key: the pointer to key. + * + * Destroys the key created using #xmlSecKeyCreate function. + */ +void +xmlSecKeyDestroy(xmlSecKeyPtr key) { + xmlSecAssert(key != NULL); + + xmlSecKeyEmpty(key); + xmlFree(key); +} + +/** + * xmlSecKeyCopy: + * @keyDst: the destination key. + * @keySrc: the source key. + * + * Copies key data from @keySrc to @keyDst. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyCopy(xmlSecKeyPtr keyDst, xmlSecKeyPtr keySrc) { + xmlSecAssert2(keyDst != NULL, -1); + xmlSecAssert2(keySrc != NULL, -1); + + /* empty destination */ + xmlSecKeyEmpty(keyDst); + + /* copy everything */ + if(keySrc->name != NULL) { + keyDst->name = xmlStrdup(keySrc->name); + if(keyDst->name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "len=%d", xmlStrlen(keySrc->name)); + return(-1); + } + } + + if(keySrc->value != NULL) { + keyDst->value = xmlSecKeyDataDuplicate(keySrc->value); + if(keyDst->value == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataDuplicate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(keySrc->dataList != NULL) { + keyDst->dataList = xmlSecPtrListDuplicate(keySrc->dataList); + if(keyDst->dataList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListDuplicate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + keyDst->usage = keySrc->usage; + keyDst->notValidBefore = keySrc->notValidBefore; + keyDst->notValidAfter = keySrc->notValidAfter; + return(0); +} + +/** + * xmlSecKeyDuplicate: + * @key: the pointer to the #xmlSecKey structure. + * + * Creates a duplicate of the given @key. + * + * Returns: the pointer to newly allocated #xmlSecKey structure + * or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyDuplicate(xmlSecKeyPtr key) { + xmlSecKeyPtr newKey; + int ret; + + xmlSecAssert2(key != NULL, NULL); + + newKey = xmlSecKeyCreate(); + if(newKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecKeyCopy(newKey, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(newKey); + return(NULL); + } + + return(newKey); +} + +/** + * xmlSecKeyMatch: + * @key: the pointer to key. + * @name: the pointer to key name (may be NULL). + * @keyReq: the pointer to key requirements. + * + * Checks whether the @key matches the given criteria. + * + * Returns: 1 if the key satisfies the given criteria or 0 otherwise. + */ +int +xmlSecKeyMatch(xmlSecKeyPtr key, const xmlChar *name, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecKeyIsValid(key), -1); + xmlSecAssert2(keyReq != NULL, -1); + + if((name != NULL) && (!xmlStrEqual(xmlSecKeyGetName(key), name))) { + return(0); + } + return(xmlSecKeyReqMatchKey(keyReq, key)); +} + +/** + * xmlSecKeyGetType: + * @key: the pointer to key. + * + * Gets @key type. + * + * Returns: key type. + */ +xmlSecKeyDataType +xmlSecKeyGetType(xmlSecKeyPtr key) { + xmlSecKeyDataPtr data; + + xmlSecAssert2(key != NULL, xmlSecKeyDataTypeUnknown); + + data = xmlSecKeyGetValue(key); + if(data == NULL) { + return(xmlSecKeyDataTypeUnknown); + } + return(xmlSecKeyDataGetType(data)); +} + +/** + * xmlSecKeyGetName: + * @key: the pointer to key. + * + * Gets key name (see also #xmlSecKeySetName function). + * + * Returns: key name. + */ +const xmlChar* +xmlSecKeyGetName(xmlSecKeyPtr key) { + xmlSecAssert2(key != NULL, NULL); + + return(key->name); +} + +/** + * xmlSecKeySetName: + * @key: the pointer to key. + * @name: the new key name. + * + * Sets key name (see also #xmlSecKeyGetName function). + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeySetName(xmlSecKeyPtr key, const xmlChar* name) { + xmlSecAssert2(key != NULL, -1); + + if(key->name != NULL) { + xmlFree(key->name); + key->name = NULL; + } + + if(name != NULL) { + key->name = xmlStrdup(name); + if(key->name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "len=%d", xmlStrlen(name)); + return(-1); + } + } + + return(0); +} + +/** + * xmlSecKeyGetValue: + * @key: the pointer to key. + * + * Gets key value (see also #xmlSecKeySetValue function). + * + * Returns: key value (crypto material). + */ +xmlSecKeyDataPtr +xmlSecKeyGetValue(xmlSecKeyPtr key) { + xmlSecAssert2(key != NULL, NULL); + + return(key->value); +} + +/** + * xmlSecKeySetValue: + * @key: the pointer to key. + * @value: the new value. + * + * Sets key value (see also #xmlSecKeyGetValue function). + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeySetValue(xmlSecKeyPtr key, xmlSecKeyDataPtr value) { + xmlSecAssert2(key != NULL, -1); + + if(key->value != NULL) { + xmlSecKeyDataDestroy(key->value); + key->value = NULL; + } + key->value = value; + + return(0); +} + +/** + * xmlSecKeyGetData: + * @key: the pointer to key. + * @dataId: the requested data klass. + * + * Gets key's data. + * + * Returns: additional data associated with the @key (see also + * #xmlSecKeyAdoptData function). + */ +xmlSecKeyDataPtr +xmlSecKeyGetData(xmlSecKeyPtr key, xmlSecKeyDataId dataId) { + + xmlSecAssert2(key != NULL, NULL); + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, NULL); + + /* special cases */ + if(dataId == xmlSecKeyDataValueId) { + return(key->value); + } else if(key->dataList != NULL) { + xmlSecKeyDataPtr tmp; + xmlSecSize pos, size; + + size = xmlSecPtrListGetSize(key->dataList); + for(pos = 0; pos < size; ++pos) { + tmp = (xmlSecKeyDataPtr)xmlSecPtrListGetItem(key->dataList, pos); + if((tmp != NULL) && (tmp->id == dataId)) { + return(tmp); + } + } + } + return(NULL); +} + +/** + * xmlSecKeyEnsureData: + * @key: the pointer to key. + * @dataId: the requested data klass. + * + * If necessary, creates key data of @dataId klass and adds to @key. + * + * Returns: pointer to key data or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecKeyEnsureData(xmlSecKeyPtr key, xmlSecKeyDataId dataId) { + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(key != NULL, NULL); + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, NULL); + + data = xmlSecKeyGetData(key, dataId); + if(data != NULL) { + return(data); + } + + data = xmlSecKeyDataCreate(dataId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "dataId=%s", + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId))); + return(NULL); + } + + ret = xmlSecKeyAdoptData(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyAdoptData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "dataId=%s", + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId))); + xmlSecKeyDataDestroy(data); + return(NULL); + } + + return(data); +} + +/** + * xmlSecKeyAdoptData: + * @key: the pointer to key. + * @data: the pointer to key data. + * + * Adds @data to the @key. The @data object will be destroyed + * by @key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyAdoptData(xmlSecKeyPtr key, xmlSecKeyDataPtr data) { + xmlSecKeyDataPtr tmp; + xmlSecSize pos, size; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + + /* special cases */ + if(data->id == xmlSecKeyDataValueId) { + if(key->value != NULL) { + xmlSecKeyDataDestroy(key->value); + } + key->value = data; + return(0); + } + + if(key->dataList == NULL) { + key->dataList = xmlSecPtrListCreate(xmlSecKeyDataListId); + if(key->dataList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + + size = xmlSecPtrListGetSize(key->dataList); + for(pos = 0; pos < size; ++pos) { + tmp = (xmlSecKeyDataPtr)xmlSecPtrListGetItem(key->dataList, pos); + if((tmp != NULL) && (tmp->id == data->id)) { + return(xmlSecPtrListSet(key->dataList, data, pos)); + } + } + + return(xmlSecPtrListAdd(key->dataList, data)); +} + +/** + * xmlSecKeyDebugDump: + * @key: the pointer to key. + * @output: the pointer to output FILE. + * + * Prints the information about the @key to the @output. + */ +void +xmlSecKeyDebugDump(xmlSecKeyPtr key, FILE *output) { + xmlSecAssert(xmlSecKeyIsValid(key)); + xmlSecAssert(output != NULL); + + fprintf(output, "== KEY\n"); + fprintf(output, "=== method: %s\n", + (key->value->id->dataNodeName != NULL) ? + (char*)(key->value->id->dataNodeName) : "NULL"); + + fprintf(output, "=== key type: "); + if((xmlSecKeyGetType(key) & xmlSecKeyDataTypeSymmetric) != 0) { + fprintf(output, "Symmetric\n"); + } else if((xmlSecKeyGetType(key) & xmlSecKeyDataTypePrivate) != 0) { + fprintf(output, "Private\n"); + } else if((xmlSecKeyGetType(key) & xmlSecKeyDataTypePublic) != 0) { + fprintf(output, "Public\n"); + } else { + fprintf(output, "Unknown\n"); + } + + if(key->name != NULL) { + fprintf(output, "=== key name: %s\n", key->name); + } + fprintf(output, "=== key usage: %d\n", key->usage); + if(key->notValidBefore < key->notValidAfter) { + fprintf(output, "=== key not valid before: %ld\n", (unsigned long)key->notValidBefore); + fprintf(output, "=== key not valid after: %ld\n", (unsigned long)key->notValidAfter); + } + if(key->value != NULL) { + xmlSecKeyDataDebugDump(key->value, output); + } + if(key->dataList != NULL) { + xmlSecPtrListDebugDump(key->dataList, output); + } +} + +/** + * xmlSecKeyDebugXmlDump: + * @key: the pointer to key. + * @output: the pointer to output FILE. + * + * Prints the information about the @key to the @output in XML format. + */ +void +xmlSecKeyDebugXmlDump(xmlSecKeyPtr key, FILE *output) { + xmlSecAssert(xmlSecKeyIsValid(key)); + xmlSecAssert(output != NULL); + + fprintf(output, "<KeyInfo>\n"); + + fprintf(output, "<KeyMethod>"); + xmlSecPrintXmlString(output, key->value->id->dataNodeName); + fprintf(output, "</KeyMethod>\n"); + + fprintf(output, "<KeyType>"); + if((xmlSecKeyGetType(key) & xmlSecKeyDataTypeSymmetric) != 0) { + fprintf(output, "Symmetric\n"); + } else if((xmlSecKeyGetType(key) & xmlSecKeyDataTypePrivate) != 0) { + fprintf(output, "Private\n"); + } else if((xmlSecKeyGetType(key) & xmlSecKeyDataTypePublic) != 0) { + fprintf(output, "Public\n"); + } else { + fprintf(output, "Unknown\n"); + } + fprintf(output, "</KeyType>\n"); + + fprintf(output, "<KeyName>"); + xmlSecPrintXmlString(output, key->name); + fprintf(output, "</KeyName>\n"); + + if(key->notValidBefore < key->notValidAfter) { + fprintf(output, "<KeyValidity notValidBefore=\"%ld\" notValidAfter=\"%ld\"/>\n", + (unsigned long)key->notValidBefore, + (unsigned long)key->notValidAfter); + } + + if(key->value != NULL) { + xmlSecKeyDataDebugXmlDump(key->value, output); + } + if(key->dataList != NULL) { + xmlSecPtrListDebugXmlDump(key->dataList, output); + } + + fprintf(output, "</KeyInfo>\n"); +} + +/** + * xmlSecKeyGenerate: + * @dataId: the requested key klass (rsa, dsa, aes, ...). + * @sizeBits: the new key size (in bits!). + * @type: the new key type (session, permanent, ...). + * + * Generates new key of requested klass @dataId and @type. + * + * Returns: pointer to newly created key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyGenerate(xmlSecKeyDataId dataId, xmlSecSize sizeBits, xmlSecKeyDataType type) { + xmlSecKeyPtr key; + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, NULL); + + data = xmlSecKeyDataCreate(dataId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecKeyDataGenerate(data, sizeBits, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyDataGenerate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d;type=%d", sizeBits, type); + xmlSecKeyDataDestroy(data); + return(NULL); + } + + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + xmlSecKeyDestroy(key); + return(NULL); + } + + return(key); +} + +/** + * xmlSecKeyGenerateByName: + * @name: the requested key klass name (rsa, dsa, aes, ...). + * @sizeBits: the new key size (in bits!). + * @type: the new key type (session, permanent, ...). + * + * Generates new key of requested @klass and @type. + * + * Returns: pointer to newly created key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyGenerateByName(const xmlChar* name, xmlSecSize sizeBits, xmlSecKeyDataType type) { + xmlSecKeyDataId dataId; + + xmlSecAssert2(name != NULL, NULL); + + dataId = xmlSecKeyDataIdListFindByName(xmlSecKeyDataIdsGet(), name, xmlSecKeyDataUsageAny); + if(dataId == xmlSecKeyDataIdUnknown) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(name), + XMLSEC_ERRORS_R_KEY_DATA_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecKeyGenerate(dataId, sizeBits, type)); +} + +/** + * xmlSecKeyReadBuffer: + * @dataId: the key value data klass. + * @buffer: the buffer that contains the binary data. + * + * Reads the key value of klass @dataId from a buffer. + * + * Returns: pointer to newly created key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyReadBuffer(xmlSecKeyDataId dataId, xmlSecBuffer* buffer) { + xmlSecKeyInfoCtx keyInfoCtx; + xmlSecKeyPtr key; + int ret; + + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, NULL); + xmlSecAssert2(buffer != NULL, NULL); + + /* create key data */ + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecKeyInfoCtxInitialize(&keyInfoCtx, NULL); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + return(NULL); + } + + keyInfoCtx.keyReq.keyType = xmlSecKeyDataTypeAny; + ret = xmlSecKeyDataBinRead(dataId, key, + xmlSecBufferGetData(buffer), + xmlSecBufferGetSize(buffer), + &keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyDataBinRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyInfoCtxFinalize(&keyInfoCtx); + xmlSecKeyDestroy(key); + return(NULL); + } + xmlSecKeyInfoCtxFinalize(&keyInfoCtx); + + return(key); +} + +/** + * xmlSecKeyReadBinaryFile: + * @dataId: the key value data klass. + * @filename: the key binary filename. + * + * Reads the key value of klass @dataId from a binary file @filename. + * + * Returns: pointer to newly created key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyReadBinaryFile(xmlSecKeyDataId dataId, const char* filename) { + xmlSecKeyPtr key; + xmlSecBuffer buffer; + int ret; + + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, NULL); + xmlSecAssert2(filename != NULL, NULL); + + /* read file to buffer */ + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecBufferReadFile(&buffer, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecBufferReadFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + + key = xmlSecKeyReadBuffer(dataId, &buffer); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyReadBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + + xmlSecBufferFinalize(&buffer); + return (key); +} + +/** + * xmlSecKeyReadMemory: + * @dataId: the key value data klass. + * @data: the memory containing the key + * @dataSize: the size of the memory block + * + * Reads the key value of klass @dataId from a memory block @data. + * + * Returns: pointer to newly created key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyReadMemory(xmlSecKeyDataId dataId, const xmlSecByte* data, xmlSecSize dataSize) { + xmlSecBuffer buffer; + xmlSecKeyPtr key; + int ret; + + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, NULL); + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(dataSize > 0, NULL); + + /* read file to buffer */ + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + if (xmlSecBufferAppend(&buffer, data, dataSize) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + + key = xmlSecKeyReadBuffer(dataId, &buffer); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(dataId)), + "xmlSecKeyReadBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + + xmlSecBufferFinalize(&buffer); + return (key); +} + +/** + * xmlSecKeysMngrGetKey: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> node processing context. + * + * Reads the <dsig:KeyInfo/> node @keyInfoNode and extracts the key. + * + * Returns: the pointer to key or NULL if the key is not found or + * an error occurs. + */ +xmlSecKeyPtr +xmlSecKeysMngrGetKey(xmlNodePtr keyInfoNode, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyPtr key; + int ret; + + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + + /* first try to read data from <dsig:KeyInfo/> node */ + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + if(keyInfoNode != NULL) { + ret = xmlSecKeyInfoNodeRead(keyInfoNode, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(keyInfoNode))); + xmlSecKeyDestroy(key); + return(NULL); + } + + if((xmlSecKeyGetValue(key) != NULL) && + (xmlSecKeyMatch(key, NULL, &(keyInfoCtx->keyReq)) != 0)) { + return(key); + } + } + xmlSecKeyDestroy(key); + + /* if we have keys manager, try it */ + if(keyInfoCtx->keysMngr != NULL) { + key = xmlSecKeysMngrFindKey(keyInfoCtx->keysMngr, NULL, keyInfoCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrFindKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + if(xmlSecKeyGetValue(key) != NULL) { + return(key); + } + xmlSecKeyDestroy(key); + } + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_KEY_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +/*********************************************************************** + * + * Keys list + * + **********************************************************************/ +static xmlSecPtrListKlass xmlSecKeyPtrListKlass = { + BAD_CAST "keys-list", + (xmlSecPtrDuplicateItemMethod)xmlSecKeyDuplicate, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecKeyDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecKeyDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecKeyDebugXmlDump,/* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecKeyPtrListGetKlass: + * + * The keys list klass. + * + * Returns: keys list id. + */ +xmlSecPtrListId +xmlSecKeyPtrListGetKlass(void) { + return(&xmlSecKeyPtrListKlass); +} + diff --git a/src/keysdata.c b/src/keysdata.c new file mode 100644 index 00000000..1101f7f8 --- /dev/null +++ b/src/keysdata.c @@ -0,0 +1,1387 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Key data. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ + +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/transforms.h> +#include <xmlsec/base64.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/errors.h> + + +/************************************************************************** + * + * Global xmlSecKeyDataIds list functions + * + *************************************************************************/ +static xmlSecPtrList xmlSecAllKeyDataIds; + +/** + * xmlSecKeyDataIdsGet: + * + * Gets global registered key data klasses list. + * + * Returns: the pointer to list of all registered key data klasses. + */ +xmlSecPtrListPtr +xmlSecKeyDataIdsGet(void) { + return(&xmlSecAllKeyDataIds); +} + +/** + * xmlSecKeyDataIdsInit: + * + * Initializes the key data klasses. This function is called from the + * #xmlSecInit function and the application should not call it directly. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyDataIdsInit(void) { + int ret; + + ret = xmlSecPtrListInitialize(xmlSecKeyDataIdsGet(), xmlSecKeyDataIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListPtrInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyDataIdListId"); + return(-1); + } + + ret = xmlSecKeyDataIdsRegisterDefault(); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataIdsRegisterDefault", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyDataIdsShutdown: + * + * Shuts down the keys data klasses. This function is called from the + * #xmlSecShutdown function and the application should not call it directly. + */ +void +xmlSecKeyDataIdsShutdown(void) { + xmlSecPtrListFinalize(xmlSecKeyDataIdsGet()); +} + +/** + * xmlSecKeyDataIdsRegister: + * @id: the key data klass. + * + * Registers @id in the global list of key data klasses. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyDataIdsRegister(xmlSecKeyDataId id) { + int ret; + + xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); + + ret = xmlSecPtrListAdd(xmlSecKeyDataIdsGet(), (xmlSecPtr)id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "dataId=%s", + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id))); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyDataIdsRegisterDefault: + * + * Registers default (implemented by XML Security Library) + * key data klasses: <dsig:KeyName/> element processing klass, + * <dsig:KeyValue/> element processing klass, ... + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyDataIdsRegisterDefault(void) { + if(xmlSecKeyDataIdsRegister(xmlSecKeyDataNameId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyDataNameId"); + return(-1); + } + + if(xmlSecKeyDataIdsRegister(xmlSecKeyDataValueId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyDataValueId"); + return(-1); + } + + if(xmlSecKeyDataIdsRegister(xmlSecKeyDataRetrievalMethodId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyDataRetrievalMethodId"); + return(-1); + } + +#ifndef XMLSEC_NO_XMLENC + if(xmlSecKeyDataIdsRegister(xmlSecKeyDataEncryptedKeyId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyDataEncryptedKeyId"); + return(-1); + } +#endif /* XMLSEC_NO_XMLENC */ + + return(0); +} + +/************************************************************************** + * + * xmlSecKeyData functions + * + *************************************************************************/ +/** + * xmlSecKeyDataCreate: + * @id: the data id. + * + * Allocates and initializes new key data of the specified type @id. + * Caller is responsible for destroing returend object with + * #xmlSecKeyDataDestroy function. + * + * Returns: the pointer to newly allocated key data structure + * or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecKeyDataCreate(xmlSecKeyDataId id) { + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(id != NULL, NULL); + xmlSecAssert2(id->klassSize >= sizeof(xmlSecKeyDataKlass), NULL); + xmlSecAssert2(id->objSize >= sizeof(xmlSecKeyData), NULL); + xmlSecAssert2(id->name != NULL, NULL); + + /* Allocate a new xmlSecKeyData and fill the fields. */ + data = (xmlSecKeyDataPtr)xmlMalloc(id->objSize); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", id->objSize); + return(NULL); + } + memset(data, 0, id->objSize); + data->id = id; + + if(id->initialize != NULL) { + ret = (id->initialize)(data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "id->initialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + } + + return(data); +} + +/** + * xmlSecKeyDataDuplicate: + * @data: the pointer to the key data. + * + * Creates a duplicate of the given @data. Caller is responsible for + * destroing returend object with #xmlSecKeyDataDestroy function. + * + * Returns: the pointer to newly allocated key data structure + * or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecKeyDataDuplicate(xmlSecKeyDataPtr data) { + xmlSecKeyDataPtr newData; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(data->id->duplicate != NULL, NULL); + + newData = xmlSecKeyDataCreate(data->id); + if(newData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = (data->id->duplicate)(newData, data); + if(newData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "id->duplicate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(newData); + return(NULL); + } + + return(newData); +} + +/** + * xmlSecKeyDataDestroy: + * @data: the pointer to the key data. + * + * Destroys the data and frees all allocated memory. + */ +void +xmlSecKeyDataDestroy(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(data->id->objSize > 0); + + if(data->id->finalize != NULL) { + (data->id->finalize)(data); + } + memset(data, 0, data->id->objSize); + xmlFree(data); +} + + +/** + * xmlSecKeyDataXmlRead: + * @id: the data klass. + * @key: the destination key. + * @node: the pointer to an XML node. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Reads the key data of klass @id from XML @node and adds them to @key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(id != NULL, -1); + xmlSecAssert2(id->xmlRead != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + return((id->xmlRead)(id, key, node, keyInfoCtx)); +} + +/** + * xmlSecKeyDataXmlWrite: + * @id: the data klass. + * @key: the source key. + * @node: the pointer to an XML node. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Writes the key data of klass @id from @key to an XML @node. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(id != NULL, -1); + xmlSecAssert2(id->xmlWrite != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + return((id->xmlWrite)(id, key, node, keyInfoCtx)); +} + +/** + * xmlSecKeyDataBinRead: + * @id: the data klass. + * @key: the destination key. + * @buf: the input binary buffer. + * @bufSize: the input buffer size. + * @keyInfoCtx: the <dsig:KeyInfo/> node processing context. + * + * Reads the key data of klass @id from binary buffer @buf to @key. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyDataBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(id != NULL, -1); + xmlSecAssert2(id->binRead != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + + return((id->binRead)(id, key, buf, bufSize, keyInfoCtx)); +} + +/** + * xmlSecKeyDataBinWrite: + * @id: the data klass. + * @key: the source key. + * @buf: the output binary buffer. + * @bufSize: the output buffer size. + * @keyInfoCtx: the <dsig:KeyInfo/> node processing context. + * + * Writes the key data of klass @id from the @key to a binary buffer @buf. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeyDataBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlSecByte** buf, xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(id != NULL, -1); + xmlSecAssert2(id->binWrite != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + + return((id->binWrite)(id, key, buf, bufSize, keyInfoCtx)); +} + +/** + * xmlSecKeyDataGenerate: + * @data: the pointer to key data. + * @sizeBits: the desired key data size (in bits). + * @type: the desired key data type. + * + * Generates new key data of given size and type. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, + xmlSecKeyDataType type) { + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(data->id->generate != NULL, -1); + + /* write data */ + ret = data->id->generate(data, sizeBits, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "id->generate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", sizeBits); + return(-1); + } + return(0); +} + +/** + * xmlSecKeyDataGetType: + * @data: the pointer to key data. + * + * Gets key data type. + * + * Returns: key data type. + */ +xmlSecKeyDataType +xmlSecKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataIsValid(data), xmlSecKeyDataTypeUnknown); + xmlSecAssert2(data->id->getType != NULL, xmlSecKeyDataTypeUnknown); + + return(data->id->getType(data)); +} + +/** + * xmlSecKeyDataGetSize: + * @data: the pointer to key data. + * + * Gets key data size. + * + * Returns: key data size (in bits). + */ +xmlSecSize +xmlSecKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(data->id->getSize != NULL, 0); + + return(data->id->getSize(data)); +} + +/** + * xmlSecKeyDataGetIdentifier: + * @data: the pointer to key data. + * + * Gets key data identifier string. + * + * Returns: key data id string. + */ +const xmlChar* +xmlSecKeyDataGetIdentifier(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(data->id->getIdentifier != NULL, NULL); + + return(data->id->getIdentifier(data)); +} + +/** + * xmlSecKeyDataDebugDump: + * @data: the pointer to key data. + * @output: the pointer to output FILE. + * + * Prints key data debug info. + */ +void +xmlSecKeyDataDebugDump(xmlSecKeyDataPtr data, FILE *output) { + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(data->id->debugDump != NULL); + xmlSecAssert(output != NULL); + + data->id->debugDump(data, output); +} + +/** + * xmlSecKeyDataDebugXmlDump: + * @data: the pointer to key data. + * @output: the pointer to output FILE. + * + * Prints key data debug info in XML format. + */ +void +xmlSecKeyDataDebugXmlDump(xmlSecKeyDataPtr data, FILE *output) { + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(data->id->debugXmlDump != NULL); + xmlSecAssert(output != NULL); + + data->id->debugXmlDump(data, output); +} + +/************************************************************************** + * + * xmlSecKeyDataBinary methods + * + * key (xmlSecBuffer) is located after xmlSecKeyData structure + * + *************************************************************************/ +/** + * xmlSecKeyDataBinaryValueInitialize: + * @data: the pointer to binary key data. + * + * Initializes key data. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueInitialize(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), -1); + + /* initialize buffer */ + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + ret = xmlSecBufferInitialize(buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyDataBinaryValueDuplicate: + * @dst: the pointer to destination binary key data. + * @src: the pointer to source binary key data. + * + * Copies binary key data from @src to @dst. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecBufferPtr buffer; + int ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecKeyDataBinarySize), -1); + xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecKeyDataBinarySize), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(src); + xmlSecAssert2(buffer != NULL, -1); + + /* copy data */ + ret = xmlSecKeyDataBinaryValueSetBuffer(dst, + xmlSecBufferGetData(buffer), + xmlSecBufferGetSize(buffer)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecKeyDataBinaryValueSetBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyDataBinaryValueFinalize: + * @data: the pointer to binary key data. + * + * Cleans up binary key data. + */ +void +xmlSecKeyDataBinaryValueFinalize(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize)); + + /* initialize buffer */ + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert(buffer != NULL); + + xmlSecBufferFinalize(buffer); +} + +/** + * xmlSecKeyDataBinaryValueXmlRead: + * @id: the data klass. + * @key: the pointer to destination key. + * @node: the pointer to an XML node. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Reads binary key data from @node to the key by base64 decoding the @node content. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar* str; + xmlSecSize len; + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + str = xmlNodeGetContent(node); + if(str == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* usual trick: decode into the same buffer */ + ret = xmlSecBase64Decode(str, (xmlSecByte*)str, xmlStrlen(str)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(-1); + } + len = ret; + + /* check do we have a key already */ + data = xmlSecKeyGetValue(key); + if(data != NULL) { + xmlSecBufferPtr buffer; + + if(!xmlSecKeyDataCheckId(data, id)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(-1); + } + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + if((buffer != NULL) && ((xmlSecSize)xmlSecBufferGetSize(buffer) != len)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, + "cur-data-size=%d;new-data-size=%d", + xmlSecBufferGetSize(buffer), len); + xmlFree(str); + return(-1); + } + if((buffer != NULL) && (len > 0) && (memcmp(xmlSecBufferGetData(buffer), str, len) != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, + "key already has a different value"); + xmlFree(str); + return(-1); + } + if(buffer != NULL) { + /* we already have exactly the same key */ + xmlFree(str); + return(0); + } + + /* we have binary key value with empty buffer */ + } + + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(-1); + } + + ret = xmlSecKeyDataBinaryValueSetBuffer(data, (xmlSecByte*)str, len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataBinaryValueSetBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", len); + xmlSecKeyDataDestroy(data); + xmlFree(str); + return(-1); + } + xmlFree(str); + + if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), data) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyReqMatchKeyValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(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); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyDataBinaryValueXmlWrite: + * @id: the data klass. + * @key: the pointer to source key. + * @node: the pointer to an XML node. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Base64 encodes binary key data of klass @id from the @key and + * sets to the @node content. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecBufferPtr buffer; + xmlSecKeyDataPtr value; + xmlChar* str; + + xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if((xmlSecKeyDataTypeSymmetric & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only symmetric key */ + return(0); + } + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(xmlSecKeyDataIsValid(value), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(value); + xmlSecAssert2(buffer != NULL, -1); + + str = xmlSecBase64Encode(xmlSecBufferGetData(buffer), + xmlSecBufferGetSize(buffer), + keyInfoCtx->base64LineSize); + if(str == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlNodeSetContent(node, str); + xmlFree(str); + return(0); +} + +/** + * xmlSecKeyDataBinaryValueBinRead: + * @id: the data klass. + * @key: the pointer to destination key. + * @buf: the source binary buffer. + * @bufSize: the source binary buffer size. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Reads binary key data of the klass @id from @buf to the @key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + /* check do we have a key already */ + data = xmlSecKeyGetValue(key); + if(data != NULL) { + xmlSecBufferPtr buffer; + + if(!xmlSecKeyDataCheckId(data, id)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + if((buffer != NULL) && ((xmlSecSize)xmlSecBufferGetSize(buffer) != bufSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, + "cur-data-size=%d;new-data-size=%d", + xmlSecBufferGetSize(buffer), bufSize); + return(-1); + } + if((buffer != NULL) && (bufSize > 0) && (memcmp(xmlSecBufferGetData(buffer), buf, bufSize) != 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + XMLSEC_ERRORS_R_KEY_DATA_ALREADY_EXIST, + "key already has a different value"); + return(-1); + } + if(buffer != NULL) { + /* we already have exactly the same key */ + return(0); + } + + /* we have binary key value with empty buffer */ + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecKeyDataBinaryValueSetBuffer(data, buf, bufSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataBinaryValueSetBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", bufSize); + xmlSecKeyDataDestroy(data); + return(-1); + } + + if(xmlSecKeyReqMatchKeyValue(&(keyInfoCtx->keyReq), data) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyReqMatchKeyValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(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); + return(-1); + } + + return(0); +} + +/** + * xmlSecKeyDataBinaryValueBinWrite: + * @id: the data klass. + * @key: the pointer to source key. + * @buf: the destination binary buffer. + * @bufSize: the destination binary buffer size. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Writes binary key data of klass @id from the @key to @buf. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlSecByte** buf, xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr value; + xmlSecBufferPtr buffer; + + xmlSecAssert2(id != xmlSecKeyDataIdUnknown, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + if((xmlSecKeyDataTypeSymmetric & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only symmetric key */ + return(0); + } + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(xmlSecKeyDataIsValid(value), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(key->value); + xmlSecAssert2(buffer != NULL, -1); + + (*bufSize) = xmlSecBufferGetSize(buffer); + (*buf) = (xmlSecByte*) xmlMalloc((*bufSize)); + if((*buf) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + memcpy((*buf), xmlSecBufferGetData(buffer), (*bufSize)); + return(0); +} + +/** + * xmlSecKeyDataBinaryValueDebugDump: + * @data: the pointer to binary key data. + * @output: the pointer to output FILE. + * + * Prints binary key data debug information to @output. + */ +void +xmlSecKeyDataBinaryValueDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecBufferPtr buffer; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize)); + xmlSecAssert(data->id->dataNodeName != NULL); + xmlSecAssert(output != NULL); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert(buffer != NULL); + + /* print only size, everything else is sensitive */ + fprintf(output, "=== %s: size=%d\n", data->id->dataNodeName, + xmlSecKeyDataGetSize(data)); +} + +/** + * xmlSecKeyDataBinaryValueDebugXmlDump: + * @data: the pointer to binary key data. + * @output: the pointer to output FILE. + * + * Prints binary key data debug information to @output in XML format. + */ +void +xmlSecKeyDataBinaryValueDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecBufferPtr buffer; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize)); + xmlSecAssert(data->id->dataNodeName != NULL); + xmlSecAssert(output != NULL); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert(buffer != NULL); + + /* print only size, everything else is sensitive */ + fprintf(output, "<%s size=\"%d\" />\n", data->id->dataNodeName, + xmlSecKeyDataGetSize(data)); +} + +/** + * xmlSecKeyDataBinaryValueGetSize: + * @data: the pointer to binary key data. + * + * Gets the binary key data size. + * + * Returns: binary key data size in bits. + */ +xmlSecSize +xmlSecKeyDataBinaryValueGetSize(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), 0); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), 0); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, 0); + + /* return size in bits */ + return(8 * xmlSecBufferGetSize(buffer)); +} + +/** + * xmlSecKeyDataBinaryValueGetBuffer: + * @data: the pointer to binary key data. + * + * Gets the binary key data buffer. + * + * Returns: pointer to binary key data buffer. + */ +xmlSecBufferPtr +xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), NULL); + + /* key (xmlSecBuffer) is located after xmlSecKeyData structure */ + return((xmlSecBufferPtr)(((xmlSecByte*)data) + sizeof(xmlSecKeyData))); +} + +/** + * xmlSecKeyDataBinaryValueSetBuffer: + * @data: the pointer to binary key data. + * @buf: the pointer to binary buffer. + * @bufSize: the binary buffer size. + * + * Sets the value of @data to @buf. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecKeyDataBinaryValueSetBuffer(xmlSecKeyDataPtr data, + const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecKeyDataBinarySize), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} + +/*********************************************************************** + * + * Keys Data list + * + **********************************************************************/ +static xmlSecPtrListKlass xmlSecKeyDataListKlass = { + BAD_CAST "key-data-list", + (xmlSecPtrDuplicateItemMethod)xmlSecKeyDataDuplicate, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecKeyDataDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecKeyDataDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecKeyDataDebugXmlDump, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecKeyDataListGetKlass: + * + * The key data list klass. + * + * Returns: pointer to the key data list klass. + */ +xmlSecPtrListId +xmlSecKeyDataListGetKlass(void) { + return(&xmlSecKeyDataListKlass); +} + + +/*********************************************************************** + * + * Keys Data Ids list + * + **********************************************************************/ +static xmlSecPtrListKlass xmlSecKeyDataIdListKlass = { + BAD_CAST "key-data-ids-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + NULL, /* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecKeyDataIdListGetKlass: + * + * The key data id list klass. + * + * Returns: pointer to the key data id list klass. + */ +xmlSecPtrListId +xmlSecKeyDataIdListGetKlass(void) { + return(&xmlSecKeyDataIdListKlass); +} + +/** + * xmlSecKeyDataIdListFind: + * @list: the pointer to key data ids list. + * @dataId: the key data klass. + * + * Lookups @dataId in @list. + * + * Returns: 1 if @dataId is found in the @list, 0 if not and a negative + * value if an error occurs. + */ +int +xmlSecKeyDataIdListFind(xmlSecPtrListPtr list, xmlSecKeyDataId dataId) { + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyDataIdListId), 0); + xmlSecAssert2(dataId != NULL, 0); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + if((xmlSecKeyDataId)xmlSecPtrListGetItem(list, i) == dataId) { + return(1); + } + } + return(0); +} + +/** + * xmlSecKeyDataIdListFindByNode: + * @list: the pointer to key data ids list. + * @nodeName: the desired key data klass XML node name. + * @nodeNs: the desired key data klass XML node namespace. + * @usage: the desired key data usage. + * + * Lookups data klass in the list with given @nodeName, @nodeNs and + * @usage in the @list. + * + * Returns: key data klass is found and NULL otherwise. + */ +xmlSecKeyDataId +xmlSecKeyDataIdListFindByNode(xmlSecPtrListPtr list, const xmlChar* nodeName, + const xmlChar* nodeNs, xmlSecKeyDataUsage usage) { + xmlSecKeyDataId dataId; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyDataIdListId), xmlSecKeyDataIdUnknown); + xmlSecAssert2(nodeName != NULL, xmlSecKeyDataIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + dataId = (xmlSecKeyDataId)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, xmlSecKeyDataIdUnknown); + + if(((usage & dataId->usage) != 0) && + xmlStrEqual(nodeName, dataId->dataNodeName) && + xmlStrEqual(nodeNs, dataId->dataNodeNs)) { + + return(dataId); + } + } + return(xmlSecKeyDataIdUnknown); +} + +/** + * xmlSecKeyDataIdListFindByHref: + * @list: the pointer to key data ids list. + * @href: the desired key data klass href. + * @usage: the desired key data usage. + * + * Lookups data klass in the list with given @href and @usage in @list. + * + * Returns: key data klass is found and NULL otherwise. + */ +xmlSecKeyDataId +xmlSecKeyDataIdListFindByHref(xmlSecPtrListPtr list, const xmlChar* href, + xmlSecKeyDataUsage usage) { + xmlSecKeyDataId dataId; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyDataIdListId), xmlSecKeyDataIdUnknown); + xmlSecAssert2(href != NULL, xmlSecKeyDataIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + dataId = (xmlSecKeyDataId)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, xmlSecKeyDataIdUnknown); + + if(((usage & dataId->usage) != 0) && (dataId->href != NULL) && + xmlStrEqual(href, dataId->href)) { + + return(dataId); + } + } + return(xmlSecKeyDataIdUnknown); +} + +/** + * xmlSecKeyDataIdListFindByName: + * @list: the pointer to key data ids list. + * @name: the desired key data klass name. + * @usage: the desired key data usage. + * + * Lookups data klass in the list with given @name and @usage in @list. + * + * Returns: key data klass is found and NULL otherwise. + */ +xmlSecKeyDataId +xmlSecKeyDataIdListFindByName(xmlSecPtrListPtr list, const xmlChar* name, + xmlSecKeyDataUsage usage) { + xmlSecKeyDataId dataId; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyDataIdListId), xmlSecKeyDataIdUnknown); + xmlSecAssert2(name != NULL, xmlSecKeyDataIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + dataId = (xmlSecKeyDataId)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, xmlSecKeyDataIdUnknown); + + if(((usage & dataId->usage) != 0) && (dataId->name != NULL) && + xmlStrEqual(name, BAD_CAST dataId->name)) { + + return(dataId); + } + } + return(xmlSecKeyDataIdUnknown); +} + +/** + * xmlSecKeyDataIdListDebugDump: + * @list: the pointer to key data ids list. + * @output: the pointer to output FILE. + * + * Prints binary key data debug information to @output. + */ +void +xmlSecKeyDataIdListDebugDump(xmlSecPtrListPtr list, FILE* output) { + xmlSecKeyDataId dataId; + xmlSecSize i, size; + + xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecKeyDataIdListId)); + xmlSecAssert(output != NULL); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + dataId = (xmlSecKeyDataId)xmlSecPtrListGetItem(list, i); + xmlSecAssert(dataId != NULL); + xmlSecAssert(dataId->name != NULL); + + if(i > 0) { + fprintf(output, ",\"%s\"", dataId->name); + } else { + fprintf(output, "\"%s\"", dataId->name); + } + } + fprintf(output, "\n"); +} + +/** + * xmlSecKeyDataIdListDebugXmlDump: + * @list: the pointer to key data ids list. + * @output: the pointer to output FILE. + * + * Prints binary key data debug information to @output in XML format. + */ +void +xmlSecKeyDataIdListDebugXmlDump(xmlSecPtrListPtr list, FILE* output) { + xmlSecKeyDataId dataId; + xmlSecSize i, size; + + xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecKeyDataIdListId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<KeyDataIdsList>\n"); + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + dataId = (xmlSecKeyDataId)xmlSecPtrListGetItem(list, i); + xmlSecAssert(dataId != NULL); + xmlSecAssert(dataId->name != NULL); + + fprintf(output, "<DataId name=\""); + xmlSecPrintXmlString(output, dataId->name); + fprintf(output, "\"/>"); + } + fprintf(output, "</KeyDataIdsList>\n"); +} + +/************************************************************************** + * + * xmlSecKeyDataStore functions + * + *************************************************************************/ +/** + * xmlSecKeyDataStoreCreate: + * @id: the store id. + * + * Creates new key data store of the specified klass @id. Caller is responsible + * for freeng returned object with #xmlSecKeyDataStoreDestroy function. + * + * Returns: the pointer to newly allocated key data store structure + * or NULL if an error occurs. + */ +xmlSecKeyDataStorePtr +xmlSecKeyDataStoreCreate(xmlSecKeyDataStoreId id) { + xmlSecKeyDataStorePtr store; + int ret; + + xmlSecAssert2(id != NULL, NULL); + xmlSecAssert2(id->objSize > 0, NULL); + + /* Allocate a new xmlSecKeyDataStore and fill the fields. */ + store = (xmlSecKeyDataStorePtr)xmlMalloc(id->objSize); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", id->objSize); + return(NULL); + } + memset(store, 0, id->objSize); + store->id = id; + + if(id->initialize != NULL) { + ret = (id->initialize)(store); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreKlassGetName(id)), + "id->initialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataStoreDestroy(store); + return(NULL); + } + } + + return(store); +} + +/** + * xmlSecKeyDataStoreDestroy: + * @store: the pointer to the key data store.. + * + * Destroys the key data store created with #xmlSecKeyDataStoreCreate + * function. + */ +void +xmlSecKeyDataStoreDestroy(xmlSecKeyDataStorePtr store) { + xmlSecAssert(xmlSecKeyDataStoreIsValid(store)); + xmlSecAssert(store->id->objSize > 0); + + if(store->id->finalize != NULL) { + (store->id->finalize)(store); + } + memset(store, 0, store->id->objSize); + xmlFree(store); +} + +/*********************************************************************** + * + * Keys Data Store list + * + **********************************************************************/ +static xmlSecPtrListKlass xmlSecKeyDataStorePtrListKlass = { + BAD_CAST "keys-data-store-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecKeyDataStoreDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecKeyDataStorePtrListGetKlass: + * + * Key data stores list. + * + * Returns: key data stores list klass. + */ +xmlSecPtrListId +xmlSecKeyDataStorePtrListGetKlass(void) { + return(&xmlSecKeyDataStorePtrListKlass); +} + + diff --git a/src/keysmngr.c b/src/keysmngr.c new file mode 100644 index 00000000..e93cbb49 --- /dev/null +++ b/src/keysmngr.c @@ -0,0 +1,745 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Keys Manager + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/list.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/errors.h> + +/**************************************************************************** + * + * Keys Manager + * + ***************************************************************************/ +/** + * xmlSecKeysMngrCreate: + * + * Creates new keys manager. Caller is responsible for freeing it with + * #xmlSecKeysMngrDestroy function. + * + * Returns: the pointer to newly allocated keys manager or NULL if + * an error occurs. + */ +xmlSecKeysMngrPtr +xmlSecKeysMngrCreate(void) { + xmlSecKeysMngrPtr mngr; + int ret; + + /* Allocate a new xmlSecKeysMngr and fill the fields. */ + mngr = (xmlSecKeysMngrPtr)xmlMalloc(sizeof(xmlSecKeysMngr)); + if(mngr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecKeysMngr)=%d", + sizeof(xmlSecKeysMngr)); + return(NULL); + } + memset(mngr, 0, sizeof(xmlSecKeysMngr)); + + ret = xmlSecPtrListInitialize(&(mngr->storesList), xmlSecKeyDataStorePtrListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyDataStorePtrListId"); + return(NULL); + } + + return(mngr); +} + +/** + * xmlSecKeysMngrDestroy: + * @mngr: the pointer to keys manager. + * + * Destroys keys manager created with #xmlSecKeysMngrCreate function. + */ +void +xmlSecKeysMngrDestroy(xmlSecKeysMngrPtr mngr) { + xmlSecAssert(mngr != NULL); + + /* destroy keys store */ + if(mngr->keysStore != NULL) { + xmlSecKeyStoreDestroy(mngr->keysStore); + } + + /* destroy other data stores */ + xmlSecPtrListFinalize(&(mngr->storesList)); + + memset(mngr, 0, sizeof(xmlSecKeysMngr)); + xmlFree(mngr); +} + +/** + * xmlSecKeysMngrFindKey: + * @mngr: the pointer to keys manager. + * @name: the desired key name. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> node processing context. + * + * Lookups key in the keys manager keys store. The caller is responsible + * for destroying the returned key using #xmlSecKeyDestroy method. + * + * Returns: the pointer to a key or NULL if key is not found or an error occurs. + */ +xmlSecKeyPtr +xmlSecKeysMngrFindKey(xmlSecKeysMngrPtr mngr, const xmlChar* name, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyStorePtr store; + + xmlSecAssert2(mngr != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + /* no store. is it an error? */ + return(NULL); + } + + return(xmlSecKeyStoreFindKey(store, name, keyInfoCtx)); +} + +/** + * xmlSecKeysMngrAdoptKeysStore: + * @mngr: the pointer to keys manager. + * @store: the pointer to keys store. + * + * Adopts keys store in the keys manager @mngr. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeysMngrAdoptKeysStore(xmlSecKeysMngrPtr mngr, xmlSecKeyStorePtr store) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(xmlSecKeyStoreIsValid(store), -1); + + if(mngr->keysStore != NULL) { + xmlSecKeyStoreDestroy(mngr->keysStore); + } + mngr->keysStore = store; + + return(0); +} + +/** + * xmlSecKeysMngrGetKeysStore: + * @mngr: the pointer to keys manager. + * + * Gets the keys store. + * + * Returns: the keys store in the keys manager @mngr or NULL if + * there is no store or an error occurs. + */ +xmlSecKeyStorePtr +xmlSecKeysMngrGetKeysStore(xmlSecKeysMngrPtr mngr) { + xmlSecAssert2(mngr != NULL, NULL); + + return(mngr->keysStore); +} + +/** + * xmlSecKeysMngrAdoptDataStore: + * @mngr: the pointer to keys manager. + * @store: the pointer to data store. + * + * Adopts data store in the keys manager. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecKeysMngrAdoptDataStore(xmlSecKeysMngrPtr mngr, xmlSecKeyDataStorePtr store) { + xmlSecKeyDataStorePtr tmp; + xmlSecSize pos, size; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(xmlSecKeyDataStoreIsValid(store), -1); + + size = xmlSecPtrListGetSize(&(mngr->storesList)); + for(pos = 0; pos < size; ++pos) { + tmp = (xmlSecKeyDataStorePtr)xmlSecPtrListGetItem(&(mngr->storesList), pos); + if((tmp != NULL) && (tmp->id == store->id)) { + return(xmlSecPtrListSet(&(mngr->storesList), store, pos)); + } + } + + return(xmlSecPtrListAdd(&(mngr->storesList), store)); +} + + +/** + * xmlSecKeysMngrGetDataStore: + * @mngr: the pointer to keys manager. + * @id: the desired data store klass. + * + * Lookups the data store of given klass @id in the keys manager. + * + * Returns: pointer to data store or NULL if it is not found or an error + * occurs. + */ +xmlSecKeyDataStorePtr +xmlSecKeysMngrGetDataStore(xmlSecKeysMngrPtr mngr, xmlSecKeyDataStoreId id) { + xmlSecKeyDataStorePtr tmp; + xmlSecSize pos, size; + + xmlSecAssert2(mngr != NULL, NULL); + xmlSecAssert2(id != xmlSecKeyDataStoreIdUnknown, NULL); + + size = xmlSecPtrListGetSize(&(mngr->storesList)); + for(pos = 0; pos < size; ++pos) { + tmp = (xmlSecKeyDataStorePtr)xmlSecPtrListGetItem(&(mngr->storesList), pos); + if((tmp != NULL) && (tmp->id == id)) { + return(tmp); + } + } + + return(NULL); +} + +/************************************************************************** + * + * xmlSecKeyStore functions + * + *************************************************************************/ +/** + * xmlSecKeyStoreCreate: + * @id: the key store klass. + * + * Creates new store of the specified klass @klass. Caller is responsible + * for freeing the returned store by calling #xmlSecKeyStoreDestroy function. + * + * Returns: the pointer to newly allocated keys store or NULL if an error occurs. + */ +xmlSecKeyStorePtr +xmlSecKeyStoreCreate(xmlSecKeyStoreId id) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(id != NULL, NULL); + xmlSecAssert2(id->objSize > 0, NULL); + + /* Allocate a new xmlSecKeyStore and fill the fields. */ + store = (xmlSecKeyStorePtr)xmlMalloc(id->objSize); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", id->objSize); + return(NULL); + } + memset(store, 0, id->objSize); + store->id = id; + + if(id->initialize != NULL) { + ret = (id->initialize)(store); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreKlassGetName(id)), + "id->initialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyStoreDestroy(store); + return(NULL); + } + } + + return(store); +} + +/** + * xmlSecKeyStoreDestroy: + * @store: the pointer to keys store. + * + * Destroys the store created with #xmlSecKeyStoreCreate function. + */ +void +xmlSecKeyStoreDestroy(xmlSecKeyStorePtr store) { + xmlSecAssert(xmlSecKeyStoreIsValid(store)); + xmlSecAssert(store->id->objSize > 0); + + if(store->id->finalize != NULL) { + (store->id->finalize)(store); + } + memset(store, 0, store->id->objSize); + xmlFree(store); +} + +/** + * xmlSecKeyStoreFindKey: + * @store: the pointer to keys store. + * @name: the desired key name. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> node processing context. + * + * Lookups key in the store. The caller is responsible for destroying + * the returned key using #xmlSecKeyDestroy method. + * + * Returns: the pointer to a key or NULL if key is not found or an error occurs. + */ +xmlSecKeyPtr +xmlSecKeyStoreFindKey(xmlSecKeyStorePtr store, const xmlChar* name, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecKeyStoreIsValid(store), NULL); + xmlSecAssert2(store->id->findKey != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + return(store->id->findKey(store, name, keyInfoCtx)); +} + +/**************************************************************************** + * + * Simple Keys Store + * + * keys list (xmlSecPtrList) is located after xmlSecKeyStore + * + ***************************************************************************/ +#define xmlSecSimpleKeysStoreSize \ + (sizeof(xmlSecKeyStore) + sizeof(xmlSecPtrList)) +#define xmlSecSimpleKeysStoreGetList(store) \ + ((xmlSecKeyStoreCheckSize((store), xmlSecSimpleKeysStoreSize)) ? \ + (xmlSecPtrListPtr)(((xmlSecByte*)(store)) + sizeof(xmlSecKeyStore)) : \ + (xmlSecPtrListPtr)NULL) + +static int xmlSecSimpleKeysStoreInitialize (xmlSecKeyStorePtr store); +static void xmlSecSimpleKeysStoreFinalize (xmlSecKeyStorePtr store); +static xmlSecKeyPtr xmlSecSimpleKeysStoreFindKey (xmlSecKeyStorePtr store, + const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyStoreKlass xmlSecSimpleKeysStoreKlass = { + sizeof(xmlSecKeyStoreKlass), + xmlSecSimpleKeysStoreSize, + + /* data */ + BAD_CAST "simple-keys-store", /* const xmlChar* name; */ + + /* constructors/destructor */ + xmlSecSimpleKeysStoreInitialize, /* xmlSecKeyStoreInitializeMethod initialize; */ + xmlSecSimpleKeysStoreFinalize, /* xmlSecKeyStoreFinalizeMethod finalize; */ + xmlSecSimpleKeysStoreFindKey, /* xmlSecKeyStoreFindKeyMethod findKey; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecSimpleKeysStoreGetKlass: + * + * The simple list based keys store klass. + * + * Returns: simple list based keys store klass. + */ +xmlSecKeyStoreId +xmlSecSimpleKeysStoreGetKlass(void) { + return(&xmlSecSimpleKeysStoreKlass); +} + +/** + * xmlSecSimpleKeysStoreAdoptKey: + * @store: the pointer to simple 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 +xmlSecSimpleKeysStoreAdoptKey(xmlSecKeyStorePtr store, xmlSecKeyPtr key) { + xmlSecPtrListPtr list; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId), -1); + xmlSecAssert2(key != NULL, -1); + + list = xmlSecSimpleKeysStoreGetList(store); + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyPtrListId), -1); + + ret = xmlSecPtrListAdd(list, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecSimpleKeysStoreLoad: + * @store: the pointer to simple 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 +xmlSecSimpleKeysStoreLoad(xmlSecKeyStorePtr store, const char *uri, + xmlSecKeysMngrPtr keysMngr) { + xmlDocPtr doc; + xmlNodePtr root; + xmlNodePtr cur; + xmlSecKeyPtr key; + xmlSecKeyInfoCtx keyInfoCtx; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId), -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 = xmlSecSimpleKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecSimpleKeysStoreAdoptKey", + 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); + +} + +/** + * xmlSecSimpleKeysStoreSave: + * @store: the pointer to simple 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 +xmlSecSimpleKeysStoreSave(xmlSecKeyStorePtr store, const char *filename, xmlSecKeyDataType type) { + xmlSecKeyInfoCtx keyInfoCtx; + xmlSecPtrListPtr list; + xmlSecKeyPtr key; + xmlSecSize i, keysSize; + xmlDocPtr doc; + xmlNodePtr cur; + xmlSecKeyDataPtr data; + xmlSecPtrListPtr idsList; + xmlSecKeyDataId dataId; + xmlSecSize idsSize, j; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId), -1); + xmlSecAssert2(filename != NULL, -1); + + list = xmlSecSimpleKeysStoreGetList(store); + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyPtrListId), -1); + + /* create doc */ + doc = xmlSecCreateTree(BAD_CAST "Keys", xmlSecNs); + if(doc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecCreateTree", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + idsList = xmlSecKeyDataIdsGet(); + xmlSecAssert2(idsList != NULL, -1); + + keysSize = xmlSecPtrListGetSize(list); + idsSize = xmlSecPtrListGetSize(idsList); + for(i = 0; i < keysSize; ++i) { + key = (xmlSecKeyPtr)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(key != NULL, -1); + + cur = xmlSecAddChild(xmlDocGetRootElement(doc), xmlSecNodeKeyInfo, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyInfo)); + xmlFreeDoc(doc); + return(-1); + } + + /* special data key name */ + if(xmlSecKeyGetName(key) != NULL) { + if(xmlSecAddChild(cur, xmlSecNodeKeyName, xmlSecDSigNs) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyName)); + xmlFreeDoc(doc); + return(-1); + } + } + + /* create nodes for other keys data */ + for(j = 0; j < idsSize; ++j) { + dataId = (xmlSecKeyDataId)xmlSecPtrListGetItem(idsList, j); + xmlSecAssert2(dataId != xmlSecKeyDataIdUnknown, -1); + + if(dataId->dataNodeName == NULL) { + continue; + } + + data = xmlSecKeyGetData(key, dataId); + if(data == NULL) { + continue; + } + + if(xmlSecAddChild(cur, dataId->dataNodeName, dataId->dataNodeNs) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(dataId->dataNodeName)); + 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); + xmlFreeDoc(doc); + return(-1); + } + + keyInfoCtx.mode = xmlSecKeyInfoModeWrite; + keyInfoCtx.keyReq.keyId = xmlSecKeyDataIdUnknown; + keyInfoCtx.keyReq.keyType = type; + keyInfoCtx.keyReq.keyUsage = xmlSecKeyDataUsageAny; + + /* finally write key in the node */ + ret = xmlSecKeyInfoNodeWrite(cur, key, &keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecKeyInfoNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyInfoCtxFinalize(&keyInfoCtx); + xmlFreeDoc(doc); + return(-1); + } + xmlSecKeyInfoCtxFinalize(&keyInfoCtx); + } + + /* now write result */ + ret = xmlSaveFormatFile(filename, doc, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSaveFormatFile", + XMLSEC_ERRORS_R_XML_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + xmlFreeDoc(doc); + return(-1); + } + + xmlFreeDoc(doc); + return(0); +} + +/** + * xmlSecSimpleKeysStoreGetKeys: + * @store: the pointer to simple keys store. + * + * Gets list of keys from simple keys store. + * + * Returns: pointer to the list of keys stored in the keys store or NULL + * if an error occurs. + */ +xmlSecPtrListPtr +xmlSecSimpleKeysStoreGetKeys(xmlSecKeyStorePtr store) { + xmlSecPtrListPtr list; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId), NULL); + + list = xmlSecSimpleKeysStoreGetList(store); + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyPtrListId), NULL); + + return list; +} + +static int +xmlSecSimpleKeysStoreInitialize(xmlSecKeyStorePtr store) { + xmlSecPtrListPtr list; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId), -1); + + list = xmlSecSimpleKeysStoreGetList(store); + xmlSecAssert2(list != NULL, -1); + + ret = xmlSecPtrListInitialize(list, xmlSecKeyPtrListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecKeyPtrListId"); + return(-1); + } + + return(0); +} + +static void +xmlSecSimpleKeysStoreFinalize(xmlSecKeyStorePtr store) { + xmlSecPtrListPtr list; + + xmlSecAssert(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId)); + + list = xmlSecSimpleKeysStoreGetList(store); + xmlSecAssert(list != NULL); + + xmlSecPtrListFinalize(list); +} + +static xmlSecKeyPtr +xmlSecSimpleKeysStoreFindKey(xmlSecKeyStorePtr store, const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecPtrListPtr list; + xmlSecKeyPtr key; + xmlSecSize pos, size; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecSimpleKeysStoreId), NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + list = xmlSecSimpleKeysStoreGetList(store); + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecKeyPtrListId), NULL); + + size = xmlSecPtrListGetSize(list); + for(pos = 0; pos < size; ++pos) { + key = (xmlSecKeyPtr)xmlSecPtrListGetItem(list, pos); + if((key != NULL) && (xmlSecKeyMatch(key, name, &(keyInfoCtx->keyReq)) == 1)) { + return(xmlSecKeyDuplicate(key)); + } + } + return(NULL); +} + diff --git a/src/list.c b/src/list.c new file mode 100644 index 00000000..a4b6ad54 --- /dev/null +++ b/src/list.c @@ -0,0 +1,508 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * List of pointers. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/list.h> +#include <xmlsec/errors.h> + + +static int xmlSecPtrListEnsureSize (xmlSecPtrListPtr list, + xmlSecSize size); + +static xmlSecAllocMode gAllocMode = xmlSecAllocModeDouble; +static xmlSecSize gInitialSize = 64; + +/** + * xmlSecPtrListSetDefaultAllocMode: + * @defAllocMode: the new default memory allocation mode. + * @defInitialSize: the new default minimal initial size. + * + * Sets new default allocation mode and minimal initial list size. + */ +void +xmlSecPtrListSetDefaultAllocMode(xmlSecAllocMode defAllocMode, xmlSecSize defInitialSize) { + xmlSecAssert(defInitialSize > 0); + + gAllocMode = defAllocMode; + gInitialSize = defInitialSize; +} + +/** + * xmlSecPtrListCreate: + * @id: the list klass. + * + * Creates new list object. Caller is responsible for freeing returned list + * by calling #xmlSecPtrListDestroy function. + * + * Returns: pointer to newly allocated list or NULL if an error occurs. + */ +xmlSecPtrListPtr +xmlSecPtrListCreate(xmlSecPtrListId id) { + xmlSecPtrListPtr list; + int ret; + + xmlSecAssert2(id != xmlSecPtrListIdUnknown, NULL); + + /* Allocate a new xmlSecPtrList and fill the fields. */ + list = (xmlSecPtrListPtr)xmlMalloc(sizeof(xmlSecPtrList)); + if(list == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListKlassGetName(id)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecPtrList)=%d", + sizeof(xmlSecPtrList)); + return(NULL); + } + + ret = xmlSecPtrListInitialize(list, id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListKlassGetName(id)), + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(list); + return(NULL); + } + + return(list); +} + +/** + * xmlSecPtrListDestroy: + * @list: the pointer to list. + * + * Destroys @list created with #xmlSecPtrListCreate function. + */ +void +xmlSecPtrListDestroy(xmlSecPtrListPtr list) { + xmlSecAssert(xmlSecPtrListIsValid(list)); + xmlSecPtrListFinalize(list); + xmlFree(list); +} + +/** + * xmlSecPtrListInitialize: + * @list: the pointer to list. + * @id: the list klass. + * + * Initializes the list of given klass. Caller is responsible + * for cleaning up by calling #xmlSecPtrListFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecPtrListInitialize(xmlSecPtrListPtr list, xmlSecPtrListId id) { + xmlSecAssert2(id != xmlSecPtrListIdUnknown, -1); + xmlSecAssert2(list != NULL, -1); + + memset(list, 0, sizeof(xmlSecPtrList)); + list->id = id; + list->allocMode = gAllocMode; + + return(0); +} + +/** + * xmlSecPtrListFinalize: + * @list: the pointer to list. + * + * Cleans up the list initialized with #xmlSecPtrListInitialize + * function. + */ +void +xmlSecPtrListFinalize(xmlSecPtrListPtr list) { + xmlSecAssert(xmlSecPtrListIsValid(list)); + + xmlSecPtrListEmpty(list); + memset(list, 0, sizeof(xmlSecPtrList)); +} + +/** + * xmlSecPtrListEmpty: + * @list: the pointer to list. + * + * Remove all items from @list (if any). + */ +void +xmlSecPtrListEmpty(xmlSecPtrListPtr list) { + xmlSecAssert(xmlSecPtrListIsValid(list)); + + if(list->id->destroyItem != NULL) { + xmlSecSize pos; + + for(pos = 0; pos < list->use; ++pos) { + xmlSecAssert(list->data != NULL); + if(list->data[pos] != NULL) { + list->id->destroyItem(list->data[pos]); + } + } + } + if(list->max > 0) { + xmlSecAssert(list->data != NULL); + + memset(list->data, 0, sizeof(xmlSecPtr) * list->use); + xmlFree(list->data); + } + list->max = list->use = 0; + list->data = NULL; +} + +/** + * xmlSecPtrListCopy: + * @dst: the pointer to destination list. + * @src: the pointer to source list. + * + * Copies @src list items to @dst list using #duplicateItem method + * of the list klass. If #duplicateItem method is NULL then + * we jsut copy pointers to items. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecPtrListCopy(xmlSecPtrListPtr dst, xmlSecPtrListPtr src) { + xmlSecSize i; + int ret; + + xmlSecAssert2(xmlSecPtrListIsValid(dst), -1); + xmlSecAssert2(xmlSecPtrListIsValid(src), -1); + xmlSecAssert2(dst->id == src->id, -1); + + /* allocate memory */ + ret = xmlSecPtrListEnsureSize(dst, dst->use + src->use); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListGetName(src)), + "xmlSecPtrListEnsureSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", src->use); + return(-1); + } + + /* copy one item after another */ + for(i = 0; i < src->use; ++i, ++dst->use) { + xmlSecAssert2(src->data != NULL, -1); + xmlSecAssert2(dst->data != NULL, -1); + + if((dst->id->duplicateItem != NULL) && (src->data[i] != NULL)) { + dst->data[dst->use] = dst->id->duplicateItem(src->data[i]); + if(dst->data[dst->use] == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListGetName(src)), + "duplicateItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + dst->data[dst->use] = src->data[i]; + } + } + + return(0); +} + +/** + * xmlSecPtrListDuplicate: + * @list: the pointer to list. + * + * Creates a new copy of @list and all its items. + * + * Returns: pointer to newly allocated list or NULL if an error occurs. + */ +xmlSecPtrListPtr +xmlSecPtrListDuplicate(xmlSecPtrListPtr list) { + xmlSecPtrListPtr newList; + int ret; + + xmlSecAssert2(xmlSecPtrListIsValid(list), NULL); + + newList = xmlSecPtrListCreate(list->id); + if(newList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListGetName(list)), + "xmlSecPtrListCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecPtrListCopy(newList, list); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListGetName(list)), + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecPtrListDestroy(newList); + return(NULL); + } + return(newList); +} + +/** + * xmlSecPtrListGetSize: + * @list: the pointer to list. + * + * Gets list size. + * + * Returns: the number of itmes in @list. + */ +xmlSecSize +xmlSecPtrListGetSize(xmlSecPtrListPtr list) { + xmlSecAssert2(xmlSecPtrListIsValid(list), 0); + + return(list->use); +} + +/** + * xmlSecPtrListGetItem: + * @list: the pointer to list. + * @pos: the item position. + * + * Gets item from the list. + * + * Returns: the list item at position @pos or NULL if @pos is greater + * than the number of items in the list or an error occurs. + */ +xmlSecPtr +xmlSecPtrListGetItem(xmlSecPtrListPtr list, xmlSecSize pos) { + xmlSecAssert2(xmlSecPtrListIsValid(list), NULL); + xmlSecAssert2(list->data != NULL, NULL); + xmlSecAssert2(pos < list->use, NULL); + + return(list->data[pos]); +} + +/** + * xmlSecPtrListAdd: + * @list: the pointer to list. + * @item: the item. + * + * Adds @item to the end of the @list. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecPtrListAdd(xmlSecPtrListPtr list, xmlSecPtr item) { + int ret; + + xmlSecAssert2(xmlSecPtrListIsValid(list), -1); + + ret = xmlSecPtrListEnsureSize(list, list->use + 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListGetName(list)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", list->use + 1); + return(-1); + } + + list->data[list->use++] = item; + return(0); +} + +/** + * xmlSecPtrListSet: + * @list: the pointer to list. + * @item: the item. + * @pos: the pos. + * + * Sets the value of list item at position @pos. The old value + * is destroyed. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecPtrListSet(xmlSecPtrListPtr list, xmlSecPtr item, xmlSecSize pos) { + xmlSecAssert2(xmlSecPtrListIsValid(list), -1); + xmlSecAssert2(list->data != NULL, -1); + xmlSecAssert2(pos < list->use, -1); + + if((list->id->destroyItem != NULL) && (list->data[pos] != NULL)) { + list->id->destroyItem(list->data[pos]); + } + list->data[pos] = item; + return(0); +} + +/** + * xmlSecPtrListRemove: + * @list: the pointer to list. + * @pos: the position. + * + * Destroys list item at the position @pos and sets it value to NULL. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecPtrListRemove(xmlSecPtrListPtr list, xmlSecSize pos) { + xmlSecAssert2(xmlSecPtrListIsValid(list), -1); + xmlSecAssert2(list->data != NULL, -1); + xmlSecAssert2(pos < list->use, -1); + + if((list->id->destroyItem != NULL) && (list->data[pos] != NULL)) { + list->id->destroyItem(list->data[pos]); + } + list->data[pos] = NULL; + if(pos == list->use - 1) { + --list->use; + } + return(0); +} + +/** + * xmlSecPtrListDebugDump: + * @list: the pointer to list. + * @output: the pointer to output FILE. + * + * Prints debug information about @list to the @output. + */ +void +xmlSecPtrListDebugDump(xmlSecPtrListPtr list, FILE* output) { + xmlSecAssert(xmlSecPtrListIsValid(list)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== list size: %d\n", list->use); + if(list->id->debugDumpItem != NULL) { + xmlSecSize pos; + + for(pos = 0; pos < list->use; ++pos) { + xmlSecAssert(list->data != NULL); + if(list->data[pos] != NULL) { + list->id->debugDumpItem(list->data[pos], output); + } + } + } +} + +/** + * xmlSecPtrListDebugXmlDump: + * @list: the pointer to list. + * @output: the pointer to output FILE. + * + * Prints debug information about @list to the @output in XML format. + */ +void +xmlSecPtrListDebugXmlDump(xmlSecPtrListPtr list, FILE* output) { + xmlSecAssert(xmlSecPtrListIsValid(list)); + xmlSecAssert(output != NULL); + + fprintf(output, "<List size=\"%d\">\n", list->use); + if(list->id->debugXmlDumpItem != NULL) { + xmlSecSize pos; + + for(pos = 0; pos < list->use; ++pos) { + xmlSecAssert(list->data != NULL); + if(list->data[pos] != NULL) { + list->id->debugXmlDumpItem(list->data[pos], output); + } + } + } + fprintf(output, "</List>\n"); +} + +static int +xmlSecPtrListEnsureSize(xmlSecPtrListPtr list, xmlSecSize size) { + xmlSecPtr* newData; + xmlSecSize newSize = 0; + + xmlSecAssert2(xmlSecPtrListIsValid(list), -1); + + if(size < list->max) { + return(0); + } + + switch(list->allocMode) { + case xmlSecAllocModeExact: + newSize = size + 8; + break; + case xmlSecAllocModeDouble: + newSize = 2 * size + 32; + break; + } + + if(newSize < gInitialSize) { + newSize = gInitialSize; + } + + if(list->data != NULL) { + newData = (xmlSecPtr*)xmlRealloc(list->data, sizeof(xmlSecPtr) * newSize); + } else { + newData = (xmlSecPtr*)xmlMalloc(sizeof(xmlSecPtr) * newSize); + } + if(newData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecPtrListGetName(list)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecPtr)*%d=%d", + newSize, sizeof(xmlSecPtr) * newSize); + return(-1); + } + + list->data = newData; + list->max = newSize; + + return(0); +} + +/*********************************************************************** + * + * strings list + * + **********************************************************************/ +static xmlSecPtr xmlSecStringListDuplicateItem (xmlSecPtr ptr); +static void xmlSecStringListDestroyItem (xmlSecPtr ptr); + +static xmlSecPtrListKlass xmlSecStringListKlass = { + BAD_CAST "strings-list", + xmlSecStringListDuplicateItem, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + xmlSecStringListDestroyItem, /* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecStringListGetKlass: + * + * The strins list class. + * + * Returns: strings list klass. + */ +xmlSecPtrListId +xmlSecStringListGetKlass(void) { + return(&xmlSecStringListKlass); +} + +static xmlSecPtr +xmlSecStringListDuplicateItem(xmlSecPtr ptr) { + xmlSecAssert2(ptr != NULL, NULL); + + return(xmlStrdup((xmlChar*)ptr)); +} + +static void +xmlSecStringListDestroyItem(xmlSecPtr ptr) { + xmlSecAssert(ptr != NULL); + + xmlFree(ptr); +} + + diff --git a/src/membuf.c b/src/membuf.c new file mode 100644 index 00000000..55053253 --- /dev/null +++ b/src/membuf.c @@ -0,0 +1,209 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Memory buffer transform + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keys.h> +#include <xmlsec/base64.h> +#include <xmlsec/membuf.h> +#include <xmlsec/errors.h> + + +/***************************************************************************** + * + * Memory Buffer Transform + * + * xmlSecBuffer is located after xmlSecTransform + * + ****************************************************************************/ +#define xmlSecTransformMemBufSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer)) +#define xmlSecTransformMemBufGetBuf(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecTransformMemBufSize)) ? \ + (xmlSecBufferPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \ + (xmlSecBufferPtr)NULL) + +static int xmlSecTransformMemBufInitialize (xmlSecTransformPtr transform); +static void xmlSecTransformMemBufFinalize (xmlSecTransformPtr transform); +static int xmlSecTransformMemBufExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static xmlSecTransformKlass xmlSecTransformMemBufKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecTransformMemBufSize, /* xmlSecSize objSize */ + + xmlSecNameMemBuf, /* const xmlChar* name; */ + NULL, /* const xmlChar* href; */ + 0, /* xmlSecAlgorithmUsage usage; */ + + xmlSecTransformMemBufInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformMemBufFinalize, /* xmlSecTransformFianlizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecTransformMemBufExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformMemBufGetKlass: + * + * The memory buffer transorm (used to store the data that go through it). + * + * Returns: memory buffer transform klass. + */ +xmlSecTransformId +xmlSecTransformMemBufGetKlass(void) { + return(&xmlSecTransformMemBufKlass); +} + +/** + * xmlSecTransformMemBufGetBuffer: + * @transform: the pointer to memory buffer transform. + * + * Gets the pointer to memory buffer transform buffer. + * + * Returns: pointer to the transform's #xmlSecBuffer. + */ +xmlSecBufferPtr +xmlSecTransformMemBufGetBuffer(xmlSecTransformPtr transform) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformMemBufId), NULL); + + buffer = xmlSecTransformMemBufGetBuf(transform); + xmlSecAssert2(buffer != NULL, NULL); + + return(buffer); +} + +static int +xmlSecTransformMemBufInitialize(xmlSecTransformPtr transform) { + xmlSecBufferPtr buffer; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformMemBufId), -1); + + buffer = xmlSecTransformMemBufGetBuf(transform); + xmlSecAssert2(buffer != NULL, -1); + + ret = xmlSecBufferInitialize(buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecTransformMemBufFinalize(xmlSecTransformPtr transform) { + xmlSecBufferPtr buffer; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformMemBufId)); + + buffer = xmlSecTransformMemBufGetBuf(transform); + xmlSecAssert(buffer != NULL); + + xmlSecBufferFinalize(xmlSecTransformMemBufGetBuf(transform)); +} + +static int +xmlSecTransformMemBufExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr buffer; + xmlSecBufferPtr in, out; + xmlSecSize inSize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformMemBufId), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + buffer = xmlSecTransformMemBufGetBuf(transform); + xmlSecAssert2(buffer != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + /* just copy everything from in to our buffer and out */ + ret = xmlSecBufferAppend(buffer, xmlSecBufferGetData(in), inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + ret = xmlSecBufferAppend(out, xmlSecBufferGetData(in), inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_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 != 0) { + transform->status = xmlSecTransformStatusFinished; + } + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(inSize == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + diff --git a/src/mscrypto/Makefile.am b/src/mscrypto/Makefile.am new file mode 100644 index 00000000..318af513 --- /dev/null +++ b/src/mscrypto/Makefile.am @@ -0,0 +1,58 @@ +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 =\ + app.c \ + certkeys.c \ + ciphers.c \ + crypto.c \ + digests.c \ + keysstore.c \ + kt_rsa.c \ + signatures.c \ + symkeys.c \ + x509.c \ + x509vfy.c \ + csp_calg.h \ + csp_oid.h \ + globals.h \ + xmlsec-mingw.h \ + $(NULL) + +if SHAREDLIB_HACK +libxmlsec1_mscrypto_la_SOURCES += ../strings.c +endif + +libxmlsec1_mscrypto_la_LIBADD = \ + ../libxmlsec1.la \ + $(MSCRYPTO_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(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..61a9b6f3 --- /dev/null +++ b/src/mscrypto/Makefile.in @@ -0,0 +1,760 @@ +# Makefile.in generated by automake 1.11 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)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +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 = app.c certkeys.c ciphers.c \ + crypto.c digests.c keysstore.c kt_rsa.c signatures.c symkeys.c \ + x509.c x509vfy.c csp_calg.h csp_oid.h globals.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-keysstore.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@ +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@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_ENABLED = @PKG_CONFIG_ENABLED@ +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_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_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 = app.c certkeys.c ciphers.c crypto.c \ + digests.c keysstore.c kt_rsa.c signatures.c symkeys.c x509.c \ + x509vfy.c csp_calg.h csp_oid.h globals.h xmlsec-mingw.h \ + $(NULL) $(am__append_1) +libxmlsec1_mscrypto_la_LIBADD = \ + ../libxmlsec1.la \ + $(MSCRYPTO_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(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-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-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-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-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..f7d45636 --- /dev/null +++ b/src/mscrypto/README @@ -0,0 +1,52 @@ +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) Missing crypto functionality: + - HMAC (http://bugzilla.gnome.org/show_bug.cgi?id=123670): does not look + like MS would support it soon. + - RSA-OAEP (http://bugzilla.gnome.org/show_bug.cgi?id=123671): MS says + that they will support this in the near future. + - AES KW (http://bugzilla.gnome.org/show_bug.cgi?id=123672): no native + support, might be possible to implement on top of AES cipher itself + - DES KW (http://bugzilla.gnome.org/show_bug.cgi?id=123673): no native + support, might be possible to implement on top of AES cipher itself + +3) Actual AES Crypto provider name is different from the "official" one +(http://bugzilla.gnome.org/show_bug.cgi?id=123674). + +4) 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..c3a4b0d8 --- /dev/null +++ b/src/mscrypto/app.c @@ -0,0 +1,1288 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +/* I don't see any other way then to use a global var to get the + * config info to the mscrypto keysstore :( WK + */ +static char *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) { + /* 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); + } + gXmlSecMSCryptoAppCertStoreName = xmlStrdup(config); + } + + 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. + */ +const char* +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) { + int ret, len; + 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; + + 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; + } + + len = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pwd, -1, NULL, 0); + if(len <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "MultiByteToWideChar", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + wcPwd = (WCHAR *)xmlMalloc((len + 1) * sizeof(WCHAR)); + if(wcPwd == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "len=%d", len); + goto done; + } + + ret = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pwd, -1, wcPwd, len); + if (ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "MultiByteToWideChar", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + 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..73a6c260 --- /dev/null +++ b/src/mscrypto/certkeys.c @@ -0,0 +1,2633 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +// 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 + +#define XMLSEC_CONTAINER_NAME "xmlsec-key-container" + +/************************************************************************** + * + * 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; + LPCTSTR providerName; + DWORD providerType; + 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_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 = 0; + if (!CryptAcquireContext(&hProv, + NULL, + NULL, /* ctx->providerName, */ + ctx->providerType, + CRYPT_VERIFYCONTEXT)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_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)); +} + +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)); +} + +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->providerName = ctxSrc->providerName; + ctxDst->providerType = ctxSrc->providerType; + 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; */ +}; + +/** + * 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->providerName = MS_ENHANCED_PROV; + ctx->providerType = PROV_RSA_FULL; + + 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 */ + if (!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, 0)) { + if(NTE_BAD_KEYSET == GetLastError()) { + if(!CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_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); + + if (!CryptAcquireContext(&hProv, XMLSEC_CONTAINER_NAME, MS_STRONG_PROV, PROV_RSA_FULL, 0)) { + if (NTE_BAD_KEYSET == GetLastError()) { + if(!CryptAcquireContext(&hProv, XMLSEC_CONTAINER_NAME, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + } + + 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; */ +}; + +/** + * 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->providerName = MS_DEF_DSS_PROV; + ctx->providerType = PROV_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 */ + + if (!CryptAcquireContext(&hProv, NULL, MS_DEF_DSS_PROV, PROV_DSS, 0)) { + if (NTE_BAD_KEYSET == GetLastError()) { + if (!CryptAcquireContext(&hProv, NULL, MS_DEF_DSS_PROV, PROV_DSS, CRYPT_NEWKEYSET)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_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); + + if(!CryptAcquireContext(&hProv, XMLSEC_CONTAINER_NAME, ctx->providerName, ctx->providerType, 0)) { + if (NTE_BAD_KEYSET == GetLastError()) { + if(!CryptAcquireContext(&hProv, XMLSEC_CONTAINER_NAME, ctx->providerName, ctx->providerType, CRYPT_NEWKEYSET)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_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; */ +}; + +/** + * 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; + HCRYPTPROV tmp_ctx = 0; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecMSCryptoKeyDataGost2001Id), xmlSecKeyDataTypeUnknown); + + xmlSecMSCryptoKeyDataInitialize(data); + + ctx = xmlSecMSCryptoKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + /* GOST Algorithm is provided by several CSP's, so we try to find any installed */ + if (CryptAcquireContext(&tmp_ctx, NULL, NULL, PROV_MAGPRO_GOST, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + ctx->providerName = "MagPro CSP"; + ctx->providerType = PROV_MAGPRO_GOST; + } else { + if (CryptAcquireContext(&tmp_ctx, NULL, NULL, PROV_CRYPTOPRO_GOST, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { + ctx->providerName = "CryptoPro CSP"; + ctx->providerType = PROV_CRYPTOPRO_GOST; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecMSCryptoKeyDataGost2001Initialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return -1; + } + } + CryptReleaseContext(tmp_ctx, 0); + 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..59161639 --- /dev/null +++ b/src/mscrypto/ciphers.c @@ -0,0 +1,1350 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +#ifndef MS_ENH_RSA_AES_PROV_PROTO +#define MS_ENH_RSA_AES_PROV_PROTO "Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)" +#endif /* MS_ENH_RSA_AES_PROV_PROTO */ + +static BOOL xmlSecMSCryptoCreatePrivateExponentOneKey (HCRYPTPROV hProv, + HCRYPTKEY *hPrivateKey); +static BOOL xmlSecMSCryptoImportPlainSessionBlob (HCRYPTPROV hProv, + HCRYPTKEY hPrivateKey, + ALG_ID dwAlgId, + LPBYTE pbKeyMaterial, + DWORD dwKeyMaterial, + HCRYPTKEY *hSessionKey); + +/************************************************************************** + * + * Internal MSCrypto Block cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecMSCryptoBlockCipherCtx xmlSecMSCryptoBlockCipherCtx, + *xmlSecMSCryptoBlockCipherCtxPtr; +struct _xmlSecMSCryptoBlockCipherCtx { + ALG_ID algorithmIdentifier; + int mode; + HCRYPTPROV cryptProvider; + HCRYPTKEY cryptKey; + HCRYPTKEY pubPrivKey; + xmlSecKeyDataId keyId; + LPCTSTR providerName; + int providerType; + int keyInitialized; + int ctxInitialized; + xmlSecSize keySize; +}; +/* 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->keyInitialized != 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); + +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; + + 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->providerName = MS_ENHANCED_PROV; + ctx->providerType = PROV_RSA_FULL; + 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->providerName = MS_ENH_RSA_AES_PROV_PROTO; + ctx->providerType = PROV_RSA_AES; + ctx->keySize = 16; + } else if(transform->id == xmlSecMSCryptoTransformAes192CbcId) { + ctx->algorithmIdentifier = CALG_AES_192; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providerName = MS_ENH_RSA_AES_PROV_PROTO; + ctx->providerType = PROV_RSA_AES; + ctx->keySize = 24; + } else if(transform->id == xmlSecMSCryptoTransformAes256CbcId) { + ctx->algorithmIdentifier = CALG_AES_256; + ctx->keyId = xmlSecMSCryptoKeyDataAesId; + ctx->providerName = MS_ENH_RSA_AES_PROV_PROTO; + ctx->providerType = PROV_RSA_AES; + ctx->keySize = 32; + } else +#endif /* XMLSEC_NO_AES */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(!CryptAcquireContext(&ctx->cryptProvider, NULL /*"xmlSecMSCryptoTempContainer"*/, + ctx->providerName, ctx->providerType, 0)) { + DWORD dwError = GetLastError(); + if (dwError == NTE_EXISTS) { + if (!CryptAcquireContext(&ctx->cryptProvider, "xmlSecMSCryptoTempContainer", + ctx->providerName, ctx->providerType, 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + return(-1); + } + } else if (dwError == 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) + */ + if(!CryptAcquireContext(&ctx->cryptProvider, NULL, ctx->providerName, + ctx->providerType, CRYPT_NEWKEYSET)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_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); + CryptAcquireContext(&ctx->cryptProvider, "xmlSecMSCryptoTempContainer", + MS_ENHANCED_PROV, ctx->providerType, CRYPT_DELETEKEYSET); + } + + 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->keyInitialized == 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, + &(ctx->cryptKey))) { + + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoImportPlainSessionBlob", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->keyInitialized = 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 */ + +/* + * 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 + * + * aleksey: also check "Base Provider Key BLOBs" article for priv key blob format + **/ +static 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; +} + +static BOOL +xmlSecMSCryptoImportPlainSessionBlob(HCRYPTPROV hProv, HCRYPTKEY hPrivateKey, + ALG_ID dwAlgId, LPBYTE pbKeyMaterial, + DWORD dwKeyMaterial, HCRYPTKEY *hSessionKey) { + ALG_ID dwPrivKeyAlg; + LPBYTE keyBlob = NULL; + DWORD keyBlobLen, rndBlobSize, dwSize, n; + PUBLICKEYSTRUC* pubKeyStruc; + ALG_ID* algId; + DWORD dwPublicKeySize; + DWORD dwProvSessionKeySize; + 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; + } + + /* 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; + + /* Our key is too big, leave */ + if ((dwKeyMaterial * 8) > dwProvSessionKeySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "dwKeyMaterial=%ld;dwProvSessionKeySize=%ld", + dwKeyMaterial, dwProvSessionKeySize); + goto done; + } + + /* 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); +} + diff --git a/src/mscrypto/crypto.c b/src/mscrypto/crypto.c new file mode 100644 index 00000000..d60d3c60 --- /dev/null +++ b/src/mscrypto/crypto.c @@ -0,0 +1,387 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#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_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 + */ +#ifndef XMLSEC_NO_AES + gXmlSecMSCryptoFunctions->transformAes128CbcGetKlass = xmlSecMSCryptoTransformAes128CbcGetKlass; + gXmlSecMSCryptoFunctions->transformAes192CbcGetKlass = xmlSecMSCryptoTransformAes192CbcGetKlass; + gXmlSecMSCryptoFunctions->transformAes256CbcGetKlass = xmlSecMSCryptoTransformAes256CbcGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecMSCryptoFunctions->transformDes3CbcGetKlass = xmlSecMSCryptoTransformDes3CbcGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_RSA + gXmlSecMSCryptoFunctions->transformRsaSha1GetKlass = xmlSecMSCryptoTransformRsaSha1GetKlass; + gXmlSecMSCryptoFunctions->transformRsaPkcs1GetKlass = xmlSecMSCryptoTransformRsaPkcs1GetKlass; +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_DSA + gXmlSecMSCryptoFunctions->transformDsaSha1GetKlass = xmlSecMSCryptoTransformDsaSha1GetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + gXmlSecMSCryptoFunctions->transformGost2001GostR3411_94GetKlass = xmlSecMSCryptoTransformGost2001GostR3411_94GetKlass; +#endif /* XMLSEC_NO_GOST */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecMSCryptoFunctions->transformSha1GetKlass = xmlSecMSCryptoTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_GOST + gXmlSecMSCryptoFunctions->transformGostR3411_94GetKlass = xmlSecMSCryptoTransformGostR3411_94GetKlass; +#endif /* XMLSEC_NO_GOST */ + + /** + * 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); +} + + +/** + * 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); + } + + if (FALSE == CryptAcquireContext(&hProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CryptAcquireContext", + XMLSEC_ERRORS_R_CRYPTO_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); +} + +/** + * 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; + LPVOID lpMsgBuf; + xmlChar buf[500]; + + dwError = GetLastError(); + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dwError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) &lpMsgBuf, + 0, + NULL); + if((msg != NULL) && ((*msg) != '\0')) { + xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "%s;last error=%d (0x%08x);last error msg=%s", msg, dwError, dwError, (LPTSTR)lpMsgBuf); + } else { + xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "last error=%d (0x%08x);last error msg=%s", dwError, dwError, (LPTSTR)lpMsgBuf); + } + xmlSecErrorsDefaultCallback(file, line, func, + errorObject, errorSubject, + reason, (char*)buf); + + LocalFree(lpMsgBuf); +} + +/** + * 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. + */ +BYTE* +xmlSecMSCryptoCertStrToName(DWORD dwCertEncodingType, LPCTSTR 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((*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); +} + + diff --git a/src/mscrypto/csp_calg.h b/src/mscrypto/csp_calg.h new file mode 100644 index 00000000..139b722a --- /dev/null +++ b/src/mscrypto/csp_calg.h @@ -0,0 +1,92 @@ +/** + * 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 PROV_CRYPTOPRO_GOST 75 + +/*! @} */ +/*! \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..d3cd19e8 --- /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..19acc658 --- /dev/null +++ b/src/mscrypto/digests.c @@ -0,0 +1,413 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#define MSCRYPTO_MAX_HASH_SIZE 256 + +typedef struct _xmlSecMSCryptoDigestCtx xmlSecMSCryptoDigestCtx, *xmlSecMSCryptoDigestCtxPtr; +struct _xmlSecMSCryptoDigestCtx { + HCRYPTPROV provider; + ALG_ID alg_id; + 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); + + +static int +xmlSecMSCryptoDigestCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + +#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_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformSha1Id)) { + ctx->alg_id = CALG_SHA; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_GOST + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGostR3411_94Id)) { + ctx->alg_id = CALG_MAGPRO_HASH_R3411_94; + + /* TODO: Check what provider is best suited here.... */ + if (!CryptAcquireContext(&ctx->provider, NULL, 0, PROV_MAGPRO_GOST, CRYPT_VERIFYCONTEXT)) { + if (!CryptAcquireContext(&ctx->provider, NULL, 0, PROV_CRYPTOPRO_GOST, CRYPT_VERIFYCONTEXT)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); + } else +#endif /* XMLSEC_NO_GOST*/ + + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* TODO: Check what provider is best suited here.... */ + if (!CryptAcquireContext(&ctx->provider, NULL, MS_STRONG_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + if (!CryptAcquireContext(&ctx->provider, NULL, MS_ENHANCED_PROV,PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_CRYPTO_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); + } + 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)), + "CryptHashData", + 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", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + 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_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_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..b58931d5 --- /dev/null +++ b/src/mscrypto/globals.h @@ -0,0 +1,24 @@ +/* + * XML Security Library + * + * globals.h: internal header only used during the compilation + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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 + +#endif /* ! __XMLSEC_GLOBALS_H__ */ diff --git a/src/mscrypto/keysstore.c b/src/mscrypto/keysstore.c new file mode 100644 index 00000000..6e2401b4 --- /dev/null +++ b/src/mscrypto/keysstore.c @@ -0,0 +1,678 @@ +/** + * 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. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +#define XMLSEC_MSCRYPTO_APP_DEFAULT_CERT_STORE_NAME "MY" + +/**************************************************************************** + * + * 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) { + const char* storeName; + HCERTSTORE hStoreHandle = NULL; + PCCERT_CONTEXT pCertContext = 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); + } + + /* first attempt: search by cert id == name */ + if(pCertContext == NULL) { + size_t len = xmlStrlen(name) + 1; + wchar_t * lpCertID; + + /* aleksey todo: shouldn't we call MultiByteToWideChar first to get the buffer size? */ + lpCertID = (wchar_t *)xmlMalloc(sizeof(wchar_t) * len); + if(lpCertID == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(hStoreHandle, 0); + return(NULL); + } + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, lpCertID, len); + + pCertContext = CertFindCertificateInStore( + hStoreHandle, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_STR, + lpCertID, + NULL); + xmlFree(lpCertID); + } + + /* We don't give up easily, now try to fetch the cert with a full blown + * subject dn + */ + if (NULL == pCertContext) { + BYTE* bdata; + DWORD len; + + bdata = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + name, + CERT_OID_NAME_STR, + &len); + if(bdata != NULL) { + CERT_NAME_BLOB cnb; + + cnb.cbData = len; + cnb.pbData = bdata; + + pCertContext = CertFindCertificateInStore(hStoreHandle, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } + + /* We don't give up easily, now try to fetch the cert with a full blown + * subject dn, and try with a reversed dn + */ + if (NULL == pCertContext) { + BYTE* bdata; + DWORD len; + + bdata = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + name, + CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &len); + if(bdata != NULL) { + CERT_NAME_BLOB cnb; + + cnb.cbData = len; + cnb.pbData = bdata; + + pCertContext = CertFindCertificateInStore(hStoreHandle, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(bdata); + } + } + + /* + * Try ro find certificate with name="Friendly Name" + */ + if (NULL == pCertContext) { + DWORD dwPropSize; + PBYTE pbFriendlyName; + PCCERT_CONTEXT pCertCtxIter = NULL; + size_t len = xmlStrlen(name) + 1; + wchar_t * lpFName; + + lpFName = (wchar_t *)xmlMalloc(sizeof(wchar_t) * len); + if(lpFName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CertCloseStore(hStoreHandle, 0); + return(NULL); + } + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, name, -1, lpFName, len); + + 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(lpFName); + CertCloseStore(hStoreHandle, 0); + return(NULL); + } + if (TRUE != CertGetCertificateContextProperty(pCertCtxIter, + CERT_FRIENDLY_NAME_PROP_ID, + pbFriendlyName, + &dwPropSize)) { + xmlFree(pbFriendlyName); + continue; + } + + /* Compare FriendlyName to name */ + if (!wcscmp(lpFName, (const wchar_t *)pbFriendlyName)) { + pCertContext = pCertCtxIter; + xmlFree(pbFriendlyName); + break; + } + xmlFree(pbFriendlyName); + } + + xmlFree(lpFName); + } + + /* 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? */ + 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..ec86ac53 --- /dev/null +++ b/src/mscrypto/kt_rsa.c @@ -0,0 +1,410 @@ +/** + * + * XMLSec library + * + * RSA Algorithms support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +/************************************************************************** + * + * Internal MSCRYPTO RSA PKCS1 CTX + * + *************************************************************************/ +typedef struct _xmlSecMSCryptoRsaPkcs1Ctx xmlSecMSCryptoRsaPkcs1Ctx, + *xmlSecMSCryptoRsaPkcs1CtxPtr; +struct _xmlSecMSCryptoRsaPkcs1Ctx { + xmlSecKeyDataPtr data; + DWORD typeFlags; +}; + +/********************************************************************* + * + * RSA PKCS1 key transport transform + * + * xmlSecMSCryptoRsaPkcs1Ctx is located after xmlSecTransform + * + ********************************************************************/ +#define xmlSecMSCryptoRsaPkcs1Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecMSCryptoRsaPkcs1Ctx)) +#define xmlSecMSCryptoRsaPkcs1GetCtx(transform) \ + ((xmlSecMSCryptoRsaPkcs1CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecMSCryptoRsaPkcs1Initialize (xmlSecTransformPtr transform); +static void xmlSecMSCryptoRsaPkcs1Finalize (xmlSecTransformPtr transform); +static int xmlSecMSCryptoRsaPkcs1SetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecMSCryptoRsaPkcs1SetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecMSCryptoRsaPkcs1Execute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecMSCryptoRsaPkcs1Process (xmlSecTransformPtr transform, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecMSCryptoRsaPkcs1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecMSCryptoRsaPkcs1Size, /* xmlSecSize objSize */ + + xmlSecNameRsaPkcs1, /* const xmlChar* name; */ + xmlSecHrefRsaPkcs1, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecMSCryptoRsaPkcs1Initialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecMSCryptoRsaPkcs1Finalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecMSCryptoRsaPkcs1SetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecMSCryptoRsaPkcs1SetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecMSCryptoRsaPkcs1Execute, /* 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); +} + +static int +xmlSecMSCryptoRsaPkcs1Initialize(xmlSecTransformPtr transform) { + xmlSecMSCryptoRsaPkcs1CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1Size), -1); + + ctx = xmlSecMSCryptoRsaPkcs1GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecMSCryptoRsaPkcs1Ctx)); + return(0); +} + +static void +xmlSecMSCryptoRsaPkcs1Finalize(xmlSecTransformPtr transform) { + xmlSecMSCryptoRsaPkcs1CtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1Size)); + + ctx = xmlSecMSCryptoRsaPkcs1GetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (ctx->data != NULL) { + xmlSecKeyDataDestroy(ctx->data); + ctx->data = NULL; + } + + memset(ctx, 0, sizeof(xmlSecMSCryptoRsaPkcs1Ctx)); +} + +static int +xmlSecMSCryptoRsaPkcs1SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecMSCryptoRsaPkcs1CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1Size), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1GetCtx(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 +xmlSecMSCryptoRsaPkcs1SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecMSCryptoRsaPkcs1CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1Size), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecMSCryptoKeyDataRsaId), -1); + + ctx = xmlSecMSCryptoRsaPkcs1GetCtx(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 +xmlSecMSCryptoRsaPkcs1Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoRsaPkcs1CtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1GetCtx(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 = xmlSecMSCryptoRsaPkcs1Process(transform, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecMSCryptoRsaPkcs1Process", + 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 +xmlSecMSCryptoRsaPkcs1Process(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { + xmlSecMSCryptoRsaPkcs1CtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + xmlSecSize keySize; + int ret; + HCRYPTKEY hKey = 0; + DWORD dwInLen; + DWORD dwBufLen; + DWORD dwOutLen; + BYTE * outBuf; + BYTE * inBuf; + int i; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecMSCryptoRsaPkcs1Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecMSCryptoRsaPkcs1GetCtx(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) { + BYTE ch; + + 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); + if (!CryptEncrypt(hKey, 0, TRUE, 0, 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. + */ + for(i = 0; i < outSize / 2; i++) { + ch = outBuf[i]; + outBuf[i] = outBuf[outSize - (i + 1)]; + outBuf[outSize - (i + 1)] = ch; + } + } 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); + + xmlSecAssert2(inBuf != 0, -1); + xmlSecAssert2(outBuf != 0, -1); + for (i = 0; i < inSize; i++) { + outBuf[i] = inBuf[inSize - (i + 1)]; + } + + if (0 == (hKey = xmlSecMSCryptoKeyDataGetDecryptKey(ctx->data))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoKeyDataGetKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (-1); + } + if (!CryptDecrypt(hKey, 0, TRUE, 0, 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); +} + +#endif /* XMLSEC_NO_RSA */ + diff --git a/src/mscrypto/mingw-crypt32.def b/src/mscrypto/mingw-crypt32.def new file mode 100644 index 00000000..0857d558 --- /dev/null +++ b/src/mscrypto/mingw-crypt32.def @@ -0,0 +1,32 @@ +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 + CertGetPublicKeyLength@8 = crypt32.CertGetPublicKeyLength + CertNameToStrA@20 = crypt32.CertNameToStrA + CertOpenStore@20 = crypt32.CertOpenStore + CertOpenSystemStoreA@8 = crypt32.CertOpenSystemStoreA + CertStrToNameA@28 = crypt32.CertStrToNameA + 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/signatures.c b/src/mscrypto/signatures.c new file mode 100644 index 00000000..a567db7d --- /dev/null +++ b/src/mscrypto/signatures.c @@ -0,0 +1,663 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +/*FIXME: include header files*/ +extern HCRYPTPROV xmlSecMSCryptoKeyDataGetMSCryptoProvider(xmlSecKeyDataPtr data); +extern DWORD xmlSecMSCryptoKeyDataGetMSCryptoKeySpec(xmlSecKeyDataPtr data); + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +/************************************************************************** + * + * 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_GOST + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + return(1); + } +#endif /* XMLSEC_NO_GOST*/ + +#ifndef XMLSEC_NO_RSA + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_RSA */ + + 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_RSA + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + ctx->digestAlgId = CALG_SHA1; + ctx->keyId = xmlSecMSCryptoKeyDataRsaId; + } else +#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*/ + +#ifndef XMLSEC_NO_DSA + if(xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) { + ctx->digestAlgId = CALG_SHA1; + ctx->keyId = xmlSecMSCryptoKeyDataDsaId; + } else +#endif /* XMLSEC_NO_DSA */ + + if(1) { + 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; + HCRYPTKEY hKey; + DWORD dwError; + BYTE *tmpBuf, *j, *k, *l, *m; + 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 */ + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) { + j = (BYTE *)data; + k = (BYTE *)data + 20; + l = tmpBuf + 19; + m = tmpBuf + 39; + while (l >= tmpBuf) { + *l-- = *j++; + *m-- = *k++; + } +#ifndef XMLSEC_NO_GOST + } else if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + j = (BYTE *)data; + l = tmpBuf + dataSize - 1; + while (l >= tmpBuf) { + *l-- = *j++; + } +#endif /*ndef XMLSEC_NO_GOST*/ + } else if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + j = (BYTE *)data; + l = tmpBuf + dataSize - 1; + while (l >= tmpBuf) { + *l-- = *j++; + } + } else { + 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, *i, *j, *m, *n; + + 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); + + /* Now encode into a signature block, + * convert signature value to big endian */ + if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformDsaSha1Id)) { + i = tmpBuf; + j = tmpBuf + 20; + m = outBuf + 19; + n = outBuf + 39; + while (m >= outBuf) { + *m-- = *i++; + *n-- = *j++; + } +#ifndef XMLSEC_NO_GOST + } else if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformGost2001GostR3411_94Id)) { + i = tmpBuf; + j = outBuf + dwSigLen - 1; + + while (j >= outBuf) { + *j-- = *i++; + } +#endif /*ndef XMLSEC_NO_GOST*/ + } else if (xmlSecTransformCheckId(transform, xmlSecMSCryptoTransformRsaSha1Id)) { + i = tmpBuf; + j = outBuf + dwSigLen - 1; + + while (j >= outBuf) { + *j-- = *i++; + } + } else { + /* 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 +/**************************************************************************** + * + * 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_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..371c52de --- /dev/null +++ b/src/mscrypto/symkeys.c @@ -0,0 +1,333 @@ +/** + * + * XMLSec library + * + * DES Algorithm support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +/***************************************************************************** + * + * 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, + size_t bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoSymKeyDataBinWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + unsigned char** buf, + size_t* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecMSCryptoSymKeyDataGenerate (xmlSecKeyDataPtr data, + size_t sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecMSCryptoSymKeyDataGetType(xmlSecKeyDataPtr data); +static size_t xmlSecMSCryptoSymKeyDataGetSize (xmlSecKeyDataPtr data); +static void xmlSecMSCryptoSymKeyDataDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecMSCryptoSymKeyDataDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); +static int xmlSecMSCryptoSymKeyDataKlassCheck (xmlSecKeyDataKlass* klass); + +#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 */ + +/* + * 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, size_t bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinRead(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecMSCryptoSymKeyDataBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + unsigned char** buf, size_t* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecMSCryptoSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinWrite(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecMSCryptoSymKeyDataGenerate(xmlSecKeyDataPtr data, size_t 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 size_t +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); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(klass == xmlSecMSCryptoKeyDataAesId) { + return(1); + } +#endif /* XMLSEC_NO_AES */ + + return(0); +} diff --git a/src/mscrypto/x509.c b/src/mscrypto/x509.c new file mode 100644 index 00000000..e065590e --- /dev/null +++ b/src/mscrypto/x509.c @@ -0,0 +1,2270 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + + +/************************************************************************* + * + * 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) { + xmlChar *res = NULL; + char *str; + 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); + str = (char *)xmlMalloc(csz); + if (NULL == str) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + csz = CertNameToStr(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, nm, CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, str, csz); + if (csz < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CertNameToStr", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(NULL); + } + + /* aleksey: this is a hack, but mscrypto can not read E= flag and wants Email= instead. + * don't ask me how is it possible not to read something you wrote yourself but also + * see comment in the xmlSecMSCryptoX509FindCert function. + */ + if(strncmp(str, "E=", 2) == 0) { + res = xmlMalloc(strlen(str) + 13 + 1); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", + strlen(str) + 13 + 1); + xmlFree(str); + return(NULL); + } + + memcpy(res, "emailAddress=", 13); + strcpy(res + 13, BAD_CAST (str + 2)); + } else { + res = xmlStrdup(BAD_CAST str); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(str); + return(NULL); + } + } + xmlFree(str); + 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; + LPSTR subject, issuer; + DWORD dwSize; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + /* todo: add error checks */ + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, NULL, 0); + subject = (LPSTR)xmlMalloc(dwSize); + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, subject, dwSize); + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0); + issuer = (LPSTR)xmlMalloc(dwSize); + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, CERT_NAME_ISSUER_FLAG, NULL, issuer, dwSize); + + fprintf(output, "=== X509 Certificate\n"); + fprintf(output, "==== Subject Name: %s\n", subject); + fprintf(output, "==== Issuer Name: %s\n", issuer); + if (subject) xmlFree(subject); + if (issuer) xmlFree(issuer); + 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"); +} + + +static void +xmlSecMSCryptoX509CertDebugXmlDump(PCCERT_CONTEXT cert, FILE* output) { + PCRYPT_INTEGER_BLOB sn; + unsigned int i; + LPSTR subject, issuer; + DWORD dwSize; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + /* todo: add error checks */ + + /* subject */ + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, NULL, 0); + subject = (LPSTR)xmlMalloc(dwSize); + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, subject, dwSize); + + fprintf(output, "<SubjectName>"); + xmlSecPrintXmlString(output, BAD_CAST subject); + fprintf(output, "</SubjectName>\n"); + xmlFree(subject); + + + /* issuer */ + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0); + issuer = (LPSTR)xmlMalloc(dwSize); + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, CERT_NAME_ISSUER_FLAG, NULL, issuer, dwSize); + + fprintf(output, "<IssuerName>"); + xmlSecPrintXmlString(output, BAD_CAST issuer); + fprintf(output, "</IssuerName>\n"); + xmlFree(issuer); + + /* 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"); +} + + +/************************************************************************** + * + * 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..d854e7a0 --- /dev/null +++ b/src/mscrypto/x509vfy.c @@ -0,0 +1,1062 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyrigth (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> + +#if defined(__MINGW32__) +# include "xmlsec-mingw.h" +#endif + +/************************************************************************** + * + * 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, + xmlChar *subjectName, + xmlChar *issuerName, + xmlChar *issuerSerial, + 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) { + LPSTR subject; + DWORD dwSize; + + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecMSCryptoX509StoreId)); + xmlSecAssert(cert != NULL); + xmlSecAssert(flags != 0); + + /* get certs subject */ + dwSize = CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, NULL, 0); + subject = xmlMalloc(dwSize + 1); + if(subject == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return; + } + memset(subject, 0, dwSize + 1); + if(dwSize > 0) { + CertGetNameString(cert, CERT_NAME_RDN_TYPE, 0, NULL, subject, dwSize); + } + + /* 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 + * + *****************************************************************************/ +static PCCERT_CONTEXT +xmlSecMSCryptoX509FindCert(HCERTSTORE store, xmlChar *subjectName, xmlChar *issuerName, + xmlChar *issuerSerial, xmlChar *ski) { + PCCERT_CONTEXT pCert = NULL; + int ret; + + xmlSecAssert2(store != 0, NULL); + + if((pCert == NULL) && (NULL != subjectName)) { + CERT_NAME_BLOB cnb; + BYTE *cName; + DWORD cNameLen; + + cName = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + subjectName, + CERT_OID_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &cNameLen); + if(cName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoCertStrToName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + cnb.pbData = cName; + cnb.cbData = cNameLen; + pCert = CertFindCertificateInStore(store, + PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_NAME, + &cnb, + NULL); + xmlFree(cName); + } + + if((pCert == NULL) && (NULL != issuerName) && (NULL != issuerSerial)) { + xmlSecBn issuerSerialBn; + xmlChar * p; + CERT_INFO certInfo; + CERT_NAME_BLOB cnb; + BYTE *cName = NULL; + DWORD cNameLen = 0; + + /* aleksey: for some unknown to me reasons, mscrypto wants Email + * instead of emailAddress. 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. + * Also see xmlSecMSCryptoX509NameWrite function. + */ + while( (p = (xmlChar*)xmlStrstr(issuerName, BAD_CAST "emailAddress=")) != NULL) { + memcpy(p, " Email=", 13); + } + + + + /* get issuer name */ + cName = xmlSecMSCryptoCertStrToName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + issuerName, + CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG | CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG, + &cNameLen); + if(cName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecMSCryptoCertStrToName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + cnb.pbData = cName; + cnb.cbData = cNameLen; + + /* 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); + xmlFree(cName); + 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); + xmlFree(cName); + 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); + xmlFree(cName); + return(NULL); + } + + certInfo.Issuer.cbData = cnb.cbData ; + certInfo.Issuer.pbData = cnb.pbData ; + certInfo.SerialNumber.cbData = xmlSecBnGetSize( &issuerSerialBn ) ; + certInfo.SerialNumber.pbData = xmlSecBnGetData( &issuerSerialBn ) ; + + pCert = CertFindCertificateInStore( + store, + X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, + 0, + CERT_FIND_SUBJECT_CERT, + &certInfo, + NULL + ) ; + + xmlFree(cName); + 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); +} + + +#endif /* XMLSEC_NO_X509 */ + + diff --git a/src/mscrypto/xmlsec-mingw.h b/src/mscrypto/xmlsec-mingw.h new file mode 100644 index 00000000..85d8cc3d --- /dev/null +++ b/src/mscrypto/xmlsec-mingw.h @@ -0,0 +1,165 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2007 Roumen Petrov. + */ + +#ifndef __XMLSEC_MSCRYPTO_XMLSEC_MINGW_H__ +#define __XMLSEC_MSCRYPTO_XMLSEC_MINGW_H__ + + +/*defines*/ +#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__*/ diff --git a/src/nodeset.c b/src/nodeset.c new file mode 100644 index 00000000..74c2d5b3 --- /dev/null +++ b/src/nodeset.c @@ -0,0 +1,599 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Enchanced nodes set + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/nodeset.h> +#include <xmlsec/errors.h> + +#define xmlSecGetParent(node) \ + (((node)->type != XML_NAMESPACE_DECL) ? \ + (node)->parent : \ + (xmlNodePtr)((xmlNsPtr)(node))->next) + +static int xmlSecNodeSetOneContains (xmlSecNodeSetPtr nset, + xmlNodePtr node, + xmlNodePtr parent); +static int xmlSecNodeSetWalkRecursive (xmlSecNodeSetPtr nset, + xmlSecNodeSetWalkCallback walkFunc, + void* data, + xmlNodePtr cur, + xmlNodePtr parent); + +/** + * xmlSecNodeSetCreate: + * @doc: the pointer to parent XML document. + * @nodes: the list of nodes. + * @type: the nodes set type. + * + * Creates new nodes set. Caller is responsible for freeng returend object + * by calling #xmlSecNodeSetDestroy function. + * + * Returns: pointer to newly allocated node set or NULL if an error occurs. + */ +xmlSecNodeSetPtr +xmlSecNodeSetCreate(xmlDocPtr doc, xmlNodeSetPtr nodes, xmlSecNodeSetType type) { + xmlSecNodeSetPtr nset; + + nset = (xmlSecNodeSetPtr)xmlMalloc(sizeof(xmlSecNodeSet)); + if(nset == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecNodeSet)=%d", + sizeof(xmlSecNodeSet)); + return(NULL); + } + memset(nset, 0, sizeof(xmlSecNodeSet)); + + nset->doc = doc; + nset->nodes = nodes; + nset->type = type; + nset->next = nset->prev = nset; + return(nset); +} + +/** + * xmlSecNodeSetDestroy: + * @nset: the pointer to node set. + * + * Destroys the nodes set created with #xmlSecNodeSetCreate function. + */ +void +xmlSecNodeSetDestroy(xmlSecNodeSetPtr nset) { + xmlSecNodeSetPtr tmp; + + xmlSecAssert(nset != NULL); + + while((tmp = nset) != NULL) { + if((nset->next != NULL) && (nset->next != nset)) { + nset->next->prev = nset->prev; + nset->prev->next = nset->next; + nset = nset->next; + } else { + nset = NULL; + } + + if(tmp->nodes != NULL) { + xmlXPathFreeNodeSet(tmp->nodes); + } + if(tmp->children != NULL) { + xmlSecNodeSetDestroy(tmp->children); + } + if((tmp->doc != NULL) && (tmp->destroyDoc != 0)) { + xmlFreeDoc(tmp->doc); + } + memset(tmp, 0, sizeof(xmlSecNodeSet)); + xmlFree(tmp); + } +} + +/** + * xmlSecNodeSetDocDestroy: + * @nset: the pointer to node set. + * + * Instructs node set to destroy nodes parent doc when node set is destroyed. + */ +void +xmlSecNodeSetDocDestroy(xmlSecNodeSetPtr nset) { + xmlSecAssert(nset != NULL); + + nset->destroyDoc = 1; +} + +static int +xmlSecNodeSetOneContains(xmlSecNodeSetPtr nset, xmlNodePtr node, xmlNodePtr parent) { + int in_nodes_set = 1; + + xmlSecAssert2(nset != NULL, 0); + xmlSecAssert2(node != NULL, 0); + + /* special cases: */ + switch(nset->type) { + case xmlSecNodeSetTreeWithoutComments: + case xmlSecNodeSetTreeWithoutCommentsInvert: + if(node->type == XML_COMMENT_NODE) { + return(0); + } + break; + case xmlSecNodeSetList: + return(xmlSecNodeSetContains(nset->children, node, parent)); + default: + break; + } + + if(nset->nodes != NULL) { + if(node->type != XML_NAMESPACE_DECL) { + in_nodes_set = xmlXPathNodeSetContains(nset->nodes, node); + } else { + xmlNs ns; + + memcpy(&ns, node, sizeof(ns)); + + /* this is a libxml hack! check xpath.c for details */ + if((parent != NULL) && (parent->type == XML_ATTRIBUTE_NODE)) { + ns.next = (xmlNsPtr)parent->parent; + } else { + ns.next = (xmlNsPtr)parent; + } + + /* + * If the input is an XPath node-set, then the node-set must explicitly + * contain every node to be rendered to the canonical form. + */ + in_nodes_set = (xmlXPathNodeSetContains(nset->nodes, (xmlNodePtr)&ns)); + } + } + + switch(nset->type) { + case xmlSecNodeSetNormal: + return(in_nodes_set); + case xmlSecNodeSetInvert: + return(!in_nodes_set); + case xmlSecNodeSetTree: + case xmlSecNodeSetTreeWithoutComments: + if(in_nodes_set) { + return(1); + } + if((parent != NULL) && (parent->type == XML_ELEMENT_NODE)) { + return(xmlSecNodeSetOneContains(nset, parent, parent->parent)); + } + return(0); + case xmlSecNodeSetTreeInvert: + case xmlSecNodeSetTreeWithoutCommentsInvert: + if(in_nodes_set) { + return(0); + } + if((parent != NULL) && (parent->type == XML_ELEMENT_NODE)) { + return(xmlSecNodeSetOneContains(nset, parent, parent->parent)); + } + return(1); + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "type=%d", nset->type); + } + + return(0); +} + +/** + * xmlSecNodeSetContains: + * @nset: the pointer to node set. + * @node: the pointer to XML node to check. + * @parent: the pointer to @node parent node. + * + * Checks whether the @node is in the nodes set or not. + * + * Returns: 1 if the @node is in the nodes set @nset, 0 if it is not + * and a negative value if an error occurs. + */ +int +xmlSecNodeSetContains(xmlSecNodeSetPtr nset, xmlNodePtr node, xmlNodePtr parent) { + int status = 1; + xmlSecNodeSetPtr cur; + + xmlSecAssert2(node != NULL, 0); + + /* special cases: */ + if(nset == NULL) { + return(1); + } + + status = 1; + cur = nset; + do { + switch(cur->op) { + case xmlSecNodeSetIntersection: + if(status && !xmlSecNodeSetOneContains(cur, node, parent)) { + status = 0; + } + break; + case xmlSecNodeSetSubtraction: + if(status && xmlSecNodeSetOneContains(cur, node, parent)) { + status = 0; + } + break; + case xmlSecNodeSetUnion: + if(!status && xmlSecNodeSetOneContains(cur, node, parent)) { + status = 1; + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_OPERATION, + "operation=%d", cur->op); + return(-1); + } + cur = cur->next; + } while(cur != nset); + + return(status); +} + +/** + * xmlSecNodeSetAdd: + * @nset: the pointer to currrent nodes set (or NULL). + * @newNSet: the pointer to new nodes set. + * @op: the operation type. + * + * Adds @newNSet to the @nset using operation @op. + * + * Returns: the pointer to combined nodes set or NULL if an error + * occurs. + */ +xmlSecNodeSetPtr +xmlSecNodeSetAdd(xmlSecNodeSetPtr nset, xmlSecNodeSetPtr newNSet, + xmlSecNodeSetOp op) { + xmlSecAssert2(newNSet != NULL, NULL); + xmlSecAssert2(newNSet->next == newNSet, NULL); + + newNSet->op = op; + if(nset == NULL) { + return(newNSet); + } + + newNSet->next = nset; + newNSet->prev = nset->prev; + nset->prev->next = newNSet; + nset->prev = newNSet; + return(nset); +} + +/** + * xmlSecNodeSetAddList: + * @nset: the pointer to currrent nodes set (or NULL). + * @newNSet: the pointer to new nodes set. + * @op: the operation type. + * + * Adds @newNSet to the @nset as child using operation @op. + * + * Returns: the pointer to combined nodes set or NULL if an error + * occurs. + */ +xmlSecNodeSetPtr +xmlSecNodeSetAddList(xmlSecNodeSetPtr nset, xmlSecNodeSetPtr newNSet, xmlSecNodeSetOp op) { + xmlSecNodeSetPtr tmp1, tmp2; + + xmlSecAssert2(newNSet != NULL, NULL); + + tmp1 = xmlSecNodeSetCreate(newNSet->doc, NULL, xmlSecNodeSetList); + if(tmp1 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + tmp1->children = newNSet; + + tmp2 = xmlSecNodeSetAdd(nset, tmp1, op); + if(tmp2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecNodeSetDestroy(tmp1); + return(NULL); + } + return(tmp2); +} + + +/** + * xmlSecNodeSetWalk: + * @nset: the pointer to node set. + * @walkFunc: the callback functions. + * @data: the application specific data passed to the @walkFunc. + * + * Calls the function @walkFunc once per each node in the nodes set @nset. + * If the @walkFunc returns a negative value, then the walk procedure + * is interrupted. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNodeSetWalk(xmlSecNodeSetPtr nset, xmlSecNodeSetWalkCallback walkFunc, void* data) { + xmlNodePtr cur; + int ret = 0; + + xmlSecAssert2(nset != NULL, -1); + xmlSecAssert2(nset->doc != NULL, -1); + xmlSecAssert2(walkFunc != NULL, -1); + + /* special cases */ + if(nset->nodes != NULL) { + int i; + + switch(nset->type) { + case xmlSecNodeSetNormal: + case xmlSecNodeSetTree: + case xmlSecNodeSetTreeWithoutComments: + for(i = 0; (ret >= 0) && (i < nset->nodes->nodeNr); ++i) { + ret = xmlSecNodeSetWalkRecursive(nset, walkFunc, data, + nset->nodes->nodeTab[i], + xmlSecGetParent(nset->nodes->nodeTab[i])); + } + return(ret); + default: + break; + } + } + + for(cur = nset->doc->children; (cur != NULL) && (ret >= 0); cur = cur->next) { + ret = xmlSecNodeSetWalkRecursive(nset, walkFunc, data, cur, xmlSecGetParent(cur)); + } + return(ret); +} + +static int +xmlSecNodeSetWalkRecursive(xmlSecNodeSetPtr nset, xmlSecNodeSetWalkCallback walkFunc, + void* data, xmlNodePtr cur, xmlNodePtr parent) { + int ret; + + xmlSecAssert2(nset != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + xmlSecAssert2(walkFunc != NULL, -1); + + /* the node itself */ + if(xmlSecNodeSetContains(nset, cur, parent)) { + ret = walkFunc(nset, cur, parent, data); + + if(ret < 0) { + return(ret); + } + } + + /* element node has attributes, namespaces */ + if(cur->type == XML_ELEMENT_NODE) { + xmlAttrPtr attr; + xmlNodePtr node; + xmlNsPtr ns, tmp; + + attr = (xmlAttrPtr)cur->properties; + while(attr != NULL) { + if(xmlSecNodeSetContains(nset, (xmlNodePtr)attr, cur)) { + ret = walkFunc(nset, (xmlNodePtr)attr, cur, data); + if(ret < 0) { + return(ret); + } + } + attr = attr->next; + } + + node = cur; + while(node != NULL) { + ns = node->nsDef; + while(ns != NULL) { + tmp = xmlSearchNs(nset->doc, cur, ns->prefix); + if((tmp == ns) && xmlSecNodeSetContains(nset, (xmlNodePtr)ns, cur)) { + ret = walkFunc(nset, (xmlNodePtr)ns, cur, data); + if(ret < 0) { + return(ret); + } + } + ns = ns->next; + } + node = node->parent; + } + } + + /* element and document nodes have children */ + if((cur->type == XML_ELEMENT_NODE) || (cur->type == XML_DOCUMENT_NODE)) { + xmlNodePtr node; + + node = cur->children; + while(node != NULL) { + ret = xmlSecNodeSetWalkRecursive(nset, walkFunc, data, node, cur); + if(ret < 0) { + return(ret); + } + node = node->next; + } + } + return(0); +} + +/** + * xmlSecNodeSetGetChildren: + * @doc: the pointer to an XML document. + * @parent: the pointer to parent XML node or NULL if we want to include all document nodes. + * @withComments: the flag include comments or not. + * @invert: the "invert" flag. + * + * Creates a new nodes set that contains: + * - if @withComments is not 0 and @invert is 0: + * all nodes in the @parent subtree; + * - if @withComments is 0 and @invert is 0: + * all nodes in the @parent subtree except comment nodes; + * - if @withComments is not 0 and @invert not is 0: + * all nodes in the @doc except nodes in the @parent subtree; + * - if @withComments is 0 and @invert is 0: + * all nodes in the @doc except nodes in the @parent subtree + * and comment nodes. + * + * Returns: pointer to the newly created #xmlSecNodeSet structure + * or NULL if an error occurs. + */ +xmlSecNodeSetPtr +xmlSecNodeSetGetChildren(xmlDocPtr doc, const xmlNodePtr parent, int withComments, int invert) { + xmlNodeSetPtr nodes; + xmlSecNodeSetType type; + + xmlSecAssert2(doc != NULL, NULL); + + nodes = xmlXPathNodeSetCreate(parent); + if(nodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlXPathNodeSetCreate", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* if parent is NULL then we add all the doc children */ + if(parent == NULL) { + xmlNodePtr cur; + for(cur = doc->children; cur != NULL; cur = cur->next) { + if(withComments || (cur->type != XML_COMMENT_NODE)) { + xmlXPathNodeSetAdd(nodes, cur); + } + } + } + + if(withComments && invert) { + type = xmlSecNodeSetTreeInvert; + } else if(withComments && !invert) { + type = xmlSecNodeSetTree; + } else if(!withComments && invert) { + type = xmlSecNodeSetTreeWithoutCommentsInvert; + } else { /* if(!withComments && !invert) */ + type = xmlSecNodeSetTreeWithoutComments; + } + + return(xmlSecNodeSetCreate(doc, nodes, type)); +} + +static int +xmlSecNodeSetDumpTextNodesWalkCallback(xmlSecNodeSetPtr nset, xmlNodePtr cur, + xmlNodePtr parent ATTRIBUTE_UNUSED, + void* data) { + xmlSecAssert2(nset != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + xmlSecAssert2(data != NULL, -1); + + if(cur->type == XML_TEXT_NODE) { + xmlOutputBufferWriteString((xmlOutputBufferPtr)data, + (char*)(cur->content)); + } + return(0); +} + +/** + * xmlSecNodeSetDumpTextNodes: + * @nset: the pointer to node set. + * @out: the output buffer. + * + * Dumps content of all the text nodes from @nset to @out. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNodeSetDumpTextNodes(xmlSecNodeSetPtr nset, xmlOutputBufferPtr out) { + xmlSecAssert2(nset != NULL, -1); + xmlSecAssert2(out != NULL, -1); + + return(xmlSecNodeSetWalk(nset, xmlSecNodeSetDumpTextNodesWalkCallback, out)); +} + +/** + * xmlSecNodeSetDebugDump: + * @nset: the pointer to node set. + * @output: the pointer to output FILE. + * + * Prints information about @nset to the @output. + */ +void +xmlSecNodeSetDebugDump(xmlSecNodeSetPtr nset, FILE *output) { + int i, l; + xmlNodePtr cur; + + xmlSecAssert(nset != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "== Nodes set "); + switch(nset->type) { + case xmlSecNodeSetNormal: + fprintf(output, "(xmlSecNodeSetNormal)\n"); + break; + case xmlSecNodeSetInvert: + fprintf(output, "(xmlSecNodeSetInvert)\n"); + break; + case xmlSecNodeSetTree: + fprintf(output, "(xmlSecNodeSetTree)\n"); + break; + case xmlSecNodeSetTreeWithoutComments: + fprintf(output, "(xmlSecNodeSetTreeWithoutComments)\n"); + break; + case xmlSecNodeSetTreeInvert: + fprintf(output, "(xmlSecNodeSetTreeInvert)\n"); + break; + case xmlSecNodeSetTreeWithoutCommentsInvert: + fprintf(output, "(xmlSecNodeSetTreeWithoutCommentsInvert)\n"); + break; + case xmlSecNodeSetList: + fprintf(output, "(xmlSecNodeSetList)\n"); + fprintf(output, ">>>\n"); + xmlSecNodeSetDebugDump(nset->children, output); + fprintf(output, "<<<\n"); + return; + default: + fprintf(output, "(unknown=%d)\n", nset->type); + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "type=%d", nset->type); + } + + l = xmlXPathNodeSetGetLength(nset->nodes); + for(i = 0; i < l; ++i) { + cur = xmlXPathNodeSetItem(nset->nodes, i); + if(cur->type != XML_NAMESPACE_DECL) { + fprintf(output, "%d: %s\n", cur->type, + (cur->name) ? cur->name : BAD_CAST "null"); + } else { + xmlNsPtr ns = (xmlNsPtr)cur; + fprintf(output, "%d: %s=%s (%s:%s)\n", cur->type, + (ns->prefix) ? ns->prefix : BAD_CAST "null", + (ns->href) ? ns->href : BAD_CAST "null", + (((xmlNodePtr)ns->next)->ns && + ((xmlNodePtr)ns->next)->ns->prefix) ? + ((xmlNodePtr)ns->next)->ns->prefix : BAD_CAST "null", + ((xmlNodePtr)ns->next)->name); + } + } +} diff --git a/src/nss/Makefile.am b/src/nss/Makefile.am new file mode 100644 index 00000000..5209533f --- /dev/null +++ b/src/nss/Makefile.am @@ -0,0 +1,57 @@ +NULL = + +EXTRA_DIST = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-nss.la \ + $(NULL) + +libxmlsec1_nss_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(NSS_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_nss_la_SOURCES =\ + app.c \ + bignum.c \ + ciphers.c \ + crypto.c \ + digests.c \ + hmac.c \ + pkikeys.c \ + signatures.c \ + symkeys.c \ + x509.c \ + x509vfy.c \ + keysstore.c \ + keytrans.c \ + kw_des.c \ + kw_aes.c \ + globals.h \ + $(NULL) + +if SHAREDLIB_HACK +libxmlsec1_nss_la_SOURCES += ../strings.c +endif + +libxmlsec1_nss_la_LIBADD = \ + ../libxmlsec1.la \ + $(NSS_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_nss_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_nss_la_LDFLAGS = \ + @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) diff --git a/src/nss/Makefile.in b/src/nss/Makefile.in new file mode 100644 index 00000000..d6bc31ec --- /dev/null +++ b/src/nss/Makefile.in @@ -0,0 +1,786 @@ +# Makefile.in generated by automake 1.11 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/nss +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +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_nss_la_SOURCES_DIST = app.c bignum.c ciphers.c crypto.c \ + digests.c hmac.c pkikeys.c signatures.c symkeys.c x509.c \ + x509vfy.c keysstore.c keytrans.c kw_des.c kw_aes.c globals.h \ + ../strings.c +am__objects_1 = +@SHAREDLIB_HACK_TRUE@am__objects_2 = libxmlsec1_nss_la-strings.lo +am_libxmlsec1_nss_la_OBJECTS = libxmlsec1_nss_la-app.lo \ + libxmlsec1_nss_la-bignum.lo libxmlsec1_nss_la-ciphers.lo \ + libxmlsec1_nss_la-crypto.lo libxmlsec1_nss_la-digests.lo \ + libxmlsec1_nss_la-hmac.lo libxmlsec1_nss_la-pkikeys.lo \ + libxmlsec1_nss_la-signatures.lo libxmlsec1_nss_la-symkeys.lo \ + libxmlsec1_nss_la-x509.lo libxmlsec1_nss_la-x509vfy.lo \ + libxmlsec1_nss_la-keysstore.lo libxmlsec1_nss_la-keytrans.lo \ + libxmlsec1_nss_la-kw_des.lo libxmlsec1_nss_la-kw_aes.lo \ + $(am__objects_1) $(am__objects_2) +libxmlsec1_nss_la_OBJECTS = $(am_libxmlsec1_nss_la_OBJECTS) +libxmlsec1_nss_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libxmlsec1_nss_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_nss_la_SOURCES) +DIST_SOURCES = $(am__libxmlsec1_nss_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@ +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@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_ENABLED = @PKG_CONFIG_ENABLED@ +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_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_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 = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-nss.la \ + $(NULL) + +libxmlsec1_nss_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(NSS_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_nss_la_SOURCES = app.c bignum.c ciphers.c crypto.c \ + digests.c hmac.c pkikeys.c signatures.c symkeys.c x509.c \ + x509vfy.c keysstore.c keytrans.c kw_des.c kw_aes.c globals.h \ + $(NULL) $(am__append_1) +libxmlsec1_nss_la_LIBADD = \ + ../libxmlsec1.la \ + $(NSS_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_nss_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_nss_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/nss/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/nss/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-nss.la: $(libxmlsec1_nss_la_OBJECTS) $(libxmlsec1_nss_la_DEPENDENCIES) + $(libxmlsec1_nss_la_LINK) -rpath $(libdir) $(libxmlsec1_nss_la_OBJECTS) $(libxmlsec1_nss_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-app.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-bignum.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-ciphers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-crypto.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-digests.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-hmac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-keysstore.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-keytrans.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-kw_aes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-kw_des.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-pkikeys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-signatures.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-strings.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-symkeys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_la-x509.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_nss_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_nss_la-app.lo: app.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-app.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-app.Tpo -c -o libxmlsec1_nss_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-app.Tpo $(DEPDIR)/libxmlsec1_nss_la-app.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='app.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c + +libxmlsec1_nss_la-bignum.lo: bignum.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-bignum.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-bignum.Tpo -c -o libxmlsec1_nss_la-bignum.lo `test -f 'bignum.c' || echo '$(srcdir)/'`bignum.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-bignum.Tpo $(DEPDIR)/libxmlsec1_nss_la-bignum.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bignum.c' object='libxmlsec1_nss_la-bignum.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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-bignum.lo `test -f 'bignum.c' || echo '$(srcdir)/'`bignum.c + +libxmlsec1_nss_la-ciphers.lo: ciphers.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-ciphers.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-ciphers.Tpo -c -o libxmlsec1_nss_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-ciphers.Tpo $(DEPDIR)/libxmlsec1_nss_la-ciphers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ciphers.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c + +libxmlsec1_nss_la-crypto.lo: crypto.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-crypto.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-crypto.Tpo -c -o libxmlsec1_nss_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-crypto.Tpo $(DEPDIR)/libxmlsec1_nss_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c + +libxmlsec1_nss_la-digests.lo: digests.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-digests.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-digests.Tpo -c -o libxmlsec1_nss_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-digests.Tpo $(DEPDIR)/libxmlsec1_nss_la-digests.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='digests.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c + +libxmlsec1_nss_la-hmac.lo: hmac.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-hmac.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-hmac.Tpo -c -o libxmlsec1_nss_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-hmac.Tpo $(DEPDIR)/libxmlsec1_nss_la-hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hmac.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c + +libxmlsec1_nss_la-pkikeys.lo: pkikeys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-pkikeys.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-pkikeys.Tpo -c -o libxmlsec1_nss_la-pkikeys.lo `test -f 'pkikeys.c' || echo '$(srcdir)/'`pkikeys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-pkikeys.Tpo $(DEPDIR)/libxmlsec1_nss_la-pkikeys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='pkikeys.c' object='libxmlsec1_nss_la-pkikeys.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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-pkikeys.lo `test -f 'pkikeys.c' || echo '$(srcdir)/'`pkikeys.c + +libxmlsec1_nss_la-signatures.lo: signatures.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-signatures.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-signatures.Tpo -c -o libxmlsec1_nss_la-signatures.lo `test -f 'signatures.c' || echo '$(srcdir)/'`signatures.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-signatures.Tpo $(DEPDIR)/libxmlsec1_nss_la-signatures.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='signatures.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-signatures.lo `test -f 'signatures.c' || echo '$(srcdir)/'`signatures.c + +libxmlsec1_nss_la-symkeys.lo: symkeys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-symkeys.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-symkeys.Tpo -c -o libxmlsec1_nss_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-symkeys.Tpo $(DEPDIR)/libxmlsec1_nss_la-symkeys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='symkeys.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c + +libxmlsec1_nss_la-x509.lo: x509.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-x509.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-x509.Tpo -c -o libxmlsec1_nss_la-x509.lo `test -f 'x509.c' || echo '$(srcdir)/'`x509.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-x509.Tpo $(DEPDIR)/libxmlsec1_nss_la-x509.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x509.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-x509.lo `test -f 'x509.c' || echo '$(srcdir)/'`x509.c + +libxmlsec1_nss_la-x509vfy.lo: x509vfy.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-x509vfy.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-x509vfy.Tpo -c -o libxmlsec1_nss_la-x509vfy.lo `test -f 'x509vfy.c' || echo '$(srcdir)/'`x509vfy.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-x509vfy.Tpo $(DEPDIR)/libxmlsec1_nss_la-x509vfy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x509vfy.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-x509vfy.lo `test -f 'x509vfy.c' || echo '$(srcdir)/'`x509vfy.c + +libxmlsec1_nss_la-keysstore.lo: keysstore.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-keysstore.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-keysstore.Tpo -c -o libxmlsec1_nss_la-keysstore.lo `test -f 'keysstore.c' || echo '$(srcdir)/'`keysstore.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-keysstore.Tpo $(DEPDIR)/libxmlsec1_nss_la-keysstore.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keysstore.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-keysstore.lo `test -f 'keysstore.c' || echo '$(srcdir)/'`keysstore.c + +libxmlsec1_nss_la-keytrans.lo: keytrans.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-keytrans.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-keytrans.Tpo -c -o libxmlsec1_nss_la-keytrans.lo `test -f 'keytrans.c' || echo '$(srcdir)/'`keytrans.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-keytrans.Tpo $(DEPDIR)/libxmlsec1_nss_la-keytrans.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='keytrans.c' object='libxmlsec1_nss_la-keytrans.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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-keytrans.lo `test -f 'keytrans.c' || echo '$(srcdir)/'`keytrans.c + +libxmlsec1_nss_la-kw_des.lo: kw_des.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-kw_des.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-kw_des.Tpo -c -o libxmlsec1_nss_la-kw_des.lo `test -f 'kw_des.c' || echo '$(srcdir)/'`kw_des.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-kw_des.Tpo $(DEPDIR)/libxmlsec1_nss_la-kw_des.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kw_des.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-kw_des.lo `test -f 'kw_des.c' || echo '$(srcdir)/'`kw_des.c + +libxmlsec1_nss_la-kw_aes.lo: kw_aes.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-kw_aes.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-kw_aes.Tpo -c -o libxmlsec1_nss_la-kw_aes.lo `test -f 'kw_aes.c' || echo '$(srcdir)/'`kw_aes.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-kw_aes.Tpo $(DEPDIR)/libxmlsec1_nss_la-kw_aes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kw_aes.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_la-kw_aes.lo `test -f 'kw_aes.c' || echo '$(srcdir)/'`kw_aes.c + +libxmlsec1_nss_la-strings.lo: ../strings.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_nss_la-strings.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_nss_la-strings.Tpo -c -o libxmlsec1_nss_la-strings.lo `test -f '../strings.c' || echo '$(srcdir)/'`../strings.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_nss_la-strings.Tpo $(DEPDIR)/libxmlsec1_nss_la-strings.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../strings.c' object='libxmlsec1_nss_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_nss_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_nss_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/nss/README b/src/nss/README new file mode 100644 index 00000000..884ade99 --- /dev/null +++ b/src/nss/README @@ -0,0 +1,137 @@ +WHAT VERSION OF NSS? +------------------------------------------------------------------------ +NSS 3.8 or greater and NSPR 4.3 or greater are required. + +KEYS MANAGER +------------------------------------------------------------------------ + +xmlsec-nss key manager uses a custom Keys Store, and a custom X509 Store. +The custom Keys Store and the X509 Store use the NSS database as the underlying +store for public/private keys, Certs and CRLs. + +The NSS Keys store uses the Simple Keys Store on top of the NSS repository. +The reason for this is that XMLSEC's generic adoptkey/getKey functions use a +XMLSEC key object that contains more attributes than the raw NSS key object, +and the getkey function may use a combination of one or more of these attributes +(name, type, usage, Id) to find a key. There is no straightforward 1-1 mapping +between XMLSEC's adoptkey/getkey and NSS's APIs. + +For example, the store may be asked to adopt a symmetric key, and later asked +to find it just by name. Or the store may be asked to adopt a private key +just by its type, and later asked to find it just by type. The key returned +by getKey is expected to contain all the attributes that were present at the +time of adoptkey - NSS store does not provide a way to store app-specific +attributes. + +When a key is adopted by the NSS Keys Store, it is simply saved in the +Simple Keys Store. It is not saved into the NSS database. The only +way to load keys into the NSS database is with a load operation through +the XMLSEC API or via an administrator operation. + +When a getKey is done on the NSS Keys Store, it first checks the Simple +Keys Store. If the key is found there, it is returned. If not, the key +is searched in the NSS database. If found, the key is stored in the +Simple Keys Store before it is returned. + + +Thus, the various sources for keys/certs/crls for an XMLSEC-NSS application +are: +- elements in XML documents +- PKCS12 and DER files +- NSS Database + + +KNOWN ISSUES. +------------------------------------------------------------------------ +1) NSS needs to provide a way to convert a DER integer string to an ASCII +decimal string. Once NSS is fixed, the function xmlSecNssASN1IntegerWrite +in src/nss/x509.c needs to be implemented. + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=212864 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118633 + +2) RSA Encryption/Decryption using PKCS#1 v1.5 padding not currently exposed +in NSS. This causes some tests to fail. + + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=214236 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118628 + +3) RSA-OAEP is not yet implemented in NSS. This is the only REQUIRED algorithm +that is missing from xmlsec-nss. + + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=158747 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118629 + +4) There are 2 fixes in NSS that will be rolled into the next release (3.9). +They are: + - http://bugzilla.mozilla.org/show_bug.cgi?id=208194 + Once available, need to change src/nss/x509.c. Replace + PR_AtomicIncrement(&(crlSrc->referenceCount)); + with + SEC_DupCrl(crlSrc); + (there is a comment there that already has the correct line) + + - http://bugzilla.mozilla.org/show_bug.cgi?id=211384 + No changes required. The "NSS_Shutdown failed" in some of the + current tests will go away + +xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118630 + +5) CERT_FindCertByNameString does not work in all cases + + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=210709 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118631 + +6) CERT_FindCertBySubjectKeyID does not work in all cases + + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=211051 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118632 + +7) Finding a cert by Issuer & Serial Number needs the ability to +convert an ASCII decimal string to a DER integer string. Filed +an RFE against NSS. Once fixed, xmlSecNumToItem in x509vfy.c +needs to be changed to use the new function(s) provided + + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=212864 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118633 + +8) RIPEMD160 Digest and RIPEMD160 HMAC is not supported by NSS + + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118634 + +9) AES Key wrap algorithm is implemented in NSS but not exposed due to +some bug src/nss/kw_aes.c uses a workaround which should be removed +when the bug is fixed + + NSS bug: http://bugzilla.mozilla.org/show_bug.cgi?id=213795 + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118635 + +10) Not all file formats are supported + +- xmlSecNssAppKeyLoad(): This function loads a PKI key from a file. + The following formats are supported: + . xmlSecKeyDataFormatDer: This expects the private key to be in + PrivateKeyInfo format. Note that the DER files containing + private keys in the xmlsec test suite aren't in that format + . xmlsecKeyDataFormatPkcs12 + + The following formats are not supported: + . xmlSecKeyDataFormatPkcs8Pem + . xmlSecKeyDataFormatPkcs8Der + + +- xmlSecNssAppCertLoad(): This function loads a cert from a file. + The following formats are supported: + xmlSecKeyDataFormatDer + + The following formats are not supported: + xmlSecKeyDataFormatPem + +11) "Trusted" vs "Untrusted" certificates: +The distinction between "trusted" and "untrusted" certificates in +xmlsec-openssl is maintained because the OPENSSL application (and +not the OPENSSL library) has to maintain a cert store and verify +certificates. With NSS, no such distinction is necessary in the +application. + +Aleksey: Not sure that I understand this point but thats what Tej wrote. + diff --git a/src/nss/app.c b/src/nss/app.c new file mode 100644 index 00000000..8aaf3327 --- /dev/null +++ b/src/nss/app.c @@ -0,0 +1,1598 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <nspr.h> +#include <nss.h> +#include <pk11func.h> +#include <cert.h> +#include <keyhi.h> +#include <pkcs12.h> +#include <p12plcy.h> +/* +#include <ssl.h> +*/ + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/app.h> +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/x509.h> +#include <xmlsec/nss/pkikeys.h> +#include <xmlsec/nss/keysstore.h> + +/* workaround - NSS exports this but doesn't declare it */ +extern CERTCertificate * __CERT_NewTempCertificate (CERTCertDBHandle *handle, + SECItem *derCert, + char *nickname, + PRBool isperm, + PRBool copyDER); +static int xmlSecNssAppCreateSECItem (SECItem *contents, + const xmlSecByte* data, + xmlSecSize dataSize); +static int xmlSecNssAppReadSECItem (SECItem *contents, + const char *fn); +static PRBool xmlSecNssAppAscii2UCS2Conv (PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen, + PRBool swapBytes); +static SECItem *xmlSecNssAppNicknameCollisionCallback (SECItem *old_nick, + PRBool *cancel, + void *wincx); +static xmlSecKeyPtr xmlSecNssAppDerKeyLoadSECItem (SECItem* secItem); + +/** + * xmlSecNssAppInit: + * @config: the path to NSS database files. + * + * 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 +xmlSecNssAppInit(const char* config) { + SECStatus rv; + + if(config) { + rv = NSS_InitReadWrite(config); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "NSS_InitReadWrite", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "config=%s", + xmlSecErrorsSafeString(config)); + return(-1); + } + } else { + rv = NSS_NoDB_Init(NULL); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "NSS_NoDB_Init", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* configure PKCS11 */ + PK11_ConfigurePKCS11("manufacturesID", "libraryDescription", + "tokenDescription", "privateTokenDescription", + "slotDescription", "privateSlotDescription", + "fipsSlotDescription", "fipsPrivateSlotDescription", + 0, 0); + + /* setup for PKCS12 */ + PORT_SetUCS2_ASCIIConversionFunction(xmlSecNssAppAscii2UCS2Conv); + SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); + SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); + + return(0); +} + +/** + * xmlSecNssAppShutdown: + * + * 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 +xmlSecNssAppShutdown(void) { + SECStatus rv; +/* + SSL_ClearSessionCache(); +*/ + PK11_LogoutAll(); + rv = NSS_Shutdown(); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "NSS_Shutdown", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + + +static int +xmlSecNssAppCreateSECItem(SECItem *contents, const xmlSecByte* data, xmlSecSize dataSize) { + xmlSecAssert2(contents != NULL, -1); + xmlSecAssert2(data != NULL, -1); + + contents->data = 0; + if (!SECITEM_AllocItem(NULL, contents, dataSize)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECITEM_AllocItem", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(dataSize > 0) { + xmlSecAssert2(contents->data != NULL, -1); + memcpy(contents->data, data, dataSize); + } + + return (0); +} + +static int +xmlSecNssAppReadSECItem(SECItem *contents, const char *fn) { + PRFileInfo info; + PRFileDesc *file = NULL; + PRInt32 numBytes; + PRStatus prStatus; + int ret = -1; + + xmlSecAssert2(contents != NULL, -1); + xmlSecAssert2(fn != NULL, -1); + + file = PR_Open(fn, PR_RDONLY, 00660); + if (file == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PR_Open", + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s", + xmlSecErrorsSafeString(fn)); + goto done; + } + + prStatus = PR_GetOpenFileInfo(file, &info); + if (prStatus != PR_SUCCESS) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PR_GetOpenFileInfo", + XMLSEC_ERRORS_R_IO_FAILED, + "filename=%s", + xmlSecErrorsSafeString(fn)); + goto done; + } + + contents->data = 0; + if (!SECITEM_AllocItem(NULL, contents, info.size)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECITEM_AllocItem", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + numBytes = PR_Read(file, contents->data, info.size); + if (numBytes != info.size) { + SECITEM_FreeItem(contents, PR_FALSE); + goto done; + } + + ret = 0; +done: + if (file) { + PR_Close(file); + } + + return (ret); +} + +static PRBool +xmlSecNssAppAscii2UCS2Conv(PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen, + PRBool swapBytes ATTRIBUTE_UNUSED) +{ + SECItem it; + + if (toUnicode == PR_FALSE) { + return (PR_FALSE); + } + + memset(&it, 0, sizeof(it)); + it.data = inBuf; + it.len = inBufLen; + + return(PORT_UCS2_UTF8Conversion(toUnicode, it.data, it.len, + outBuf, maxOutBufLen, outBufLen)); +} + +static SECItem * +xmlSecNssAppNicknameCollisionCallback(SECItem *old_nick ATTRIBUTE_UNUSED, + PRBool *cancel, + void *wincx ATTRIBUTE_UNUSED) +{ + if (cancel == NULL) { + return (NULL); + } + + /* XXX not handled yet */ + *cancel = PR_TRUE; + return (NULL); +} + +/** + * xmlSecNssAppKeyLoad: + * @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 a file + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppKeyLoad(const char *filename, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + SECItem secItem; + xmlSecKeyPtr res; + int ret; + + xmlSecAssert2(filename != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + /* read the file contents */ + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppReadSECItem(&secItem, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppReadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecNssAppKeyLoadSECItem(&secItem, format, pwd, pwdCallback, pwdCallbackCtx); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeyLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(NULL); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(res); +} + +/** + * xmlSecNssAppKeyLoadMemory: + * @data: the key binary data. + * @dataSize: the key binary data size. + * @format: the key data format. + * @pwd: the key data2 password. + * @pwdCallback: the key password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key from a binary @data. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + SECItem secItem; + xmlSecKeyPtr res; + int ret; + + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppCreateSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecNssAppKeyLoadSECItem(&secItem, format, pwd, pwdCallback, pwdCallbackCtx); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeyLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(NULL); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(res); +} + +/** + * xmlSecNssAppKeyLoadSECItem: + * @secItem: the pointer to sec item. + * @format: the key format. + * @pwd: the key password. + * @pwdCallback: the key password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key from a file + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppKeyLoadSECItem(SECItem* secItem, xmlSecKeyDataFormat format, + const char *pwd, + void* pwdCallback, + void* pwdCallbackCtx) { + xmlSecKeyPtr key = NULL; + + xmlSecAssert2(secItem != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + switch(format) { +#ifndef XMLSEC_NO_X509 + case xmlSecKeyDataFormatPkcs12: + key = xmlSecNssAppPkcs12LoadSECItem(secItem, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppPkcs12LoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; + case xmlSecKeyDataFormatCertDer: + key = xmlSecNssAppKeyFromCertLoadSECItem(secItem, format); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeyFromCertLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; +#endif /* XMLSEC_NO_X509 */ + case xmlSecKeyDataFormatDer: + key = xmlSecNssAppDerKeyLoadSECItem(secItem); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppDerKeyLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeyLoad", + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(NULL); + } + + return(key); +} + +static xmlSecKeyPtr +xmlSecNssAppDerKeyLoadSECItem(SECItem* secItem) { + xmlSecKeyPtr key = NULL; + xmlSecKeyPtr retval = NULL; + xmlSecKeyDataPtr data = NULL; + int ret; + SECKEYPublicKey *pubkey = NULL; + SECKEYPrivateKey *privkey = NULL; + CERTSubjectPublicKeyInfo *spki = NULL; + SECItem nickname; + PK11SlotInfo *slot = NULL; + SECStatus status; + + xmlSecAssert2(secItem != NULL, NULL); + + /* we're importing a key about which we know nothing yet, just use the + * internal slot + */ + slot = xmlSecNssGetInternalKeySlot(); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssGetInternalKeySlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + nickname.len = 0; + nickname.data = NULL; + + + /* TRY PRIVATE KEY FIRST + * Note: This expects the key to be in PrivateKeyInfo format. The + * DER files created from PEM via openssl utilities aren't in that + * format + */ + status = PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, secItem, + &nickname, NULL, PR_FALSE, + PR_TRUE, KU_ALL, &privkey, NULL); + if (status != SECSuccess) { + /* TRY PUBLIC KEY */ + spki = SECKEY_DecodeDERSubjectPublicKeyInfo(secItem); + if (spki == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECKEY_DecodeDERSubjectPublicKeyInfo", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + } + + pubkey = SECKEY_ExtractPublicKey(spki); + if (pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECKEY_ExtractPublicKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + + data = xmlSecNssPKIAdoptKey(privkey, pubkey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssPKIAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + privkey = NULL; + pubkey = 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, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data))); + goto done; + } + retval = key; + key = NULL; + data = NULL; + + +done: + if(slot != NULL) { + PK11_FreeSlot(slot); + } + if(privkey != NULL) { + SECKEY_DestroyPrivateKey(privkey); + } + if(pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if(key != NULL) { + xmlSecKeyDestroy(key); + } + if(data != NULL) { + xmlSecKeyDataDestroy(data); + } + if(spki != NULL) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } + return (retval); +} + +#ifndef XMLSEC_NO_X509 +/** + * xmlSecNssAppKeyCertLoad: + * @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 +xmlSecNssAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, xmlSecKeyDataFormat format) { + SECItem secItem; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* read the file contents */ + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppReadSECItem(&secItem, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppReadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecNssAppKeyCertLoadSECItem(key, &secItem, format); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeyCertLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(-1); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(0); +} + +/** + * xmlSecNssAppKeyCertLoadMemory: + * @key: the pointer to key. + * @data: the key binary data. + * @dataSize: the key binary data size. + * @format: the certificate format. + * + * Reads the certificate from @data and adds it to key + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format) { + SECItem secItem; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* read the file contents */ + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppCreateSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecNssAppKeyCertLoadSECItem(key, &secItem, format); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeyCertLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(-1); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(0); +} + +/** + * xmlSecNssAppKeyCertLoadSECItem: + * @key: the pointer to key. + * @secItem: the pointer to SECItem. + * @format: the certificate format. + * + * Reads the certificate from @secItem and adds it to key + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppKeyCertLoadSECItem(xmlSecKeyPtr key, SECItem* secItem, xmlSecKeyDataFormat format) { + CERTCertificate *cert=NULL; + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(secItem != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + data = xmlSecKeyEnsureData(key, xmlSecNssKeyDataX509Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecNssKeyDataX509Id))); + return(-1); + } + + switch(format) { + case xmlSecKeyDataFormatPkcs8Der: + case xmlSecKeyDataFormatDer: + cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), + secItem, NULL, PR_FALSE, PR_TRUE); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "__CERT_NewTempCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "format=%d", format); + return(-1); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(-1); + } + + xmlSecAssert2(cert != NULL, -1); + ret = xmlSecNssKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data))); + CERT_DestroyCertificate(cert); + return(-1); + } + + return(0); +} + +/** + * xmlSecNssAppPkcs12Load: + * @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. + * For uniformity, call xmlSecNssAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppPkcs12Load(const char *filename, const char *pwd, + void *pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + SECItem secItem; + xmlSecKeyPtr res; + int ret; + + xmlSecAssert2(filename != NULL, NULL); + + /* read the file contents */ + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppReadSECItem(&secItem, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppReadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecNssAppPkcs12LoadSECItem(&secItem, pwd, pwdCallback, pwdCallbackCtx); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppPkcs12LoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(NULL); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(res); +} + +/** + * xmlSecNssAppPkcs12LoadMemory: + * @data: the key binary data. + * @dataSize: the key binary data size. + * @pwd: the PKCS12 password. + * @pwdCallback: the password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key and all associated certificates from the PKCS12 binary data. + * For uniformity, call xmlSecNssAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, const char *pwd, + void *pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + SECItem secItem; + xmlSecKeyPtr res; + int ret; + + xmlSecAssert2(data != NULL, NULL); + + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppCreateSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecNssAppPkcs12LoadSECItem(&secItem, pwd, pwdCallback, pwdCallbackCtx); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppPkcs12LoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(NULL); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(res); +} + + +/** + * xmlSecNssAppPkcs12LoadSECItem: + * @secItem: the @SECItem object. + * @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 SECItem. + * For uniformity, call xmlSecNssAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppPkcs12LoadSECItem(SECItem* secItem, const char *pwd, + void *pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + xmlSecKeyPtr key = NULL; + xmlSecKeyDataPtr data = NULL; + xmlSecKeyDataPtr x509Data = NULL; + int ret; + PK11SlotInfo *slot = NULL; + SECItem pwditem; + SECItem uc2_pwditem; + SECStatus rv; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + CERTCertList *certlist = NULL; + CERTCertListNode *head = NULL; + CERTCertificate *cert = NULL; + CERTCertificate *tmpcert = NULL; + SEC_PKCS12DecoderContext *p12ctx = NULL; + + + xmlSecAssert2((secItem != NULL), NULL); + + if (pwd == NULL) { + pwd = ""; + } + memset(&uc2_pwditem, 0, sizeof(uc2_pwditem)); + + /* we're importing a key about which we know nothing yet, just use the + * internal slot. We have no criteria to choose a slot. + */ + slot = xmlSecNssGetInternalKeySlot(); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssGetInternalKeySlot", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + pwditem.data = (unsigned char *)pwd; + pwditem.len = strlen(pwd)+1; + if (!SECITEM_AllocItem(NULL, &uc2_pwditem, 2*pwditem.len)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECITEM_AllocItem", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + if (PORT_UCS2_ASCIIConversion(PR_TRUE, pwditem.data, pwditem.len, + uc2_pwditem.data, 2*pwditem.len, + &(uc2_pwditem.len), 0) == PR_FALSE) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PORT_UCS2_ASCIIConversion", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + p12ctx = SEC_PKCS12DecoderStart(&uc2_pwditem, slot, NULL, + NULL, NULL, NULL, NULL, NULL); + if (p12ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_PKCS12DecoderStart", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = SEC_PKCS12DecoderUpdate(p12ctx, secItem->data, secItem->len); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_PKCS12DecoderUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = SEC_PKCS12DecoderVerify(p12ctx); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_PKCS12DecoderVerify", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = SEC_PKCS12DecoderValidateBags(p12ctx, xmlSecNssAppNicknameCollisionCallback); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_PKCS12DecoderValidateBags", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = SEC_PKCS12DecoderImportBags(p12ctx); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_PKCS12DecoderImportBags", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + certlist = SEC_PKCS12DecoderGetCerts(p12ctx); + if (certlist == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_PKCS12DecoderGetCerts", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + x509Data = xmlSecKeyDataCreate(xmlSecNssKeyDataX509Id); + if(x509Data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecNssKeyDataX509Id))); + goto done; + } + + for (head = CERT_LIST_HEAD(certlist); + !CERT_LIST_END(head, certlist); + head = CERT_LIST_NEXT(head)) { + cert = head->cert; + privkey = PK11_FindKeyByAnyCert(cert, NULL); + + if (privkey != NULL) { + if (data != NULL) { + /* we already found a private key. + * assume the first private key we find is THE ONE + */ + SECKEY_DestroyPrivateKey(privkey); + privkey = NULL; + } else { + pubkey = CERT_ExtractPublicKey(cert); + if (pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_ExtractPublicKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + data = xmlSecNssPKIAdoptKey(privkey, pubkey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssPKIAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + pubkey = NULL; + privkey = NULL; + + tmpcert = CERT_DupCertificate(cert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecNssKeyDataX509AdoptKeyCert(x509Data, tmpcert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + CERT_DestroyCertificate(tmpcert); + goto done; + } + + } + } + + tmpcert = CERT_DupCertificate(cert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + ret = xmlSecNssKeyDataX509AdoptCert(x509Data, tmpcert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + CERT_DestroyCertificate(tmpcert); + goto done; + } + + } /* end for loop */ + + if (data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppPkcs12Load", + 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, data); + 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; + } + 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))); + xmlSecKeyDestroy(key); + key = NULL; + goto done; + } + x509Data = NULL; + +done: + if (p12ctx) { + SEC_PKCS12DecoderFinish(p12ctx); + } + SECITEM_FreeItem(&uc2_pwditem, PR_FALSE); + if (slot) { + PK11_FreeSlot(slot); + } + if (certlist) { + CERT_DestroyCertList(certlist); + } + if(x509Data != NULL) { + xmlSecKeyDataDestroy(x509Data); + } + if(data != NULL) { + xmlSecKeyDataDestroy(data); + } + if (privkey) { + SECKEY_DestroyPrivateKey(privkey); + } + if (pubkey) { + SECKEY_DestroyPublicKey(pubkey); + } + + return(key); +} + +/** + * xmlSecNssAppKeyFromCertLoadSECItem: + * @secItem: the @SECItem object. + * @format: the cert format. + * + * Loads public key from cert. + * + * Returns: pointer to key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecNssAppKeyFromCertLoadSECItem(SECItem* secItem, xmlSecKeyDataFormat format) { + xmlSecKeyPtr key; + xmlSecKeyDataPtr keyData; + xmlSecKeyDataPtr certData; + CERTCertificate *cert=NULL; + int ret; + + xmlSecAssert2(secItem != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + /* load cert */ + switch(format) { + case xmlSecKeyDataFormatCertDer: + cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), + secItem, NULL, PR_FALSE, PR_TRUE); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "__CERT_NewTempCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "format=%d", format); + return(NULL); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(NULL); + } + + /* get key value */ + keyData = xmlSecNssX509CertGetKey(cert); + if(keyData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509CertGetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + return(NULL); + } + + /* create key */ + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(keyData); + CERT_DestroyCertificate(cert); + return(NULL); + } + + /* set key value */ + ret = xmlSecKeySetValue(key, keyData); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + xmlSecKeyDataDestroy(keyData); + CERT_DestroyCertificate(cert); + return(NULL); + } + + /* create cert data */ + certData = xmlSecKeyEnsureData(key, xmlSecNssKeyDataX509Id); + if(certData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + CERT_DestroyCertificate(cert); + return(NULL); + } + + /* put cert in the cert data */ + ret = xmlSecNssKeyDataX509AdoptCert(certData, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + CERT_DestroyCertificate(cert); + return(NULL); + } + + return(key); +} + + +/** + * xmlSecNssAppKeysMngrCertLoad: + * @mngr: the pointer to keys manager. + * @filename: the certificate file. + * @format: the certificate file format (PEM or DER). + * @type: the certificate type (trusted/untrusted). + * + * Reads cert from @filename and adds to the list of trusted or known + * untrusted certs in @store + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, + xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + SECItem secItem; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* read the file contents */ + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppReadSECItem(&secItem, filename); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppReadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecNssAppKeysMngrCertLoadSECItem(mngr, &secItem, format, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeysMngrCertLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(-1); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(0); +} + +/** + * xmlSecNssAppKeysMngrCertLoadMemory: + * @mngr: the pointer to keys manager. + * @data: the key binary data. + * @dataSize: the key binary data size. + * @format: the certificate format (PEM or DER). + * @type: the certificate type (trusted/untrusted). + * + * 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 +xmlSecNssAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + SECItem secItem; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + memset(&secItem, 0, sizeof(secItem)); + ret = xmlSecNssAppCreateSECItem(&secItem, data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppCreateSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecNssAppKeysMngrCertLoadSECItem(mngr, &secItem, format, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAppKeysMngrCertLoadSECItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&secItem, PR_FALSE); + return(-1); + } + + SECITEM_FreeItem(&secItem, PR_FALSE); + return(0); +} + +/** + * xmlSecNssAppKeysMngrCertLoadSECItem: + * @mngr: the pointer to keys manager. + * @secItem: the pointer to SECItem. + * @format: the certificate format (PEM or DER). + * @type: the certificate type (trusted/untrusted). + * + * Reads cert from @secItem and adds to the list of trusted or known + * untrusted certs in @store + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppKeysMngrCertLoadSECItem(xmlSecKeysMngrPtr mngr, SECItem* secItem, + xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + xmlSecKeyDataStorePtr x509Store; + CERTCertificate* cert; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(secItem != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecNssX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssX509StoreId"); + return(-1); + } + + switch(format) { + case xmlSecKeyDataFormatDer: + cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), + secItem, NULL, PR_FALSE, PR_TRUE); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "__CERT_NewTempCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "format=%d", format); + return(-1); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(-1); + } + + ret = xmlSecNssX509StoreAdoptCert(x509Store, cert, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509StoreAdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + return(-1); + } + + return(0); +} + +#endif /* XMLSEC_NO_X509 */ + +/** + * xmlSecNssAppDefaultKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Initializes @mngr with NSS keys store #xmlSecNssKeysStoreId + * and a default NSS crypto key data stores. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + + /* create NSS keys store if needed */ + if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) { + xmlSecKeyStorePtr keysStore; + + keysStore = xmlSecKeyStoreCreate(xmlSecNssKeysStoreId); + if(keysStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssKeysStoreId"); + 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 = xmlSecNssKeysMngrInit(mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeysMngrInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + mngr->getKey = xmlSecKeysMngrGetKey; + return(0); +} + +/** + * xmlSecNssAppDefaultKeysMngrAdoptKey: + * @mngr: the pointer to keys manager. + * @key: the pointer to key. + * + * Adds @key to the keys manager @mngr created with #xmlSecNssAppDefaultKeysMngrInit + * function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppDefaultKeysMngrAdoptKey(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 = xmlSecNssKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeysStoreAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecNssAppDefaultKeysMngrLoad: + * @mngr: the pointer to keys manager. + * @uri: the uri. + * + * Loads XML keys file from @uri to the keys manager @mngr created + * with #xmlSecNssAppDefaultKeysMngrInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssAppDefaultKeysMngrLoad(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 = xmlSecNssKeysStoreLoad(store, uri, mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeysStoreLoad", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", xmlSecErrorsSafeString(uri)); + return(-1); + } + + return(0); +} + +/** + * xmlSecNssAppDefaultKeysMngrSave: + * @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 +xmlSecNssAppDefaultKeysMngrSave(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 = xmlSecNssKeysStoreSave(store, filename, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeysStoreSave", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename%s", xmlSecErrorsSafeString(filename)); + return(-1); + } + + return(0); +} + +/** + * xmlSecNssAppGetDefaultPwdCallback: + * + * Gets default password callback. + * + * Returns: default password callback. + */ +void* +xmlSecNssAppGetDefaultPwdCallback(void) { + return(NULL); +} + diff --git a/src/nss/bignum.c b/src/nss/bignum.c new file mode 100644 index 00000000..40bd5359 --- /dev/null +++ b/src/nss/bignum.c @@ -0,0 +1,163 @@ +/** + * XMLSec library + * + * Reading/writing bignum values + * + * This is free software; see Copyright file in the source + * distribution for precise wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <nss.h> +#include <secitem.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/base64.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/bignum.h> + +/** + * xmlSecNssNodeGetBigNumValue: + * @arena: the arena from which to allocate memory + * @cur: the poitner to an XML node. + * @a: a SECItem object to hold the BigNum value + * + * Converts the node content from CryptoBinary format + * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary) + * to a SECItem. If no SECItem object provided then a new + * one is created (caller is responsible for freeing it). + * + * Returns: a pointer to SECItem produced from CryptoBinary string + * or NULL if an error occurs. + */ +SECItem * +xmlSecNssNodeGetBigNumValue(PRArenaPool *arena, const xmlNodePtr cur, + SECItem *a) { + xmlSecBuffer buf; + int ret; + SECItem *rv; + int len; + + xmlSecAssert2(arena != NULL, NULL); + xmlSecAssert2(cur != NULL, NULL); + + ret = xmlSecBufferInitialize(&buf, 128); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecBufferBase64NodeContentRead(&buf, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferBase64NodeContentRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(NULL); + } + + len = xmlSecBufferGetSize(&buf); + + if (a == NULL) { + rv = SECITEM_AllocItem(arena, NULL, len); + } else { + rv = a; + xmlSecAssert2(rv->data == NULL, NULL); + rv->len = len; + rv->data = PORT_ArenaZAlloc(arena, len); + } + + PORT_Memcpy(rv->data, xmlSecBufferGetData(&buf), len); + + xmlSecBufferFinalize(&buf); + return(rv); +} + +/** + * xmlSecNssNodeSetBigNumValue: + * @cur: the pointer to an XML node. + * @a: a SECItem containing the BigNum value. + * @addLineBreaks: if the flag is equal to 1 then + * linebreaks will be added before and after + * new buffer content. + * + * Converts SECItem to CryptoBinary string + * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary) + * and sets it as the content of the given node. If the + * addLineBreaks is set then line breaks are added + * before and after the CryptoBinary string. + * + * Returns: 0 on success or -1 otherwise. + */ +int +xmlSecNssNodeSetBigNumValue(xmlNodePtr cur, const SECItem *a, int addLineBreaks) { + xmlSecBuffer buf; + int ret; + + xmlSecAssert2(a != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + + ret = xmlSecBufferInitialize(&buf, a->len + 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", a->len + 1); + return(-1); + } + + PORT_Memcpy(xmlSecBufferGetData(&buf), a->data, a->len); + + ret = xmlSecBufferSetSize(&buf, a->len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", a->len); + xmlSecBufferFinalize(&buf); + return(-1); + } + + if(addLineBreaks) { + xmlNodeSetContent(cur, xmlSecStringCR); + } else { + xmlNodeSetContent(cur, xmlSecStringEmpty); + } + + ret = xmlSecBufferBase64NodeContentWrite(&buf, cur, xmlSecBase64GetDefaultLineSize()); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferBase64NodeContentWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + + if(addLineBreaks) { + xmlNodeAddContent(cur, xmlSecStringCR); + } + + xmlSecBufferFinalize(&buf); + return(0); +} + diff --git a/src/nss/ciphers.c b/src/nss/ciphers.c new file mode 100644 index 00000000..48bd6e11 --- /dev/null +++ b/src/nss/ciphers.c @@ -0,0 +1,838 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <nspr.h> +#include <nss.h> +#include <secoid.h> +#include <pk11func.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> + +#define XMLSEC_NSS_MAX_KEY_SIZE 32 +#define XMLSEC_NSS_MAX_IV_SIZE 32 +#define XMLSEC_NSS_MAX_BLOCK_SIZE 32 + +/************************************************************************** + * + * Internal Nss Block cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecNssBlockCipherCtx xmlSecNssBlockCipherCtx, + *xmlSecNssBlockCipherCtxPtr; +struct _xmlSecNssBlockCipherCtx { + CK_MECHANISM_TYPE cipher; + PK11Context* cipherCtx; + xmlSecKeyDataId keyId; + int keyInitialized; + int ctxInitialized; + xmlSecByte key[XMLSEC_NSS_MAX_KEY_SIZE]; + xmlSecSize keySize; + xmlSecByte iv[XMLSEC_NSS_MAX_IV_SIZE]; + xmlSecSize ivSize; +}; +static int xmlSecNssBlockCipherCtxInit (xmlSecNssBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssBlockCipherCtxUpdate (xmlSecNssBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssBlockCipherCtxFinal (xmlSecNssBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int +xmlSecNssBlockCipherCtxInit(xmlSecNssBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + SECItem keyItem; + SECItem ivItem; + PK11SlotInfo* slot; + PK11SymKey* symKey; + int ivLen; + SECStatus rv; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->cipherCtx == NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ivLen = PK11_GetIVLength(ctx->cipher); + xmlSecAssert2(ivLen > 0, -1); + xmlSecAssert2((xmlSecSize)ivLen <= sizeof(ctx->iv), -1); + + if(encrypt) { + /* generate random iv */ + rv = PK11_GenerateRandom(ctx->iv, ivLen); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_GenerateRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", ivLen); + return(-1); + } + + /* write iv to the output */ + ret = xmlSecBufferAppend(out, ctx->iv, ivLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ivLen); + return(-1); + } + + } else { + /* if we don't have enough data, exit and hope that + * we'll have iv next time */ + if(xmlSecBufferGetSize(in) < (xmlSecSize)ivLen) { + return(0); + } + + /* copy iv to our buffer*/ + xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1); + memcpy(ctx->iv, xmlSecBufferGetData(in), ivLen); + + /* and remove from input */ + ret = xmlSecBufferRemoveHead(in, ivLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ivLen); + return(-1); + } + } + + memset(&keyItem, 0, sizeof(keyItem)); + keyItem.data = ctx->key; + keyItem.len = ctx->keySize; + memset(&ivItem, 0, sizeof(ivItem)); + ivItem.data = ctx->iv; + ivItem.len = ctx->ivSize; + + slot = PK11_GetBestSlot(ctx->cipher, NULL); + if(slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + symKey = PK11_ImportSymKey(slot, ctx->cipher, PK11_OriginDerive, + CKA_SIGN, &keyItem, NULL); + if(symKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_ImportSymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_FreeSlot(slot); + return(-1); + } + + ctx->cipherCtx = PK11_CreateContextBySymKey(ctx->cipher, + (encrypt) ? CKA_ENCRYPT : CKA_DECRYPT, + symKey, &ivItem); + if(ctx->cipherCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_CreateContextBySymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_FreeSymKey(symKey); + PK11_FreeSlot(slot); + return(-1); + } + + ctx->ctxInitialized = 1; + PK11_FreeSymKey(symKey); + PK11_FreeSlot(slot); + return(0); +} + +static int +xmlSecNssBlockCipherCtxUpdate(xmlSecNssBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + xmlSecSize inSize, inBlocks, outSize; + int blockLen; + int outLen = 0; + xmlSecByte* outBuf; + SECStatus rv; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = PK11_GetBlockSize(ctx->cipher, NULL); + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(inSize < (xmlSecSize)blockLen) { + return(0); + } + + if(encrypt) { + inBlocks = inSize / ((xmlSecSize)blockLen); + } else { + /* we want to have the last block in the input buffer + * for padding check */ + inBlocks = (inSize - 1) / ((xmlSecSize)blockLen); + } + inSize = inBlocks * ((xmlSecSize)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; + + rv = PK11_CipherOp(ctx->cipherCtx, outBuf, &outLen, inSize + blockLen, + xmlSecBufferGetData(in), inSize); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_CipherOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2((xmlSecSize)outLen == inSize, -1); + + /* 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); +} + +static int +xmlSecNssBlockCipherCtxFinal(xmlSecNssBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + xmlSecSize inSize, outSize; + int blockLen, outLen = 0; + xmlSecByte* inBuf; + xmlSecByte* outBuf; + SECStatus rv; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->cipherCtx != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = PK11_GetBlockSize(ctx->cipher, NULL); + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(encrypt != 0) { + xmlSecAssert2(inSize < (xmlSecSize)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); + + /* generate random padding */ + if((xmlSecSize)blockLen > (inSize + 1)) { + rv = PK11_GenerateRandom(inBuf + inSize, blockLen - inSize - 1); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_GenerateRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", blockLen - inSize - 1); + return(-1); + } + } + inBuf[blockLen - 1] = blockLen - inSize; + inSize = blockLen; + } else { + if(inSize != (xmlSecSize)blockLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "data=%d;block=%d", inSize, blockLen); + return(-1); + } + } + + /* 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; + + rv = PK11_CipherOp(ctx->cipherCtx, outBuf, &outLen, 2 * blockLen, + xmlSecBufferGetData(in), inSize); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "PK11_CipherOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2((xmlSecSize)outLen == inSize, -1); + + if(encrypt == 0) { + /* check padding */ + if(outLen < outBuf[blockLen - 1]) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "padding=%d;buffer=%d", + outBuf[blockLen - 1], outLen); + return(-1); + } + outLen -= outBuf[blockLen - 1]; + } + + /* 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); +} + + +/****************************************************************************** + * + * EVP Block Cipher transforms + * + * xmlSecNssBlockCipherCtx block is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecNssBlockCipherSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecNssBlockCipherCtx)) +#define xmlSecNssBlockCipherGetCtx(transform) \ + ((xmlSecNssBlockCipherCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecNssBlockCipherInitialize (xmlSecTransformPtr transform); +static void xmlSecNssBlockCipherFinalize (xmlSecTransformPtr transform); +static int xmlSecNssBlockCipherSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecNssBlockCipherSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecNssBlockCipherExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssBlockCipherCheckId (xmlSecTransformPtr transform); + + + +static int +xmlSecNssBlockCipherCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DES + if(xmlSecTransformCheckId(transform, xmlSecNssTransformDes3CbcId)) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(xmlSecTransformCheckId(transform, xmlSecNssTransformAes128CbcId) || + xmlSecTransformCheckId(transform, xmlSecNssTransformAes192CbcId) || + xmlSecTransformCheckId(transform, xmlSecNssTransformAes256CbcId)) { + + return(1); + } +#endif /* XMLSEC_NO_AES */ + + return(0); +} + +static int +xmlSecNssBlockCipherInitialize(xmlSecTransformPtr transform) { + xmlSecNssBlockCipherCtxPtr ctx; + + xmlSecAssert2(xmlSecNssBlockCipherCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssBlockCipherSize), -1); + + ctx = xmlSecNssBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssBlockCipherCtx)); + +#ifndef XMLSEC_NO_DES + if(transform->id == xmlSecNssTransformDes3CbcId) { + ctx->cipher = CKM_DES3_CBC; + ctx->keyId = xmlSecNssKeyDataDesId; + ctx->keySize = 24; + } else +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(transform->id == xmlSecNssTransformAes128CbcId) { + ctx->cipher = CKM_AES_CBC; + ctx->keyId = xmlSecNssKeyDataAesId; + ctx->keySize = 16; + } else if(transform->id == xmlSecNssTransformAes192CbcId) { + ctx->cipher = CKM_AES_CBC; + ctx->keyId = xmlSecNssKeyDataAesId; + ctx->keySize = 24; + } else if(transform->id == xmlSecNssTransformAes256CbcId) { + ctx->cipher = CKM_AES_CBC; + ctx->keyId = xmlSecNssKeyDataAesId; + ctx->keySize = 32; + } else +#endif /* XMLSEC_NO_AES */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecNssBlockCipherFinalize(xmlSecTransformPtr transform) { + xmlSecNssBlockCipherCtxPtr ctx; + + xmlSecAssert(xmlSecNssBlockCipherCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssBlockCipherSize)); + + ctx = xmlSecNssBlockCipherGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->cipherCtx != NULL) { + PK11_DestroyContext(ctx->cipherCtx, PR_TRUE); + } + + memset(ctx, 0, sizeof(xmlSecNssBlockCipherCtx)); +} + +static int +xmlSecNssBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecNssBlockCipherCtxPtr ctx; + + xmlSecAssert2(xmlSecNssBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssBlockCipherSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecNssBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyId != NULL, -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 +xmlSecNssBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecNssBlockCipherCtxPtr ctx; + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecNssBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssBlockCipherSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecNssBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != 0, -1); + xmlSecAssert2(ctx->keyInitialized == 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + xmlSecAssert2(ctx->keySize > 0, -1); + xmlSecAssert2(ctx->keySize <= sizeof(ctx->key), -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); + } + + xmlSecAssert2(xmlSecBufferGetData(buffer) != NULL, -1); + memcpy(ctx->key, xmlSecBufferGetData(buffer), ctx->keySize); + + ctx->keyInitialized = 1; + return(0); +} + +static int +xmlSecNssBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssBlockCipherCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecNssBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssBlockCipherSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecNssBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + if(ctx->ctxInitialized == 0) { + ret = xmlSecNssBlockCipherCtxInit(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssBlockCipherCtxInit", + 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 = xmlSecNssBlockCipherCtxUpdate(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssBlockCipherCtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(last) { + ret = xmlSecNssBlockCipherCtxFinal(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssBlockCipherCtxFinal", + 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 xmlSecNssAes128CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes128Cbc, /* const xmlChar* name; */ + xmlSecHrefAes128Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformAes128CbcGetKlass: + * + * AES 128 CBC encryption transform klass. + * + * Returns: pointer to AES 128 CBC encryption transform. + */ +xmlSecTransformId +xmlSecNssTransformAes128CbcGetKlass(void) { + return(&xmlSecNssAes128CbcKlass); +} + +static xmlSecTransformKlass xmlSecNssAes192CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes192Cbc, /* const xmlChar* name; */ + xmlSecHrefAes192Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformAes192CbcGetKlass: + * + * AES 192 CBC encryption transform klass. + * + * Returns: pointer to AES 192 CBC encryption transform. + */ +xmlSecTransformId +xmlSecNssTransformAes192CbcGetKlass(void) { + return(&xmlSecNssAes192CbcKlass); +} + +static xmlSecTransformKlass xmlSecNssAes256CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes256Cbc, /* const xmlChar* name; */ + xmlSecHrefAes256Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformAes256CbcGetKlass: + * + * AES 256 CBC encryption transform klass. + * + * Returns: pointer to AES 256 CBC encryption transform. + */ +xmlSecTransformId +xmlSecNssTransformAes256CbcGetKlass(void) { + return(&xmlSecNssAes256CbcKlass); +} + +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES +static xmlSecTransformKlass xmlSecNssDes3CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameDes3Cbc, /* const xmlChar* name; */ + xmlSecHrefDes3Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformDes3CbcGetKlass: + * + * Triple DES CBC encryption transform klass. + * + * Returns: pointer to Triple DES encryption transform. + */ +xmlSecTransformId +xmlSecNssTransformDes3CbcGetKlass(void) { + return(&xmlSecNssDes3CbcKlass); +} +#endif /* XMLSEC_NO_DES */ + diff --git a/src/nss/crypto.c b/src/nss/crypto.c new file mode 100644 index 00000000..141ceeac --- /dev/null +++ b/src/nss/crypto.c @@ -0,0 +1,366 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <nss.h> +#include <pk11func.h> +#include <prinit.h> + + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/dl.h> +#include <xmlsec/private.h> +#include <xmlsec/xmltree.h> + +#include <xmlsec/nss/app.h> +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/x509.h> + +static xmlSecCryptoDLFunctionsPtr gXmlSecNssFunctions = NULL; + +/** + * xmlSecCryptoGetFunctions_nss: + * + * Gets the pointer to xmlsec-nss functions table. + * + * Returns: the xmlsec-nss functions table or NULL if an error occurs. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoGetFunctions_nss(void) { + static xmlSecCryptoDLFunctions functions; + + if(gXmlSecNssFunctions != NULL) { + return(gXmlSecNssFunctions); + } + + memset(&functions, 0, sizeof(functions)); + gXmlSecNssFunctions = &functions; + + /** + * Crypto Init/shutdown + */ + gXmlSecNssFunctions->cryptoInit = xmlSecNssInit; + gXmlSecNssFunctions->cryptoShutdown = xmlSecNssShutdown; + gXmlSecNssFunctions->cryptoKeysMngrInit = xmlSecNssKeysMngrInit; + + /** + * Key data ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecNssFunctions->keyDataAesGetKlass = xmlSecNssKeyDataAesGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecNssFunctions->keyDataDesGetKlass = xmlSecNssKeyDataDesGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_DSA + gXmlSecNssFunctions->keyDataDsaGetKlass = xmlSecNssKeyDataDsaGetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecNssFunctions->keyDataHmacGetKlass = xmlSecNssKeyDataHmacGetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_RSA + gXmlSecNssFunctions->keyDataRsaGetKlass = xmlSecNssKeyDataRsaGetKlass; +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_X509 + gXmlSecNssFunctions->keyDataX509GetKlass = xmlSecNssKeyDataX509GetKlass; + gXmlSecNssFunctions->keyDataRawX509CertGetKlass = xmlSecNssKeyDataRawX509CertGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /** + * Key data store ids + */ +#ifndef XMLSEC_NO_X509 + gXmlSecNssFunctions->x509StoreGetKlass = xmlSecNssX509StoreGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /** + * Crypto transforms ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecNssFunctions->transformAes128CbcGetKlass = xmlSecNssTransformAes128CbcGetKlass; + gXmlSecNssFunctions->transformAes192CbcGetKlass = xmlSecNssTransformAes192CbcGetKlass; + gXmlSecNssFunctions->transformAes256CbcGetKlass = xmlSecNssTransformAes256CbcGetKlass; + gXmlSecNssFunctions->transformKWAes128GetKlass = xmlSecNssTransformKWAes128GetKlass; + gXmlSecNssFunctions->transformKWAes192GetKlass = xmlSecNssTransformKWAes192GetKlass; + gXmlSecNssFunctions->transformKWAes256GetKlass = xmlSecNssTransformKWAes256GetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecNssFunctions->transformDes3CbcGetKlass = xmlSecNssTransformDes3CbcGetKlass; + gXmlSecNssFunctions->transformKWDes3GetKlass = xmlSecNssTransformKWDes3GetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_DSA + gXmlSecNssFunctions->transformDsaSha1GetKlass = xmlSecNssTransformDsaSha1GetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecNssFunctions->transformHmacSha1GetKlass = xmlSecNssTransformHmacSha1GetKlass; + gXmlSecNssFunctions->transformHmacRipemd160GetKlass = xmlSecNssTransformHmacRipemd160GetKlass; + gXmlSecNssFunctions->transformHmacMd5GetKlass = xmlSecNssTransformHmacMd5GetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_RSA + gXmlSecNssFunctions->transformRsaSha1GetKlass = xmlSecNssTransformRsaSha1GetKlass; + gXmlSecNssFunctions->transformRsaPkcs1GetKlass = xmlSecNssTransformRsaPkcs1GetKlass; + +/* RSA OAEP is not supported by NSS yet */ +#ifdef TODO
+ gXmlSecNssFunctions->transformRsaOaepGetKlass = xmlSecNssTransformRsaOaepGetKlass; +#endif /* TODO: RSA OAEP is not supported by NSS yet */ + +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecNssFunctions->transformSha1GetKlass = xmlSecNssTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + + /** + * High level routines form xmlsec command line utility + */ + gXmlSecNssFunctions->cryptoAppInit = xmlSecNssAppInit; + gXmlSecNssFunctions->cryptoAppShutdown = xmlSecNssAppShutdown; + gXmlSecNssFunctions->cryptoAppDefaultKeysMngrInit = xmlSecNssAppDefaultKeysMngrInit; + gXmlSecNssFunctions->cryptoAppDefaultKeysMngrAdoptKey = xmlSecNssAppDefaultKeysMngrAdoptKey; + gXmlSecNssFunctions->cryptoAppDefaultKeysMngrLoad = xmlSecNssAppDefaultKeysMngrLoad; + gXmlSecNssFunctions->cryptoAppDefaultKeysMngrSave = xmlSecNssAppDefaultKeysMngrSave; +#ifndef XMLSEC_NO_X509 + gXmlSecNssFunctions->cryptoAppKeysMngrCertLoad = xmlSecNssAppKeysMngrCertLoad; + gXmlSecNssFunctions->cryptoAppKeysMngrCertLoadMemory= xmlSecNssAppKeysMngrCertLoadMemory; + gXmlSecNssFunctions->cryptoAppPkcs12Load = xmlSecNssAppPkcs12Load; + gXmlSecNssFunctions->cryptoAppPkcs12LoadMemory = xmlSecNssAppPkcs12LoadMemory; + gXmlSecNssFunctions->cryptoAppKeyCertLoad = xmlSecNssAppKeyCertLoad; + gXmlSecNssFunctions->cryptoAppKeyCertLoadMemory = xmlSecNssAppKeyCertLoadMemory; +#endif /* XMLSEC_NO_X509 */ + gXmlSecNssFunctions->cryptoAppKeyLoad = xmlSecNssAppKeyLoad; + gXmlSecNssFunctions->cryptoAppKeyLoadMemory = xmlSecNssAppKeyLoadMemory; + gXmlSecNssFunctions->cryptoAppDefaultPwdCallback = (void*)xmlSecNssAppGetDefaultPwdCallback(); + + return(gXmlSecNssFunctions); +} + +/** + * xmlSecNssInit: + * + * XMLSec library specific crypto engine initialization. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssInit (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(xmlSecNssErrorsDefaultCallback); + + /* register our klasses */ + if(xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(xmlSecCryptoGetFunctions_nss()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecNssShutdown: + * + * XMLSec library specific crypto engine shutdown. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssShutdown(void) { + return(0); +} + +/** + * xmlSecNssKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Adds NSS specific key data stores in keys manager. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + +#ifndef XMLSEC_NO_X509 + /* create x509 store if needed */ + if(xmlSecKeysMngrGetDataStore(mngr, xmlSecNssX509StoreId) == NULL) { + xmlSecKeyDataStorePtr x509Store; + + x509Store = xmlSecKeyDataStoreCreate(xmlSecNssX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssX509StoreId"); + 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); +} + +/** + * xmlSecNssGetInternalKeySlot: + * + * Gets internal NSS key slot. + * + * Returns: internal key slot and initializes it if needed. + */ +PK11SlotInfo * +xmlSecNssGetInternalKeySlot() +{ + PK11SlotInfo *slot = NULL; + SECStatus rv; + + slot = PK11_GetInternalKeySlot(); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GetInternalKeySlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return NULL; + } + + if (PK11_NeedUserInit(slot)) {
+ rv = PK11_InitPin(slot, NULL, NULL); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_Authenticate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return NULL; + } + } + + if(PK11_IsLoggedIn(slot, NULL) != PR_TRUE) { + rv = PK11_Authenticate(slot, PR_TRUE, NULL); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_Authenticate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return NULL; + } + } + + return(slot); +} + +/** + * xmlSecNssGenerateRandom: + * @buffer: the destination buffer. + * @size: the numer of bytes to generate. + * + * Generates @size random bytes and puts result in @buffer. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecNssGenerateRandom(xmlSecBufferPtr buffer, xmlSecSize size) { + SECStatus rv; + 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); + } + + /* get random data */ + rv = PK11_GenerateRandom((xmlSecByte*)xmlSecBufferGetData(buffer), size); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GenerateRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", size); + return(-1); + } + return(0); +} + +/** + * xmlSecNssErrorsDefaultCallback: + * @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 +xmlSecNssErrorsDefaultCallback(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg) { + xmlChar buf[500]; + int err; + + err = PORT_GetError(); + xmlSecStrPrintf(buf, sizeof(buf), BAD_CAST "%s;last nss error=%d (0x%08X)", msg, err, err); + xmlSecErrorsDefaultCallback(file, line, func, + errorObject, errorSubject, + reason, (char*)buf); +} diff --git a/src/nss/digests.c b/src/nss/digests.c new file mode 100644 index 00000000..5a1db916 --- /dev/null +++ b/src/nss/digests.c @@ -0,0 +1,331 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <nspr.h> +#include <nss.h> +#include <secoid.h> +#include <pk11func.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/app.h> +#include <xmlsec/nss/crypto.h> + +#define XMLSEC_NSS_MAX_DIGEST_SIZE 32 + +/************************************************************************** + * + * Internal NSS Digest CTX + * + *****************************************************************************/ +typedef struct _xmlSecNssDigestCtx xmlSecNssDigestCtx, *xmlSecNssDigestCtxPtr; +struct _xmlSecNssDigestCtx { + SECOidData* digest; + PK11Context* digestCtx; + xmlSecByte dgst[XMLSEC_NSS_MAX_DIGEST_SIZE]; + xmlSecSize dgstSize; /* dgst size in bytes */ +}; + +/****************************************************************************** + * + * Digest transforms + * + * xmlSecNssDigestCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecNssDigestSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecNssDigestCtx)) +#define xmlSecNssDigestGetCtx(transform) \ + ((xmlSecNssDigestCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecNssDigestInitialize (xmlSecTransformPtr transform); +static void xmlSecNssDigestFinalize (xmlSecTransformPtr transform); +static int xmlSecNssDigestVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssDigestExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssDigestCheckId (xmlSecTransformPtr transform); + +static int +xmlSecNssDigestCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + + return(0); +} + +static int +xmlSecNssDigestInitialize(xmlSecTransformPtr transform) { + xmlSecNssDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecNssDigestCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssDigestSize), -1); + + ctx = xmlSecNssDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecNssDigestCtx)); + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha1Id)) { + ctx->digest = SECOID_FindOIDByTag(SEC_OID_SHA1); + } else +#endif /* XMLSEC_NO_SHA1 */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(ctx->digest == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "SECOID_FindOIDByTag", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + + ctx->digestCtx = PK11_CreateDigestContext(ctx->digest->offset); + if(ctx->digestCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_CreateDigestContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + + return(0); +} + +static void +xmlSecNssDigestFinalize(xmlSecTransformPtr transform) { + xmlSecNssDigestCtxPtr ctx; + + xmlSecAssert(xmlSecNssDigestCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssDigestSize)); + + ctx = xmlSecNssDigestGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->digestCtx != NULL) { + PK11_DestroyContext(ctx->digestCtx, PR_TRUE); + } + memset(ctx, 0, sizeof(xmlSecNssDigestCtx)); +} + +static int +xmlSecNssDigestVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecNssDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecNssDigestCheckId(transform), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssDigestSize), -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecNssDigestGetCtx(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_DATA, + "data and digest sizes are different (data=%d, dgst=%d)", + dataSize, ctx->dgstSize); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + if(memcmp(ctx->dgst, data, dataSize) != 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 +xmlSecNssDigestExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssDigestCtxPtr ctx; + xmlSecBufferPtr in, out; + SECStatus rv; + int ret; + + xmlSecAssert2(xmlSecNssDigestCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(transformCtx != NULL, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssDigestSize), -1); + + ctx = xmlSecNssDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + if(transform->status == xmlSecTransformStatusNone) { + rv = PK11_DigestBegin(ctx->digestCtx); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_DigestBegin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { + rv = PK11_DigestOp(ctx->digestCtx, xmlSecBufferGetData(in), inSize); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_DigestOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + 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) { + rv = PK11_DigestFinal(ctx->digestCtx, ctx->dgst, &ctx->dgstSize, sizeof(ctx->dgst)); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + xmlSecAssert2(ctx->dgstSize > 0, -1); + + 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(&(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_SHA1 +/****************************************************************************** + * + * SHA1 Digest transforms + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecNssSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssDigestSize, /* xmlSecSize objSize */ + + /* data */ + xmlSecNameSha1, /* const xmlChar* name; */ + xmlSecHrefSha1, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + /* methods */ + xmlSecNssDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformSha1GetKlass: + * + * SHA-1 digest transform klass. + * + * Returns: pointer to SHA-1 digest transform klass. + */ +xmlSecTransformId +xmlSecNssTransformSha1GetKlass(void) { + return(&xmlSecNssSha1Klass); +} +#endif /* XMLSEC_NO_SHA1 */ + + + diff --git a/src/nss/globals.h b/src/nss/globals.h new file mode 100644 index 00000000..272a27b8 --- /dev/null +++ b/src/nss/globals.h @@ -0,0 +1,24 @@ +/* + * XML Security Library + * + * globals.h: internal header only used during the compilation + * + * 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_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 + +#endif /* ! __XMLSEC_GLOBALS_H__ */ diff --git a/src/nss/hmac.c b/src/nss/hmac.c new file mode 100644 index 00000000..98bf0c12 --- /dev/null +++ b/src/nss/hmac.c @@ -0,0 +1,633 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#ifndef XMLSEC_NO_HMAC +#include "globals.h" + +#include <string.h> + +#include <nspr.h> +#include <nss.h> +#include <secoid.h> +#include <pk11func.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/app.h> +#include <xmlsec/nss/crypto.h> + +/* sizes in bits */ +#define XMLSEC_NSS_MIN_HMAC_SIZE 80 +#define XMLSEC_NSS_MAX_HMAC_SIZE (128 * 8) + +/************************************************************************** + * + * Configuration + * + *****************************************************************************/ +static int g_xmlsec_nss_hmac_min_length = XMLSEC_NSS_MIN_HMAC_SIZE; + +/** + * xmlSecNssHmacGetMinOutputLength: + * + * Gets the value of min HMAC length. + * + * Returns: the min HMAC output length + */ +int xmlSecNssHmacGetMinOutputLength(void) +{ + return g_xmlsec_nss_hmac_min_length; +} + +/** + * xmlSecNssHmacSetMinOutputLength: + * @min_length: the new min length + * + * Sets the min HMAC output length + */ +void xmlSecNssHmacSetMinOutputLength(int min_length) +{ + g_xmlsec_nss_hmac_min_length = min_length; +} + +/************************************************************************** + * + * Internal NSS HMAC CTX + * + *****************************************************************************/ +typedef struct _xmlSecNssHmacCtx xmlSecNssHmacCtx, *xmlSecNssHmacCtxPtr; +struct _xmlSecNssHmacCtx { + CK_MECHANISM_TYPE digestType; + PK11Context* digestCtx; + xmlSecByte dgst[XMLSEC_NSS_MAX_HMAC_SIZE / 8]; + xmlSecSize dgstSize; /* dgst size in bits */ +}; + +/****************************************************************************** + * + * HMAC transforms + * + * xmlSecNssHmacCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecNssHmacGetCtx(transform) \ + ((xmlSecNssHmacCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecNssHmacSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecNssHmacCtx)) +#define xmlSecNssHmacCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecNssTransformHmacSha1Id) || \ + xmlSecTransformCheckId((transform), xmlSecNssTransformHmacMd5Id) || \ + xmlSecTransformCheckId((transform), xmlSecNssTransformHmacRipemd160Id)) + +static int xmlSecNssHmacInitialize (xmlSecTransformPtr transform); +static void xmlSecNssHmacFinalize (xmlSecTransformPtr transform); +static int xmlSecNssHmacNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssHmacSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecNssHmacSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecNssHmacVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssHmacExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static int +xmlSecNssHmacInitialize(xmlSecTransformPtr transform) { + xmlSecNssHmacCtxPtr ctx; + + xmlSecAssert2(xmlSecNssHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize), -1); + + ctx = xmlSecNssHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssHmacCtx)); + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha1Id)) { + ctx->digestType = CKM_SHA_1_HMAC; + } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacMd5Id)) { + ctx->digestType = CKM_MD5_HMAC; + } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacRipemd160Id)) { + ctx->digestType = CKM_RIPEMD160_HMAC; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecNssHmacFinalize(xmlSecTransformPtr transform) { + xmlSecNssHmacCtxPtr ctx; + + xmlSecAssert(xmlSecNssHmacCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize)); + + ctx = xmlSecNssHmacGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->digestCtx != NULL) { + PK11_DestroyContext(ctx->digestCtx, PR_TRUE); + } + memset(ctx, 0, sizeof(xmlSecNssHmacCtx)); +} + +/** + * xmlSecNssHmacNodeRead: + * + * HMAC (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> + * + * Schema Definition: + * + * <simpleType name="HMACOutputLengthType"> + * <restriction base="integer"/> + * </simpleType> + * + * DTD: + * + * <!ELEMENT HMACOutputLength (#PCDATA)> + */ +static int +xmlSecNssHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssHmacCtxPtr ctx; + xmlNodePtr cur; + + xmlSecAssert2(xmlSecNssHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize), -1); + xmlSecAssert2(node!= NULL, -1); + xmlSecAssert2(transformCtx!= NULL, -1); + + ctx = xmlSecNssHmacGetCtx(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 lenght to 0 or very + small value + */ + if((int)ctx->dgstSize < xmlSecNssHmacGetMinOutputLength()) { + 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_INVALID_NODE, + "no nodes expected"); + return(-1); + } + return(0); +} + + +static int +xmlSecNssHmacSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecNssHmacCtxPtr ctx; + + xmlSecAssert2(xmlSecNssHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(keyReq != NULL, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize), -1); + + ctx = xmlSecNssHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecNssKeyDataHmacId; + keyReq->keyType= xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationSign) { + keyReq->keyUsage = xmlSecKeyUsageSign; + } else { + keyReq->keyUsage = xmlSecKeyUsageVerify; + } + + return(0); +} + +static int +xmlSecNssHmacSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecNssHmacCtxPtr ctx; + xmlSecKeyDataPtr value; + xmlSecBufferPtr buffer; + SECItem keyItem; + SECItem ignore; + PK11SlotInfo* slot; + PK11SymKey* symKey; + + xmlSecAssert2(xmlSecNssHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecNssHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestType != 0, -1); + xmlSecAssert2(ctx->digestCtx == NULL, -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(xmlSecKeyDataCheckId(value, xmlSecNssKeyDataHmacId), -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, + "key is empty"); + return(-1); + } + + memset(&ignore, 0, sizeof(ignore)); + memset(&keyItem, 0, sizeof(keyItem)); + keyItem.data = xmlSecBufferGetData(buffer); + keyItem.len = xmlSecBufferGetSize(buffer); + + slot = PK11_GetBestSlot(ctx->digestType, NULL); + if(slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + symKey = PK11_ImportSymKey(slot, ctx->digestType, PK11_OriginDerive, + CKA_SIGN, &keyItem, NULL); + if(symKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_ImportSymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PK11_FreeSlot(slot); + return(-1); + } + + ctx->digestCtx = PK11_CreateContextBySymKey(ctx->digestType, CKA_SIGN, symKey, &ignore); + if(ctx->digestCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_CreateContextBySymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PK11_FreeSymKey(symKey); + PK11_FreeSlot(slot); + return(-1); + } + + PK11_FreeSymKey(symKey); + PK11_FreeSlot(slot); + return(0); +} + +static int +xmlSecNssHmacVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + static xmlSecByte last_byte_masks[] = + { 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; + + xmlSecNssHmacCtxPtr ctx; + xmlSecByte mask; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize), -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecNssHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + xmlSecAssert2(ctx->dgstSize > 0, -1); + + /* compare the digest size in bytes */ + if(dataSize != ((ctx->dgstSize + 7) / 8)){ + 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 +xmlSecNssHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssHmacCtxPtr ctx; + xmlSecBufferPtr in, out; + SECStatus rv; + int ret; + + xmlSecAssert2(xmlSecNssHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssHmacSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecNssHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digestCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + if(transform->status == xmlSecTransformStatusNone) { + rv = PK11_DigestBegin(ctx->digestCtx); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_DigestBegin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { + rv = PK11_DigestOp(ctx->digestCtx, xmlSecBufferGetData(in), inSize); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_DigestOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + 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) { + xmlSecSize dgstSize; + + rv = PK11_DigestFinal(ctx->digestCtx, ctx->dgst, &dgstSize, sizeof(ctx->dgst)); + if(rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + xmlSecAssert2(dgstSize > 0, -1); + + /* check/set the result digest size */ + if(ctx->dgstSize == 0) { + ctx->dgstSize = dgstSize * 8; /* no dgst size specified, use all we have */ + } else if(ctx->dgstSize <= 8 * dgstSize) { + dgstSize = ((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 * dgstSize, ctx->dgstSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationSign) { + ret = xmlSecBufferAppend(out, ctx->dgst, dgstSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", 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(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "size=%d", transform->status); + return(-1); + } + + return(0); +} + +/** + * HMAC SHA1 + */ +static xmlSecTransformKlass xmlSecNssHmacSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha1, /* const xmlChar* name; */ + xmlSecHrefHmacSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecNssHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecNssHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecNssHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformHmacSha1GetKlass: + * + * The HMAC-SHA1 transform klass. + * + * Returns: the HMAC-SHA1 transform klass. + */ +xmlSecTransformId +xmlSecNssTransformHmacSha1GetKlass(void) { + return(&xmlSecNssHmacSha1Klass); +} + +/** + * HMAC Ripemd160 + */ +static xmlSecTransformKlass xmlSecNssHmacRipemd160Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacRipemd160, /* const xmlChar* name; */ + xmlSecHrefHmacRipemd160, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecNssHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecNssHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecNssHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformHmacRipemd160GetKlass: + * + * The HMAC-RIPEMD160 transform klass. + * + * Returns: the HMAC-RIPEMD160 transform klass. + */ +xmlSecTransformId +xmlSecNssTransformHmacRipemd160GetKlass(void) { + return(&xmlSecNssHmacRipemd160Klass); +} + +/** + * HMAC Md5 + */ +static xmlSecTransformKlass xmlSecNssHmacMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacMd5, /* const xmlChar* name; */ + xmlSecHrefHmacMd5, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecNssHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecNssHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecNssHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformHmacMd5GetKlass: + * + * The HMAC-MD5 transform klass. + * + * Returns: the HMAC-MD5 transform klass. + */ +xmlSecTransformId +xmlSecNssTransformHmacMd5GetKlass(void) { + return(&xmlSecNssHmacMd5Klass); +} + + +#endif /* XMLSEC_NO_HMAC */ + + diff --git a/src/nss/keysstore.c b/src/nss/keysstore.c new file mode 100644 index 00000000..a583f604 --- /dev/null +++ b/src/nss/keysstore.c @@ -0,0 +1,485 @@ +/** + * XMLSec library + * + * Nss keys store that uses Simple Keys Store under the hood. Uses the + * Nss DB as a backing store for the finding keys, but the NSS DB is + * 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 NSS DB is looked up. + * If store is called to adopt a key, that key is not written to the NSS + * DB. + * Thus, the NSS DB 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 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <nss.h> +#include <cert.h> +#include <pk11func.h> +#include <keyhi.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/nss/crypto.h> +#include <xmlsec/nss/keysstore.h> +#include <xmlsec/nss/x509.h> +#include <xmlsec/nss/pkikeys.h> + +/**************************************************************************** + * + * Nss Keys Store. Uses Simple Keys Store under the hood + * + * Simple Keys Store ptr is located after xmlSecKeyStore + * + ***************************************************************************/ +#define xmlSecNssKeysStoreSize \ + (sizeof(xmlSecKeyStore) + sizeof(xmlSecKeyStorePtr)) + +#define xmlSecNssKeysStoreGetSS(store) \ + ((xmlSecKeyStoreCheckSize((store), xmlSecNssKeysStoreSize)) ? \ + (xmlSecKeyStorePtr*)(((xmlSecByte*)(store)) + sizeof(xmlSecKeyStore)) : \ + (xmlSecKeyStorePtr*)NULL) + +static int xmlSecNssKeysStoreInitialize (xmlSecKeyStorePtr store); +static void xmlSecNssKeysStoreFinalize (xmlSecKeyStorePtr store); +static xmlSecKeyPtr xmlSecNssKeysStoreFindKey (xmlSecKeyStorePtr store, + const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyStoreKlass xmlSecNssKeysStoreKlass = { + sizeof(xmlSecKeyStoreKlass), + xmlSecNssKeysStoreSize, + + /* data */ + BAD_CAST "NSS-keys-store", /* const xmlChar* name; */ + + /* constructors/destructor */ + xmlSecNssKeysStoreInitialize, /* xmlSecKeyStoreInitializeMethod initialize; */ + xmlSecNssKeysStoreFinalize, /* xmlSecKeyStoreFinalizeMethod finalize; */ + xmlSecNssKeysStoreFindKey, /* xmlSecKeyStoreFindKeyMethod findKey; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeysStoreGetKlass: + * + * The Nss list based keys store klass. + * + * Returns: Nss list based keys store klass. + */ +xmlSecKeyStoreId +xmlSecNssKeysStoreGetKlass(void) { + return(&xmlSecNssKeysStoreKlass); +} + +/** + * xmlSecNssKeysStoreAdoptKey: + * @store: the pointer to Nss 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 +xmlSecNssKeysStoreAdoptKey(xmlSecKeyStorePtr store, xmlSecKeyPtr key) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1); + xmlSecAssert2((key != NULL), -1); + + ss = xmlSecNssKeysStoreGetSS(store); + xmlSecAssert2(((ss != NULL) && (*ss != NULL) && + (xmlSecKeyStoreCheckId(*ss, xmlSecSimpleKeysStoreId))), -1); + + return (xmlSecSimpleKeysStoreAdoptKey(*ss, key)); +} + +/** + * xmlSecNssKeysStoreLoad: + * @store: the pointer to Nss 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 +xmlSecNssKeysStoreLoad(xmlSecKeyStorePtr store, const char *uri, + xmlSecKeysMngrPtr keysMngr) { + xmlDocPtr doc; + xmlNodePtr root; + xmlNodePtr cur; + xmlSecKeyPtr key; + xmlSecKeyInfoCtx keyInfoCtx; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -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 = xmlSecNssKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyStoreGetName(store)), + "xmlSecNssKeysStoreAdoptKey", + 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); +} + +/** + * xmlSecNssKeysStoreSave: + * @store: the pointer to Nss 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 +xmlSecNssKeysStoreSave(xmlSecKeyStorePtr store, const char *filename, xmlSecKeyDataType type) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1); + xmlSecAssert2((filename != NULL), -1); + + ss = xmlSecNssKeysStoreGetSS(store); + xmlSecAssert2(((ss != NULL) && (*ss != NULL) && + (xmlSecKeyStoreCheckId(*ss, xmlSecSimpleKeysStoreId))), -1); + + return (xmlSecSimpleKeysStoreSave(*ss, filename, type)); +} + +static int +xmlSecNssKeysStoreInitialize(xmlSecKeyStorePtr store) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), -1); + + ss = xmlSecNssKeysStoreGetSS(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 +xmlSecNssKeysStoreFinalize(xmlSecKeyStorePtr store) { + xmlSecKeyStorePtr *ss; + + xmlSecAssert(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId)); + + ss = xmlSecNssKeysStoreGetSS(store); + xmlSecAssert((ss != NULL) && (*ss != NULL)); + + xmlSecKeyStoreDestroy(*ss); +} + +static xmlSecKeyPtr +xmlSecNssKeysStoreFindKey(xmlSecKeyStorePtr store, const xmlChar* name, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyStorePtr* ss; + xmlSecKeyPtr key = NULL; + xmlSecKeyPtr retval = NULL; + xmlSecKeyReqPtr keyReq = NULL; + CERTCertificate *cert = NULL; + SECKEYPublicKey *pubkey = NULL; + SECKEYPrivateKey *privkey = NULL; + xmlSecKeyDataPtr data = NULL; + xmlSecKeyDataPtr x509Data = NULL; + int ret; + + xmlSecAssert2(xmlSecKeyStoreCheckId(store, xmlSecNssKeysStoreId), NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ss = xmlSecNssKeysStoreGetSS(store); + xmlSecAssert2(((ss != NULL) && (*ss != NULL)), NULL); + + key = xmlSecKeyStoreFindKey(*ss, name, keyInfoCtx); + if (key != NULL) { + return (key); + } + + /* Try to find the key in the NSS DB, and construct an xmlSecKey. + * we must have a name to lookup keys in NSS DB. + */ + if (name == NULL) { + goto done; + } + + /* what type of key are we looking for? + * TBD: For now, we'll look only for public/private keys using the + * name as a cert nickname. Later on, we can attempt to find + * symmetric keys using PK11_FindFixedKey + */ + keyReq = &(keyInfoCtx->keyReq); + if (keyReq->keyType & + (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate)) { + cert = CERT_FindCertByNickname (CERT_GetDefaultCertDB(), (char *)name); + if (cert == NULL) { + goto done; + } + + if (keyReq->keyType & xmlSecKeyDataTypePublic) { + pubkey = CERT_ExtractPublicKey(cert); + if (pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_ExtractPublicKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + + if (keyReq->keyType & xmlSecKeyDataTypePrivate) { + privkey = PK11_FindKeyByAnyCert(cert, NULL); + if (privkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_FindKeyByAnyCert", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + + data = xmlSecNssPKIAdoptKey(privkey, pubkey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssPKIAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + privkey = NULL; + pubkey = NULL; + + key = xmlSecKeyCreate(); + if (key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + x509Data = xmlSecKeyDataCreate(xmlSecNssKeyDataX509Id); + if(x509Data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecNssKeyDataX509Id))); + goto done; + } + + ret = xmlSecNssKeyDataX509AdoptKeyCert(x509Data, cert); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + cert = CERT_DupCertificate(cert); + if (cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + ret = xmlSecNssKeyDataX509AdoptCert(x509Data, cert); + if (ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + cert = NULL; + + 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; + + retval = key; + key = NULL; + } + +done: + if (cert != NULL) { + CERT_DestroyCertificate(cert); + } + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (privkey != NULL) { + SECKEY_DestroyPrivateKey(privkey); + } + if (data != NULL) { + xmlSecKeyDataDestroy(data); + } + if (x509Data != NULL) { + xmlSecKeyDataDestroy(x509Data); + } + if (key != NULL) { + xmlSecKeyDestroy(key); + } + + return (retval); +} diff --git a/src/nss/keytrans.c b/src/nss/keytrans.c new file mode 100644 index 00000000..5d256c22 --- /dev/null +++ b/src/nss/keytrans.c @@ -0,0 +1,744 @@ +/** + * + * XMLSec library + * + * AES Algorithm support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright ................................. + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <nss.h> +#include <pk11func.h> +#include <keyhi.h> +#include <key.h> +#include <hasht.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/pkikeys.h> + +/********************************************************************* + * + * key transform transforms + * + ********************************************************************/ +typedef struct _xmlSecNssKeyTransportCtx xmlSecNssKeyTransportCtx; +typedef struct _xmlSecNssKeyTransportCtx* xmlSecNssKeyTransportCtxPtr; + +#define xmlSecNssKeyTransportSize \ + ( sizeof( xmlSecTransform ) + sizeof( xmlSecNssKeyTransportCtx ) ) +#define xmlSecNssKeyTransportGetCtx( transform ) \ + ( ( xmlSecNssKeyTransportCtxPtr )( ( ( xmlSecByte* )( transform ) ) + sizeof( xmlSecTransform ) ) ) + +struct _xmlSecNssKeyTransportCtx { + CK_MECHANISM_TYPE cipher ; + SECKEYPublicKey* pubkey ; + SECKEYPrivateKey* prikey ; + xmlSecKeyDataId keyId ; + xmlSecBufferPtr material ; /* to be encrypted/decrypted material */ +} ; + +static int xmlSecNssKeyTransportInitialize(xmlSecTransformPtr transform); +static void xmlSecNssKeyTransportFinalize(xmlSecTransformPtr transform); +static int xmlSecNssKeyTransportSetKeyReq(xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecNssKeyTransportSetKey(xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecNssKeyTransportExecute(xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static int +xmlSecNssKeyTransportCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_RSA + if( xmlSecTransformCheckId( transform, xmlSecNssTransformRsaPkcs1Id ) +/* RSA OAEP is not supported by NSS yet */ +#ifdef TODO + || xmlSecTransformCheckId( transform, xmlSecNssTransformRsaOaepId ) +#endif /* TODO: RSA OAEP is not supported by NSS yet */ + + ) { + + return(1); + } +#endif /* XMLSEC_NO_RSA */ + + return(0); +} + +static int +xmlSecNssKeyTransportInitialize(xmlSecTransformPtr transform) { + xmlSecNssKeyTransportCtxPtr context ; + xmlSecAssert2(xmlSecNssKeyTransportCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKeyTransportSize), -1); + + context = xmlSecNssKeyTransportGetCtx( transform ) ; + xmlSecAssert2( context != NULL , -1 ) ; + +#ifndef XMLSEC_NO_RSA + if( transform->id == xmlSecNssTransformRsaPkcs1Id ) { + context->cipher = CKM_RSA_PKCS ; + context->keyId = xmlSecNssKeyDataRsaId ; +/* RSA OAEP is not supported by NSS yet */ +#ifdef TODO + } else if( transform->id == xmlSecNssTransformRsaOaepId ) { + context->cipher = CKM_RSA_PKCS_OAEP ; + context->keyId = xmlSecNssKeyDataRsaId ; +#endif /* TODO: RSA OAEP is not supported by NSS yet */ + } else +#endif /* XMLSEC_NO_RSA */ + + if( 1 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + context->pubkey = NULL ; + context->prikey = NULL ; + context->material = NULL ; + + return(0); +} + +static void +xmlSecNssKeyTransportFinalize(xmlSecTransformPtr transform) { + xmlSecNssKeyTransportCtxPtr context ; + + xmlSecAssert(xmlSecNssKeyTransportCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKeyTransportSize)); + + context = xmlSecNssKeyTransportGetCtx( transform ) ; + xmlSecAssert( context != NULL ) ; + + if( context->pubkey != NULL ) { + SECKEY_DestroyPublicKey( context->pubkey ) ; + context->pubkey = NULL ; + } + + if( context->prikey != NULL ) { + SECKEY_DestroyPrivateKey( context->prikey ) ; + context->prikey = NULL ; + } + + if( context->material != NULL ) { + xmlSecBufferDestroy(context->material); + context->material = NULL ; + } +} + +static int +xmlSecNssKeyTransportSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecNssKeyTransportCtxPtr context ; + + xmlSecAssert2(xmlSecNssKeyTransportCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKeyTransportSize), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(keyReq != NULL, -1); + + context = xmlSecNssKeyTransportGetCtx( transform ) ; + xmlSecAssert2( context != NULL , -1 ) ; + + keyReq->keyId = context->keyId; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + keyReq->keyType = xmlSecKeyDataTypePublic; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + keyReq->keyType = xmlSecKeyDataTypePrivate; + } + + return(0); +} + +static int +xmlSecNssKeyTransportSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecNssKeyTransportCtxPtr context = NULL ; + xmlSecKeyDataPtr keyData = NULL ; + SECKEYPublicKey* pubkey = NULL ; + SECKEYPrivateKey* prikey = NULL ; + + xmlSecAssert2(xmlSecNssKeyTransportCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKeyTransportSize), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(key != NULL, -1); + + context = xmlSecNssKeyTransportGetCtx( transform ) ; + if( (context == NULL) || (context->keyId == NULL) || (context->pubkey != NULL) ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + "xmlSecNssKeyTransportGetCtx" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + xmlSecAssert2( xmlSecKeyCheckId( key, context->keyId ), -1 ) ; + + keyData = xmlSecKeyGetValue( key ) ; + if( keyData == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecKeyGetName( key ) ) , + "xmlSecKeyGetValue" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + if( ( pubkey = xmlSecNssPKIKeyDataGetPubKey( keyData ) ) == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecKeyDataGetName( keyData ) ) , + "xmlSecNssPKIKeyDataGetPubKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + context->pubkey = pubkey ; + } else { + if( ( prikey = xmlSecNssPKIKeyDataGetPrivKey( keyData ) ) == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecKeyDataGetName( keyData ) ) , + "xmlSecNssPKIKeyDataGetPrivKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + context->prikey = prikey ; + } + + return(0) ; +} + +/** + * key wrap transform + */ +static int +xmlSecNssKeyTransportCtxInit( + xmlSecNssKeyTransportCtxPtr ctx , + xmlSecBufferPtr in , + xmlSecBufferPtr out , + int encrypt , + xmlSecTransformCtxPtr transformCtx +) { + int blockSize ; + + xmlSecAssert2( ctx != NULL , -1 ) ; + xmlSecAssert2( ctx->cipher != CKM_INVALID_MECHANISM , -1 ) ; + xmlSecAssert2( ( ctx->pubkey != NULL && encrypt ) || ( ctx->prikey != NULL && !encrypt ), -1 ) ; + xmlSecAssert2( ctx->keyId != NULL , -1 ) ; + xmlSecAssert2( in != NULL , -1 ) ; + xmlSecAssert2( out != NULL , -1 ) ; + xmlSecAssert2( transformCtx != NULL , -1 ) ; + + if( ctx->material != NULL ) { + xmlSecBufferDestroy( ctx->material ) ; + ctx->material = NULL ; + } + + if( ctx->pubkey != NULL ) { + blockSize = SECKEY_PublicKeyStrength( ctx->pubkey ) ; + } else if( ctx->prikey != NULL ) { + blockSize = PK11_SignatureLen( ctx->prikey ) ; + } else { + blockSize = -1 ; + } + + if( blockSize < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + ctx->material = xmlSecBufferCreate( blockSize ) ; + if( ctx->material == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferCreate" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + /* read raw key material into context */ + if( xmlSecBufferSetData( ctx->material, xmlSecBufferGetData(in), xmlSecBufferGetSize(in) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferSetData" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + if( xmlSecBufferRemoveHead( in , xmlSecBufferGetSize(in) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferRemoveHead" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + return(0); +} + +/** + * key wrap transform update + */ +static int +xmlSecNssKeyTransportCtxUpdate( + xmlSecNssKeyTransportCtxPtr ctx , + xmlSecBufferPtr in , + xmlSecBufferPtr out , + int encrypt , + xmlSecTransformCtxPtr transformCtx +) { + xmlSecAssert2( ctx != NULL , -1 ) ; + xmlSecAssert2( ctx->cipher != CKM_INVALID_MECHANISM , -1 ) ; + xmlSecAssert2( ( ctx->pubkey != NULL && encrypt ) || ( ctx->prikey != NULL && !encrypt ), -1 ) ; + xmlSecAssert2( ctx->keyId != NULL , -1 ) ; + xmlSecAssert2( ctx->material != NULL , -1 ) ; + xmlSecAssert2( in != NULL , -1 ) ; + xmlSecAssert2( out != NULL , -1 ) ; + xmlSecAssert2( transformCtx != NULL , -1 ) ; + + /* read raw key material and append into context */ + if( xmlSecBufferAppend( ctx->material, xmlSecBufferGetData(in), xmlSecBufferGetSize(in) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferAppend" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + if( xmlSecBufferRemoveHead( in , xmlSecBufferGetSize(in) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferRemoveHead" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + return(0); +} + +/** + * Block cipher transform final + */ +static int +xmlSecNssKeyTransportCtxFinal(xmlSecNssKeyTransportCtxPtr ctx, xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, xmlSecTransformCtxPtr transformCtx) { + PK11SymKey* symKey ; + PK11SlotInfo* slot ; + SECItem oriskv ; + int blockSize ; + xmlSecBufferPtr result ; + + xmlSecAssert2( ctx != NULL , -1 ) ; + xmlSecAssert2( ctx->cipher != CKM_INVALID_MECHANISM , -1 ) ; + xmlSecAssert2( ( ctx->pubkey != NULL && encrypt ) || ( ctx->prikey != NULL && !encrypt ), -1 ) ; + xmlSecAssert2( ctx->keyId != NULL , -1 ) ; + xmlSecAssert2( ctx->material != NULL , -1 ) ; + xmlSecAssert2( in != NULL , -1 ) ; + xmlSecAssert2( out != NULL , -1 ) ; + xmlSecAssert2( transformCtx != NULL , -1 ) ; + + /* read raw key material and append into context */ + if( xmlSecBufferAppend( ctx->material, xmlSecBufferGetData(in), xmlSecBufferGetSize(in) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferAppend" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + if( xmlSecBufferRemoveHead( in , xmlSecBufferGetSize(in) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferRemoveHead" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + /* Now we get all of the key materail */ + /* from now on we will wrap or unwrap the key */ + if( ctx->pubkey != NULL ) { + blockSize = SECKEY_PublicKeyStrength( ctx->pubkey ) ; + } else if( ctx->prikey != NULL ) { + blockSize = PK11_SignatureLen( ctx->prikey ) ; + } else { + blockSize = -1 ; + } + + if( blockSize < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_GetBlockSize" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + result = xmlSecBufferCreate( blockSize * 2 ) ; + if( result == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL, + "xmlSecBufferCreate" , + XMLSEC_ERRORS_R_XMLSEC_FAILED , + XMLSEC_ERRORS_NO_MESSAGE) ; + return(-1); + } + + oriskv.type = siBuffer ; + oriskv.data = xmlSecBufferGetData( ctx->material ) ; + oriskv.len = xmlSecBufferGetSize( ctx->material ) ; + + if( encrypt != 0 ) { + CK_OBJECT_HANDLE id ; + SECItem wrpskv ; + + /* Create template symmetric key from material */ + slot = ctx->pubkey->pkcs11Slot; + if( slot == NULL ) { + slot = PK11_GetBestSlot( ctx->cipher, NULL ) ; + if( slot == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecNssSlotGet" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + xmlSecBufferDestroy(result); + return(-1); + } + + id = PK11_ImportPublicKey( slot, ctx->pubkey, PR_FALSE ) ; + if( id == CK_INVALID_HANDLE ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_ImportPublicKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + xmlSecBufferDestroy(result); + PK11_FreeSlot( slot ) ; + return(-1); + } + } + + /* pay attention to mechanism */ + symKey = PK11_ImportSymKey( slot, ctx->cipher, PK11_OriginUnwrap, CKA_WRAP, &oriskv, NULL ) ; + if( symKey == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_ImportSymKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + xmlSecBufferDestroy(result); + PK11_FreeSlot( slot ) ; + return(-1); + } + + wrpskv.type = siBuffer ; + wrpskv.data = xmlSecBufferGetData( result ) ; + wrpskv.len = xmlSecBufferGetMaxSize( result ) ; + + if( PK11_PubWrapSymKey( ctx->cipher, ctx->pubkey, symKey, &wrpskv ) != SECSuccess ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_PubWrapSymKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + PK11_FreeSymKey( symKey ) ; + xmlSecBufferDestroy(result); + PK11_FreeSlot( slot ) ; + return(-1); + } + + if( xmlSecBufferSetSize( result , wrpskv.len ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferSetSize" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + PK11_FreeSymKey( symKey ) ; + xmlSecBufferDestroy(result); + PK11_FreeSlot( slot ) ; + return(-1); + } + PK11_FreeSymKey( symKey ) ; + PK11_FreeSlot( slot ) ; + } else { + SECItem* keyItem ; + + /* pay attention to mechanism */ + symKey = PK11_PubUnwrapSymKey( ctx->prikey, &oriskv, ctx->cipher, CKA_UNWRAP, 0 ); + if( symKey == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_PubUnwrapSymKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + xmlSecBufferDestroy(result); + return(-1); + } + + /* Extract raw data from symmetric key */ + if( PK11_ExtractKeyValue( symKey ) != SECSuccess ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_ExtractKeyValue" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + PK11_FreeSymKey( symKey ) ; + xmlSecBufferDestroy(result); + return(-1); + } + + keyItem = PK11_GetKeyData( symKey ); + if( keyItem == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_GetKeyData" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + PK11_FreeSymKey( symKey ) ; + xmlSecBufferDestroy(result); + return(-1); + } + + if( xmlSecBufferSetData( result, keyItem->data, keyItem->len ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "PK11_PubUnwrapSymKey" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + PK11_FreeSymKey( symKey ) ; + xmlSecBufferDestroy(result); + return(-1); + } + PK11_FreeSymKey( symKey ) ; + } + + /* Write output */ + if( xmlSecBufferAppend( out, xmlSecBufferGetData(result), xmlSecBufferGetSize(result) ) < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + "xmlSecBufferAppend" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + xmlSecBufferDestroy(result); + return(-1); + } + xmlSecBufferDestroy(result); + + return(0); +} + +static int +xmlSecNssKeyTransportExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssKeyTransportCtxPtr context = NULL ; + xmlSecBufferPtr inBuf, outBuf ; + int operation ; + int rtv ; + + xmlSecAssert2( xmlSecNssKeyTransportCheckId( transform ), -1 ) ; + xmlSecAssert2( xmlSecTransformCheckSize( transform, xmlSecNssKeyTransportSize ), -1 ) ; + xmlSecAssert2( ( transform->operation == xmlSecTransformOperationEncrypt ) || ( transform->operation == xmlSecTransformOperationDecrypt ), -1 ) ; + xmlSecAssert2( transformCtx != NULL , -1 ) ; + + context = xmlSecNssKeyTransportGetCtx( transform ) ; + if( context == NULL ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + "xmlSecNssKeyTransportGetCtx" , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + inBuf = &( transform->inBuf ) ; + outBuf = &( transform->outBuf ) ; + + if( transform->status == xmlSecTransformStatusNone ) { + transform->status = xmlSecTransformStatusWorking ; + } + + operation = ( transform->operation == xmlSecTransformOperationEncrypt ) ? 1 : 0 ; + if( transform->status == xmlSecTransformStatusWorking ) { + if( context->material == NULL ) { + rtv = xmlSecNssKeyTransportCtxInit( context, inBuf , outBuf , operation , transformCtx ) ; + if( rtv < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + "xmlSecNssKeyTransportCtxInit" , + XMLSEC_ERRORS_R_INVALID_STATUS , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + } + + if( (context->material == NULL) && (last != 0) ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + NULL , + XMLSEC_ERRORS_R_INVALID_STATUS , + "No enough data to intialize transform" ) ; + return(-1); + } + + if( context->material != NULL ) { + rtv = xmlSecNssKeyTransportCtxUpdate( context, inBuf , outBuf , operation , transformCtx ) ; + if( rtv < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + "xmlSecNssKeyTransportCtxUpdate" , + XMLSEC_ERRORS_R_INVALID_STATUS , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + } + + if( last ) { + rtv = xmlSecNssKeyTransportCtxFinal( context, inBuf , outBuf , operation , transformCtx ) ; + if( rtv < 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + "xmlSecNssKeyTransportCtxFinal" , + XMLSEC_ERRORS_R_INVALID_STATUS , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + transform->status = xmlSecTransformStatusFinished ; + } + } else if( transform->status == xmlSecTransformStatusFinished ) { + if( xmlSecBufferGetSize( inBuf ) != 0 ) { + xmlSecError( XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString( xmlSecTransformGetName( transform ) ) , + NULL , + XMLSEC_ERRORS_R_INVALID_STATUS , + "status=%d", transform->status ) ; + return(-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 + +static xmlSecTransformKlass xmlSecNssRsaPkcs1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssKeyTransportSize, /* xmlSecSize objSize */ + + xmlSecNameRsaPkcs1, /* const xmlChar* name; */ + xmlSecHrefRsaPkcs1, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssKeyTransportInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssKeyTransportFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssKeyTransportSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssKeyTransportSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssKeyTransportExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformRsaPkcs1GetKlass: + * + * The RSA-PKCS1 key transport transform klass. + * + * Returns: RSA-PKCS1 key transport transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaPkcs1GetKlass(void) { + return(&xmlSecNssRsaPkcs1Klass); +} + + +/* RSA OAEP is not supported by NSS yet */ +#ifdef TODO + +static xmlSecTransformKlass xmlSecNssRsaOaepKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssKeyTransportSize, /* xmlSecSize objSize */ + + xmlSecNameRsaOaep, /* const xmlChar* name; */ + xmlSecHrefRsaOaep, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssKeyTransportInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssKeyTransportFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssKeyTransportSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssKeyTransportSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssKeyTransportExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformRsaOaepGetKlass: + * + * The RSA-PKCS1 key transport transform klass. + * + * Returns: RSA-PKCS1 key transport transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaOaepGetKlass(void) { + return(&xmlSecNssRsaOaepKlass); +} +#endif /* TODO: RSA OAEP is not supported by NSS yet */ + +#endif /* XMLSEC_NO_RSA */ + diff --git a/src/nss/kw_aes.c b/src/nss/kw_aes.c new file mode 100644 index 00000000..0c3a5708 --- /dev/null +++ b/src/nss/kw_aes.c @@ -0,0 +1,857 @@ +/** + * + * XMLSec library + * + * AES Algorithm support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#ifndef XMLSEC_NO_AES + +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <nss.h> +#include <pk11func.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> + +#define XMLSEC_NSS_AES128_KEY_SIZE 16 +#define XMLSEC_NSS_AES192_KEY_SIZE 24 +#define XMLSEC_NSS_AES256_KEY_SIZE 32 +#define XMLSEC_NSS_AES_IV_SIZE 16 +#define XMLSEC_NSS_AES_BLOCK_SIZE 16 + +#ifndef NSS_AES_KEYWRAP_BUG_FIXED +static PK11SymKey* xmlSecNssMakeAesKey(const xmlSecByte *key, + xmlSecSize keySize, int enc); +static void xmlSecNssAesOp(PK11SymKey *aeskey, + const xmlSecByte *in, xmlSecByte *out, + int enc); +#endif /* NSS_AES_KEYWRAP_BUG_FIXED */ + +/********************************************************************* + * + * AES KW transforms + * + * key (xmlSecBuffer) is located after xmlSecTransform structure + * + ********************************************************************/ +#define xmlSecNssKWAesGetKey(transform) \ + ((xmlSecBufferPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecNssKWAesSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer)) + +static int xmlSecNssKWAesInitialize (xmlSecTransformPtr transform); +static void xmlSecNssKWAesFinalize (xmlSecTransformPtr transform); +static int xmlSecNssKWAesSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecNssKWAesSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecNssKWAesExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static xmlSecSize xmlSecNssKWAesGetKeySize (xmlSecTransformPtr transform); +static int xmlSecNssKWAesOp (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte* in, + xmlSecSize inSize, + xmlSecByte* out, + xmlSecSize outSize, + int enc); + +static xmlSecTransformKlass xmlSecNssKWAes128Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes128, /* const xmlChar* name; */ + xmlSecHrefKWAes128, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static xmlSecTransformKlass xmlSecNssKWAes192Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes192, /* const xmlChar* name; */ + xmlSecHrefKWAes192, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static xmlSecTransformKlass xmlSecNssKWAes256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes256, /* const xmlChar* name; */ + xmlSecHrefKWAes256, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +#define XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE 8 + +#define xmlSecNssKWAesCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes128Id) || \ + xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes192Id) || \ + xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes256Id)) + +/** + * xmlSecNssTransformKWAes128GetKlass: + * + * The AES-128 key wrapper transform klass. + * + * Returns: AES-128 key wrapper transform klass. + */ +xmlSecTransformId +xmlSecNssTransformKWAes128GetKlass(void) { + return(&xmlSecNssKWAes128Klass); +} + +/** + * xmlSecNssTransformKWAes192GetKlass: + * + * The AES-192 key wrapper transform klass. + * + * Returns: AES-192 key wrapper transform klass. + */ +xmlSecTransformId +xmlSecNssTransformKWAes192GetKlass(void) { + return(&xmlSecNssKWAes192Klass); +} + +/** + * xmlSecNssTransformKWAes256GetKlass: + * + * The AES-256 key wrapper transform klass. + * + * Returns: AES-256 key wrapper transform klass. + */ +xmlSecTransformId +xmlSecNssTransformKWAes256GetKlass(void) { + return(&xmlSecNssKWAes256Klass); +} + +static int +xmlSecNssKWAesInitialize(xmlSecTransformPtr transform) { + int ret; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + + ret = xmlSecBufferInitialize(xmlSecNssKWAesGetKey(transform), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecNssKWAesFinalize(xmlSecTransformPtr transform) { + xmlSecAssert(xmlSecNssKWAesCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize)); + + if(xmlSecNssKWAesGetKey(transform) != NULL) { + xmlSecBufferFinalize(xmlSecNssKWAesGetKey(transform)); + } +} + +static int +xmlSecNssKWAesSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecNssKeyDataAesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * xmlSecNssKWAesGetKeySize(transform); + + return(0); +} + +static int +xmlSecNssKWAesSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecBufferPtr buffer; + xmlSecSize keySize; + xmlSecSize expectedKeySize; + int ret; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + xmlSecAssert2(xmlSecNssKWAesGetKey(transform) != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataAesId), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + expectedKeySize = xmlSecNssKWAesGetKeySize(transform); + if(keySize < expectedKeySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "key=%d;expected=%d", + keySize, expectedKeySize); + return(-1); + } + + ret = xmlSecBufferSetData(xmlSecNssKWAesGetKey(transform), + xmlSecBufferGetData(buffer), + expectedKeySize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "expected-size=%d", expectedKeySize); + return(-1); + } + + return(0); +} + +static int +xmlSecNssKWAesExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr in, out, key; + xmlSecSize inSize, outSize, keySize, expectedKeySize; + int ret; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + key = xmlSecNssKWAesGetKey(transform); + xmlSecAssert2(key != NULL, -1); + + keySize = xmlSecBufferGetSize(key); + expectedKeySize = xmlSecNssKWAesGetKeySize(transform); + xmlSecAssert2(keySize == expectedKeySize, -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_NSS_KW_AES_MAGIC_BLOCK_SIZE + + XMLSEC_NSS_AES_BLOCK_SIZE; + } else { + outSize = inSize + XMLSEC_NSS_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 = xmlSecNssKWAesOp(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssKWAesOp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecNssKWAesOp(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssKWAesOp", + 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); +} + +static xmlSecSize +xmlSecNssKWAesGetKeySize(xmlSecTransformPtr transform) { + if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes128Id)) { + return(XMLSEC_NSS_AES128_KEY_SIZE); + } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes192Id)) { + return(XMLSEC_NSS_AES192_KEY_SIZE); + } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes256Id)) { + return(XMLSEC_NSS_AES256_KEY_SIZE); + } + return(0); +} + +/** + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap: + * + * Assume that the data to be wrapped consists of N 64-bit data blocks + * denoted P(1), P(2), P(3) ... P(N). The result of wrapping will be N+1 + * 64-bit blocks denoted C(0), C(1), C(2), ... C(N). The key encrypting + * key is represented by K. Assume integers i, j, and t and intermediate + * 64-bit register A, 128-bit register B, and array of 64-bit quantities + * R(1) through R(N). + * + * "|" represents concatentation so x|y, where x and y and 64-bit quantities, + * is the 128-bit quantity with x in the most significant bits and y in the + * least significant bits. AES(K)enc(x) is the operation of AES encrypting + * the 128-bit quantity x under the key K. AES(K)dec(x) is the corresponding + * decryption opteration. XOR(x,y) is the bitwise exclusive or of x and y. + * MSB(x) and LSB(y) are the most significant 64 bits and least significant + * 64 bits of x and y respectively. + * + * If N is 1, a single AES operation is performed for wrap or unwrap. + * If N>1, then 6*N AES operations are performed for wrap or unwrap. + * + * The key wrap algorithm is as follows: + * + * 1. If N is 1: + * * B=AES(K)enc(0xA6A6A6A6A6A6A6A6|P(1)) + * * C(0)=MSB(B) + * * C(1)=LSB(B) + * If N>1, perform the following steps: + * 2. Initialize variables: + * * Set A to 0xA6A6A6A6A6A6A6A6 + * * Fori=1 to N, + * R(i)=P(i) + * 3. Calculate intermediate values: + * * Forj=0 to 5, + * o For i=1 to N, + * t= i + j*N + * B=AES(K)enc(A|R(i)) + * A=XOR(t,MSB(B)) + * R(i)=LSB(B) + * 4. Output the results: + * * Set C(0)=A + * * For i=1 to N, + * C(i)=R(i) + * + * The key unwrap algorithm is as follows: + * + * 1. If N is 1: + * * B=AES(K)dec(C(0)|C(1)) + * * P(1)=LSB(B) + * * If MSB(B) is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, + * return an integrity check failure error. + * If N>1, perform the following steps: + * 2. Initialize the variables: + * * A=C(0) + * * For i=1 to N, + * R(i)=C(i) + * 3. Calculate intermediate values: + * * For j=5 to 0, + * o For i=N to 1, + * t= i + j*N + * B=AES(K)dec(XOR(t,A)|R(i)) + * A=MSB(B) + * R(i)=LSB(B) + * 4. Output the results: + * * For i=1 to N, + * P(i)=R(i) + * * If A is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, return + * an integrity check failure error. + */ + +#ifndef NSS_AES_KEYWRAP_BUG_FIXED +static const xmlSecByte xmlSecNssKWAesMagicBlock[XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE] = { + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 +}; + +static int +xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize, int enc) { + xmlSecByte block[XMLSEC_NSS_AES_BLOCK_SIZE]; + xmlSecByte *p; + int N, i, j, t; + int result = -1; + PK11SymKey *aeskey = NULL; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize > 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize + 8, -1); + + if (enc == 1) { + aeskey = xmlSecNssMakeAesKey(key, keySize, enc); + if(aeskey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssMakeAesKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* prepend magic block */ + if(in != out) { + memcpy(out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, in, inSize); + } else { + memmove(out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, out, inSize); + } + memcpy(out, xmlSecNssKWAesMagicBlock, XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE); + + N = (inSize / 8); + if(N == 1) { + xmlSecNssAesOp(aeskey, out, out, enc); + } else { + for(j = 0; j <= 5; ++j) { + for(i = 1; i <= N; ++i) { + t = i + (j * N); + p = out + i * 8; + + memcpy(block, out, 8); + memcpy(block + 8, p, 8); + + xmlSecNssAesOp(aeskey, block, block, enc); + block[7] ^= t; + memcpy(out, block, 8); + memcpy(p, block + 8, 8); + } + } + } + + result = inSize + 8; + } else { + aeskey = xmlSecNssMakeAesKey(key, keySize, enc); + if(aeskey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssMakeAesKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* copy input */ + if(in != out) { + memcpy(out, in, inSize); + } + + N = (inSize / 8) - 1; + if(N == 1) { + xmlSecNssAesOp(aeskey, out, out, enc); + } else { + for(j = 5; j >= 0; --j) { + for(i = N; i > 0; --i) { + t = i + (j * N); + p = out + i * 8; + + memcpy(block, out, 8); + memcpy(block + 8, p, 8); + block[7] ^= t; + + xmlSecNssAesOp(aeskey, block, block, enc); + memcpy(out, block, 8); + memcpy(p, block + 8, 8); + } + } + } + /* do not left data in memory */ + memset(block, 0, sizeof(block)); + + if(memcmp(xmlSecNssKWAesMagicBlock, out, XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "bad magic block"); + goto done; + } + + memmove(out, out + XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE, inSize - XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE); + result = (inSize - XMLSEC_NSS_KW_AES_MAGIC_BLOCK_SIZE); + } + +done: + if (aeskey != NULL) { + PK11_FreeSymKey(aeskey); + } + + return (result); +} + +static PK11SymKey * +xmlSecNssMakeAesKey(const xmlSecByte *key, xmlSecSize keySize, int enc) { + CK_MECHANISM_TYPE cipherMech; + PK11SlotInfo* slot = NULL; + PK11SymKey* aeskey = NULL; + SECItem keyItem; + + xmlSecAssert2(key != NULL, NULL); + xmlSecAssert2(keySize > 0, NULL); + + cipherMech = CKM_AES_ECB; + slot = PK11_GetBestSlot(cipherMech, NULL); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + keyItem.data = (unsigned char *)key; + keyItem.len = keySize; + aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, + enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL); + if (aeskey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ImportSymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + +done: + if (slot) { + PK11_FreeSlot(slot); + } + + return(aeskey); +} + +/* encrypt a block (XMLSEC_NSS_AES_BLOCK_SIZE), in and out can overlap */ +static void +xmlSecNssAesOp(PK11SymKey *aeskey, const xmlSecByte *in, xmlSecByte *out, + int enc) { + + CK_MECHANISM_TYPE cipherMech; + SECItem* SecParam = NULL; + PK11Context* EncContext = NULL; + SECStatus rv; + int tmp1_outlen; + unsigned int tmp2_outlen; + + xmlSecAssert(in != NULL); + xmlSecAssert(out != NULL); + + cipherMech = CKM_AES_ECB; + SecParam = PK11_ParamFromIV(cipherMech, NULL); + if (SecParam == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ParamFromIV", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + EncContext = PK11_CreateContextBySymKey(cipherMech, + enc ? CKA_ENCRYPT : CKA_DECRYPT, + aeskey, SecParam); + if (EncContext == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CreateContextBySymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + tmp1_outlen = tmp2_outlen = 0; + rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, + XMLSEC_NSS_AES_BLOCK_SIZE, (unsigned char *)in, + XMLSEC_NSS_AES_BLOCK_SIZE); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CipherOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, + &tmp2_outlen, XMLSEC_NSS_AES_BLOCK_SIZE-tmp1_outlen); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + +done: + if (SecParam) { + SECITEM_FreeItem(SecParam, PR_TRUE); + } + if (EncContext) { + PK11_DestroyContext(EncContext, PR_TRUE); + } + +} + +#else /* NSS_AES_KEYWRAP_BUG_FIXED */ + +/* Note: When the bug gets fixed, it is not enough to just remove + * the #ifdef (NSS_AES_KEYWRAP_BUG_FIXED). The code also has + * to change from doing the Init/Update/Final to just a straight + * encrypt or decrypt. PK11 wrappers have to be exposed by + * NSS, and these should be used. + * Follow the NSS bug system for more details on the fix + * http://bugzilla.mozilla.org/show_bug.cgi?id=213795 + */ + +/* NSS implements the AES Key Wrap algorithm described at + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap + */ + +static int +xmlSecNssKWAesOp(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize, int enc) { + + CK_MECHANISM_TYPE cipherMech; + PK11SlotInfo* slot = NULL; + PK11SymKey* aeskey = NULL; + SECItem* SecParam = NULL; + PK11Context* EncContext = NULL; + SECItem keyItem; + SECStatus rv; + int result_len = -1; + int tmp1_outlen; + unsigned int tmp2_outlen; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize > 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize + 8, -1); + + cipherMech = CKM_NETSCAPE_AES_KEY_WRAP; + slot = PK11_GetBestSlot(cipherMech, NULL); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + keyItem.data = (unsigned char *)key; + keyItem.len = keySize; + aeskey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, + enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL); + if (aeskey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ImportSymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + SecParam = PK11_ParamFromIV(cipherMech, NULL); + if (SecParam == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ParamFromIV", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + EncContext = PK11_CreateContextBySymKey(cipherMech, + enc ? CKA_ENCRYPT : CKA_DECRYPT, + aeskey, SecParam); + if (EncContext == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CreateContextBySymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + tmp1_outlen = tmp2_outlen = 0; + rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, outSize, + (unsigned char *)in, inSize); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CipherOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, + &tmp2_outlen, outSize-tmp1_outlen); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + result_len = tmp1_outlen + tmp2_outlen; + +done: + if (slot) { + PK11_FreeSlot(slot); + } + if (aeskey) { + PK11_FreeSymKey(aeskey); + } + if (SecParam) { + SECITEM_FreeItem(SecParam, PR_TRUE); + } + if (EncContext) { + PK11_DestroyContext(EncContext, PR_TRUE); + } + + return(result_len); +} +#endif /* NSS_AES_KEYWRAP_BUG_FIXED */ + +#endif /* XMLSEC_NO_AES */ diff --git a/src/nss/kw_des.c b/src/nss/kw_des.c new file mode 100644 index 00000000..0cb6f24a --- /dev/null +++ b/src/nss/kw_des.c @@ -0,0 +1,758 @@ +/** + * + * XMLSec library + * + * DES Algorithm support + * + * This is free software; see Copyright file in the source + * distribution for precise wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ + +#ifndef XMLSEC_NO_DES +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <nss.h> +#include <pk11func.h> +#include <hasht.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> + +#define XMLSEC_NSS_DES3_KEY_LENGTH 24 +#define XMLSEC_NSS_DES3_IV_LENGTH 8 +#define XMLSEC_NSS_DES3_BLOCK_LENGTH 8 + +static xmlSecByte *xmlSecNssComputeSHA1(const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize); + + +/********************************************************************* + * + * Triple DES Key Wrap transform + * + * key (xmlSecBuffer) is located after xmlSecTransform structure + * + ********************************************************************/ +#define xmlSecNssKWDes3GetKey(transform) \ + ((xmlSecBufferPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecNssKWDes3Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer)) + +static int xmlSecNssKWDes3Initialize (xmlSecTransformPtr transform); +static void xmlSecNssKWDes3Finalize (xmlSecTransformPtr transform); +static int xmlSecNssKWDes3SetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecNssKWDes3SetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecNssKWDes3Execute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssKWDes3Encode (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize); +static int xmlSecNssKWDes3Decode (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize); +static int xmlSecNssKWDes3Encrypt (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *iv, + xmlSecSize ivSize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize, + int enc); +static int xmlSecNssKWDes3BufferReverse (xmlSecByte *buf, + xmlSecSize size); + +static xmlSecTransformKlass xmlSecNssKWDes3Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssKWDes3Size, /* xmlSecSize objSize */ + + xmlSecNameKWDes3, /* const xmlChar* name; */ + xmlSecHrefKWDes3, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecNssKWDes3Initialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssKWDes3Finalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssKWDes3SetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecNssKWDes3SetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssKWDes3Execute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformKWDes3GetKlass: + * + * The Triple DES key wrapper transform klass. + * + * Returns: Triple DES key wrapper transform klass. + */ +xmlSecTransformId +xmlSecNssTransformKWDes3GetKlass(void) { + return(&xmlSecNssKWDes3Klass); +} + +static int +xmlSecNssKWDes3Initialize(xmlSecTransformPtr transform) { + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size), -1); + + ret = xmlSecBufferInitialize(xmlSecNssKWDes3GetKey(transform), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecNssKWDes3Finalize(xmlSecTransformPtr transform) { + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size)); + + if(xmlSecNssKWDes3GetKey(transform) != NULL) { + xmlSecBufferFinalize(xmlSecNssKWDes3GetKey(transform)); + } +} + +static int +xmlSecNssKWDes3SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecNssKeyDataDesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage= xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage= xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * XMLSEC_NSS_DES3_KEY_LENGTH; + return(0); +} + +static int +xmlSecNssKWDes3SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecBufferPtr buffer; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size), -1); + xmlSecAssert2(xmlSecNssKWDes3GetKey(transform) != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataDesId), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + if(keySize < XMLSEC_NSS_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_NSS_DES3_KEY_LENGTH); + return(-1); + } + + ret = xmlSecBufferSetData(xmlSecNssKWDes3GetKey(transform), + xmlSecBufferGetData(buffer), + XMLSEC_NSS_DES3_KEY_LENGTH); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", XMLSEC_NSS_DES3_KEY_LENGTH); + return(-1); + } + + return(0); +} + +static int +xmlSecNssKWDes3Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr in, out, key; + xmlSecSize inSize, outSize, keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + key = xmlSecNssKWDes3GetKey(transform); + xmlSecAssert2(key != NULL, -1); + + keySize = xmlSecBufferGetSize(key); + xmlSecAssert2(keySize == XMLSEC_NSS_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_NSS_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_NSS_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_NSS_DES3_IV_LENGTH + + XMLSEC_NSS_DES3_BLOCK_LENGTH + + XMLSEC_NSS_DES3_BLOCK_LENGTH; + } else { + outSize = inSize + XMLSEC_NSS_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 = xmlSecNssKWDes3Encode(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssKWDes3Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "key=%d,in=%d,out=%d", + keySize, inSize, outSize); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecNssKWDes3Decode(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssKWDes3Decode", + 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); +} + +static xmlSecByte xmlSecNssKWDes3Iv[XMLSEC_NSS_DES3_IV_LENGTH] = { + 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 +}; +/** + * CMS Triple DES Key Wrap + * + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap + * + * The following algorithm wraps (encrypts) a key (the wrapped key, WK) + * under a TRIPLEDES key-encryption-key (KEK) as specified in [CMS-Algorithms]: + * + * 1. Represent the key being wrapped as an octet sequence. If it is a + * TRIPLEDES key, this is 24 octets (192 bits) with odd parity bit as + * the bottom bit of each octet. + * 2. Compute the CMS key checksum (section 5.6.1) call this CKS. + * 3. Let WKCKS = WK || CKS, where || is concatenation. + * 4. Generate 8 random octets [RANDOM] and call this IV. + * 5. Encrypt WKCKS in CBC mode using KEK as the key and IV as the + * initialization vector. Call the results TEMP1. + * 6. Left TEMP2 = IV || TEMP1. + * 7. Reverse the order of the octets in TEMP2 and call the result TEMP3. + * 8. Encrypt TEMP3 in CBC mode using the KEK and an initialization vector + * of 0x4adda22c79e82105. The resulting cipher text is the desired result. + * It is 40 octets long if a 168 bit key is being wrapped. + * + */ +static int +xmlSecNssKWDes3Encode(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + xmlSecByte sha1[SHA1_LENGTH]; + xmlSecByte iv[XMLSEC_NSS_DES3_IV_LENGTH]; + xmlSecSize s; + int ret; + SECStatus status; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == XMLSEC_NSS_DES3_KEY_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize + 16, -1); + + /* step 2: calculate sha1 and CMS */ + if(xmlSecNssComputeSHA1(in, inSize, sha1, SHA1_LENGTH) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssComputeSHA1", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 3: construct WKCKS */ + memcpy(out, in, inSize); + memcpy(out + inSize, sha1, XMLSEC_NSS_DES3_BLOCK_LENGTH); + + /* step 4: generate random iv */ + status = PK11_GenerateRandom(iv, XMLSEC_NSS_DES3_IV_LENGTH); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GenerateRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 5: first encryption, result is TEMP1 */ + ret = xmlSecNssKWDes3Encrypt(key, keySize, + iv, XMLSEC_NSS_DES3_IV_LENGTH, + out, inSize + XMLSEC_NSS_DES3_BLOCK_LENGTH, + out, outSize, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 6: construct TEMP2=IV || TEMP1 */ + memmove(out + XMLSEC_NSS_DES3_IV_LENGTH, out, + inSize + XMLSEC_NSS_DES3_IV_LENGTH); + memcpy(out, iv, XMLSEC_NSS_DES3_IV_LENGTH); + s = ret + XMLSEC_NSS_DES3_IV_LENGTH; + + /* step 7: reverse octets order, result is TEMP3 */ + ret = xmlSecNssKWDes3BufferReverse(out, s); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3BufferReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 8: second encryption with static IV */ + ret = xmlSecNssKWDes3Encrypt(key, keySize, + xmlSecNssKWDes3Iv, XMLSEC_NSS_DES3_IV_LENGTH, + out, s, out, outSize, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + s = ret; + return(s); +} + +/** + * CMS Triple DES Key Wrap + * + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap + * + * The following algorithm unwraps (decrypts) a key as specified in + * [CMS-Algorithms]: + * + * 1. Check if the length of the cipher text is reasonable given the key type. + * It must be 40 bytes for a 168 bit key and either 32, 40, or 48 bytes for + * a 128, 192, or 256 bit key. If the length is not supported or inconsistent + * with the algorithm for which the key is intended, return error. + * 2. Decrypt the cipher text with TRIPLEDES in CBC mode using the KEK and + * an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3. + * 3. Reverse the order of the octets in TEMP3 and call the result TEMP2. + * 4. Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining + * octets. + * 5. Decrypt TEMP1 using TRIPLEDES in CBC mode using the KEK and the IV found + * in the previous step. Call the result WKCKS. + * 6. Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are + * those octets before the CKS. + * 7. Calculate a CMS key checksum (section 5.6.1) over the WK and compare + * with the CKS extracted in the above step. If they are not equal, return + * error. + * 8. WK is the wrapped key, now extracted for use in data decryption. + */ +static int +xmlSecNssKWDes3Decode(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + xmlSecByte sha1[SHA1_LENGTH]; + xmlSecSize s; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == XMLSEC_NSS_DES3_KEY_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + /* step 2: first decryption with static IV, result is TEMP3 */ + ret = xmlSecNssKWDes3Encrypt(key, keySize, + xmlSecNssKWDes3Iv, XMLSEC_NSS_DES3_IV_LENGTH, + in, inSize, out, outSize, 0); + if((ret < 0) || (ret < XMLSEC_NSS_DES3_IV_LENGTH)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + s = ret; + + /* step 3: reverse octets order in TEMP3, result is TEMP2 */ + ret = xmlSecNssKWDes3BufferReverse(out, s); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3BufferReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* steps 4 and 5: get IV and decrypt second time, result is WKCKS */ + ret = xmlSecNssKWDes3Encrypt(key, keySize, + out, XMLSEC_NSS_DES3_IV_LENGTH, + out + XMLSEC_NSS_DES3_IV_LENGTH, + s - XMLSEC_NSS_DES3_IV_LENGTH, + out, outSize, 0); + if((ret < 0) || (ret < XMLSEC_NSS_DES3_BLOCK_LENGTH)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + s = ret - XMLSEC_NSS_DES3_BLOCK_LENGTH; + + /* steps 6 and 7: calculate SHA1 and validate it */ + if(xmlSecNssComputeSHA1(out, s, sha1, SHA1_LENGTH) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssComputeSHA1", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(memcmp(sha1, out + s, XMLSEC_NSS_DES3_BLOCK_LENGTH) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "SHA1 does not match"); + return(-1); + } + + return(s); +} + +static int +xmlSecNssKWDes3Encrypt(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *iv, xmlSecSize ivSize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize, int enc) { + CK_MECHANISM_TYPE cipherMech; + PK11SlotInfo* slot = NULL; + PK11SymKey* SymKey = NULL; + SECItem* SecParam = NULL; + PK11Context* EncContext = NULL; + SECItem keyItem, ivItem; + SECStatus rv; + int result_len = -1; + int tmp1_outlen; + unsigned int tmp2_outlen; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == XMLSEC_NSS_DES3_KEY_LENGTH, -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize == XMLSEC_NSS_DES3_IV_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + cipherMech = CKM_DES3_CBC; + slot = PK11_GetBestSlot(cipherMech, NULL); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + keyItem.data = (unsigned char *)key; + keyItem.len = keySize; + SymKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap, + enc ? CKA_ENCRYPT : CKA_DECRYPT, &keyItem, NULL); + if (SymKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ImportSymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ivItem.data = (unsigned char *)iv; + ivItem.len = ivSize; + + SecParam = PK11_ParamFromIV(cipherMech, &ivItem); + if (SecParam == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ParamFromIV", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + EncContext = PK11_CreateContextBySymKey(cipherMech, + enc ? CKA_ENCRYPT : CKA_DECRYPT, + SymKey, SecParam); + if (EncContext == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CreateContextBySymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + tmp1_outlen = tmp2_outlen = 0; + rv = PK11_CipherOp(EncContext, out, &tmp1_outlen, outSize, + (unsigned char *)in, inSize); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CipherOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + rv = PK11_DigestFinal(EncContext, out+tmp1_outlen, + &tmp2_outlen, outSize-tmp1_outlen); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + result_len = tmp1_outlen + tmp2_outlen; + +done: + if (slot) { + PK11_FreeSlot(slot); + } + if (SymKey) { + PK11_FreeSymKey(SymKey); + } + if (SecParam) { + SECITEM_FreeItem(SecParam, PR_TRUE); + } + if (EncContext) { + PK11_DestroyContext(EncContext, PR_TRUE); + } + + return(result_len); +} + +static int +xmlSecNssKWDes3BufferReverse(xmlSecByte *buf, xmlSecSize size) { + xmlSecSize s; + xmlSecSize i; + xmlSecByte c; + + xmlSecAssert2(buf != NULL, -1); + + s = size / 2; + --size; + for(i = 0; i < s; ++i) { + c = buf[i]; + buf[i] = buf[size - i]; + buf[size - i] = c; + } + return(0); +} + +static xmlSecByte * +xmlSecNssComputeSHA1(const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) +{ + PK11Context *context = NULL; + SECStatus s; + xmlSecByte *digest = NULL; + unsigned int len; + + xmlSecAssert2(in != NULL, NULL); + xmlSecAssert2(out != NULL, NULL); + xmlSecAssert2(outSize >= SHA1_LENGTH, NULL); + + /* Create a context for hashing (digesting) */ + context = PK11_CreateDigestContext(SEC_OID_SHA1); + if (context == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CreateDigestContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + s = PK11_DigestBegin(context); + if (s != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestBegin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + s = PK11_DigestOp(context, in, inSize); + if (s != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + s = PK11_DigestFinal(context, out, &len, outSize); + if (s != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + xmlSecAssert2(len == SHA1_LENGTH, NULL); + + digest = out; + +done: + if (context != NULL) { + PK11_DestroyContext(context, PR_TRUE); + } + return (digest); +} + +#endif /* XMLSEC_NO_DES */ + diff --git a/src/nss/pkikeys.c b/src/nss/pkikeys.c new file mode 100644 index 00000000..f8549352 --- /dev/null +++ b/src/nss/pkikeys.c @@ -0,0 +1,1554 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <pk11func.h> +#include <keyhi.h> +#include <pk11pqg.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/nss/crypto.h> +#include <xmlsec/nss/bignum.h> +#include <xmlsec/nss/pkikeys.h> + +/************************************************************************** + * + * Internal NSS PKI key CTX + * + *************************************************************************/ +typedef struct _xmlSecNssPKIKeyDataCtx xmlSecNssPKIKeyDataCtx, + *xmlSecNssPKIKeyDataCtxPtr; +struct _xmlSecNssPKIKeyDataCtx { + SECKEYPublicKey *pubkey; + SECKEYPrivateKey *privkey; +}; + +/****************************************************************************** + * + * PKI key (dsa/rsa) + * + * xmlSecNssPKIKeyDataCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecNssPKIKeyDataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecNssPKIKeyDataCtx)) +#define xmlSecNssPKIKeyDataGetCtx(data) \ + ((xmlSecNssPKIKeyDataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + + +static int xmlSecNssPKIKeyDataInitialize (xmlSecKeyDataPtr data); +static void xmlSecNssPKIKeyDataFinalize (xmlSecKeyDataPtr data); + + +static void xmlSecNSSPKIKeyDataCtxFree (xmlSecNssPKIKeyDataCtxPtr ctx); +static int xmlSecNSSPKIKeyDataCtxDup (xmlSecNssPKIKeyDataCtxPtr ctxDst, + xmlSecNssPKIKeyDataCtxPtr ctxSrc); +static int xmlSecNssPKIKeyDataAdoptKey (xmlSecKeyDataPtr data, + SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey); + + +static int +xmlSecNssPKIKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), -1); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssPKIKeyDataCtx)); + + return(0); +} + + +static void +xmlSecNssPKIKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize)); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + xmlSecNSSPKIKeyDataCtxFree(ctx); + memset(ctx, 0, sizeof(xmlSecNssPKIKeyDataCtx)); +} + + +static void +xmlSecNSSPKIKeyDataCtxFree(xmlSecNssPKIKeyDataCtxPtr ctx) +{ + xmlSecAssert(ctx != NULL); + if (ctx->privkey != NULL) { + SECKEY_DestroyPrivateKey(ctx->privkey); + ctx->privkey = NULL; + } + + if (ctx->pubkey) + { + SECKEY_DestroyPublicKey(ctx->pubkey); + ctx->pubkey = NULL; + } + +} + +static int +xmlSecNSSPKIKeyDataCtxDup(xmlSecNssPKIKeyDataCtxPtr ctxDst, + xmlSecNssPKIKeyDataCtxPtr ctxSrc) +{ + xmlSecNSSPKIKeyDataCtxFree(ctxDst); + if (ctxSrc->privkey != NULL) { + ctxDst->privkey = SECKEY_CopyPrivateKey(ctxSrc->privkey); + if(ctxDst->privkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECKEY_CopyPrivateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + + if (ctxSrc->pubkey != NULL) { + ctxDst->pubkey = SECKEY_CopyPublicKey(ctxSrc->pubkey); + if(ctxDst->pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SECKEY_CopyPublicKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + return (0); +} + +static int +xmlSecNssPKIKeyDataAdoptKey(xmlSecKeyDataPtr data, + SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey) +{ + xmlSecNssPKIKeyDataCtxPtr ctx; + KeyType pubType = nullKey ; + KeyType priType = nullKey ; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), -1); + + if( privkey != NULL ) { + priType = SECKEY_GetPrivateKeyType( privkey ) ; + } + + if( pubkey != NULL ) { + pubType = SECKEY_GetPublicKeyType( pubkey ) ; + } + + if( priType != nullKey && pubType != nullKey ) { + if( pubType != priType ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + "different type of private and public key" ) ; + return -1 ; + } + } + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if (ctx->privkey) { + SECKEY_DestroyPrivateKey(ctx->privkey); + } + ctx->privkey = privkey; + + if (ctx->pubkey) { + SECKEY_DestroyPublicKey(ctx->pubkey); + } + ctx->pubkey = pubkey; + + return(0); +} + +/** + * xmlSecNssPKIAdoptKey: + * @privkey: the NSS Private Key handle + * @pubkey: the NSS Public Key handle + * + * Build a KeyData object from the given Private Key and Public + * Key handles. + * + * Returns: pointer to KeyData object or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecNssPKIAdoptKey(SECKEYPrivateKey *privkey, + SECKEYPublicKey *pubkey) +{ + xmlSecKeyDataPtr data = NULL; + int ret; + KeyType pubType = nullKey ; + KeyType priType = nullKey ; + + if( privkey != NULL ) { + priType = SECKEY_GetPrivateKeyType( privkey ) ; + } + + if( pubkey != NULL ) { + pubType = SECKEY_GetPublicKeyType( pubkey ) ; + } + + if( priType != nullKey && pubType != nullKey ) { + if( pubType != priType ) { + xmlSecError( XMLSEC_ERRORS_HERE , + NULL , + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + "different type of private and public key" ) ; + return( NULL ) ; + } + } + + pubType = priType != nullKey ? priType : pubType ; + switch(pubType) { +#ifndef XMLSEC_NO_RSA + case rsaKey: + data = xmlSecKeyDataCreate(xmlSecNssKeyDataRsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssKeyDataRsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_RSA */ +#ifndef XMLSEC_NO_DSA + case dsaKey: + data = xmlSecKeyDataCreate(xmlSecNssKeyDataDsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNssKeyDataDsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_DSA */ + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "PKI key type %d not supported", pubType); + return(NULL); + } + + xmlSecAssert2(data != NULL, NULL); + ret = xmlSecNssPKIKeyDataAdoptKey(data, privkey, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + return(data); +} + +/** + * xmlSecNssPKIKeyDataGetPubKey: + * @data: the pointer to NSS Key data. + * + * Gets the Public Key from the key data. + * + * Returns: pointer to SECKEYPublicKey or NULL if an error occurs. + * Caller is responsible for freeing the key when done + */ +SECKEYPublicKey * +xmlSecNssPKIKeyDataGetPubKey(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + SECKEYPublicKey *ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), NULL); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->pubkey != NULL, NULL); + + ret = SECKEY_CopyPublicKey(ctx->pubkey); + return(ret); +} + +/** + * xmlSecNssPKIKeyDataGetPrivKey: + * @data: the pointer to NSS Key data. + * + * Gets the Private Key from the key data. + * + * Returns: pointer to SECKEYPrivateKey or NULL if an error occurs. + * Caller is responsible for freeing the key when done + */ +SECKEYPrivateKey* +xmlSecNssPKIKeyDataGetPrivKey(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + SECKEYPrivateKey* ret; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), NULL); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->privkey != NULL, NULL); + + ret = SECKEY_CopyPrivateKey(ctx->privkey); + return(ret); +} + +/** + * xmlSecNssPKIKeyDataGetKeyType: + * @data: the pointer to NSS Key data. + * + * Gets the Key Type from the key data. + * + * Returns: Key Type + */ +KeyType +xmlSecNssPKIKeyDataGetKeyType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + KeyType kt; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), nullKey); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecNssPKIKeyDataSize), nullKey); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, nullKey); + + if (ctx->pubkey != NULL) { + kt = SECKEY_GetPublicKeyType(ctx->pubkey); + } else { + kt = SECKEY_GetPrivateKeyType(ctx->privkey); + } + return(kt); +} + +/** + * xmlSecNssPKIKeyDataDuplicate + * @dst: the pointer to NSS Key data to copy to. + * @src: the pointer to NSS Key data to copy from. + * + * Duplicates the keydata from src to dst + * + * Returns: -1 on error, 0 on success + */ +int +xmlSecNssPKIKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecNssPKIKeyDataCtxPtr ctxDst; + xmlSecNssPKIKeyDataCtxPtr ctxSrc; + + xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecNssPKIKeyDataSize), -1); + xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecNssPKIKeyDataSize), -1); + + ctxDst = xmlSecNssPKIKeyDataGetCtx(dst); + xmlSecAssert2(ctxDst != NULL, -1); + + ctxSrc = xmlSecNssPKIKeyDataGetCtx(src); + xmlSecAssert2(ctxSrc != NULL, -1); + + if (xmlSecNSSPKIKeyDataCtxDup(ctxDst, ctxSrc) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecNssPKIKeydataCtxDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +#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 xmlSecNssKeyDataDsaInitialize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataDsaDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssKeyDataDsaFinalize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataDsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataDsaXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataDsaGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecNssKeyDataDsaGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecNssKeyDataDsaGetSize (xmlSecKeyDataPtr data); +static void xmlSecNssKeyDataDsaDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssKeyDataDsaDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecNssKeyDataDsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecNssPKIKeyDataSize, + + /* data */ + xmlSecNameDSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeDSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssKeyDataDsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssKeyDataDsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssKeyDataDsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssKeyDataDsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssKeyDataDsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssKeyDataDsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssKeyDataDsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssKeyDataDsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssKeyDataDsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssKeyDataDsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataDsaGetKlass: + * + * The DSA key data klass. + * + * Returns: pointer to DSA key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataDsaGetKlass(void) { + return(&xmlSecNssKeyDataDsaKlass); +} + + +static int +xmlSecNssKeyDataDsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), -1); + + return(xmlSecNssPKIKeyDataInitialize(data)); +} + +static int +xmlSecNssKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecNssKeyDataDsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecNssKeyDataDsaId), -1); + + return(xmlSecNssPKIKeyDataDuplicate(dst, src)); +} + +static void +xmlSecNssKeyDataDsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId)); + + xmlSecNssPKIKeyDataFinalize(data); +} + +static int +xmlSecNssKeyDataDsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data = NULL; + xmlNodePtr cur; + int ret; + PK11SlotInfo *slot = NULL; + CK_OBJECT_HANDLE handle; + SECKEYPublicKey *pubkey=NULL; + PRArenaPool *arena = NULL; + + + xmlSecAssert2(id == xmlSecNssKeyDataDsaId, -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, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + slot = PK11_GetBestSlot(CKM_DSA, NULL); + if(slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if(arena == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_NewArena", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + ret = -1; + goto done; + } + + pubkey = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(SECKEYPublicKey)); + if(pubkey == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_ArenaZAlloc", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PORT_FreeArena(arena, PR_FALSE); + ret = -1; + goto done; + } + pubkey->arena = arena; + pubkey->u.dsa.params.arena = arena; + pubkey->keyType = dsaKey; + + 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)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.params.prime)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + ret = -1; + 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)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.params.subPrime)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + ret = -1; + 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)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.params.base)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * NSS 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)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.dsa.publicValue)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", xmlSecErrorsSafeString(xmlSecNodeDSAY)); + ret = -1; + 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); + ret = -1; + goto done; + } + + handle = PK11_ImportPublicKey(slot, pubkey, PR_FALSE); + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, NULL, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + pubkey = NULL; + + 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; + + ret = 0; + +done: + if (slot != NULL) { + PK11_FreeSlot(slot); + } + if (ret != 0) { + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (data != NULL) { + xmlSecKeyDataDestroy(data); + } + } + return(ret); +} + +static int +xmlSecNssKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecNssPKIKeyDataCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataDsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecNssPKIKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == dsaKey, -1); + + if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only private key or public key */ + return(0); + } + + /* 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)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.params.prime), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + return(-1); + } + + /* 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)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.params.subPrime), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + return(-1); + } + + /* 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)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.params.base), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + return(-1); + } + + /* next is X node: not supported in NSS */ + + /* 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)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.dsa.publicValue), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + return(-1); + } + + return(0); +} + +static int +xmlSecNssKeyDataDsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + PQGParams *pqgParams = NULL; + PQGVerify *pqgVerify = NULL; + SECStatus rv; + SECStatus res; + PK11SlotInfo *slot = NULL; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + int ret = -1; + int j; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + j = PQG_PBITS_TO_INDEX(sizeBits); + rv = PK11_PQG_ParamGen(j, &pqgParams, &pqgVerify); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_PQG_ParamGen", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", sizeBits); + goto done; + } + + rv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &res); + if (rv != SECSuccess || res != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_PQG_VerifyParams", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", sizeBits); + goto done; + } + + slot = PK11_GetBestSlot(CKM_DSA_KEY_PAIR_GEN, NULL); + PK11_Authenticate(slot, PR_TRUE, NULL /* default pwd callback */); + privkey = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, pqgParams, + &pubkey, PR_FALSE, PR_TRUE, NULL); + + if((privkey == NULL) || (pubkey == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_GenerateKeyPair", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, privkey, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = 0; + +done: + if (slot != NULL) { + PK11_FreeSlot(slot); + } + if (pqgParams != NULL) { + PK11_PQG_DestroyParams(pqgParams); + } + if (pqgVerify != NULL) { + PK11_PQG_DestroyVerify(pqgVerify); + } + if (ret == 0) { + return (0); + } + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (privkey != NULL) { + SECKEY_DestroyPrivateKey(privkey); + } + return(-1); +} + +static xmlSecKeyDataType +xmlSecNssKeyDataDsaGetType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), xmlSecKeyDataTypeUnknown); + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == dsaKey, -1); + if (ctx->privkey != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } + + return(xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecNssKeyDataDsaGetSize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId), 0); + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == dsaKey, -1); + + return(8 * SECKEY_PublicKeyStrength(ctx->pubkey)); +} + +static void +xmlSecNssKeyDataDsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecNssKeyDataDsaGetSize(data)); +} + +static void +xmlSecNssKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<DSAKeyValue size=\"%d\" />\n", + xmlSecNssKeyDataDsaGetSize(data)); +} + +#endif /* XMLSEC_NO_DSA */ + +#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) > + * + * ============================================================================ + * + * To support reading/writing private keys an PrivateExponent element is added + * to the end + * + *************************************************************************/ + +static int xmlSecNssKeyDataRsaInitialize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataRsaDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssKeyDataRsaFinalize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataRsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataRsaXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataRsaGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecNssKeyDataRsaGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecNssKeyDataRsaGetSize (xmlSecKeyDataPtr data); +static void xmlSecNssKeyDataRsaDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssKeyDataRsaDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecNssKeyDataRsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecNssPKIKeyDataSize, + + /* data */ + xmlSecNameRSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefRSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeRSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssKeyDataRsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssKeyDataRsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssKeyDataRsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssKeyDataRsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssKeyDataRsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssKeyDataRsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssKeyDataRsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssKeyDataRsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssKeyDataRsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssKeyDataRsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataRsaGetKlass: + * + * The RSA key data klass. + * + * Returns: pointer to RSA key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataRsaGetKlass(void) { + return(&xmlSecNssKeyDataRsaKlass); +} + +static int +xmlSecNssKeyDataRsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), -1); + + return(xmlSecNssPKIKeyDataInitialize(data)); +} + +static int +xmlSecNssKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecNssKeyDataRsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecNssKeyDataRsaId), -1); + + return(xmlSecNssPKIKeyDataDuplicate(dst, src)); +} + +static void +xmlSecNssKeyDataRsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId)); + + xmlSecNssPKIKeyDataFinalize(data); +} + +static int +xmlSecNssKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data = NULL; + xmlNodePtr cur; + int ret; + PK11SlotInfo *slot = NULL; + SECKEYPublicKey *pubkey=NULL; + PRArenaPool *arena = NULL; + + xmlSecAssert2(id == xmlSecNssKeyDataRsaId, -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"); + ret = -1; + goto done; + } + + slot = PK11_GetBestSlot(CKM_RSA_PKCS, NULL); + if(slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PK11_GetBestSlot", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + ret = -1; + goto done; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if(arena == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_NewArena", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + ret = -1; + goto done; + } + + pubkey = (SECKEYPublicKey *)PORT_ArenaZAlloc(arena, + sizeof(SECKEYPublicKey)); + if(pubkey == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "PORT_ArenaZAlloc", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PORT_FreeArena(arena, PR_FALSE); + ret = -1; + goto done; + } + pubkey->arena = arena; + pubkey->keyType = rsaKey; + + 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)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.rsa.modulus)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + ret = -1; + 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)); + ret = -1; + goto done; + } + if(xmlSecNssNodeGetBigNumValue(arena, cur, &(pubkey->u.rsa.publicExponent)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeGetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + ret = -1; + goto done; + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * NSS 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"); + ret = -1; + 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); + ret = -1; + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, NULL, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + goto done; + } + pubkey = NULL; + + 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; + + ret = 0; + +done: + if (slot != 0) { + PK11_FreeSlot(slot); + } + if (ret != 0) { + if (pubkey != 0) { + SECKEY_DestroyPublicKey(pubkey); + } + if (data != 0) { + xmlSecKeyDataDestroy(data); + } + } + return(ret); +} + +static int +xmlSecNssKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecNssPKIKeyDataCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataRsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + ctx = xmlSecNssPKIKeyDataGetCtx(xmlSecKeyGetValue(key)); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == rsaKey, -1); + + + if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only private key or public key */ + return(0); + } + + /* 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)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.rsa.modulus), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + 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)); + return(-1); + } + ret = xmlSecNssNodeSetBigNumValue(cur, &(ctx->pubkey->u.rsa.publicExponent), 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssNodeSetBigNumValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + return(-1); + } + + /* next is PrivateExponent node: not supported in NSS */ + + return(0); +} + +static int +xmlSecNssKeyDataRsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + PK11RSAGenParams params; + PK11SlotInfo *slot = NULL; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + int ret = -1; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + params.keySizeInBits = sizeBits; + params.pe = 65537; + + slot = PK11_GetBestSlot(CKM_RSA_PKCS_KEY_PAIR_GEN, NULL); + PK11_Authenticate(slot, PR_TRUE, NULL /* default pwd callback */); + privkey = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ¶ms, + &pubkey, PR_FALSE, PR_TRUE, NULL); + + if(privkey == NULL || pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PK11_GenerateKeyPair", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + + goto done; + } + + ret = xmlSecNssPKIKeyDataAdoptKey(data, privkey, pubkey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssPKIKeyDataAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = 0; + +done: + if (slot != NULL) { + PK11_FreeSlot(slot); + } + if (ret == 0) { + return (0); + } + + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (privkey != NULL) { + SECKEY_DestroyPrivateKey(privkey); + } + return(-1); +} + +static xmlSecKeyDataType +xmlSecNssKeyDataRsaGetType(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), xmlSecKeyDataTypeUnknown); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pubkey == NULL || SECKEY_GetPublicKeyType(ctx->pubkey) == rsaKey, -1); + if (ctx->privkey != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } + + return(xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecNssKeyDataRsaGetSize(xmlSecKeyDataPtr data) { + xmlSecNssPKIKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId), 0); + + ctx = xmlSecNssPKIKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(SECKEY_GetPublicKeyType(ctx->pubkey) == rsaKey, -1); + + return(8 * SECKEY_PublicKeyStrength(ctx->pubkey)); +} + +static void +xmlSecNssKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== rsa key: size = %d\n", + xmlSecNssKeyDataRsaGetSize(data)); +} + +static void +xmlSecNssKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<RSAKeyValue size=\"%d\" />\n", + xmlSecNssKeyDataRsaGetSize(data)); +} + +#endif /* XMLSEC_NO_RSA */ + + + diff --git a/src/nss/signatures.c b/src/nss/signatures.c new file mode 100644 index 00000000..3c9639c3 --- /dev/null +++ b/src/nss/signatures.c @@ -0,0 +1,550 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#include <string.h> + +#include <cryptohi.h> +#include <keyhi.h> +#include <secerr.h> +#include <prmem.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/pkikeys.h> + + +/************************************************************************** + * + * Internal NSS signatures ctx + * + *****************************************************************************/ +typedef struct _xmlSecNssSignatureCtx xmlSecNssSignatureCtx, + *xmlSecNssSignatureCtxPtr; +struct _xmlSecNssSignatureCtx { + xmlSecKeyDataId keyId; + SECOidTag alg; + + union { + struct { + SGNContext *sigctx; + SECKEYPrivateKey *privkey; + } sig; + + struct { + VFYContext *vfyctx; + SECKEYPublicKey *pubkey; + } vfy; + } u; +}; + +/****************************************************************************** + * + * Signature transforms + * + * xmlSecNssSignatureCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecNssSignatureSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecNssSignatureCtx)) +#define xmlSecNssSignatureGetCtx(transform) \ + ((xmlSecNssSignatureCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecNssSignatureCheckId (xmlSecTransformPtr transform); +static int xmlSecNssSignatureInitialize (xmlSecTransformPtr transform); +static void xmlSecNssSignatureFinalize (xmlSecTransformPtr transform); +static int xmlSecNssSignatureSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecNssSignatureSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecNssSignatureVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecNssSignatureExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static int +xmlSecNssSignatureCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DSA + if(xmlSecTransformCheckId(transform, xmlSecNssTransformDsaSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_RSA */ + + return(0); +} + +static int +xmlSecNssSignatureInitialize(xmlSecTransformPtr transform) { + xmlSecNssSignatureCtxPtr ctx; + + xmlSecAssert2(xmlSecNssSignatureCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssSignatureSize), -1); + ctx = xmlSecNssSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssSignatureCtx)); + +#ifndef XMLSEC_NO_DSA + if(xmlSecTransformCheckId(transform, xmlSecNssTransformDsaSha1Id)) { + ctx->keyId = xmlSecNssKeyDataDsaId; + + /* This creates a signature which is ASN1 encoded */ + /*ctx->alg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;*/ + + /* Fortezza uses the same DSA signature format as XML does. + * DSA and FORTEZZA keys are treated as equivalent keys for doing + * DSA signatures (which is how they are supposed to be treated). + */ + ctx->alg = SEC_OID_MISSI_DSS; + } else +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha1Id)) { + ctx->keyId = xmlSecNssKeyDataRsaId; + ctx->alg = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + } else +#endif /* XMLSEC_NO_RSA */ + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecNssSignatureFinalize(xmlSecTransformPtr transform) { + xmlSecNssSignatureCtxPtr ctx; + + xmlSecAssert(xmlSecNssSignatureCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssSignatureSize)); + xmlSecAssert((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify)); + + ctx = xmlSecNssSignatureGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if (transform->operation == xmlSecTransformOperationSign) { + SGN_DestroyContext(ctx->u.sig.sigctx, PR_TRUE); + if (ctx->u.sig.privkey) { + SECKEY_DestroyPrivateKey(ctx->u.sig.privkey); + } + } else { + VFY_DestroyContext(ctx->u.vfy.vfyctx, PR_TRUE); + if (ctx->u.vfy.pubkey) { + SECKEY_DestroyPublicKey(ctx->u.vfy.pubkey); + } + } + + memset(ctx, 0, sizeof(xmlSecNssSignatureCtx)); +} + +static int +xmlSecNssSignatureSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecNssSignatureCtxPtr ctx; + xmlSecKeyDataPtr value; + + xmlSecAssert2(xmlSecNssSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssSignatureSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecNssSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(value != NULL, -1); + + if (transform->operation == xmlSecTransformOperationSign) { + if (ctx->u.sig.privkey) + SECKEY_DestroyPrivateKey(ctx->u.sig.privkey); + ctx->u.sig.privkey = xmlSecNssPKIKeyDataGetPrivKey(value); + if(ctx->u.sig.privkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssPKIKeyDataGetPrivKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->u.sig.sigctx = SGN_NewContext(ctx->alg, ctx->u.sig.privkey); + if (ctx->u.sig.sigctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "SGN_NewContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } else { + if (ctx->u.vfy.pubkey) + SECKEY_DestroyPublicKey(ctx->u.vfy.pubkey); + ctx->u.vfy.pubkey = xmlSecNssPKIKeyDataGetPubKey(value); + if(ctx->u.vfy.pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNssPKIKeyDataGetPubKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->u.vfy.vfyctx = VFY_CreateContext(ctx->u.vfy.pubkey, NULL, + ctx->alg, NULL); + if (ctx->u.vfy.vfyctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "VFY_CreateContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + + return(0); +} + +static int +xmlSecNssSignatureSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecNssSignatureCtxPtr ctx; + + xmlSecAssert2(xmlSecNssSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssSignatureSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecNssSignatureGetCtx(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 +xmlSecNssSignatureVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecNssSignatureCtxPtr ctx; + SECStatus status; + SECItem signature; + + xmlSecAssert2(xmlSecNssSignatureCheckId(transform), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssSignatureSize), -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecNssSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + signature.data = (unsigned char *)data; + signature.len = dataSize; + status = VFY_EndWithSignature(ctx->u.vfy.vfyctx, &signature); + + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "VFY_Update, VFY_End", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + + if (PORT_GetError() == SEC_ERROR_PKCS7_BAD_SIGNATURE) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "VFY_End", + XMLSEC_ERRORS_R_DATA_NOT_MATCH, + "signature does not verify"); + transform->status = xmlSecTransformStatusFail; + } + return(-1); + } + + transform->status = xmlSecTransformStatusOk; + return(0); +} + +static int +xmlSecNssSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssSignatureCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + SECStatus status; + SECItem signature; + int ret; + + xmlSecAssert2(xmlSecNssSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssSignatureSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecNssSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + ctx = xmlSecNssSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + if(transform->operation == xmlSecTransformOperationSign) { + xmlSecAssert2(ctx->u.sig.sigctx != NULL, -1); + xmlSecAssert2(ctx->u.sig.privkey != NULL, -1); + } else { + xmlSecAssert2(ctx->u.vfy.vfyctx != NULL, -1); + xmlSecAssert2(ctx->u.vfy.pubkey != NULL, -1); + } + + if(transform->status == xmlSecTransformStatusNone) { + xmlSecAssert2(outSize == 0, -1); + + if(transform->operation == xmlSecTransformOperationSign) { + status = SGN_Begin(ctx->u.sig.sigctx); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "SGN_Begin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } else { + status = VFY_Begin(ctx->u.vfy.vfyctx); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "VFY_Begin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (inSize > 0)) { + xmlSecAssert2(outSize == 0, -1); + + if(transform->operation == xmlSecTransformOperationSign) { + status = SGN_Update(ctx->u.sig.sigctx, xmlSecBufferGetData(in), inSize); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "SGN_Update", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } else { + status = VFY_Update(ctx->u.vfy.vfyctx, xmlSecBufferGetData(in), inSize); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "VFY_Update", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + 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)) { + xmlSecAssert2(outSize == 0, -1); + if(transform->operation == xmlSecTransformOperationSign) { + memset(&signature, 0, sizeof(signature)); + status = SGN_End(ctx->u.sig.sigctx, &signature); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "SGN_End", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + + outSize = signature.len; + ret = xmlSecBufferSetMaxSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + PR_Free(signature.data); + return(-1); + } + + memcpy(xmlSecBufferGetData(out), signature.data, signature.len); + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + PR_Free(signature.data); + return(-1); + } + PR_Free(signature.data); + } + 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_DSA +/**************************************************************************** + * + * DSA-SHA1 signature transform + * + ***************************************************************************/ + +static xmlSecTransformKlass xmlSecNssDsaSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameDsaSha1, /* const xmlChar* name; */ + xmlSecHrefDsaSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecNssSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecNssSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformDsaSha1GetKlass: + * + * The DSA-SHA1 signature transform klass. + * + * Returns: DSA-SHA1 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformDsaSha1GetKlass(void) { + return(&xmlSecNssDsaSha1Klass); +} + +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA +/**************************************************************************** + * + * RSA-SHA1 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecNssRsaSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha1, /* const xmlChar* name; */ + xmlSecHrefRsaSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecNssSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecNssSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecNssSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecNssSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecNssSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecNssSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssTransformRsaSha1GetKlass: + * + * The RSA-SHA1 signature transform klass. + * + * Returns: RSA-SHA1 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaSha1GetKlass(void) { + return(&xmlSecNssRsaSha1Klass); +} + +#endif /* XMLSEC_NO_DSA */ + + diff --git a/src/nss/symkeys.c b/src/nss/symkeys.c new file mode 100644 index 00000000..fb23f4fd --- /dev/null +++ b/src/nss/symkeys.c @@ -0,0 +1,440 @@ +/** + * + * 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> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.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/nss/crypto.h> + +/***************************************************************************** + * + * Symmetic (binary) keys - just a wrapper for xmlSecKeyDataBinary + * + ****************************************************************************/ +static int xmlSecNssSymKeyDataInitialize (xmlSecKeyDataPtr data); +static int xmlSecNssSymKeyDataDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssSymKeyDataFinalize (xmlSecKeyDataPtr data); +static int xmlSecNssSymKeyDataXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssSymKeyDataXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssSymKeyDataBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const xmlSecByte* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssSymKeyDataBinWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlSecByte** buf, + xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssSymKeyDataGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecNssSymKeyDataGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecNssSymKeyDataGetSize (xmlSecKeyDataPtr data); +static void xmlSecNssSymKeyDataDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssSymKeyDataDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); +static int xmlSecNssSymKeyDataKlassCheck (xmlSecKeyDataKlass* klass); + +#define xmlSecNssSymKeyDataCheckId(data) \ + (xmlSecKeyDataIsValid((data)) && \ + xmlSecNssSymKeyDataKlassCheck((data)->id)) + +static int +xmlSecNssSymKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecNssSymKeyDataCheckId(data), -1); + + return(xmlSecKeyDataBinaryValueInitialize(data)); +} + +static int +xmlSecNssSymKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecNssSymKeyDataCheckId(dst), -1); + xmlSecAssert2(xmlSecNssSymKeyDataCheckId(src), -1); + xmlSecAssert2(dst->id == src->id, -1); + + return(xmlSecKeyDataBinaryValueDuplicate(dst, src)); +} + +static void +xmlSecNssSymKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecNssSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueFinalize(data); +} + +static int +xmlSecNssSymKeyDataXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecNssSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlRead(id, key, node, keyInfoCtx)); +} + +static int +xmlSecNssSymKeyDataXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecNssSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlWrite(id, key, node, keyInfoCtx)); +} + +static int +xmlSecNssSymKeyDataBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecNssSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinRead(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecNssSymKeyDataBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlSecByte** buf, xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecNssSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinWrite(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecNssSymKeyDataGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecNssSymKeyDataCheckId(data), -1); + xmlSecAssert2(sizeBits > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecNssGenerateRandom(buffer, (sizeBits + 7) / 8)); +} + +static xmlSecKeyDataType +xmlSecNssSymKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecNssSymKeyDataCheckId(data), xmlSecKeyDataTypeUnknown); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, xmlSecKeyDataTypeUnknown); + + return((xmlSecBufferGetSize(buffer) > 0) ? xmlSecKeyDataTypeSymmetric : xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecNssSymKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecNssSymKeyDataCheckId(data), 0); + + return(xmlSecKeyDataBinaryValueGetSize(data)); +} + +static void +xmlSecNssSymKeyDataDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecNssSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugDump(data, output); +} + +static void +xmlSecNssSymKeyDataDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecNssSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugXmlDump(data, output); +} + +static int +xmlSecNssSymKeyDataKlassCheck(xmlSecKeyDataKlass* klass) { +#ifndef XMLSEC_NO_DES + if(klass == xmlSecNssKeyDataDesId) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(klass == xmlSecNssKeyDataAesId) { + return(1); + } +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_HMAC + if(klass == xmlSecNssKeyDataHmacId) { + return(1); + } +#endif /* XMLSEC_NO_HMAC */ + + return(0); +} + +#ifndef XMLSEC_NO_AES +/************************************************************************** + * + * <xmlsec:AESKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecNssKeyDataAesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameAESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefAESKeyValue, /* const xmlChar* href; */ + xmlSecNodeAESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecNssSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecNssSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataAesGetKlass: + * + * The AES key data klass. + * + * Returns: AES key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataAesGetKlass(void) { + return(&xmlSecNssKeyDataAesKlass); +} + +/** + * xmlSecNssKeyDataAesSet: + * @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 +xmlSecNssKeyDataAesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataAesId), -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 xmlSecNssKeyDataDesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameDESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDESKeyValue, /* const xmlChar* href; */ + xmlSecNodeDESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecNssSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecNssSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataDesGetKlass: + * + * The DES key data klass. + * + * Returns: DES key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataDesGetKlass(void) { + return(&xmlSecNssKeyDataDesKlass); +} + +/** + * xmlSecNssKeyDataDesSet: + * @data: the pointer to DES key data. + * @buf: the pointer to key value. + * @bufSize: the key value size (in bytes). + * + * Sets the value of DES key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNssKeyDataDesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataDesId), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} + +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_HMAC +/************************************************************************** + * + * <xmlsec:HMACKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecNssKeyDataHmacKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameHMACKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefHMACKeyValue, /* const xmlChar* href; */ + xmlSecNodeHMACKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecNssSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecNssSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecNssSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecNssSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataHmacGetKlass: + * + * The HMAC key data klass. + * + * Returns: HMAC key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataHmacGetKlass(void) { + return(&xmlSecNssKeyDataHmacKlass); +} + +/** + * xmlSecNssKeyDataHmacSet: + * @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 +xmlSecNssKeyDataHmacSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataHmacId), -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/nss/x509.c b/src/nss/x509.c new file mode 100644 index 00000000..aea40122 --- /dev/null +++ b/src/nss/x509.c @@ -0,0 +1,2205 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#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 <prmem.h> +#include <pratom.h> +#include <keyhi.h> +#include <cert.h> +#include <certdb.h> +#include <pk11func.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/errors.h> + +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/x509.h> +#include <xmlsec/nss/pkikeys.h> + + +/* workaround - NSS exports this but doesn't declare it */ +extern CERTCertificate * __CERT_NewTempCertificate(CERTCertDBHandle *handle, + SECItem *derCert, + char *nickname, + PRBool isperm, + PRBool copyDER); + +/************************************************************************* + * + * X509 utility functions + * + ************************************************************************/ +static int xmlSecNssX509DataNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509CertificateNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509CertificateNodeWrite (CERTCertificate* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509SubjectNameNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509SubjectNameNodeWrite (CERTCertificate* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509IssuerSerialNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509IssuerSerialNodeWrite (CERTCertificate* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509SKINodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509SKINodeWrite (CERTCertificate* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509CRLNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssX509CRLNodeWrite (CERTSignedCrl* crl, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, + xmlSecKeyPtr key, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static CERTCertificate* xmlSecNssX509CertDerRead (const xmlSecByte* buf, + xmlSecSize size); +static CERTCertificate* xmlSecNssX509CertBase64DerRead (xmlChar* buf); +static xmlChar* xmlSecNssX509CertBase64DerWrite (CERTCertificate* cert, + int base64LineWrap); +static CERTSignedCrl* xmlSecNssX509CrlDerRead (xmlSecByte* buf, + xmlSecSize size, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static CERTSignedCrl* xmlSecNssX509CrlBase64DerRead (xmlChar* buf, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static xmlChar* xmlSecNssX509CrlBase64DerWrite (CERTSignedCrl* crl, + int base64LineWrap); +static xmlChar* xmlSecNssX509NameWrite (CERTName* nm); +static xmlChar* xmlSecNssASN1IntegerWrite (SECItem *num); +static xmlChar* xmlSecNssX509SKIWrite (CERTCertificate* cert); +static void xmlSecNssX509CertDebugDump (CERTCertificate* cert, + FILE* output); +static void xmlSecNssX509CertDebugXmlDump (CERTCertificate* cert, + FILE* output); +static int xmlSecNssX509CertGetTime (PRTime* t, + time_t* res); + +/************************************************************************* + * + * Internal NSS X509 data CTX + * + ************************************************************************/ +typedef struct _xmlSecNssX509DataCtx xmlSecNssX509DataCtx, + *xmlSecNssX509DataCtxPtr; +typedef struct _xmlSecNssX509CrlNode xmlSecNssX509CrlNode, + *xmlSecNssX509CrlNodePtr; +struct _xmlSecNssX509CrlNode { + xmlSecNssX509CrlNodePtr next; + CERTSignedCrl *crl; +}; + +struct _xmlSecNssX509DataCtx { + CERTCertificate* keyCert; + + CERTCertList* certsList; + unsigned int numCerts; + + xmlSecNssX509CrlNodePtr crlsList; + 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) > + * + * ----------------------------------------------------------------------- + * + * xmlSecNssX509DataCtx is located after xmlSecTransform + * + *************************************************************************/ +#define xmlSecNssX509DataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecNssX509DataCtx)) +#define xmlSecNssX509DataGetCtx(data) \ + ((xmlSecNssX509DataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + +static int xmlSecNssKeyDataX509Initialize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataX509Duplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecNssKeyDataX509Finalize (xmlSecKeyDataPtr data); +static int xmlSecNssKeyDataX509XmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecNssKeyDataX509XmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static xmlSecKeyDataType xmlSecNssKeyDataX509GetType (xmlSecKeyDataPtr data); +static const xmlChar* xmlSecNssKeyDataX509GetIdentifier (xmlSecKeyDataPtr data); + +static void xmlSecNssKeyDataX509DebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecNssKeyDataX509DebugXmlDump(xmlSecKeyDataPtr data, + FILE* output); + + + +static xmlSecKeyDataKlass xmlSecNssKeyDataX509Klass = { + sizeof(xmlSecKeyDataKlass), + xmlSecNssX509DataSize, + + /* data */ + xmlSecNameX509Data, + xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefX509Data, /* const xmlChar* href; */ + xmlSecNodeX509Data, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecNssKeyDataX509Initialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecNssKeyDataX509Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecNssKeyDataX509Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecNssKeyDataX509GetType, /* xmlSecKeyDataGetTypeMethod getType; */ + NULL, /* xmlSecKeyDataGetSizeMethod getSize; */ + xmlSecNssKeyDataX509GetIdentifier, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecNssKeyDataX509XmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecNssKeyDataX509XmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecNssKeyDataX509DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecNssKeyDataX509DebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataX509GetKlass: + * + * The NSS X509 key data klass (http://www.w3.org/TR/xmldsig-core/#sec-X509Data). + * + * Returns: the X509 data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataX509GetKlass(void) { + return(&xmlSecNssKeyDataX509Klass); +} + +/** + * xmlSecNssKeyDataX509GetKeyCert: + * @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. + */ +CERTCertificate* +xmlSecNssKeyDataX509GetKeyCert(xmlSecKeyDataPtr data) { + xmlSecNssX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), NULL); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + + return(ctx->keyCert); +} + +/** + * xmlSecNssKeyDataX509AdoptKeyCert: + * @data: the pointer to X509 key data. + * @cert: the pointer to NSS X509 certificate. + * + * Sets the key's certificate in @data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNssKeyDataX509AdoptKeyCert(xmlSecKeyDataPtr data, CERTCertificate* cert) { + xmlSecNssX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->keyCert != NULL) { + CERT_DestroyCertificate(ctx->keyCert); + } + ctx->keyCert = cert; + return(0); +} + +/** + * xmlSecNssKeyDataX509AdoptCert: + * @data: the pointer to X509 key data. + * @cert: the pointer to NSS X509 certificate. + * + * Adds certificate to the X509 key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNssKeyDataX509AdoptCert(xmlSecKeyDataPtr data, CERTCertificate* cert) { + xmlSecNssX509DataCtxPtr ctx; + SECStatus ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->certsList == NULL) { + ctx->certsList = CERT_NewCertList(); + if(ctx->certsList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CERT_NewCertList", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + + ret = CERT_AddCertToListTail(ctx->certsList, cert); + if(ret != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CERT_AddCertToListTail", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + ctx->numCerts++; + + return(0); +} + +/** + * xmlSecNssKeyDataX509GetCert: + * @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. + */ +CERTCertificate* +xmlSecNssKeyDataX509GetCert(xmlSecKeyDataPtr data, xmlSecSize pos) { + xmlSecNssX509DataCtxPtr ctx; + CERTCertListNode* head; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), NULL); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->certsList != NULL, NULL); + xmlSecAssert2(pos < ctx->numCerts, NULL); + + head = CERT_LIST_HEAD(ctx->certsList); + while (pos > 0) + { + head = CERT_LIST_NEXT(head); + pos--; + } + + return (head->cert); +} + +/** + * xmlSecNssKeyDataX509GetCertsSize: + * @data: the pointer to X509 key data. + * + * Gets the number of certificates in @data. + * + * Returns: te number of certificates in @data. + */ +xmlSecSize +xmlSecNssKeyDataX509GetCertsSize(xmlSecKeyDataPtr data) { + xmlSecNssX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), 0); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(ctx->numCerts); +} + +/** + * xmlSecNssKeyDataX509AdoptCrl: + * @data: the pointer to X509 key data. + * @crl: the pointer to NSS X509 CRL. + * + * Adds CRL to the X509 key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNssKeyDataX509AdoptCrl(xmlSecKeyDataPtr data, CERTSignedCrl* crl) { + xmlSecNssX509DataCtxPtr ctx; + xmlSecNssX509CrlNodePtr crlnode; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(crl != NULL, -1); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + crlnode = (xmlSecNssX509CrlNodePtr)PR_Malloc(sizeof(xmlSecNssX509CrlNode)); + + if(crlnode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "PR_Malloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + memset(crlnode, 0, sizeof(xmlSecNssX509CrlNode)); + crlnode->next = ctx->crlsList; + crlnode->crl = crl; + ctx->crlsList = crlnode; + ctx->numCrls++; + + return(0); +} + +/** + * xmlSecNssKeyDataX509GetCrl: + * @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. + */ +CERTSignedCrl * +xmlSecNssKeyDataX509GetCrl(xmlSecKeyDataPtr data, xmlSecSize pos) { + xmlSecNssX509DataCtxPtr ctx; + xmlSecNssX509CrlNodePtr head; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), NULL); + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + + xmlSecAssert2(ctx->crlsList != NULL, NULL); + xmlSecAssert2(pos < ctx->numCrls, NULL); + + head = ctx->crlsList; + while (pos > 0) + { + head = head->next; + pos--; + } + + return (head->crl); +} + +/** + * xmlSecNssKeyDataX509GetCrlsSize: + * @data: the pointer to X509 key data. + * + * Gets the number of CRLs in @data. + * + * Returns: te number of CRLs in @data. + */ +xmlSecSize +xmlSecNssKeyDataX509GetCrlsSize(xmlSecKeyDataPtr data) { + xmlSecNssX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), 0); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return(ctx->numCrls); +} + +static int +xmlSecNssKeyDataX509Initialize(xmlSecKeyDataPtr data) { + xmlSecNssX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssX509DataCtx)); + return(0); +} + +static int +xmlSecNssKeyDataX509Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + CERTCertificate* certSrc; + CERTCertificate* certDst; + CERTSignedCrl* crlSrc; + CERTSignedCrl* crlDst; + xmlSecSize size, pos; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecNssKeyDataX509Id), -1); + + /* copy certsList */ + size = xmlSecNssKeyDataX509GetCertsSize(src); + for(pos = 0; pos < size; ++pos) { + /* TBD: function below does linear scan, eliminate loop within + * loop + */ + certSrc = xmlSecNssKeyDataX509GetCert(src, pos); + if(certSrc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)), + "xmlSecNssKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + certDst = CERT_DupCertificate(certSrc); + if(certDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + + ret = xmlSecNssKeyDataX509AdoptCert(dst, certDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(certDst); + return(-1); + } + } + + /* copy crls */ + size = xmlSecNssKeyDataX509GetCrlsSize(src); + for(pos = 0; pos < size; ++pos) { + crlSrc = xmlSecNssKeyDataX509GetCrl(src, pos); + if(crlSrc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)), + "xmlSecNssKeyDataX509GetCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + /* TBD: SEC_DupCrl isn't exported by NSS yet */ + /*crlDst = SEC_DupCrl(crlSrc);*/ + crlDst = crlSrc; + PR_AtomicIncrement(&(crlSrc->referenceCount)); + + if(crlDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "SEC_DupCrl", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + + ret = xmlSecNssKeyDataX509AdoptCrl(dst, crlDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecNssKeyDataX509AdoptCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SEC_DestroyCrl(crlDst); + return(-1); + } + } + + /* copy key cert if exist */ + certSrc = xmlSecNssKeyDataX509GetKeyCert(src); + if(certSrc != NULL) { + certDst = CERT_DupCertificate(certSrc); + if(certDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + ret = xmlSecNssKeyDataX509AdoptKeyCert(dst, certDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecNssKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(certDst); + return(-1); + } + } + return(0); +} + +static void +xmlSecNssKeyDataX509Finalize(xmlSecKeyDataPtr data) { + xmlSecNssX509DataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id)); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert(ctx != NULL); + + if(ctx->certsList != NULL) { + CERT_DestroyCertList(ctx->certsList); + } + + if(ctx->crlsList != NULL) { + xmlSecNssX509CrlNodePtr head; + xmlSecNssX509CrlNodePtr tmp; + + head = ctx->crlsList; + while (head) + { + tmp = head->next; + SEC_DestroyCrl(head->crl); + PR_Free(head); + head = tmp; + } + } + + if(ctx->keyCert != NULL) { + CERT_DestroyCertificate(ctx->keyCert); + } + + memset(ctx, 0, sizeof(xmlSecNssX509DataCtx)); +} + +static int +xmlSecNssKeyDataX509XmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataX509Id, -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 = xmlSecNssX509DataNodeRead(data, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssX509DataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) == 0) { + ret = xmlSecNssKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssKeyDataX509VerifyAndExtractKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +static int +xmlSecNssKeyDataX509XmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + CERTCertificate* cert; + CERTSignedCrl* crl; + xmlSecSize size, pos; + int content = 0; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataX509Id, -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 = xmlSecNssKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecNssKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + if((content & XMLSEC_X509DATA_CERTIFICATE_NODE) != 0) { + ret = xmlSecNssX509CertificateNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssX509CertificateNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_SUBJECTNAME_NODE) != 0) { + ret = xmlSecNssX509SubjectNameNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssX509SubjectNameNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_ISSUERSERIAL_NODE) != 0) { + ret = xmlSecNssX509IssuerSerialNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssX509IssuerSerialNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_SKI_NODE) != 0) { + ret = xmlSecNssX509SKINodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssX509SKINodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + } + + /* write crls if needed */ + if((content & XMLSEC_X509DATA_CRL_NODE) != 0) { + size = xmlSecNssKeyDataX509GetCrlsSize(data); + for(pos = 0; pos < size; ++pos) { + crl = xmlSecNssKeyDataX509GetCrl(data, pos); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssKeyDataX509GetCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + ret = xmlSecNssX509CRLNodeWrite(crl, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssX509CRLNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + } + + return(0); +} + +static xmlSecKeyDataType +xmlSecNssKeyDataX509GetType(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), xmlSecKeyDataTypeUnknown); + + /* TODO: return verified/not verified status */ + return(xmlSecKeyDataTypeUnknown); +} + +static const xmlChar* +xmlSecNssKeyDataX509GetIdentifier(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), NULL); + + /* TODO */ + return(NULL); +} + +static void +xmlSecNssKeyDataX509DebugDump(xmlSecKeyDataPtr data, FILE* output) { + CERTCertificate* cert; + xmlSecSize size, pos; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== X509 Data:\n"); + cert = xmlSecNssKeyDataX509GetKeyCert(data); + if(cert != NULL) { + fprintf(output, "==== Key Certificate:\n"); + xmlSecNssX509CertDebugDump(cert, output); + } + + size = xmlSecNssKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecNssKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return; + } + fprintf(output, "==== Certificate:\n"); + xmlSecNssX509CertDebugDump(cert, output); + } + + /* we don't print out crls */ +} + +static void +xmlSecNssKeyDataX509DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + CERTCertificate* cert; + xmlSecSize size, pos; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "<X509Data>\n"); + cert = xmlSecNssKeyDataX509GetKeyCert(data); + if(cert != NULL) { + fprintf(output, "<KeyCertificate>\n"); + xmlSecNssX509CertDebugXmlDump(cert, output); + fprintf(output, "</KeyCertificate>\n"); + } + + size = xmlSecNssKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecNssKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return; + } + fprintf(output, "<Certificate>\n"); + xmlSecNssX509CertDebugXmlDump(cert, output); + fprintf(output, "</Certificate>\n"); + } + + /* we don't print out crls */ + fprintf(output, "</X509Data>\n"); +} + +static int +xmlSecNssX509DataNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -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 = xmlSecNssX509CertificateNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) { + ret = xmlSecNssX509SubjectNameNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) { + ret = xmlSecNssX509IssuerSerialNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) { + ret = xmlSecNssX509SKINodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) { + ret = xmlSecNssX509CRLNodeRead(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 +xmlSecNssX509CertificateNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar *content; + CERTCertificate* cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -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 = xmlSecNssX509CertBase64DerRead(content); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssX509CertBase64DerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + ret = xmlSecNssKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + xmlFree(content); + return(-1); + } + + xmlFree(content); + return(0); +} + +static int +xmlSecNssX509CertificateNodeWrite(CERTCertificate* 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 = xmlSecNssX509CertBase64DerWrite(cert, keyInfoCtx->base64LineSize); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509CertBase64DerWrite", + 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 +xmlSecNssX509SubjectNameNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlChar* subject; + CERTCertificate* cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecNssX509StoreId); + 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 = xmlSecNssX509StoreFindCert(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 = xmlSecNssKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + xmlFree(subject); + return(-1); + } + + xmlFree(subject); + return(0); +} + +static int +xmlSecNssX509SubjectNameNodeWrite(CERTCertificate* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlChar* buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + buf = xmlSecNssX509NameWrite(&(cert->subject)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameWrite(&(cert->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 +xmlSecNssX509IssuerSerialNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlNodePtr cur; + xmlChar *issuerName; + xmlChar *issuerSerial; + CERTCertificate* cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecNssX509StoreId); + 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 = xmlSecNssX509StoreFindCert(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 = xmlSecNssKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + xmlFree(issuerSerial); + xmlFree(issuerName); + return(-1); + } + + xmlFree(issuerSerial); + xmlFree(issuerName); + return(0); +} + +static int +xmlSecNssX509IssuerSerialNodeWrite(CERTCertificate* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlNodePtr cur; + xmlNodePtr issuerNameNode; + xmlNodePtr issuerNumberNode; + xmlChar* buf; + + 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 = xmlSecNssX509NameWrite(&(cert->issuer)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameWrite(&(cert->issuer))", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecNodeEncodeAndSetContent(issuerNameNode, buf); + xmlFree(buf); + + buf = xmlSecNssASN1IntegerWrite(&(cert->serialNumber)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssASN1IntegerWrite(&(cert->serialNumber))", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlNodeSetContent(issuerNumberNode, buf); + xmlFree(buf); + + return(0); +} + +static int +xmlSecNssX509SKINodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlChar* ski; + CERTCertificate* cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecNssX509StoreId); + 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 = xmlSecNssX509StoreFindCert(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 = xmlSecNssKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + xmlFree(ski); + return(-1); + } + + xmlFree(ski); + return(0); +} + +static int +xmlSecNssX509SKINodeWrite(CERTCertificate* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlChar *buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + buf = xmlSecNssX509SKIWrite(cert); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509SKIWrite", + 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 +xmlSecNssX509CRLNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar *content; + CERTSignedCrl* crl; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -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 = xmlSecNssX509CrlBase64DerRead(content, keyInfoCtx); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssX509CrlBase64DerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + SEC_DestroyCrl(crl); + xmlFree(content); + return(0); +} + +static int +xmlSecNssX509CRLNodeWrite(CERTSignedCrl* 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 = xmlSecNssX509CrlBase64DerWrite(crl, keyInfoCtx->base64LineSize); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509CrlBase64DerWrite", + 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 +xmlSecNssKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, xmlSecKeyPtr key, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecNssX509DataCtxPtr ctx; + xmlSecKeyDataStorePtr x509Store; + int ret; + SECStatus status; + PRTime notBefore, notAfter; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecNssKeyDataX509Id), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + ctx = xmlSecNssX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecNssX509StoreId); + 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) && (ctx->certsList != NULL) && (xmlSecKeyGetValue(key) == NULL)) { + CERTCertificate* cert; + + cert = xmlSecNssX509StoreVerify(x509Store, ctx->certsList, keyInfoCtx); + if(cert != NULL) { + xmlSecKeyDataPtr keyValue; + + ctx->keyCert = CERT_DupCertificate(cert); + if(ctx->keyCert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + keyValue = xmlSecNssX509CertGetKey(ctx->keyCert); + if(keyValue == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssX509CertGetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* 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); + } + + status = CERT_GetCertTimes(ctx->keyCert, ¬Before, ¬After); + if (status == SECSuccess) { + ret = xmlSecNssX509CertGetTime(¬Before, &(key->notValidBefore)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssX509CertGetTime", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "notValidBefore"); + return(-1); + } + ret = xmlSecNssX509CertGetTime(¬After, &(key->notValidAfter)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecNssX509CertGetTime", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "notValidAfter"); + return(-1); + } + } else { + key->notValidBefore = key->notValidAfter = 0; + } + } 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 +xmlSecNssX509CertGetTime(PRTime* t, time_t* res) { + + PRTime tmp64_1, tmp64_2; + PRUint32 tmp32 = 1000000; + + xmlSecAssert2(t != NULL, -1); + xmlSecAssert2(res != NULL, -1); + + /* PRTime is time in microseconds since epoch. Divide by 1000000 to + * convert to seconds, then convert to an unsigned 32 bit number + */ + (*res) = 0; + LL_UI2L(tmp64_1, tmp32); + LL_DIV(tmp64_2, *t, tmp64_1); + LL_L2UI(tmp32, tmp64_2); + + (*res) = (time_t)(tmp32); + + return(0); +} + +/** + * xmlSecNssX509CertGetKey: + * @cert: the certificate. + * + * Extracts public key from the @cert. + * + * Returns: public key value or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecNssX509CertGetKey(CERTCertificate* cert) { + xmlSecKeyDataPtr data; + SECKEYPublicKey *pubkey = NULL; + + xmlSecAssert2(cert != NULL, NULL); + + pubkey = CERT_ExtractPublicKey(cert); + if(pubkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_ExtractPublicKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(NULL); + } + + data = xmlSecNssPKIAdoptKey(NULL, pubkey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssPKIAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECKEY_DestroyPublicKey(pubkey); + return(NULL); + } + + return(data); +} + +static CERTCertificate* +xmlSecNssX509CertBase64DerRead(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(xmlSecNssX509CertDerRead((xmlSecByte*)buf, ret)); +} + + +static CERTCertificate* +xmlSecNssX509CertDerRead(const xmlSecByte* buf, xmlSecSize size) { + CERTCertificate *cert; + SECItem derCert; + + xmlSecAssert2(buf != NULL, NULL); + xmlSecAssert2(size > 0, NULL); + + derCert.data = (unsigned char *)buf; + derCert.len = size; + + /* decode cert and import to temporary cert db */ + cert = __CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &derCert, + NULL, PR_FALSE, PR_TRUE); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "__CERT_NewTempCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(NULL); + } + + + return(cert); +} + +static xmlChar* +xmlSecNssX509CertBase64DerWrite(CERTCertificate* cert, int base64LineWrap) { + xmlChar *res = NULL; + xmlSecByte *p = NULL; + long size; + + xmlSecAssert2(cert != NULL, NULL); + + p = cert->derCert.data; + size = cert->derCert.len; + if((size <= 0) || (p == NULL)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "cert->derCert", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + 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 CERTSignedCrl* +xmlSecNssX509CrlBase64DerRead(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(xmlSecNssX509CrlDerRead((xmlSecByte*)buf, ret, keyInfoCtx)); +} + + +static CERTSignedCrl* +xmlSecNssX509CrlDerRead(xmlSecByte* buf, xmlSecSize size, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + CERTSignedCrl *crl = NULL; + SECItem derCrl; + PK11SlotInfo *slot = NULL; + PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS; + + xmlSecAssert2(buf != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + xmlSecAssert2(size > 0, NULL); + + derCrl.data = buf; + derCrl.len = size; + + /* we're importing a CRL, it is ok to use the internal slot. + * crlutil does it :) + */ + slot = xmlSecNssGetInternalKeySlot(); + if (slot == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssGetInternalKeySlot", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return NULL; + } + + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_SKIP_STRICT_CHECKS) != 0) + importOptions |= CRL_IMPORT_BYPASS_CHECKS; + + crl = PK11_ImportCRL(slot, &derCrl, NULL, SEC_CRL_TYPE, NULL, + importOptions, NULL, CRL_DECODE_DEFAULT_OPTIONS); + + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ImportCRL", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + PK11_FreeSlot(slot); + return(NULL); + } + + PK11_FreeSlot(slot); + return(crl); +} + +static xmlChar* +xmlSecNssX509CrlBase64DerWrite(CERTSignedCrl* crl, int base64LineWrap) { + xmlChar *res = NULL; + xmlSecByte *p = NULL; + long size; + + xmlSecAssert2(crl != NULL && crl->derCrl != NULL, NULL); + + p = crl->derCrl->data; + size = crl->derCrl->len; + if((size <= 0) || (p == NULL)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "crl->derCrl", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + 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* +xmlSecNssX509NameWrite(CERTName* nm) { + xmlChar *res = NULL; + char *str; + + xmlSecAssert2(nm != NULL, NULL); + + str = CERT_NameToAscii(nm); + if (str == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_NameToAscii", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlStrdup(BAD_CAST str); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PORT_Free(str); + return(NULL); + } + PORT_Free(str); + return(res); +} + +static xmlChar* +xmlSecNssASN1IntegerWrite(SECItem *num) { + xmlChar *res = NULL; + + xmlSecAssert2(num != NULL, NULL); + + /* TODO : to be implemented after + * NSS bug http://bugzilla.mozilla.org/show_bug.cgi?id=212864 is fixed + */ + return(res); +} + +static xmlChar* +xmlSecNssX509SKIWrite(CERTCertificate* cert) { + xmlChar *res = NULL; + SECItem ski; + SECStatus rv; + + xmlSecAssert2(cert != NULL, NULL); + + memset(&ski, 0, sizeof(ski)); + + rv = CERT_FindSubjectKeyIDExtension(cert, &ski); + if (rv != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_FindSubjectKeyIDExtension", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&ski, PR_FALSE); + return(NULL); + } + + res = xmlSecBase64Encode(ski.data, ski.len, 0); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + SECITEM_FreeItem(&ski, PR_FALSE); + return(NULL); + } + SECITEM_FreeItem(&ski, PR_FALSE); + + return(res); +} + + +static void +xmlSecNssX509CertDebugDump(CERTCertificate* cert, FILE* output) { + SECItem *sn; + unsigned int i; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "==== Subject Name: %s\n", cert->subjectName); + fprintf(output, "==== Issuer Name: %s\n", cert->issuerName); + sn = &cert->serialNumber; + + for (i = 0; i < sn->len; i++) { + if (i != sn->len - 1) { + fprintf(output, "%02x:", sn->data[i]); + } else { + fprintf(output, "%02x", sn->data[i]); + } + } + fprintf(output, "\n"); +} + + +static void +xmlSecNssX509CertDebugXmlDump(CERTCertificate* cert, FILE* output) { + SECItem *sn; + unsigned int i; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "<SubjectName>"); + xmlSecPrintXmlString(output, BAD_CAST cert->subjectName); + fprintf(output, "</SubjectName>\n"); + + fprintf(output, "<IssuerName>"); + xmlSecPrintXmlString(output, BAD_CAST cert->issuerName); + fprintf(output, "</IssuerName>\n"); + + fprintf(output, "<SerialNumber>"); + sn = &cert->serialNumber; + for (i = 0; i < sn->len; i++) { + if (i != sn->len - 1) { + fprintf(output, "%02x:", sn->data[i]); + } else { + fprintf(output, "%02x", sn->data[i]); + } + } + fprintf(output, "</SerialNumber>\n"); +} + + +/************************************************************************** + * + * Raw X509 Certificate processing + * + * + *************************************************************************/ +static int xmlSecNssKeyDataRawX509CertBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const xmlSecByte* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyDataKlass xmlSecNssKeyDataRawX509CertKlass = { + 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; */ + xmlSecNssKeyDataRawX509CertBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecNssKeyDataRawX509CertGetKlass: + * + * The raw X509 certificates key data klass. + * + * Returns: raw X509 certificates key data klass. + */ +xmlSecKeyDataId +xmlSecNssKeyDataRawX509CertGetKlass(void) { + return(&xmlSecNssKeyDataRawX509CertKlass); +} + +static int +xmlSecNssKeyDataRawX509CertBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + CERTCertificate* cert; + int ret; + + xmlSecAssert2(id == xmlSecNssKeyDataRawX509CertId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + cert = xmlSecNssX509CertDerRead(buf, bufSize); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509CertDerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + data = xmlSecKeyEnsureData(key, xmlSecNssKeyDataX509Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + return(-1); + } + + ret = xmlSecNssKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + CERT_DestroyCertificate(cert); + return(-1); + } + + ret = xmlSecNssKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecNssKeyDataX509VerifyAndExtractKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +#endif /* XMLSEC_NO_X509 */ diff --git a/src/nss/x509vfy.c b/src/nss/x509vfy.c new file mode 100644 index 00000000..25bf5042 --- /dev/null +++ b/src/nss/x509vfy.c @@ -0,0 +1,704 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (c) 2003 America Online, Inc. All rights reserved. + */ +#include "globals.h" + +#ifndef XMLSEC_NO_X509 + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <cert.h> +#include <secerr.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/errors.h> + +#include <xmlsec/nss/crypto.h> +#include <xmlsec/nss/x509.h> + +/************************************************************************** + * + * Internal NSS X509 store CTX + * + *************************************************************************/ +typedef struct _xmlSecNssX509StoreCtx xmlSecNssX509StoreCtx, + *xmlSecNssX509StoreCtxPtr; +struct _xmlSecNssX509StoreCtx { + CERTCertList* certsList; /* just keeping a reference to destroy later */ +}; + +/**************************************************************************** + * + * xmlSecNssKeyDataStoreX509Id: + * + * xmlSecNssX509StoreCtx is located after xmlSecTransform + * + ***************************************************************************/ +#define xmlSecNssX509StoreGetCtx(store) \ + ((xmlSecNssX509StoreCtxPtr)(((xmlSecByte*)(store)) + \ + sizeof(xmlSecKeyDataStoreKlass))) +#define xmlSecNssX509StoreSize \ + (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecNssX509StoreCtx)) + +static int xmlSecNssX509StoreInitialize (xmlSecKeyDataStorePtr store); +static void xmlSecNssX509StoreFinalize (xmlSecKeyDataStorePtr store); +static int xmlSecNssX509NameStringRead (xmlSecByte **str, + int *strLen, + xmlSecByte *res, + int resLen, + xmlSecByte delim, + int ingoreTrailingSpaces); +static xmlSecByte * xmlSecNssX509NameRead (xmlSecByte *str, + int len); + +static void xmlSecNssNumToItem(SECItem *it, unsigned long num); + + +static xmlSecKeyDataStoreKlass xmlSecNssX509StoreKlass = { + sizeof(xmlSecKeyDataStoreKlass), + xmlSecNssX509StoreSize, + + /* data */ + xmlSecNameX509Store, /* const xmlChar* name; */ + + /* constructors/destructor */ + xmlSecNssX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */ + xmlSecNssX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static CERTCertificate* xmlSecNssX509FindCert(xmlChar *subjectName, + xmlChar *issuerName, + xmlChar *issuerSerial, + xmlChar *ski); + + +/** + * xmlSecNssX509StoreGetKlass: + * + * The NSS X509 certificates key data store klass. + * + * Returns: pointer to NSS X509 certificates key data store klass. + */ +xmlSecKeyDataStoreId +xmlSecNssX509StoreGetKlass(void) { + return(&xmlSecNssX509StoreKlass); +} + +/** + * xmlSecNssX509StoreFindCert: + * @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. + */ +CERTCertificate * +xmlSecNssX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName, + xmlChar *issuerName, xmlChar *issuerSerial, + xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) { + xmlSecNssX509StoreCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ctx = xmlSecNssX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, NULL); + + return(xmlSecNssX509FindCert(subjectName, issuerName, issuerSerial, ski)); +} + +/** + * xmlSecNssX509StoreVerify: + * @store: the pointer to X509 key data 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. + */ +CERTCertificate * +xmlSecNssX509StoreVerify(xmlSecKeyDataStorePtr store, CERTCertList* certs, + xmlSecKeyInfoCtx* keyInfoCtx) { + xmlSecNssX509StoreCtxPtr ctx; + CERTCertListNode* head; + CERTCertificate* cert = NULL; + CERTCertListNode* head1; + CERTCertificate* cert1 = NULL; + SECStatus status = SECFailure; + int64 timeboundary; + int64 tmp1, tmp2; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), NULL); + xmlSecAssert2(certs != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ctx = xmlSecNssX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, NULL); + + for (head = CERT_LIST_HEAD(certs); + !CERT_LIST_END(head, certs); + head = CERT_LIST_NEXT(head)) { + cert = head->cert; + if(keyInfoCtx->certsVerificationTime > 0) { + /* convert the time since epoch in seconds to microseconds */ + LL_UI2L(timeboundary, keyInfoCtx->certsVerificationTime); + tmp1 = (int64)PR_USEC_PER_SEC; + tmp2 = timeboundary; + LL_MUL(timeboundary, tmp1, tmp2); + } else { + timeboundary = PR_Now(); + } + + /* if cert is the issuer of any other cert in the list, then it is + * to be skipped */ + for (head1 = CERT_LIST_HEAD(certs); + !CERT_LIST_END(head1, certs); + head1 = CERT_LIST_NEXT(head1)) { + + cert1 = head1->cert; + if (cert1 == cert) { + continue; + } + + if (SECITEM_CompareItem(&cert1->derIssuer, &cert->derSubject) + == SECEqual) { + break; + } + } + + if (!CERT_LIST_END(head1, certs)) { + continue; + } + + status = CERT_VerifyCertificate(CERT_GetDefaultCertDB(), + cert, PR_FALSE, + (SECCertificateUsage)0, + timeboundary , NULL, NULL, NULL); + if (status == SECSuccess) { + break; + } + } + + if (status == SECSuccess) { + return (cert); + } + + switch(PORT_GetError()) { + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + case SEC_ERROR_CA_CERT_INVALID: + case SEC_ERROR_UNKNOWN_SIGNER: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_ISSUER_FAILED, + "cert with subject name %s could not be verified because the issuer's cert is expired/invalid or not found", + cert->subjectName); + break; + case SEC_ERROR_EXPIRED_CERTIFICATE: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, + "cert with subject name %s has expired", + cert->subjectName); + break; + case SEC_ERROR_REVOKED_CERTIFICATE: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_REVOKED, + "cert with subject name %s has been revoked", + cert->subjectName); + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, + "cert with subject name %s could not be verified, errcode %d", + cert->subjectName, + PORT_GetError()); + break; + } + + return (NULL); +} + +/** + * xmlSecNssX509StoreAdoptCert: + * @store: the pointer to X509 key data store klass. + * @cert: the pointer to NSS 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 +xmlSecNssX509StoreAdoptCert(xmlSecKeyDataStorePtr store, CERTCertificate* cert, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecNssX509StoreCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecNssX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->certsList == NULL) { + ctx->certsList = CERT_NewCertList(); + if(ctx->certsList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CERT_NewCertList", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + } + + ret = CERT_AddCertToListTail(ctx->certsList, cert); + if(ret != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "CERT_AddCertToListTail", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + return(-1); + } + + return(0); +} + +static int +xmlSecNssX509StoreInitialize(xmlSecKeyDataStorePtr store) { + xmlSecNssX509StoreCtxPtr ctx; + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId), -1); + + ctx = xmlSecNssX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecNssX509StoreCtx)); + + return(0); +} + +static void +xmlSecNssX509StoreFinalize(xmlSecKeyDataStorePtr store) { + xmlSecNssX509StoreCtxPtr ctx; + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecNssX509StoreId)); + + ctx = xmlSecNssX509StoreGetCtx(store); + xmlSecAssert(ctx != NULL); + + if (ctx->certsList) { + CERT_DestroyCertList(ctx->certsList); + ctx->certsList = NULL; + } + + memset(ctx, 0, sizeof(xmlSecNssX509StoreCtx)); +} + + +/***************************************************************************** + * + * Low-level x509 functions + * + *****************************************************************************/ +static CERTCertificate* +xmlSecNssX509FindCert(xmlChar *subjectName, xmlChar *issuerName, + xmlChar *issuerSerial, xmlChar *ski) { + CERTCertificate *cert = NULL; + xmlChar *p = NULL; + CERTName *name = NULL; + SECItem *nameitem = NULL; + PRArenaPool *arena = NULL; + + if (subjectName != NULL) { + p = xmlSecNssX509NameRead(subjectName, xmlStrlen(subjectName)); + if (p == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "subject=%s", + xmlSecErrorsSafeString(subjectName)); + goto done; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PORT_NewArena", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + name = CERT_AsciiToName((char*)p); + if (name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_AsciiToName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + nameitem = SEC_ASN1EncodeItem(arena, NULL, (void *)name, + SEC_ASN1_GET(CERT_NameTemplate)); + if (nameitem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_ASN1EncodeItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "error code=%d", PORT_GetError()); + goto done; + } + + cert = CERT_FindCertByName(CERT_GetDefaultCertDB(), nameitem); + goto done; + } + + if((issuerName != NULL) && (issuerSerial != NULL)) { + CERTIssuerAndSN issuerAndSN; + + p = xmlSecNssX509NameRead(issuerName, xmlStrlen(issuerName)); + if (p == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "issuer=%s", + xmlSecErrorsSafeString(issuerName)); + goto done; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PORT_NewArena", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + name = CERT_AsciiToName((char*)p); + if (name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_AsciiToName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + nameitem = SEC_ASN1EncodeItem(arena, NULL, (void *)name, + SEC_ASN1_GET(CERT_NameTemplate)); + if (nameitem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SEC_ASN1EncodeItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "error code=%d", PORT_GetError()); + goto done; + } + + memset(&issuerAndSN, 0, sizeof(issuerAndSN)); + + issuerAndSN.derIssuer.data = nameitem->data; + issuerAndSN.derIssuer.len = nameitem->len; + + /* TBD: serial num can be arbitrarily long */ + xmlSecNssNumToItem(&issuerAndSN.serialNumber, PORT_Atoi((char *)issuerSerial)); + + cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), + &issuerAndSN); + SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE); + goto done; + } + + if(ski != NULL) { + SECItem subjKeyID; + int len; + + len = xmlSecBase64Decode(ski, (xmlSecByte*)ski, xmlStrlen(ski)); + if(len < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ski=%s", + xmlSecErrorsSafeString(ski)); + goto done; + } + + memset(&subjKeyID, 0, sizeof(subjKeyID)); + subjKeyID.data = ski; + subjKeyID.len = xmlStrlen(ski); + cert = CERT_FindCertBySubjectKeyID(CERT_GetDefaultCertDB(), + &subjKeyID); + } + +done: + if (p != NULL) { + PORT_Free(p); + } + if (arena != NULL) { + PORT_FreeArena(arena, PR_FALSE); + } + if (name != NULL) { + CERT_DestroyName(name); + } + + return(cert); +} + +static xmlSecByte * +xmlSecNssX509NameRead(xmlSecByte *str, int len) { + xmlSecByte name[256]; + xmlSecByte value[256]; + xmlSecByte *retval = NULL; + xmlSecByte *p = NULL; + int nameLen, valueLen; + + xmlSecAssert2(str != NULL, NULL); + + /* return string should be no longer than input string */ + retval = (xmlSecByte *)PORT_Alloc(len+1); + if(retval == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PORT_Alloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + p = retval; + + while(len > 0) { + /* skip spaces after comma or semicolon */ + while((len > 0) && isspace(*str)) { + ++str; --len; + } + + nameLen = xmlSecNssX509NameStringRead(&str, &len, name, sizeof(name), '=', 0); + if(nameLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameStringRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + memcpy(p, name, nameLen); + p+=nameLen; + *p++='='; + if(len > 0) { + ++str; --len; + if((*str) == '\"') { + valueLen = xmlSecNssX509NameStringRead(&str, &len, + value, sizeof(value), '"', 1); + if(valueLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameStringRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + /* skip spaces before comma or semicolon */ + while((len > 0) && isspace(*str)) { + ++str; --len; + } + if((len > 0) && ((*str) != ',')) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "comma is expected"); + goto done; + } + if(len > 0) { + ++str; --len; + } + *p++='\"'; + memcpy(p, value, valueLen); + p+=valueLen; + *p++='\"'; + } else if((*str) == '#') { + /* TODO: read octect values */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "reading octect values is not implemented yet"); + goto done; + } else { + valueLen = xmlSecNssX509NameStringRead(&str, &len, + value, sizeof(value), ',', 1); + if(valueLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameStringRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + memcpy(p, value, valueLen); + p+=valueLen; + if (len > 0) + *p++=','; + } + } else { + valueLen = 0; + } + if(len > 0) { + ++str; --len; + } + } + + *p = 0; + return(retval); + +done: + PORT_Free(retval); + return (NULL); +} + +static int +xmlSecNssX509NameStringRead(xmlSecByte **str, int *strLen, + xmlSecByte *res, int resLen, + xmlSecByte delim, int ingoreTrailingSpaces) { + xmlSecByte *p, *q, *nonSpace; + + xmlSecAssert2(str != NULL, -1); + xmlSecAssert2(strLen != NULL, -1); + xmlSecAssert2(res != NULL, -1); + + p = (*str); + nonSpace = q = res; + while(((p - (*str)) < (*strLen)) && ((*p) != delim) && ((q - res) < resLen)) { + if((*p) != '\\') { + if(ingoreTrailingSpaces && !isspace(*p)) { + nonSpace = q; + } + *(q++) = *(p++); + } else { + ++p; + nonSpace = q; + if(xmlSecIsHex((*p))) { + if((p - (*str) + 1) >= (*strLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "two hex digits expected"); + return(-1); + } + *(q++) = xmlSecGetHex(p[0]) * 16 + xmlSecGetHex(p[1]); + p += 2; + } else { + if(((++p) - (*str)) >= (*strLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "escaped symbol missed"); + return(-1); + } + *(q++) = *(p++); + } + } + } + if(((p - (*str)) < (*strLen)) && ((*p) != delim)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "buffer is too small"); + return(-1); + } + (*strLen) -= (p - (*str)); + (*str) = p; + return((ingoreTrailingSpaces) ? nonSpace - res + 1 : q - res); +} + +/* code lifted from NSS */ +static void +xmlSecNssNumToItem(SECItem *it, unsigned long ui) +{ + unsigned char bb[5]; + int len; + + bb[0] = 0; + bb[1] = (unsigned char) (ui >> 24); + bb[2] = (unsigned char) (ui >> 16); + bb[3] = (unsigned char) (ui >> 8); + bb[4] = (unsigned char) (ui); + + /* + ** Small integers are encoded in a single byte. Larger integers + ** require progressively more space. + */ + if (ui > 0x7f) { + if (ui > 0x7fff) { + if (ui > 0x7fffffL) { + if (ui >= 0x80000000L) { + len = 5; + } else { + len = 4; + } + } else { + len = 3; + } + } else { + len = 2; + } + } else { + len = 1; + } + + it->data = (unsigned char *)PORT_Alloc(len); + if (it->data == NULL) { + return; + } + + it->len = len; + PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len); +} +#endif /* XMLSEC_NO_X509 */ + + diff --git a/src/openssl/Makefile.am b/src/openssl/Makefile.am new file mode 100644 index 00000000..db2cd43e --- /dev/null +++ b/src/openssl/Makefile.am @@ -0,0 +1,56 @@ +NULL = + +EXTRA_DIST = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-openssl.la \ + $(NULL) + +libxmlsec1_openssl_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(OPENSSL_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_openssl_la_SOURCES =\ + app.c \ + bn.c \ + ciphers.c \ + crypto.c \ + digests.c \ + evp.c \ + hmac.c \ + kw_aes.c \ + kw_des.c \ + kt_rsa.c \ + signatures.c \ + symkeys.c \ + x509.c \ + x509vfy.c \ + globals.h \ + $(NULL) + +if SHAREDLIB_HACK +libxmlsec1_openssl_la_SOURCES += ../strings.c +endif + +libxmlsec1_openssl_la_LIBADD = \ + ../libxmlsec1.la \ + $(OPENSSL_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_openssl_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_openssl_la_LDFLAGS = \ + @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) diff --git a/src/openssl/Makefile.in b/src/openssl/Makefile.in new file mode 100644 index 00000000..1cb63c49 --- /dev/null +++ b/src/openssl/Makefile.in @@ -0,0 +1,778 @@ +# Makefile.in generated by automake 1.11 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/openssl +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +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_openssl_la_SOURCES_DIST = app.c bn.c ciphers.c crypto.c \ + digests.c evp.c hmac.c kw_aes.c kw_des.c kt_rsa.c signatures.c \ + symkeys.c x509.c x509vfy.c globals.h ../strings.c +am__objects_1 = +@SHAREDLIB_HACK_TRUE@am__objects_2 = libxmlsec1_openssl_la-strings.lo +am_libxmlsec1_openssl_la_OBJECTS = libxmlsec1_openssl_la-app.lo \ + libxmlsec1_openssl_la-bn.lo libxmlsec1_openssl_la-ciphers.lo \ + libxmlsec1_openssl_la-crypto.lo \ + libxmlsec1_openssl_la-digests.lo libxmlsec1_openssl_la-evp.lo \ + libxmlsec1_openssl_la-hmac.lo libxmlsec1_openssl_la-kw_aes.lo \ + libxmlsec1_openssl_la-kw_des.lo \ + libxmlsec1_openssl_la-kt_rsa.lo \ + libxmlsec1_openssl_la-signatures.lo \ + libxmlsec1_openssl_la-symkeys.lo libxmlsec1_openssl_la-x509.lo \ + libxmlsec1_openssl_la-x509vfy.lo $(am__objects_1) \ + $(am__objects_2) +libxmlsec1_openssl_la_OBJECTS = $(am_libxmlsec1_openssl_la_OBJECTS) +libxmlsec1_openssl_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libxmlsec1_openssl_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_openssl_la_SOURCES) +DIST_SOURCES = $(am__libxmlsec1_openssl_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@ +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@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_ENABLED = @PKG_CONFIG_ENABLED@ +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_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_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 = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-openssl.la \ + $(NULL) + +libxmlsec1_openssl_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(OPENSSL_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_openssl_la_SOURCES = app.c bn.c ciphers.c crypto.c \ + digests.c evp.c hmac.c kw_aes.c kw_des.c kt_rsa.c signatures.c \ + symkeys.c x509.c x509vfy.c globals.h $(NULL) $(am__append_1) +libxmlsec1_openssl_la_LIBADD = \ + ../libxmlsec1.la \ + $(OPENSSL_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_openssl_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_openssl_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/openssl/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/openssl/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-openssl.la: $(libxmlsec1_openssl_la_OBJECTS) $(libxmlsec1_openssl_la_DEPENDENCIES) + $(libxmlsec1_openssl_la_LINK) -rpath $(libdir) $(libxmlsec1_openssl_la_OBJECTS) $(libxmlsec1_openssl_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-app.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-bn.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-ciphers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-crypto.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-digests.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-evp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-hmac.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-kt_rsa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-kw_aes.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-kw_des.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-signatures.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-strings.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-symkeys.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_la-x509.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxmlsec1_openssl_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_openssl_la-app.lo: app.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-app.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-app.Tpo -c -o libxmlsec1_openssl_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-app.Tpo $(DEPDIR)/libxmlsec1_openssl_la-app.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='app.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-app.lo `test -f 'app.c' || echo '$(srcdir)/'`app.c + +libxmlsec1_openssl_la-bn.lo: bn.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-bn.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-bn.Tpo -c -o libxmlsec1_openssl_la-bn.lo `test -f 'bn.c' || echo '$(srcdir)/'`bn.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-bn.Tpo $(DEPDIR)/libxmlsec1_openssl_la-bn.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='bn.c' object='libxmlsec1_openssl_la-bn.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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-bn.lo `test -f 'bn.c' || echo '$(srcdir)/'`bn.c + +libxmlsec1_openssl_la-ciphers.lo: ciphers.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-ciphers.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-ciphers.Tpo -c -o libxmlsec1_openssl_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-ciphers.Tpo $(DEPDIR)/libxmlsec1_openssl_la-ciphers.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='ciphers.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-ciphers.lo `test -f 'ciphers.c' || echo '$(srcdir)/'`ciphers.c + +libxmlsec1_openssl_la-crypto.lo: crypto.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-crypto.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-crypto.Tpo -c -o libxmlsec1_openssl_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-crypto.Tpo $(DEPDIR)/libxmlsec1_openssl_la-crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='crypto.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-crypto.lo `test -f 'crypto.c' || echo '$(srcdir)/'`crypto.c + +libxmlsec1_openssl_la-digests.lo: digests.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-digests.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-digests.Tpo -c -o libxmlsec1_openssl_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-digests.Tpo $(DEPDIR)/libxmlsec1_openssl_la-digests.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='digests.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-digests.lo `test -f 'digests.c' || echo '$(srcdir)/'`digests.c + +libxmlsec1_openssl_la-evp.lo: evp.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-evp.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-evp.Tpo -c -o libxmlsec1_openssl_la-evp.lo `test -f 'evp.c' || echo '$(srcdir)/'`evp.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-evp.Tpo $(DEPDIR)/libxmlsec1_openssl_la-evp.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='evp.c' object='libxmlsec1_openssl_la-evp.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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-evp.lo `test -f 'evp.c' || echo '$(srcdir)/'`evp.c + +libxmlsec1_openssl_la-hmac.lo: hmac.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-hmac.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-hmac.Tpo -c -o libxmlsec1_openssl_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-hmac.Tpo $(DEPDIR)/libxmlsec1_openssl_la-hmac.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='hmac.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-hmac.lo `test -f 'hmac.c' || echo '$(srcdir)/'`hmac.c + +libxmlsec1_openssl_la-kw_aes.lo: kw_aes.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-kw_aes.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-kw_aes.Tpo -c -o libxmlsec1_openssl_la-kw_aes.lo `test -f 'kw_aes.c' || echo '$(srcdir)/'`kw_aes.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-kw_aes.Tpo $(DEPDIR)/libxmlsec1_openssl_la-kw_aes.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kw_aes.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-kw_aes.lo `test -f 'kw_aes.c' || echo '$(srcdir)/'`kw_aes.c + +libxmlsec1_openssl_la-kw_des.lo: kw_des.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-kw_des.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-kw_des.Tpo -c -o libxmlsec1_openssl_la-kw_des.lo `test -f 'kw_des.c' || echo '$(srcdir)/'`kw_des.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-kw_des.Tpo $(DEPDIR)/libxmlsec1_openssl_la-kw_des.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kw_des.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-kw_des.lo `test -f 'kw_des.c' || echo '$(srcdir)/'`kw_des.c + +libxmlsec1_openssl_la-kt_rsa.lo: kt_rsa.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-kt_rsa.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-kt_rsa.Tpo -c -o libxmlsec1_openssl_la-kt_rsa.lo `test -f 'kt_rsa.c' || echo '$(srcdir)/'`kt_rsa.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-kt_rsa.Tpo $(DEPDIR)/libxmlsec1_openssl_la-kt_rsa.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='kt_rsa.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-kt_rsa.lo `test -f 'kt_rsa.c' || echo '$(srcdir)/'`kt_rsa.c + +libxmlsec1_openssl_la-signatures.lo: signatures.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-signatures.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-signatures.Tpo -c -o libxmlsec1_openssl_la-signatures.lo `test -f 'signatures.c' || echo '$(srcdir)/'`signatures.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-signatures.Tpo $(DEPDIR)/libxmlsec1_openssl_la-signatures.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='signatures.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-signatures.lo `test -f 'signatures.c' || echo '$(srcdir)/'`signatures.c + +libxmlsec1_openssl_la-symkeys.lo: symkeys.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-symkeys.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-symkeys.Tpo -c -o libxmlsec1_openssl_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-symkeys.Tpo $(DEPDIR)/libxmlsec1_openssl_la-symkeys.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='symkeys.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-symkeys.lo `test -f 'symkeys.c' || echo '$(srcdir)/'`symkeys.c + +libxmlsec1_openssl_la-x509.lo: x509.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-x509.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-x509.Tpo -c -o libxmlsec1_openssl_la-x509.lo `test -f 'x509.c' || echo '$(srcdir)/'`x509.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-x509.Tpo $(DEPDIR)/libxmlsec1_openssl_la-x509.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x509.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-x509.lo `test -f 'x509.c' || echo '$(srcdir)/'`x509.c + +libxmlsec1_openssl_la-x509vfy.lo: x509vfy.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-x509vfy.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-x509vfy.Tpo -c -o libxmlsec1_openssl_la-x509vfy.lo `test -f 'x509vfy.c' || echo '$(srcdir)/'`x509vfy.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-x509vfy.Tpo $(DEPDIR)/libxmlsec1_openssl_la-x509vfy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='x509vfy.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_la-x509vfy.lo `test -f 'x509vfy.c' || echo '$(srcdir)/'`x509vfy.c + +libxmlsec1_openssl_la-strings.lo: ../strings.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxmlsec1_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxmlsec1_openssl_la-strings.lo -MD -MP -MF $(DEPDIR)/libxmlsec1_openssl_la-strings.Tpo -c -o libxmlsec1_openssl_la-strings.lo `test -f '../strings.c' || echo '$(srcdir)/'`../strings.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libxmlsec1_openssl_la-strings.Tpo $(DEPDIR)/libxmlsec1_openssl_la-strings.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='../strings.c' object='libxmlsec1_openssl_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_openssl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxmlsec1_openssl_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/openssl/README b/src/openssl/README new file mode 100644 index 00000000..462b1842 --- /dev/null +++ b/src/openssl/README @@ -0,0 +1,17 @@ +WHAT VERSION OF OPENSSL? +------------------------------------------------------------------------ +OpenSSL 0.9.6 is supported but some functionality requires 0.9.7 or greater. + +KEYS MANAGER +------------------------------------------------------------------------ + +OpenSSL does not have a keys or certificates storage implementation. The +default xmlsec-openssl key manager uses a simple keys store from xmlsec +core library based on plain keys list. Trusted/untrusted certificates +are stored in STACK_OF(X509) structures. + +KNOWN ISSUES. +------------------------------------------------------------------------ +1) One day we might decide to drop OpenSSL 0.9.6 supprot and remove all +these ifdef's to simplify the code. + diff --git a/src/openssl/app.c b/src/openssl/app.c new file mode 100644 index 00000000..88dbc090 --- /dev/null +++ b/src/openssl/app.c @@ -0,0 +1,1581 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include <libxml/tree.h> + +#include <openssl/evp.h> +#include <openssl/rand.h> +#include <openssl/pem.h> +#include <openssl/pkcs12.h> +#include <openssl/conf.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/private.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/app.h> +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> +#include <xmlsec/openssl/x509.h> + +static int xmlSecOpenSSLAppLoadRANDFile (const char *file); +static int xmlSecOpenSSLAppSaveRANDFile (const char *file); +static int xmlSecOpenSSLDefaultPasswordCallback(char *buf, int bufsiz, int verify, void *userdata); +static int xmlSecOpenSSLDummyPasswordCallback (char *buf, int bufsize, int verify, void *userdata); + +/** + * xmlSecOpenSSLAppInit: + * @config: the path to certs. + * + * 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 +xmlSecOpenSSLAppInit(const char* config) { + ERR_load_crypto_strings(); + OPENSSL_config(NULL); + OpenSSL_add_all_algorithms(); + + if((RAND_status() != 1) && (xmlSecOpenSSLAppLoadRANDFile(NULL) != 1)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppLoadRANDFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((config != NULL) && (xmlSecOpenSSLSetDefaultTrustedCertsFolder(BAD_CAST config) < 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLSetDefaultTrustedCertsFolder", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLAppShutdown: + * + * 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 +xmlSecOpenSSLAppShutdown(void) { + xmlSecOpenSSLAppSaveRANDFile(NULL); + RAND_cleanup(); + EVP_cleanup(); + +#ifndef XMLSEC_NO_X509 + X509_TRUST_cleanup(); +#endif /* XMLSEC_NO_X509 */ + +#ifndef XMLSEC_OPENSSL_096 + CRYPTO_cleanup_all_ex_data(); +#endif /* XMLSEC_OPENSSL_096 */ + + /* finally cleanup errors */ + ERR_remove_state(0); + ERR_free_strings(); + + return(0); +} + +/** + * xmlSecOpenSSLAppKeyLoad: + * @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 +xmlSecOpenSSLAppKeyLoad(const char *filename, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, + void* pwdCallbackCtx) { + BIO* bio; + xmlSecKeyPtr key; + + xmlSecAssert2(filename != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + bio = BIO_new_file(filename, "rb"); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + return(NULL); + } + + key = xmlSecOpenSSLAppKeyLoadBIO (bio, format, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeyLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + BIO_free(bio); + return(NULL); + } + + BIO_free(bio); + return(key); +} + +/** + * xmlSecOpenSSLAppKeyLoadMemory: + * @data: the binary key data. + * @dataSize: the size of binary key. + * @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 memory buffer. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecOpenSSLAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format, const char *pwd, + void* pwdCallback, void* pwdCallbackCtx) { + BIO* bio; + xmlSecKeyPtr key; + + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + /* this would be a read only BIO, cast from const is ok */ + bio = BIO_new_mem_buf((void*)data, dataSize); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_mem_buf", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "errno=%d", + errno); + return(NULL); + } + + key = xmlSecOpenSSLAppKeyLoadBIO (bio, format, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeyLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free(bio); + return(NULL); + } + + BIO_free(bio); + return(key); +} + + +/** + * xmlSecOpenSSLAppKeyLoadBIO: + * @bio: the key BIO. + * @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 an OpenSSL BIO object. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecOpenSSLAppKeyLoadBIO(BIO* bio, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, + void* pwdCallbackCtx) { + + xmlSecKeyPtr key = NULL; + xmlSecKeyDataPtr data; + EVP_PKEY* pKey = NULL; + int ret; + + xmlSecAssert2(bio != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + switch(format) { + case xmlSecKeyDataFormatPem: + /* try to read private key first */ + pKey = PEM_read_bio_PrivateKey(bio, NULL, + (pwd != NULL) ? xmlSecOpenSSLDummyPasswordCallback : (pem_password_cb*)pwdCallback, + (pwd != NULL) ? pwd : pwdCallbackCtx); + if(pKey == NULL) { + /* go to start of the file and try to read public key */ + BIO_reset(bio); + pKey = PEM_read_bio_PUBKEY(bio, NULL, (pem_password_cb*)pwdCallback, pwdCallbackCtx); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PEM_read_bio_PrivateKey and PEM_read_bio_PUBKEY", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + } + break; + case xmlSecKeyDataFormatDer: + /* try to read private key first */ + pKey = d2i_PrivateKey_bio(bio, NULL); + if(pKey == NULL) { + /* go to start of the file and try to read public key */ + BIO_reset(bio); + pKey = d2i_PUBKEY_bio(bio, NULL); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "d2i_PrivateKey_bio and d2i_PUBKEY_bio", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + } + break; + case xmlSecKeyDataFormatPkcs8Pem: + /* try to read private key first */ + pKey = PEM_read_bio_PrivateKey(bio, NULL, (pem_password_cb*)pwdCallback, pwdCallbackCtx); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PEM_read_bio_PrivateKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; + case xmlSecKeyDataFormatPkcs8Der: + /* try to read private key first */ + pKey = d2i_PKCS8PrivateKey_bio(bio, NULL, (pem_password_cb*)pwdCallback, pwdCallbackCtx); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "d2i_PrivateKey_bio and d2i_PUBKEY_bio", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; +#ifndef XMLSEC_NO_X509 + case xmlSecKeyDataFormatPkcs12: + key = xmlSecOpenSSLAppPkcs12LoadBIO(bio, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppPkcs12LoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + return(key); + + case xmlSecKeyDataFormatCertPem: + case xmlSecKeyDataFormatCertDer: + key = xmlSecOpenSSLAppKeyFromCertLoadBIO(bio, format); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeyFromCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + return(key); +#endif /* XMLSEC_NO_X509 */ + + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(NULL); + } + + data = xmlSecOpenSSLEvpKeyAdopt(pKey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLEvpKeyAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + EVP_PKEY_free(pKey); + return(NULL); + } + + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data))); + xmlSecKeyDestroy(key); + xmlSecKeyDataDestroy(data); + return(NULL); + } + + return(key); +} + + +#ifndef XMLSEC_NO_X509 +static X509* xmlSecOpenSSLAppCertLoadBIO (BIO* bio, + xmlSecKeyDataFormat format); +/** + * xmlSecOpenSSLAppKeyCertLoad: + * @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 +xmlSecOpenSSLAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, xmlSecKeyDataFormat format) { + BIO* bio; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + bio = BIO_new_file(filename, "rb"); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + return(-1); + } + + ret = xmlSecOpenSSLAppKeyCertLoadBIO (key, bio, format); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeyCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + BIO_free(bio); + return(-1); + } + + BIO_free(bio); + return(0); +} + +/** + * xmlSecOpenSSLAppKeyCertLoadMemory: + * @key: the pointer to key. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * + * Reads the certificate from memory buffer and adds it to key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format) { + BIO* bio; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* this would be a read only BIO, cast from const is ok */ + bio = BIO_new_mem_buf((void*)data, dataSize); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_mem_buf", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "errno=%d", + errno); + return(-1); + } + + ret = xmlSecOpenSSLAppKeyCertLoadBIO (key, bio, format); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeyCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free(bio); + return(-1); + } + + BIO_free(bio); + return(0); +} + +/** + * xmlSecOpenSSLAppKeyCertLoadBIO: + * @key: the pointer to key. + * @bio: the certificate bio. + * @format: the certificate file format. + * + * Reads the certificate from memory buffer and adds it to key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeyCertLoadBIO(xmlSecKeyPtr key, BIO* bio, xmlSecKeyDataFormat format) { + + xmlSecKeyDataFormat certFormat; + xmlSecKeyDataPtr data; + X509 *cert; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(bio != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + data = xmlSecKeyEnsureData(key, xmlSecOpenSSLKeyDataX509Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecOpenSSLKeyDataX509Id))); + return(-1); + } + + /* adjust cert format */ + switch(format) { + case xmlSecKeyDataFormatPkcs8Pem: + certFormat = xmlSecKeyDataFormatPem; + break; + case xmlSecKeyDataFormatPkcs8Der: + certFormat = xmlSecKeyDataFormatDer; + break; + default: + certFormat = format; + } + + cert = xmlSecOpenSSLAppCertLoadBIO(bio, certFormat); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppCertLoad", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data))); + X509_free(cert); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLAppPkcs12Load: + * @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. + * For uniformity, call xmlSecOpenSSLAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecOpenSSLAppPkcs12Load(const char *filename, const char *pwd, + void* pwdCallback, void* pwdCallbackCtx) { + BIO* bio; + xmlSecKeyPtr key; + + xmlSecAssert2(filename != NULL, NULL); + + bio = BIO_new_file(filename, "rb"); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + return(NULL); + } + + key = xmlSecOpenSSLAppPkcs12LoadBIO (bio, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppPkcs12LoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + BIO_free(bio); + return(NULL); + } + + BIO_free(bio); + return(key); +} + +/** + * xmlSecOpenSSLAppPkcs12LoadMemory: + * @data: the PKCS12 binary data. + * @dataSize: the PKCS12 binary data size. + * @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 data in memory buffer. + * For uniformity, call xmlSecOpenSSLAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecOpenSSLAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, + const char *pwd, void* pwdCallback, + void* pwdCallbackCtx) { + BIO* bio; + xmlSecKeyPtr key; + + xmlSecAssert2(data != NULL, NULL); + + /* this would be a read only BIO, cast from const is ok */ + bio = BIO_new_mem_buf((void*)data, dataSize); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_mem_buf", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "errno=%d", + errno); + return(NULL); + } + + key = xmlSecOpenSSLAppPkcs12LoadBIO (bio, pwd, pwdCallback, pwdCallbackCtx); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppPkcs12LoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free(bio); + return(NULL); + } + + BIO_free(bio); + return(key); +} + +/** + * xmlSecOpenSSLAppPkcs12LoadBIO: + * @bio: the PKCS12 key bio. + * @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 data in an OpenSSL BIO object. + * For uniformity, call xmlSecOpenSSLAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecOpenSSLAppPkcs12LoadBIO(BIO* bio, const char *pwd, + void* pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + + PKCS12 *p12 = NULL; + EVP_PKEY *pKey = NULL; + STACK_OF(X509) *chain = NULL; + xmlSecKeyPtr key = NULL; + xmlSecKeyDataPtr data = NULL; + xmlSecKeyDataPtr x509Data = NULL; + X509 *cert = NULL; + X509 *tmpcert = NULL; + int i; + int ret; + + xmlSecAssert2(bio != NULL, NULL); + + p12 = d2i_PKCS12_bio(bio, NULL); + if(p12 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "d2i_PKCS12_fp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = PKCS12_verify_mac(p12, pwd, (pwd != NULL) ? strlen(pwd) : 0); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PKCS12_verify_mac", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = PKCS12_parse(p12, pwd, &pKey, &cert, &chain); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PKCS12_parse", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + data = xmlSecOpenSSLEvpKeyAdopt(pKey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLEvpKeyAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + EVP_PKEY_free(pKey); + goto done; + } + + x509Data = xmlSecKeyDataCreate(xmlSecOpenSSLKeyDataX509Id); + if(x509Data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecOpenSSLKeyDataX509Id))); + goto done; + } + + tmpcert = X509_dup(cert); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + + /* starting from openssl 1.0.0 the PKCS12_parse() call will not create certs + chain object if there is no certificates in the pkcs12 file and it will be null + */ + if(chain == NULL) { + chain = sk_X509_new_null(); + if(chain == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "sk_X509_new_null", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + + ret = sk_X509_push(chain, tmpcert); + if(ret < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "sk_X509_push", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + X509_free(tmpcert); + goto done; + } + + ret = xmlSecOpenSSLKeyDataX509AdoptKeyCert(x509Data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + goto done; + } + cert = NULL; + + for(i = 0; i < sk_X509_num(chain); ++i) { + xmlSecAssert2(sk_X509_value(chain, i), NULL); + + tmpcert = X509_dup(sk_X509_value(chain, i)); + if(tmpcert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + X509_free(tmpcert); + goto done; + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(x509Data, tmpcert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "data=%s", + xmlSecErrorsSafeString(xmlSecKeyDataGetName(x509Data))); + 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, data); + 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; + } + 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))); + xmlSecKeyDestroy(key); + key = NULL; + goto done; + } + x509Data = NULL; + +done: + if(x509Data != NULL) { + xmlSecKeyDataDestroy(x509Data); + } + if(data != NULL) { + xmlSecKeyDataDestroy(data); + } + if(chain != NULL) { + sk_X509_pop_free(chain, X509_free); + } + if(cert != NULL) { + X509_free(cert); + } + if(p12 != NULL) { + PKCS12_free(p12); + } + return(key); +} + +/** + * xmlSecOpenSSLAppKeyFromCertLoadBIO: + * @bio: the BIO. + * @format: the cert format. + * + * Loads public key from cert. + * + * Returns: pointer to key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecOpenSSLAppKeyFromCertLoadBIO(BIO* bio, xmlSecKeyDataFormat format) { + xmlSecKeyPtr key; + xmlSecKeyDataPtr keyData; + xmlSecKeyDataPtr certData; + X509 *cert; + int ret; + + xmlSecAssert2(bio != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + /* load cert */ + cert = xmlSecOpenSSLAppCertLoadBIO(bio, format); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* get key value */ + keyData = xmlSecOpenSSLX509CertGetKey(cert); + if(keyData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509CertGetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert); + return(NULL); + } + + /* create key */ + key = xmlSecKeyCreate(); + if(key == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(keyData); + X509_free(cert); + return(NULL); + } + + /* set key value */ + ret = xmlSecKeySetValue(key, keyData); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + xmlSecKeyDataDestroy(keyData); + X509_free(cert); + return(NULL); + } + + /* create cert data */ + certData = xmlSecKeyEnsureData(key, xmlSecOpenSSLKeyDataX509Id); + if(certData == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + X509_free(cert); + return(NULL); + } + + /* put cert in the cert data */ + ret = xmlSecOpenSSLKeyDataX509AdoptCert(certData, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + X509_free(cert); + return(NULL); + } + + return(key); +} + + +/** + * xmlSecOpenSSLAppKeysMngrCertLoad: + * @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. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, + xmlSecKeyDataFormat format, xmlSecKeyDataType type) { + BIO* bio; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + bio = BIO_new_file(filename, "rb"); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + return(-1); + } + + ret = xmlSecOpenSSLAppKeysMngrCertLoadBIO(mngr, bio, format, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeysMngrCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s;errno=%d", + xmlSecErrorsSafeString(filename), + errno); + BIO_free(bio); + return(-1); + } + + BIO_free(bio); + return(0); +} + +/** + * xmlSecOpenSSLAppKeysMngrCertLoadMemory: + * @mngr: the keys manager. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * @type: the flag that indicates is the certificate trusted or not. + * + * Reads cert from binary buffer @data and adds to the list of trusted or known + * untrusted certs in @store. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + BIO* bio; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* this would be a read only BIO, cast from const is ok */ + bio = BIO_new_mem_buf((void*)data, dataSize); + if(bio == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new_mem_buf", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "errno=%d", + errno); + return(-1); + } + + ret = xmlSecOpenSSLAppKeysMngrCertLoadBIO(mngr, bio, format, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppKeysMngrCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free(bio); + return(-1); + } + + BIO_free(bio); + return(0); +} + +/** + * xmlSecOpenSSLAppKeysMngrCertLoadBIO: + * @mngr: the keys manager. + * @bio: the certificate BIO. + * @format: the certificate file format. + * @type: the flag that indicates is the certificate trusted or not. + * + * Reads cert from an OpenSSL BIO object and adds to the list of trusted or known + * untrusted certs in @store. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeysMngrCertLoadBIO(xmlSecKeysMngrPtr mngr, BIO* bio, + xmlSecKeyDataFormat format, xmlSecKeyDataType type) { + xmlSecKeyDataStorePtr x509Store; + X509* cert; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(bio != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecOpenSSLX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecOpenSSLX509StoreId"); + return(-1); + } + + cert = xmlSecOpenSSLAppCertLoadBIO(bio, format); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLAppCertLoadBIO", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecOpenSSLX509StoreAdoptCert(x509Store, cert, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509StoreAdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLAppKeysMngrAddCertsPath: + * @mngr: the keys manager. + * @path: the path to trusted certificates. + * + * Reads cert from @path and adds to the list of trusted certificates. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeysMngrAddCertsPath(xmlSecKeysMngrPtr mngr, const char *path) { + xmlSecKeyDataStorePtr x509Store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(path != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecOpenSSLX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecOpenSSLX509StoreId"); + return(-1); + } + + ret = xmlSecOpenSSLX509StoreAddCertsPath(x509Store, path); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509StoreAddCertsPath", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "path=%s", xmlSecErrorsSafeString(path)); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLAppKeysMngrAddCertsFile: + * @mngr: the keys manager. + * @file: the file containing trusted certificates. + * + * Reads certs from @file and adds to the list of trusted certificates. + * It is possible for @file to contain multiple certs. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppKeysMngrAddCertsFile(xmlSecKeysMngrPtr mngr, const char *file) { + xmlSecKeyDataStorePtr x509Store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(file != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(mngr, xmlSecOpenSSLX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetDataStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecOpenSSLX509StoreId"); + return(-1); + } + + ret = xmlSecOpenSSLX509StoreAddCertsFile(x509Store, file); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509StoreAddCertsFile", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "file=%s", xmlSecErrorsSafeString(file)); + return(-1); + } + + return(0); +} + +static X509* +xmlSecOpenSSLAppCertLoadBIO(BIO* bio, xmlSecKeyDataFormat format) { + X509 *cert; + + xmlSecAssert2(bio != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + switch(format) { + case xmlSecKeyDataFormatPem: + case xmlSecKeyDataFormatCertPem: + cert = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PEM_read_bio_X509_AUX", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; + case xmlSecKeyDataFormatDer: + case xmlSecKeyDataFormatCertDer: + cert = d2i_X509_bio(bio, NULL); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "d2i_X509_bio", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_FORMAT, + "format=%d", format); + return(NULL); + } + + return(cert); +} + +#endif /* XMLSEC_NO_X509 */ + +/** + * xmlSecOpenSSLAppDefaultKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Initializes @mngr with simple keys store #xmlSecSimpleKeysStoreId + * and a default OpenSSL crypto key data stores. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + + /* create simple keys store if needed */ + if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) { + xmlSecKeyStorePtr keysStore; + + keysStore = xmlSecKeyStoreCreate(xmlSecSimpleKeysStoreId); + if(keysStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecSimpleKeysStoreId"); + 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 = xmlSecOpenSSLKeysMngrInit(mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKeysMngrInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* TODO */ + mngr->getKey = xmlSecKeysMngrGetKey; + return(0); +} + +/** + * xmlSecOpenSSLAppDefaultKeysMngrAdoptKey: + * @mngr: the pointer to keys manager. + * @key: the pointer to key. + * + * Adds @key to the keys manager @mngr created with #xmlSecOpenSSLAppDefaultKeysMngrInit + * function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(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 = xmlSecSimpleKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLAppDefaultKeysMngrLoad: + * @mngr: the pointer to keys manager. + * @uri: the uri. + * + * Loads XML keys file from @uri to the keys manager @mngr created + * with #xmlSecOpenSSLAppDefaultKeysMngrInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLAppDefaultKeysMngrLoad(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 = xmlSecSimpleKeysStoreLoad(store, uri, mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreLoad", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", xmlSecErrorsSafeString(uri)); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLAppDefaultKeysMngrSave: + * @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 +xmlSecOpenSSLAppDefaultKeysMngrSave(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 = xmlSecSimpleKeysStoreSave(store, filename, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreSave", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename%s", xmlSecErrorsSafeString(filename)); + return(-1); + } + + return(0); +} + + +/** + * Random numbers initialization from openssl (apps/app_rand.c) + */ +static int seeded = 0; +static int egdsocket = 0; + +static int +xmlSecOpenSSLAppLoadRANDFile(const char *file) { + char buffer[1024]; + + if(file == NULL) { + file = RAND_file_name(buffer, sizeof(buffer)); + }else if(RAND_egd(file) > 0) { + /* we try if the given filename is an EGD socket. + * if it is, we don't write anything back to the file. */ + egdsocket = 1; + return 1; + } + + if((file == NULL) || !RAND_load_file(file, -1)) { + if(RAND_status() == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "RAND_load_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "file=%s", xmlSecErrorsSafeString(file)); + return 0; + } + } + seeded = 1; + return 1; +} + +static int +xmlSecOpenSSLAppSaveRANDFile(const char *file) { + char buffer[1024]; + + if(egdsocket || !seeded) { + /* If we did not manage to read the seed file, + * we should not write a low-entropy seed file back -- + * it would suppress a crucial warning the next time + * we want to use it. */ + return 0; + } + + if(file == NULL) { + file = RAND_file_name(buffer, sizeof(buffer)); + } + if((file == NULL) || !RAND_write_file(file)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "RAND_write_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "file=%s", + xmlSecErrorsSafeString(file)); + return 0; + } + + return 1; +} + +/** + * xmlSecOpenSSLAppGetDefaultPwdCallback: + * + * Gets default password callback. + * + * Returns: default password callback. + */ +void* +xmlSecOpenSSLAppGetDefaultPwdCallback(void) { + return((void*)xmlSecOpenSSLDefaultPasswordCallback); +} + +static int +xmlSecOpenSSLDefaultPasswordCallback(char *buf, int bufsize, int verify, void *userdata) { + char* filename = (char*)userdata; + char* buf2; + xmlChar prompt[2048]; + int i, ret; + + xmlSecAssert2(buf != NULL, -1); + + /* try 3 times */ + for(i = 0; i < 3; i++) { + if(filename != NULL) { + xmlSecStrPrintf(prompt, sizeof(prompt), BAD_CAST "Enter password for \"%s\" file: ", filename); + } else { + xmlSecStrPrintf(prompt, sizeof(prompt), BAD_CAST "Enter password: "); + } + ret = EVP_read_pw_string(buf, bufsize, (char*)prompt, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "EVP_read_pw_string", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* if we don't need to verify password then we are done */ + if(verify == 0) { + return(strlen(buf)); + } + + if(filename != NULL) { + xmlSecStrPrintf(prompt, sizeof(prompt), BAD_CAST "Enter password for \"%s\" file again: ", filename); + } else { + xmlSecStrPrintf(prompt, sizeof(prompt), BAD_CAST "Enter password again: "); + } + + buf2 = (char*)xmlMalloc(bufsize); + if(buf2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", bufsize); + return(-1); + } + ret = EVP_read_pw_string(buf2, bufsize, (char*)prompt, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "EVP_read_pw_string", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + memset(buf2, 0, bufsize); + xmlFree(buf2); + return(-1); + } + + /* check if passwords match */ + if(strcmp(buf, buf2) == 0) { + memset(buf2, 0, bufsize); + xmlFree(buf2); + return(strlen(buf)); + } + + /* try again */ + memset(buf2, 0, bufsize); + xmlFree(buf2); + } + + return(-1); +} + +static int +xmlSecOpenSSLDummyPasswordCallback(char *buf, int bufsize, int verify, void *userdata) { + char* password = (char*)userdata; + + if((password == NULL) || (strlen(password) + 1 > bufsize)) { + return(-1); + } + + strcpy(buf, password); + return (strlen(buf)); +} + diff --git a/src/openssl/bn.c b/src/openssl/bn.c new file mode 100644 index 00000000..28025d14 --- /dev/null +++ b/src/openssl/bn.c @@ -0,0 +1,163 @@ +/** + * XMLSec library + * + * Reading/writing BIGNUM values + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/base64.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/bn.h> + +/** + * xmlSecOpenSSLNodeGetBNValue: + * @cur: the poitner to an XML node. + * @a: the BIGNUM buffer. + * + * Converts the node content from CryptoBinary format + * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary) + * to a BIGNUM. If no BIGNUM buffer provided then a new + * BIGNUM is created (caller is responsible for freeing it). + * + * Returns: a pointer to BIGNUM produced from CryptoBinary string + * or NULL if an error occurs. + */ +BIGNUM* +xmlSecOpenSSLNodeGetBNValue(const xmlNodePtr cur, BIGNUM **a) { + xmlSecBuffer buf; + int ret; + + xmlSecAssert2(cur != NULL, NULL); + + ret = xmlSecBufferInitialize(&buf, 128); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ret = xmlSecBufferBase64NodeContentRead(&buf, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferBase64NodeContentRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(NULL); + } + + (*a) = BN_bin2bn(xmlSecBufferGetData(&buf), xmlSecBufferGetSize(&buf), (*a)); + if( (*a) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_bin2bn", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(NULL); + } + xmlSecBufferFinalize(&buf); + return(*a); +} + +/** + * xmlSecOpenSSLNodeSetBNValue: + * @cur: the pointer to an XML node. + * @a: the BIGNUM. + * @addLineBreaks: if the flag is equal to 1 then + * linebreaks will be added before and after + * new buffer content. + * + * Converts BIGNUM to CryptoBinary string + * (http://www.w3.org/TR/xmldsig-core/#sec-CryptoBinary) + * and sets it as the content of the given node. If the + * addLineBreaks is set then line breaks are added + * before and after the CryptoBinary string. + * + * Returns: 0 on success or -1 otherwise. + */ +int +xmlSecOpenSSLNodeSetBNValue(xmlNodePtr cur, const BIGNUM *a, int addLineBreaks) { + xmlSecBuffer buf; + xmlSecSize size; + int ret; + + xmlSecAssert2(a != NULL, -1); + xmlSecAssert2(cur != NULL, -1); + + ret = xmlSecBufferInitialize(&buf, BN_num_bytes(a) + 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", BN_num_bytes(a) + 1); + return(-1); + } + + ret = BN_bn2bin(a, xmlSecBufferGetData(&buf)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_bn2bin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + size = ret; + + ret = xmlSecBufferSetSize(&buf, size); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + xmlSecBufferFinalize(&buf); + return(-1); + } + + if(addLineBreaks) { + xmlNodeSetContent(cur, xmlSecStringCR); + } else { + xmlNodeSetContent(cur, xmlSecStringEmpty); + } + + ret = xmlSecBufferBase64NodeContentWrite(&buf, cur, xmlSecBase64GetDefaultLineSize()); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferBase64NodeContentWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buf); + return(-1); + } + + if(addLineBreaks) { + xmlNodeAddContent(cur, xmlSecStringCR); + } + + xmlSecBufferFinalize(&buf); + return(0); +} + diff --git a/src/openssl/ciphers.c b/src/openssl/ciphers.c new file mode 100644 index 00000000..4799cb52 --- /dev/null +++ b/src/openssl/ciphers.c @@ -0,0 +1,856 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <openssl/evp.h> +#include <openssl/rand.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> + +/* this is not defined in OpenSSL 0.9.6 */ +#ifndef EVP_MAX_BLOCK_LENGTH +#define EVP_MAX_BLOCK_LENGTH 32 +#endif /* EVP_MAX_BLOCK_LENGTH */ + +/************************************************************************** + * + * Internal OpenSSL Block cipher CTX + * + *****************************************************************************/ +typedef struct _xmlSecOpenSSLEvpBlockCipherCtx xmlSecOpenSSLEvpBlockCipherCtx, + *xmlSecOpenSSLEvpBlockCipherCtxPtr; +struct _xmlSecOpenSSLEvpBlockCipherCtx { + const EVP_CIPHER* cipher; + xmlSecKeyDataId keyId; + EVP_CIPHER_CTX cipherCtx; + int keyInitialized; + int ctxInitialized; + xmlSecByte key[EVP_MAX_KEY_LENGTH]; + xmlSecByte iv[EVP_MAX_IV_LENGTH]; + xmlSecByte pad[EVP_MAX_BLOCK_LENGTH]; +}; +static int xmlSecOpenSSLEvpBlockCipherCtxInit (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpBlockCipherCtxUpdate (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpBlockCipherCtxFinal (xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx); +static int +xmlSecOpenSSLEvpBlockCipherCtxInit(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + int encrypt, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int ivLen; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ivLen = EVP_CIPHER_iv_length(ctx->cipher); + xmlSecAssert2(ivLen > 0, -1); + xmlSecAssert2((xmlSecSize)ivLen <= sizeof(ctx->iv), -1); + + if(encrypt) { + /* generate random iv */ + ret = RAND_bytes(ctx->iv, ivLen); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "RAND_bytes", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", ivLen); + return(-1); + } + + /* write iv to the output */ + ret = xmlSecBufferAppend(out, ctx->iv, ivLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ivLen); + return(-1); + } + + } else { + /* if we don't have enough data, exit and hope that + * we'll have iv next time */ + if(xmlSecBufferGetSize(in) < (xmlSecSize)ivLen) { + return(0); + } + + /* copy iv to our buffer*/ + xmlSecAssert2(xmlSecBufferGetData(in) != NULL, -1); + memcpy(ctx->iv, xmlSecBufferGetData(in), ivLen); + + /* and remove from input */ + ret = xmlSecBufferRemoveHead(in, ivLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", ivLen); + return(-1); + } + } + + /* set iv */ + ret = EVP_CipherInit(&(ctx->cipherCtx), ctx->cipher, ctx->key, ctx->iv, encrypt); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherInit", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->ctxInitialized = 1; + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems + */ +#ifndef XMLSEC_OPENSSL_096 + EVP_CIPHER_CTX_set_padding(&(ctx->cipherCtx), 0); +#endif /* XMLSEC_OPENSSL_096 */ + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherCtxUpdate(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr in, xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int blockLen, fixLength = 0, outLen = 0; + xmlSecSize inSize, outSize; + xmlSecByte* outBuf; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = EVP_CIPHER_block_size(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(inSize == 0) { + /* wait for more data */ + return(0); + } + + /* OpenSSL docs: The amount of data written depends on the block + * alignment of the encrypted data: as a result the amount of data + * written may be anything from zero bytes to (inl + cipher_block_size - 1). + */ + 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; + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems. + * + * The logic below is copied from EVP_DecryptUpdate() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ +#ifndef XMLSEC_OPENSSL_096 + if(!ctx->cipherCtx.encrypt) { + if(ctx->cipherCtx.final_used) { + memcpy(outBuf, ctx->cipherCtx.final, blockLen); + outBuf += blockLen; + fixLength = 1; + } else { + fixLength = 0; + } + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* encrypt/decrypt */ + ret = EVP_CipherUpdate(&(ctx->cipherCtx), outBuf, &outLen, xmlSecBufferGetData(in), inSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_OPENSSL_096 + if(!ctx->cipherCtx.encrypt) { + /* + * The logic below is copied from EVP_DecryptUpdate() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ + if (blockLen > 1 && !ctx->cipherCtx.buf_len) { + outLen -= blockLen; + ctx->cipherCtx.final_used = 1; + memcpy(ctx->cipherCtx.final, &outBuf[outLen], blockLen); + } else { + ctx->cipherCtx.final_used = 0; + } + if (fixLength) { + outLen += blockLen; + } + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* 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); +} + +static int +xmlSecOpenSSLEvpBlockCipherCtxFinal(xmlSecOpenSSLEvpBlockCipherCtxPtr ctx, + xmlSecBufferPtr out, + const xmlChar* cipherName, + xmlSecTransformCtxPtr transformCtx) { + int blockLen, outLen = 0, outLen2 = 0; + xmlSecSize outSize; + xmlSecByte* outBuf; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->keyInitialized != 0, -1); + xmlSecAssert2(ctx->ctxInitialized != 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + blockLen = EVP_CIPHER_block_size(ctx->cipher); + xmlSecAssert2(blockLen > 0, -1); + + outSize = xmlSecBufferGetSize(out); + + /* OpenSSL docs: The encrypted final data is written to out which should + * have sufficient space for one cipher block. We might have to write + * one more block with padding + */ + 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; + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems. + * + * The logic below is copied from EVP_DecryptFinal() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ +#ifndef XMLSEC_OPENSSL_096 + if(ctx->cipherCtx.encrypt) { + int padLen; + + xmlSecAssert2(blockLen <= EVP_MAX_BLOCK_LENGTH, -1); + + padLen = blockLen - ctx->cipherCtx.buf_len; + xmlSecAssert2(padLen > 0, -1); + + /* generate random padding */ + if(padLen > 1) { + ret = RAND_bytes(ctx->pad, padLen - 1); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "RAND_bytes", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", padLen - 1); + return(-1); + } + } + ctx->pad[padLen - 1] = padLen; + + /* write padding */ + ret = EVP_CipherUpdate(&(ctx->cipherCtx), outBuf, &outLen, ctx->pad, padLen); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outBuf += outLen; + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* finalize transform */ + ret = EVP_CipherFinal(&(ctx->cipherCtx), outBuf, &outLen2); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "EVP_CipherFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* + * The padding used in XML Enc does not follow RFC 1423 + * and is not supported by OpenSSL. In the case of OpenSSL 0.9.7 + * it is possible to disable padding and do it by yourself + * For OpenSSL 0.9.6 you have interop problems. + * + * The logic below is copied from EVP_DecryptFinal() function. + * This is a hack but it's the only way I can provide binary + * compatibility with previous versions of xmlsec. + * This needs to be fixed in the next XMLSEC API refresh. + */ +#ifndef XMLSEC_OPENSSL_096 + if(!ctx->cipherCtx.encrypt) { + /* we instructed openssl to do not use padding so there + * should be no final block + */ + xmlSecAssert2(outLen2 == 0, -1); + xmlSecAssert2(ctx->cipherCtx.buf_len == 0, -1); + xmlSecAssert2(ctx->cipherCtx.final_used, -1); + + if(blockLen > 1) { + outLen2 = blockLen - ctx->cipherCtx.final[blockLen - 1]; + if(outLen2 > 0) { + memcpy(outBuf, ctx->cipherCtx.final, outLen2); + } else if(outLen2 < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "padding=%d;buffer=%d", + ctx->cipherCtx.final[blockLen - 1], blockLen); + return(-1); + } + } + } +#endif /* XMLSEC_OPENSSL_096 */ + + /* set correct output buffer size */ + ret = xmlSecBufferSetSize(out, outSize + outLen + outLen2); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(cipherName), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize + outLen + outLen2); + return(-1); + } + + return(0); +} + + +/****************************************************************************** + * + * EVP Block Cipher transforms + * + * xmlSecOpenSSLEvpBlockCipherCtx block is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecOpenSSLEvpBlockCipherSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLEvpBlockCipherCtx)) +#define xmlSecOpenSSLEvpBlockCipherGetCtx(transform) \ + ((xmlSecOpenSSLEvpBlockCipherCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecOpenSSLEvpBlockCipherInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLEvpBlockCipherFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLEvpBlockCipherSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLEvpBlockCipherSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLEvpBlockCipherExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpBlockCipherCheckId (xmlSecTransformPtr transform); + + + +static int +xmlSecOpenSSLEvpBlockCipherCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DES + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformDes3CbcId)) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes128CbcId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes192CbcId) || + xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformAes256CbcId)) { + + return(1); + } +#endif /* XMLSEC_NO_AES */ + + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherInitialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpBlockCipherCtx)); + +#ifndef XMLSEC_NO_DES + if(transform->id == xmlSecOpenSSLTransformDes3CbcId) { + ctx->cipher = EVP_des_ede3_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataDesId; + } else +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES + if(transform->id == xmlSecOpenSSLTransformAes128CbcId) { + ctx->cipher = EVP_aes_128_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + } else if(transform->id == xmlSecOpenSSLTransformAes192CbcId) { + ctx->cipher = EVP_aes_192_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + } else if(transform->id == xmlSecOpenSSLTransformAes256CbcId) { + ctx->cipher = EVP_aes_256_cbc(); + ctx->keyId = xmlSecOpenSSLKeyDataAesId; + } else +#endif /* XMLSEC_NO_AES */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + EVP_CIPHER_CTX_init(&(ctx->cipherCtx)); + return(0); +} + +static void +xmlSecOpenSSLEvpBlockCipherFinalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + + xmlSecAssert(xmlSecOpenSSLEvpBlockCipherCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize)); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert(ctx != NULL); + + EVP_CIPHER_CTX_cleanup(&(ctx->cipherCtx)); + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpBlockCipherCtx)); +} + +static int +xmlSecOpenSSLEvpBlockCipherSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + int cipherKeyLen; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + + keyReq->keyId = ctx->keyId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + + cipherKeyLen = EVP_CIPHER_key_length(ctx->cipher); + xmlSecAssert2(cipherKeyLen > 0, -1); + + keyReq->keyBitsSize = (xmlSecSize)(8 * cipherKeyLen); + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + xmlSecBufferPtr buffer; + int cipherKeyLen; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->cipher != NULL, -1); + xmlSecAssert2(ctx->keyInitialized == 0, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + cipherKeyLen = EVP_CIPHER_key_length(ctx->cipher); + xmlSecAssert2(cipherKeyLen > 0, -1); + xmlSecAssert2((xmlSecSize)cipherKeyLen <= sizeof(ctx->key), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + if(xmlSecBufferGetSize(buffer) < (xmlSecSize)cipherKeyLen) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "keySize=%d;expected=%d", + xmlSecBufferGetSize(buffer), cipherKeyLen); + return(-1); + } + + xmlSecAssert2(xmlSecBufferGetData(buffer) != NULL, -1); + memcpy(ctx->key, xmlSecBufferGetData(buffer), cipherKeyLen); + + ctx->keyInitialized = 1; + return(0); +} + +static int +xmlSecOpenSSLEvpBlockCipherExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLEvpBlockCipherCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecOpenSSLEvpBlockCipherCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpBlockCipherSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecOpenSSLEvpBlockCipherGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + if(ctx->ctxInitialized == 0) { + ret = xmlSecOpenSSLEvpBlockCipherCtxInit(ctx, in, out, + (transform->operation == xmlSecTransformOperationEncrypt) ? 1 : 0, + xmlSecTransformGetName(transform), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpBlockCipherCtxInit", + 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 = xmlSecOpenSSLEvpBlockCipherCtxUpdate(ctx, in, out, + xmlSecTransformGetName(transform), + transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpBlockCipherCtxUpdate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(last != 0) { + /* by now there should be no input */ + xmlSecAssert2(xmlSecBufferGetSize(in) == 0, -1); + ret = xmlSecOpenSSLEvpBlockCipherCtxFinal(ctx, out, + xmlSecTransformGetName(transform), + transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpBlockCipherCtxFinal", + 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 xmlSecOpenSSLAes128CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes128Cbc, /* const xmlChar* name; */ + xmlSecHrefAes128Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformAes128CbcGetKlass: + * + * AES 128 CBC encryption transform klass. + * + * Returns: pointer to AES 128 CBC encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformAes128CbcGetKlass(void) { + return(&xmlSecOpenSSLAes128CbcKlass); +} + +static xmlSecTransformKlass xmlSecOpenSSLAes192CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes192Cbc, /* const xmlChar* name; */ + xmlSecHrefAes192Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformAes192CbcGetKlass: + * + * AES 192 CBC encryption transform klass. + * + * Returns: pointer to AES 192 CBC encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformAes192CbcGetKlass(void) { + return(&xmlSecOpenSSLAes192CbcKlass); +} + +static xmlSecTransformKlass xmlSecOpenSSLAes256CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameAes256Cbc, /* const xmlChar* name; */ + xmlSecHrefAes256Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformAes256CbcGetKlass: + * + * AES 256 CBC encryption transform klass. + * + * Returns: pointer to AES 256 CBC encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformAes256CbcGetKlass(void) { + return(&xmlSecOpenSSLAes256CbcKlass); +} + +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES +static xmlSecTransformKlass xmlSecOpenSSLDes3CbcKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpBlockCipherSize, /* xmlSecSize objSize */ + + xmlSecNameDes3Cbc, /* const xmlChar* name; */ + xmlSecHrefDes3Cbc, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLEvpBlockCipherInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpBlockCipherFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpBlockCipherSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLEvpBlockCipherSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpBlockCipherExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformDes3CbcGetKlass: + * + * Triple DES CBC encryption transform klass. + * + * Returns: pointer to Triple DES encryption transform. + */ +xmlSecTransformId +xmlSecOpenSSLTransformDes3CbcGetKlass(void) { + return(&xmlSecOpenSSLDes3CbcKlass); +} +#endif /* XMLSEC_NO_DES */ + diff --git a/src/openssl/crypto.c b/src/openssl/crypto.c new file mode 100644 index 00000000..fa226620 --- /dev/null +++ b/src/openssl/crypto.c @@ -0,0 +1,474 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <openssl/evp.h> +#include <openssl/rand.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/dl.h> +#include <xmlsec/private.h> + +#include <xmlsec/openssl/app.h> +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/x509.h> + +static int xmlSecOpenSSLErrorsInit (void); + +static xmlSecCryptoDLFunctionsPtr gXmlSecOpenSSLFunctions = NULL; +static xmlChar* gXmlSecOpenSSLTrustedCertsFolder = NULL; + +/** + * xmlSecCryptoGetFunctions_openssl: + * + * Gets the pointer to xmlsec-openssl functions table. + * + * Returns: the xmlsec-openssl functions table or NULL if an error occurs. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoGetFunctions_openssl(void) { + static xmlSecCryptoDLFunctions functions; + + if(gXmlSecOpenSSLFunctions != NULL) { + return(gXmlSecOpenSSLFunctions); + } + + memset(&functions, 0, sizeof(functions)); + gXmlSecOpenSSLFunctions = &functions; + + /** + * Crypto Init/shutdown + */ + gXmlSecOpenSSLFunctions->cryptoInit = xmlSecOpenSSLInit; + gXmlSecOpenSSLFunctions->cryptoShutdown = xmlSecOpenSSLShutdown; + gXmlSecOpenSSLFunctions->cryptoKeysMngrInit = xmlSecOpenSSLKeysMngrInit; + + /** + * Key data ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecOpenSSLFunctions->keyDataAesGetKlass = xmlSecOpenSSLKeyDataAesGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecOpenSSLFunctions->keyDataDesGetKlass = xmlSecOpenSSLKeyDataDesGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_DSA + gXmlSecOpenSSLFunctions->keyDataDsaGetKlass = xmlSecOpenSSLKeyDataDsaGetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecOpenSSLFunctions->keyDataHmacGetKlass = xmlSecOpenSSLKeyDataHmacGetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_RSA + gXmlSecOpenSSLFunctions->keyDataRsaGetKlass = xmlSecOpenSSLKeyDataRsaGetKlass; +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_X509 + gXmlSecOpenSSLFunctions->keyDataX509GetKlass = xmlSecOpenSSLKeyDataX509GetKlass; + gXmlSecOpenSSLFunctions->keyDataRawX509CertGetKlass = xmlSecOpenSSLKeyDataRawX509CertGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /** + * Key data store ids + */ +#ifndef XMLSEC_NO_X509 + gXmlSecOpenSSLFunctions->x509StoreGetKlass = xmlSecOpenSSLX509StoreGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /** + * Crypto transforms ids + */ + /******************************* AES ********************************/ +#ifndef XMLSEC_NO_AES + gXmlSecOpenSSLFunctions->transformAes128CbcGetKlass = xmlSecOpenSSLTransformAes128CbcGetKlass; + gXmlSecOpenSSLFunctions->transformAes192CbcGetKlass = xmlSecOpenSSLTransformAes192CbcGetKlass; + gXmlSecOpenSSLFunctions->transformAes256CbcGetKlass = xmlSecOpenSSLTransformAes256CbcGetKlass; + gXmlSecOpenSSLFunctions->transformKWAes128GetKlass = xmlSecOpenSSLTransformKWAes128GetKlass; + gXmlSecOpenSSLFunctions->transformKWAes192GetKlass = xmlSecOpenSSLTransformKWAes192GetKlass; + gXmlSecOpenSSLFunctions->transformKWAes256GetKlass = xmlSecOpenSSLTransformKWAes256GetKlass; +#endif /* XMLSEC_NO_AES */ + + /******************************* DES ********************************/ +#ifndef XMLSEC_NO_DES + gXmlSecOpenSSLFunctions->transformDes3CbcGetKlass = xmlSecOpenSSLTransformDes3CbcGetKlass; + gXmlSecOpenSSLFunctions->transformKWDes3GetKlass = xmlSecOpenSSLTransformKWDes3GetKlass; +#endif /* XMLSEC_NO_DES */ + + + /******************************* DSA ********************************/ +#ifndef XMLSEC_NO_DSA +#ifndef XMLSEC_NO_SHA1 + gXmlSecOpenSSLFunctions->transformDsaSha1GetKlass = xmlSecOpenSSLTransformDsaSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ +#endif /* XMLSEC_NO_DSA */ + + /******************************* HMAC ********************************/ +#ifndef XMLSEC_NO_HMAC +#ifndef XMLSEC_NO_MD5 + gXmlSecOpenSSLFunctions->transformHmacMd5GetKlass = xmlSecOpenSSLTransformHmacMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + gXmlSecOpenSSLFunctions->transformHmacRipemd160GetKlass = xmlSecOpenSSLTransformHmacRipemd160GetKlass; +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecOpenSSLFunctions->transformHmacSha1GetKlass = xmlSecOpenSSLTransformHmacSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + gXmlSecOpenSSLFunctions->transformHmacSha224GetKlass = xmlSecOpenSSLTransformHmacSha224GetKlass; +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + gXmlSecOpenSSLFunctions->transformHmacSha256GetKlass = xmlSecOpenSSLTransformHmacSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + gXmlSecOpenSSLFunctions->transformHmacSha384GetKlass = xmlSecOpenSSLTransformHmacSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + gXmlSecOpenSSLFunctions->transformHmacSha512GetKlass = xmlSecOpenSSLTransformHmacSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + +#endif /* XMLSEC_NO_HMAC */ + + /******************************* MD5 ********************************/ +#ifndef XMLSEC_NO_MD5 + gXmlSecOpenSSLFunctions->transformMd5GetKlass = xmlSecOpenSSLTransformMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + + /******************************* RIPEMD160 ********************************/ +#ifndef XMLSEC_NO_RIPEMD160 + gXmlSecOpenSSLFunctions->transformRipemd160GetKlass = xmlSecOpenSSLTransformRipemd160GetKlass; +#endif /* XMLSEC_NO_RIPEMD160 */ + + /******************************* RSA ********************************/ +#ifndef XMLSEC_NO_RSA +#ifndef XMLSEC_NO_MD5 + gXmlSecOpenSSLFunctions->transformRsaMd5GetKlass = xmlSecOpenSSLTransformRsaMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + gXmlSecOpenSSLFunctions->transformRsaRipemd160GetKlass = xmlSecOpenSSLTransformRsaRipemd160GetKlass; +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecOpenSSLFunctions->transformRsaSha1GetKlass = xmlSecOpenSSLTransformRsaSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + gXmlSecOpenSSLFunctions->transformRsaSha224GetKlass = xmlSecOpenSSLTransformRsaSha224GetKlass; +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + gXmlSecOpenSSLFunctions->transformRsaSha256GetKlass = xmlSecOpenSSLTransformRsaSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + gXmlSecOpenSSLFunctions->transformRsaSha384GetKlass = xmlSecOpenSSLTransformRsaSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + gXmlSecOpenSSLFunctions->transformRsaSha512GetKlass = xmlSecOpenSSLTransformRsaSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + gXmlSecOpenSSLFunctions->transformRsaPkcs1GetKlass = xmlSecOpenSSLTransformRsaPkcs1GetKlass; + gXmlSecOpenSSLFunctions->transformRsaOaepGetKlass = xmlSecOpenSSLTransformRsaOaepGetKlass; +#endif /* XMLSEC_NO_RSA */ + + /******************************* SHA ********************************/ +#ifndef XMLSEC_NO_SHA1 + gXmlSecOpenSSLFunctions->transformSha1GetKlass = xmlSecOpenSSLTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ +#ifndef XMLSEC_NO_SHA224 + gXmlSecOpenSSLFunctions->transformSha224GetKlass = xmlSecOpenSSLTransformSha224GetKlass; +#endif /* XMLSEC_NO_SHA224 */ +#ifndef XMLSEC_NO_SHA256 + gXmlSecOpenSSLFunctions->transformSha256GetKlass = xmlSecOpenSSLTransformSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ +#ifndef XMLSEC_NO_SHA384 + gXmlSecOpenSSLFunctions->transformSha384GetKlass = xmlSecOpenSSLTransformSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ +#ifndef XMLSEC_NO_SHA512 + gXmlSecOpenSSLFunctions->transformSha512GetKlass = xmlSecOpenSSLTransformSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + /** + * High level routines form xmlsec command line utility + */ + gXmlSecOpenSSLFunctions->cryptoAppInit = xmlSecOpenSSLAppInit; + gXmlSecOpenSSLFunctions->cryptoAppShutdown = xmlSecOpenSSLAppShutdown; + gXmlSecOpenSSLFunctions->cryptoAppDefaultKeysMngrInit = xmlSecOpenSSLAppDefaultKeysMngrInit; + gXmlSecOpenSSLFunctions->cryptoAppDefaultKeysMngrAdoptKey = xmlSecOpenSSLAppDefaultKeysMngrAdoptKey; + gXmlSecOpenSSLFunctions->cryptoAppDefaultKeysMngrLoad = xmlSecOpenSSLAppDefaultKeysMngrLoad; + gXmlSecOpenSSLFunctions->cryptoAppDefaultKeysMngrSave = xmlSecOpenSSLAppDefaultKeysMngrSave; +#ifndef XMLSEC_NO_X509 + gXmlSecOpenSSLFunctions->cryptoAppKeysMngrCertLoad = xmlSecOpenSSLAppKeysMngrCertLoad; + gXmlSecOpenSSLFunctions->cryptoAppKeysMngrCertLoadMemory = xmlSecOpenSSLAppKeysMngrCertLoadMemory; + gXmlSecOpenSSLFunctions->cryptoAppPkcs12Load = xmlSecOpenSSLAppPkcs12Load; + gXmlSecOpenSSLFunctions->cryptoAppPkcs12LoadMemory = xmlSecOpenSSLAppPkcs12LoadMemory; + gXmlSecOpenSSLFunctions->cryptoAppKeyCertLoad = xmlSecOpenSSLAppKeyCertLoad; + gXmlSecOpenSSLFunctions->cryptoAppKeyCertLoadMemory = xmlSecOpenSSLAppKeyCertLoadMemory; +#endif /* XMLSEC_NO_X509 */ + gXmlSecOpenSSLFunctions->cryptoAppKeyLoad = xmlSecOpenSSLAppKeyLoad; + gXmlSecOpenSSLFunctions->cryptoAppKeyLoadMemory = xmlSecOpenSSLAppKeyLoadMemory; + gXmlSecOpenSSLFunctions->cryptoAppDefaultPwdCallback = (void*)xmlSecOpenSSLAppGetDefaultPwdCallback(); + + return(gXmlSecOpenSSLFunctions); +} + +/** + * xmlSecOpenSSLInit: + * + * XMLSec library specific crypto engine initialization. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLInit (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); + } + + if(xmlSecOpenSSLErrorsInit() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLErrorsInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* register our klasses */ + if(xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(xmlSecCryptoGetFunctions_openssl()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLShutdown: + * + * XMLSec library specific crypto engine shutdown. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLShutdown(void) { + xmlSecOpenSSLSetDefaultTrustedCertsFolder(NULL); + return(0); +} + +/** + * xmlSecOpenSSLKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Adds OpenSSL specific key data stores in keys manager. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + +#ifndef XMLSEC_NO_X509 + /* create x509 store if needed */ + if(xmlSecKeysMngrGetDataStore(mngr, xmlSecOpenSSLX509StoreId) == NULL) { + xmlSecKeyDataStorePtr x509Store; + + x509Store = xmlSecKeyDataStoreCreate(xmlSecOpenSSLX509StoreId); + if(x509Store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecOpenSSLX509StoreId"); + 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); +} + +/** + * xmlSecOpenSSLGenerateRandom: + * @buffer: the destination buffer. + * @size: the numer of bytes to generate. + * + * Generates @size random bytes and puts result in @buffer. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLGenerateRandom(xmlSecBufferPtr buffer, xmlSecSize size) { + 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); + } + + /* get random data */ + ret = RAND_bytes((xmlSecByte*)xmlSecBufferGetData(buffer), size); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "RAND_bytes", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", size); + return(-1); + } + return(0); +} + +/** + * xmlSecOpenSSLErrorsDefaultCallback: + * @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 OpenSSL errors reporting callback function. + */ +void +xmlSecOpenSSLErrorsDefaultCallback(const char* file, int line, const char* func, + const char* errorObject, const char* errorSubject, + int reason, const char* msg) { + + ERR_put_error(XMLSEC_OPENSSL_ERRORS_LIB, + XMLSEC_OPENSSL_ERRORS_FUNCTION, + reason, file, line); + xmlSecErrorsDefaultCallback(file, line, func, + errorObject, errorSubject, + reason, msg); +} + +static int +xmlSecOpenSSLErrorsInit(void) { + static ERR_STRING_DATA xmlSecOpenSSLStrReasons[XMLSEC_ERRORS_MAX_NUMBER + 1]; + static ERR_STRING_DATA xmlSecOpenSSLStrLib[]= { + { ERR_PACK(XMLSEC_OPENSSL_ERRORS_LIB,0,0), "xmlsec routines"}, + { 0, NULL} + }; + static ERR_STRING_DATA xmlSecOpenSSLStrDefReason[]= { + { XMLSEC_OPENSSL_ERRORS_LIB, "xmlsec lib"}, + { 0, NULL} + }; + xmlSecSize pos; + + /* initialize reasons array */ + memset(xmlSecOpenSSLStrReasons, 0, sizeof(xmlSecOpenSSLStrReasons)); + for(pos = 0; (pos < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(pos) != NULL); ++pos) { + xmlSecOpenSSLStrReasons[pos].error = xmlSecErrorsGetCode(pos); + xmlSecOpenSSLStrReasons[pos].string = xmlSecErrorsGetMsg(pos); + } + + /* finally load xmlsec strings in OpenSSL */ + ERR_load_strings(XMLSEC_OPENSSL_ERRORS_LIB, xmlSecOpenSSLStrLib); /* define xmlsec lib name */ + ERR_load_strings(XMLSEC_OPENSSL_ERRORS_LIB, xmlSecOpenSSLStrDefReason); /* define default reason */ + ERR_load_strings(XMLSEC_OPENSSL_ERRORS_LIB, xmlSecOpenSSLStrReasons); + + /* and set default errors callback for xmlsec to us */ + xmlSecErrorsSetCallback(xmlSecOpenSSLErrorsDefaultCallback); + + return(0); +} + +/** + * xmlSecOpenSSLSetDefaultTrustedCertsFolder: + * @path: the default trusted certs path. + * + * Sets the default trusted certs folder. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecOpenSSLSetDefaultTrustedCertsFolder(const xmlChar* path) { + if(gXmlSecOpenSSLTrustedCertsFolder != NULL) { + xmlFree(gXmlSecOpenSSLTrustedCertsFolder); + gXmlSecOpenSSLTrustedCertsFolder = NULL; + } + + if(path != NULL) { + gXmlSecOpenSSLTrustedCertsFolder = xmlStrdup(BAD_CAST path); + if(gXmlSecOpenSSLTrustedCertsFolder == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +/** + * xmlSecOpenSSLGetDefaultTrustedCertsFolder: + * + * Gets the default trusted certs folder. + * + * Returns: the default trusted cert folder. + */ +const xmlChar* +xmlSecOpenSSLGetDefaultTrustedCertsFolder(void) { + return(gXmlSecOpenSSLTrustedCertsFolder); +} + + + diff --git a/src/openssl/digests.c b/src/openssl/digests.c new file mode 100644 index 00000000..c681e857 --- /dev/null +++ b/src/openssl/digests.c @@ -0,0 +1,679 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <openssl/evp.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> + +/************************************************************************** + * + * Internal OpenSSL Digest CTX + * + *****************************************************************************/ +typedef struct _xmlSecOpenSSLDigestCtx xmlSecOpenSSLDigestCtx, *xmlSecOpenSSLDigestCtxPtr; +struct _xmlSecOpenSSLDigestCtx { + const EVP_MD* digest; + EVP_MD_CTX digestCtx; + xmlSecByte dgst[EVP_MAX_MD_SIZE]; + xmlSecSize dgstSize; /* dgst size in bytes */ +}; + +/****************************************************************************** + * + * EVP Digest transforms + * + * xmlSecOpenSSLDigestCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecOpenSSLEvpDigestSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLDigestCtx)) +#define xmlSecOpenSSLEvpDigestGetCtx(transform) \ + ((xmlSecOpenSSLDigestCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + + +static int xmlSecOpenSSLEvpDigestInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLEvpDigestFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLEvpDigestVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpDigestExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpDigestCheckId (xmlSecTransformPtr transform); + +static int +xmlSecOpenSSLEvpDigestCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformMd5Id)) { + return(1); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRipemd160Id)) { + return(1); + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha1Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha224Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha256Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha384Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha512Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA512 */ + + + { + return(0); + } + + return(0); +} + +static int +xmlSecOpenSSLEvpDigestInitialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLEvpDigestCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpDigestSize), -1); + + ctx = xmlSecOpenSSLEvpDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecOpenSSLDigestCtx)); + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformMd5Id)) { + ctx->digest = EVP_md5(); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRipemd160Id)) { + ctx->digest = EVP_ripemd160(); + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha1Id)) { + ctx->digest = EVP_sha1(); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha224Id)) { + ctx->digest = EVP_sha224(); + } else +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha256Id)) { + ctx->digest = EVP_sha256(); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha384Id)) { + ctx->digest = EVP_sha384(); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformSha512Id)) { + ctx->digest = EVP_sha512(); + } else +#endif /* XMLSEC_NO_SHA512 */ + + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_OPENSSL_096 + EVP_MD_CTX_init(&(ctx->digestCtx)); +#endif /* XMLSEC_OPENSSL_096 */ + + return(0); +} + +static void +xmlSecOpenSSLEvpDigestFinalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLDigestCtxPtr ctx; + + xmlSecAssert(xmlSecOpenSSLEvpDigestCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpDigestSize)); + + ctx = xmlSecOpenSSLEvpDigestGetCtx(transform); + xmlSecAssert(ctx != NULL); + +#ifndef XMLSEC_OPENSSL_096 + EVP_MD_CTX_cleanup(&(ctx->digestCtx)); +#endif /* XMLSEC_OPENSSL_096 */ + memset(ctx, 0, sizeof(xmlSecOpenSSLDigestCtx)); +} + +static int +xmlSecOpenSSLEvpDigestVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLDigestCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLEvpDigestCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpDigestSize), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLEvpDigestGetCtx(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 +xmlSecOpenSSLEvpDigestExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLDigestCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecOpenSSLEvpDigestCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpDigestSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + xmlSecAssert2(in != NULL, -1); + + out = &(transform->outBuf); + xmlSecAssert2(out != NULL, -1); + + ctx = xmlSecOpenSSLEvpDigestGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digest != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_DigestInit(&(ctx->digestCtx), ctx->digest); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_DigestInit", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_DigestInit(&(ctx->digestCtx), ctx->digest); +#endif /* XMLSEC_OPENSSL_096 */ + transform->status = xmlSecTransformStatusWorking; + } + + if(transform->status == xmlSecTransformStatusWorking) { + xmlSecSize inSize; + + inSize = xmlSecBufferGetSize(in); + if(inSize > 0) { +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_DigestUpdate(&(ctx->digestCtx), xmlSecBufferGetData(in), inSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_DigestUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", inSize); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_DigestUpdate(&(ctx->digestCtx), xmlSecBufferGetData(in), inSize); +#endif /* XMLSEC_OPENSSL_096 */ + + 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) { + xmlSecAssert2((xmlSecSize)EVP_MD_size(ctx->digest) <= sizeof(ctx->dgst), -1); + +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_DigestFinal(&(ctx->digestCtx), ctx->dgst, &ctx->dgstSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_DigestFinal(&(ctx->digestCtx), ctx->dgst, &ctx->dgstSize); +#endif /* XMLSEC_OPENSSL_096 */ + 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 xmlSecOpenSSLMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameMd5, /* const xmlChar* name; */ + xmlSecHrefMd5, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformMd5GetKlass: + * + * MD5 digest transform klass. + * + * Returns: pointer to MD5 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformMd5GetKlass(void) { + return(&xmlSecOpenSSLMd5Klass); +} +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 +/****************************************************************************** + * + * RIPEMD160 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRipemd160Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameRipemd160, /* const xmlChar* name; */ + xmlSecHrefRipemd160, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRipemd160GetKlass: + * + * RIPEMD-160 digest transform klass. + * + * Returns: pointer to RIPEMD-160 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRipemd160GetKlass(void) { + return(&xmlSecOpenSSLRipemd160Klass); +} +#endif /* XMLSEC_NO_RIPEMD160 */ + + +#ifndef XMLSEC_NO_SHA1 +/****************************************************************************** + * + * SHA1 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameSha1, /* const xmlChar* name; */ + xmlSecHrefSha1, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformSha1GetKlass: + * + * SHA-1 digest transform klass. + * + * Returns: pointer to SHA-1 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformSha1GetKlass(void) { + return(&xmlSecOpenSSLSha1Klass); +} +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 +/****************************************************************************** + * + * SHA224 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLSha224Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameSha224, /* const xmlChar* name; */ + xmlSecHrefSha224, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformSha224GetKlass: + * + * SHA-224 digest transform klass. + * + * Returns: pointer to SHA-224 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformSha224GetKlass(void) { + return(&xmlSecOpenSSLSha224Klass); +} +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 +/****************************************************************************** + * + * SHA256 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameSha256, /* const xmlChar* name; */ + xmlSecHrefSha256, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformSha256GetKlass: + * + * SHA-256 digest transform klass. + * + * Returns: pointer to SHA-256 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformSha256GetKlass(void) { + return(&xmlSecOpenSSLSha256Klass); +} +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/****************************************************************************** + * + * SHA384 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameSha384, /* const xmlChar* name; */ + xmlSecHrefSha384, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformSha384GetKlass: + * + * SHA-384 digest transform klass. + * + * Returns: pointer to SHA-384 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformSha384GetKlass(void) { + return(&xmlSecOpenSSLSha384Klass); +} +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/****************************************************************************** + * + * SHA512 + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpDigestSize, /* xmlSecSize objSize */ + + xmlSecNameSha512, /* const xmlChar* name; */ + xmlSecHrefSha512, /* const xmlChar* href; */ + xmlSecTransformUsageDigestMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpDigestInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpDigestFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpDigestVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpDigestExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformSha512GetKlass: + * + * SHA-512 digest transform klass. + * + * Returns: pointer to SHA-512 digest transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformSha512GetKlass(void) { + return(&xmlSecOpenSSLSha512Klass); +} +#endif /* XMLSEC_NO_SHA512 */ + diff --git a/src/openssl/evp.c b/src/openssl/evp.c new file mode 100644 index 00000000..e9d87295 --- /dev/null +++ b/src/openssl/evp.c @@ -0,0 +1,1559 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <openssl/evp.h> +#include <openssl/rand.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/openssl/crypto.h> +#include <xmlsec/openssl/bn.h> +#include <xmlsec/openssl/evp.h> + +/************************************************************************** + * + * Internal OpenSSL EVP key CTX + * + *************************************************************************/ +typedef struct _xmlSecOpenSSLEvpKeyDataCtx xmlSecOpenSSLEvpKeyDataCtx, + *xmlSecOpenSSLEvpKeyDataCtxPtr; +struct _xmlSecOpenSSLEvpKeyDataCtx { + EVP_PKEY* pKey; +}; + +/****************************************************************************** + * + * EVP key (dsa/rsa) + * + * xmlSecOpenSSLEvpKeyDataCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecOpenSSLEvpKeyDataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecOpenSSLEvpKeyDataCtx)) +#define xmlSecOpenSSLEvpKeyDataGetCtx(data) \ + ((xmlSecOpenSSLEvpKeyDataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + +static int xmlSecOpenSSLEvpKeyDataInitialize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLEvpKeyDataDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecOpenSSLEvpKeyDataFinalize (xmlSecKeyDataPtr data); + +/** + * xmlSecOpenSSLEvpKeyDataAdoptEvp: + * @data: the pointer to OpenSSL EVP key data. + * @pKey: the pointer to EVP key. + * + * Sets the value of key data. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLEvpKeyDataAdoptEvp(xmlSecKeyDataPtr data, EVP_PKEY* pKey) { + xmlSecOpenSSLEvpKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecOpenSSLEvpKeyDataSize), -1); + xmlSecAssert2(pKey != NULL, -1); + + ctx = xmlSecOpenSSLEvpKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->pKey != NULL) { + EVP_PKEY_free(ctx->pKey); + } + ctx->pKey = pKey; + return(0); +} + +/** + * xmlSecOpenSSLEvpKeyDataGetEvp: + * @data: the pointer to OpenSSL EVP data. + * + * Gets the EVP_PKEY from the key data. + * + * Returns: pointer to EVP_PKEY or NULL if an error occurs. + */ +EVP_PKEY* +xmlSecOpenSSLEvpKeyDataGetEvp(xmlSecKeyDataPtr data) { + xmlSecOpenSSLEvpKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), NULL); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecOpenSSLEvpKeyDataSize), NULL); + + ctx = xmlSecOpenSSLEvpKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + + return(ctx->pKey); +} + +static int +xmlSecOpenSSLEvpKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecOpenSSLEvpKeyDataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataIsValid(data), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(data, xmlSecOpenSSLEvpKeyDataSize), -1); + + ctx = xmlSecOpenSSLEvpKeyDataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpKeyDataCtx)); + + return(0); +} + +static int +xmlSecOpenSSLEvpKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecOpenSSLEvpKeyDataCtxPtr ctxDst; + xmlSecOpenSSLEvpKeyDataCtxPtr ctxSrc; + + xmlSecAssert2(xmlSecKeyDataIsValid(dst), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(dst, xmlSecOpenSSLEvpKeyDataSize), -1); + xmlSecAssert2(xmlSecKeyDataIsValid(src), -1); + xmlSecAssert2(xmlSecKeyDataCheckSize(src, xmlSecOpenSSLEvpKeyDataSize), -1); + + ctxDst = xmlSecOpenSSLEvpKeyDataGetCtx(dst); + xmlSecAssert2(ctxDst != NULL, -1); + xmlSecAssert2(ctxDst->pKey == NULL, -1); + + ctxSrc = xmlSecOpenSSLEvpKeyDataGetCtx(src); + xmlSecAssert2(ctxSrc != NULL, -1); + + if(ctxSrc->pKey != NULL) { + ctxDst->pKey = xmlSecOpenSSLEvpKeyDup(ctxSrc->pKey); + if(ctxDst->pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecOpenSSLEvpKeyDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +static void +xmlSecOpenSSLEvpKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecOpenSSLEvpKeyDataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataIsValid(data)); + xmlSecAssert(xmlSecKeyDataCheckSize(data, xmlSecOpenSSLEvpKeyDataSize)); + + ctx = xmlSecOpenSSLEvpKeyDataGetCtx(data); + xmlSecAssert(ctx != NULL); + + if(ctx->pKey != NULL) { + EVP_PKEY_free(ctx->pKey); + } + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpKeyDataCtx)); +} + +/****************************************************************************** + * + * EVP helper functions + * + *****************************************************************************/ +/** + * xmlSecOpenSSLEvpKeyDup: + * @pKey: the pointer to EVP_PKEY. + * + * Duplicates @pKey. + * + * Returns: pointer to newly created EVP_PKEY object or NULL if an error occurs. + */ +EVP_PKEY* +xmlSecOpenSSLEvpKeyDup(EVP_PKEY* pKey) { + int ret; + + xmlSecAssert2(pKey != NULL, NULL); + + ret = CRYPTO_add(&pKey->references,1,CRYPTO_LOCK_EVP_PKEY); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CRYPTO_add", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(pKey); +} + +/** + * xmlSecOpenSSLEvpKeyAdopt: + * @pKey: the pointer to EVP_PKEY. + * + * Creates xmlsec key object from OpenSSL key object. + * + * Returns: pointer to newly created xmlsec key or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecOpenSSLEvpKeyAdopt(EVP_PKEY *pKey) { + xmlSecKeyDataPtr data = NULL; + int ret; + + xmlSecAssert2(pKey != NULL, NULL); + + switch(pKey->type) { +#ifndef XMLSEC_NO_RSA + case EVP_PKEY_RSA: + data = xmlSecKeyDataCreate(xmlSecOpenSSLKeyDataRsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecOpenSSLKeyDataRsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_RSA */ +#ifndef XMLSEC_NO_DSA + case EVP_PKEY_DSA: + data = xmlSecKeyDataCreate(xmlSecOpenSSLKeyDataDsaId); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecOpenSSLKeyDataDsaId"); + return(NULL); + } + break; +#endif /* XMLSEC_NO_DSA */ + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "evp key type %d not supported", pKey->type); + return(NULL); + } + + xmlSecAssert2(data != NULL, NULL); + ret = xmlSecOpenSSLEvpKeyDataAdoptEvp(data, pKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLEvpKeyDataAdoptEvp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(NULL); + } + return(data); +} + +#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 xmlSecOpenSSLKeyDataDsaInitialize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLKeyDataDsaDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecOpenSSLKeyDataDsaFinalize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLKeyDataDsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLKeyDataDsaXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLKeyDataDsaGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecOpenSSLKeyDataDsaGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecOpenSSLKeyDataDsaGetSize (xmlSecKeyDataPtr data); +static void xmlSecOpenSSLKeyDataDsaDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecOpenSSLKeyDataDsaDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataDsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecOpenSSLEvpKeyDataSize, + + /* data */ + xmlSecNameDSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeDSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecOpenSSLKeyDataDsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecOpenSSLKeyDataDsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecOpenSSLKeyDataDsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecOpenSSLKeyDataDsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecOpenSSLKeyDataDsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecOpenSSLKeyDataDsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecOpenSSLKeyDataDsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecOpenSSLKeyDataDsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecOpenSSLKeyDataDsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecOpenSSLKeyDataDsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataDsaGetKlass: + * + * The DSA key data klass. + * + * Returns: pointer to DSA key data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataDsaGetKlass(void) { + return(&xmlSecOpenSSLKeyDataDsaKlass); +} + +/** + * xmlSecOpenSSLKeyDataDsaAdoptDsa: + * @data: the pointer to DSA key data. + * @dsa: the pointer to OpenSSL DSA key. + * + * Sets the value of DSA key data. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLKeyDataDsaAdoptDsa(xmlSecKeyDataPtr data, DSA* dsa) { + EVP_PKEY* pKey = NULL; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), -1); + + /* construct new EVP_PKEY */ + if(dsa != NULL) { + pKey = EVP_PKEY_new(); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "EVP_PKEY_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = EVP_PKEY_assign_DSA(pKey, dsa); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "EVP_PKEY_assign_DSA", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ret = xmlSecOpenSSLKeyDataDsaAdoptEvp(data, pKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataDsaAdoptEvp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + if(pKey != NULL) { + EVP_PKEY_free(pKey); + } + return(-1); + } + return(0); +} + +/** + * xmlSecOpenSSLKeyDataDsaGetDsa: + * @data: the pointer to DSA key data. + * + * Gets the OpenSSL DSA key from DSA key data. + * + * Returns: pointer to OpenSSL DSA key or NULL if an error occurs. + */ +DSA* +xmlSecOpenSSLKeyDataDsaGetDsa(xmlSecKeyDataPtr data) { + EVP_PKEY* pKey; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), NULL); + + pKey = xmlSecOpenSSLKeyDataDsaGetEvp(data); + xmlSecAssert2((pKey == NULL) || (pKey->type == EVP_PKEY_DSA), NULL); + + return((pKey != NULL) ? pKey->pkey.dsa : (DSA*)NULL); +} + +/** + * xmlSecOpenSSLKeyDataDsaAdoptEvp: + * @data: the pointer to DSA key data. + * @pKey: the pointer to OpenSSL EVP key. + * + * Sets the DSA key data value to OpenSSL EVP key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLKeyDataDsaAdoptEvp(xmlSecKeyDataPtr data, EVP_PKEY* pKey) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), -1); + xmlSecAssert2(pKey != NULL, -1); + xmlSecAssert2(pKey->type == EVP_PKEY_DSA, -1); + + return(xmlSecOpenSSLEvpKeyDataAdoptEvp(data, pKey)); +} + +/** + * xmlSecOpenSSLKeyDataDsaGetEvp: + * @data: the pointer to DSA key data. + * + * Gets the OpenSSL EVP key from DSA key data. + * + * Returns: pointer to OpenSSL EVP key or NULL if an error occurs. + */ +EVP_PKEY* +xmlSecOpenSSLKeyDataDsaGetEvp(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), NULL); + + return(xmlSecOpenSSLEvpKeyDataGetEvp(data)); +} + +static int +xmlSecOpenSSLKeyDataDsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), -1); + + return(xmlSecOpenSSLEvpKeyDataInitialize(data)); +} + +static int +xmlSecOpenSSLKeyDataDsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecOpenSSLKeyDataDsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecOpenSSLKeyDataDsaId), -1); + + return(xmlSecOpenSSLEvpKeyDataDuplicate(dst, src)); +} + +static void +xmlSecOpenSSLKeyDataDsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId)); + + xmlSecOpenSSLEvpKeyDataFinalize(data); +} + +static int +xmlSecOpenSSLKeyDataDsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + xmlNodePtr cur; + DSA *dsa; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataDsaId, -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, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + dsa = DSA_new(); + if(dsa == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "DSA_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + 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)); + DSA_free(dsa); + return(-1); + } + if(xmlSecOpenSSLNodeGetBNValue(cur, &(dsa->p)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + DSA_free(dsa); + return(-1); + } + 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)); + DSA_free(dsa); + return(-1); + } + if(xmlSecOpenSSLNodeGetBNValue(cur, &(dsa->q)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + DSA_free(dsa); + return(-1); + } + 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)); + DSA_free(dsa); + return(-1); + } + if(xmlSecOpenSSLNodeGetBNValue(cur, &(dsa->g)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + DSA_free(dsa); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDSAX, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * we are not sure exactly what do we read */ + if(xmlSecOpenSSLNodeGetBNValue(cur, &(dsa->priv_key)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAX)); + DSA_free(dsa); + return(-1); + } + 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)); + DSA_free(dsa); + return(-1); + } + if(xmlSecOpenSSLNodeGetBNValue(cur, &(dsa->pub_key)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", xmlSecErrorsSafeString(xmlSecNodeDSAY)); + DSA_free(dsa); + return(-1); + } + 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); + DSA_free(dsa); + return(-1); + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + DSA_free(dsa); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataDsaAdoptDsa(data, dsa); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataDsaAdoptDsa", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + DSA_free(dsa); + return(-1); + } + + ret = xmlSecKeySetValue(key, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecKeySetValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLKeyDataDsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlNodePtr cur; + DSA* dsa; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataDsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataDsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + dsa = xmlSecOpenSSLKeyDataDsaGetDsa(xmlSecKeyGetValue(key)); + xmlSecAssert2(dsa != NULL, -1); + + if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only private key or public key */ + return(0); + } + + /* first is P node */ + xmlSecAssert2(dsa->p != NULL, -1); + 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)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, dsa->p, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAP)); + return(-1); + } + + /* next is Q node. */ + xmlSecAssert2(dsa->q != NULL, -1); + 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)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, dsa->q, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAQ)); + return(-1); + } + + /* next is G node. */ + xmlSecAssert2(dsa->g != NULL, -1); + 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)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, dsa->g, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAG)); + return(-1); + } + + /* next is X node: write it ONLY for private keys and ONLY if it is requested */ + if(((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) && (dsa->priv_key != NULL)) { + cur = xmlSecAddChild(node, xmlSecNodeDSAX, xmlSecNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAX)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, dsa->priv_key, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAX)); + return(-1); + } + } + + /* next is Y node. */ + xmlSecAssert2(dsa->pub_key != NULL, -1); + 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)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, dsa->pub_key, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDSAY)); + return(-1); + } + return(0); +} + +static int +xmlSecOpenSSLKeyDataDsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + DSA* dsa; + int counter_ret; + unsigned long h_ret; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + dsa = DSA_generate_parameters(sizeBits, NULL, 0, &counter_ret, &h_ret, NULL, NULL); + if(dsa == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "DSA_generate_parameters", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", sizeBits); + return(-1); + } + + ret = DSA_generate_key(dsa); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "DSA_generate_key", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + DSA_free(dsa); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataDsaAdoptDsa(data, dsa); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataDsaAdoptDsa", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + DSA_free(dsa); + return(-1); + } + + return(0); +} + +static xmlSecKeyDataType +xmlSecOpenSSLKeyDataDsaGetType(xmlSecKeyDataPtr data) { + DSA* dsa; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), xmlSecKeyDataTypeUnknown); + + dsa = xmlSecOpenSSLKeyDataDsaGetDsa(data); + if((dsa != NULL) && (dsa->p != NULL) && (dsa->q != NULL) && + (dsa->g != NULL) && (dsa->pub_key != NULL)) { + + if(dsa->priv_key != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else if(dsa->engine != NULL) { + /* + * !!! HACK !!! Also see RSA key + * We assume here that engine *always* has private key. + * This might be incorrect but it seems that there is no + * way to ask engine if given key is private or not. + */ + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } + } + + return(xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecOpenSSLKeyDataDsaGetSize(xmlSecKeyDataPtr data) { + DSA* dsa; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId), 0); + + dsa = xmlSecOpenSSLKeyDataDsaGetDsa(data); + if((dsa != NULL) && (dsa->p != NULL)) { + return(BN_num_bits(dsa->p)); + } + return(0); +} + +static void +xmlSecOpenSSLKeyDataDsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== dsa key: size = %d\n", + xmlSecOpenSSLKeyDataDsaGetSize(data)); +} + +static void +xmlSecOpenSSLKeyDataDsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<DSAKeyValue size=\"%d\" />\n", + xmlSecOpenSSLKeyDataDsaGetSize(data)); +} + +#endif /* XMLSEC_NO_DSA */ + +#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) > + * + * ============================================================================ + * + * To support reading/writing private keys an PrivateExponent element is added + * to the end + * + *************************************************************************/ + +static int xmlSecOpenSSLKeyDataRsaInitialize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLKeyDataRsaDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecOpenSSLKeyDataRsaFinalize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLKeyDataRsaXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLKeyDataRsaXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLKeyDataRsaGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecOpenSSLKeyDataRsaGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecOpenSSLKeyDataRsaGetSize (xmlSecKeyDataPtr data); +static void xmlSecOpenSSLKeyDataRsaDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecOpenSSLKeyDataRsaDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataRsaKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecOpenSSLEvpKeyDataSize, + + /* data */ + xmlSecNameRSAKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefRSAKeyValue, /* const xmlChar* href; */ + xmlSecNodeRSAKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecOpenSSLKeyDataRsaInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecOpenSSLKeyDataRsaDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecOpenSSLKeyDataRsaFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecOpenSSLKeyDataRsaGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecOpenSSLKeyDataRsaGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecOpenSSLKeyDataRsaGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecOpenSSLKeyDataRsaXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecOpenSSLKeyDataRsaXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecOpenSSLKeyDataRsaDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecOpenSSLKeyDataRsaDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataRsaGetKlass: + * + * The OpenSSL RSA key data klass. + * + * Returns: pointer to OpenSSL RSA key data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataRsaGetKlass(void) { + return(&xmlSecOpenSSLKeyDataRsaKlass); +} + +/** + * xmlSecOpenSSLKeyDataRsaAdoptRsa: + * @data: the pointer to RSA key data. + * @rsa: the pointer to OpenSSL RSA key. + * + * Sets the value of RSA key data. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLKeyDataRsaAdoptRsa(xmlSecKeyDataPtr data, RSA* rsa) { + EVP_PKEY* pKey = NULL; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), -1); + + /* construct new EVP_PKEY */ + if(rsa != NULL) { + pKey = EVP_PKEY_new(); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "EVP_PKEY_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = EVP_PKEY_assign_RSA(pKey, rsa); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "EVP_PKEY_assign_RSA", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ret = xmlSecOpenSSLKeyDataRsaAdoptEvp(data, pKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataRsaAdoptEvp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + if(pKey != NULL) { + EVP_PKEY_free(pKey); + } + return(-1); + } + return(0); +} + +/** + * xmlSecOpenSSLKeyDataRsaGetRsa: + * @data: the pointer to RSA key data. + * + * Gets the OpenSSL RSA key from RSA key data. + * + * Returns: pointer to OpenSSL RSA key or NULL if an error occurs. + */ +RSA* +xmlSecOpenSSLKeyDataRsaGetRsa(xmlSecKeyDataPtr data) { + EVP_PKEY* pKey; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), NULL); + + pKey = xmlSecOpenSSLKeyDataRsaGetEvp(data); + xmlSecAssert2((pKey == NULL) || (pKey->type == EVP_PKEY_RSA), NULL); + + return((pKey != NULL) ? pKey->pkey.rsa : (RSA*)NULL); +} + +/** + * xmlSecOpenSSLKeyDataRsaAdoptEvp: + * @data: the pointer to RSA key data. + * @pKey: the pointer to OpenSSL EVP key. + * + * Sets the RSA key data value to OpenSSL EVP key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLKeyDataRsaAdoptEvp(xmlSecKeyDataPtr data, EVP_PKEY* pKey) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), -1); + xmlSecAssert2(pKey != NULL, -1); + xmlSecAssert2(pKey->type == EVP_PKEY_RSA, -1); + + return(xmlSecOpenSSLEvpKeyDataAdoptEvp(data, pKey)); +} + +/** + * xmlSecOpenSSLKeyDataRsaGetEvp: + * @data: the pointer to RSA key data. + * + * Gets the OpenSSL EVP key from RSA key data. + * + * Returns: pointer to OpenSSL EVP key or NULL if an error occurs. + */ +EVP_PKEY* +xmlSecOpenSSLKeyDataRsaGetEvp(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), NULL); + + return(xmlSecOpenSSLEvpKeyDataGetEvp(data)); +} + +static int +xmlSecOpenSSLKeyDataRsaInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), -1); + + return(xmlSecOpenSSLEvpKeyDataInitialize(data)); +} + +static int +xmlSecOpenSSLKeyDataRsaDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecOpenSSLKeyDataRsaId), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecOpenSSLKeyDataRsaId), -1); + + return(xmlSecOpenSSLEvpKeyDataDuplicate(dst, src)); +} + +static void +xmlSecOpenSSLKeyDataRsaFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId)); + + xmlSecOpenSSLEvpKeyDataFinalize(data); +} + +static int +xmlSecOpenSSLKeyDataRsaXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + xmlNodePtr cur; + RSA *rsa; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataRsaId, -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); + } + + rsa = RSA_new(); + if(rsa == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "RSA_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + 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)); + RSA_free(rsa); + return(-1); + } + if(xmlSecOpenSSLNodeGetBNValue(cur, &(rsa->n)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + RSA_free(rsa); + return(-1); + } + 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)); + RSA_free(rsa); + return(-1); + } + if(xmlSecOpenSSLNodeGetBNValue(cur, &(rsa->e)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + RSA_free(rsa); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeRSAPrivateExponent, xmlSecNs))) { + /* next is X node. It is REQUIRED for private key but + * we are not sure exactly what do we read */ + if(xmlSecOpenSSLNodeGetBNValue(cur, &(rsa->d)) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeGetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAPrivateExponent)); + RSA_free(rsa); + return(-1); + } + 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"); + RSA_free(rsa); + return(-1); + } + + data = xmlSecKeyDataCreate(id); + if(data == NULL ) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + RSA_free(rsa); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataRsaAdoptRsa(data, rsa); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLKeyDataRsaAdoptRsa", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDataDestroy(data); + RSA_free(rsa); + return(-1); + } + + 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); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLKeyDataRsaXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlNodePtr cur; + RSA* rsa; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataRsaId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataRsaId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + rsa = xmlSecOpenSSLKeyDataRsaGetRsa(xmlSecKeyGetValue(key)); + xmlSecAssert2(rsa != NULL, -1); + + if(((xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate) & keyInfoCtx->keyReq.keyType) == 0) { + /* we can have only private key or public key */ + return(0); + } + + /* 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)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, rsa->n, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAModulus)); + 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)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, rsa->e, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAExponent)); + return(-1); + } + + /* next is PrivateExponent node: write it ONLY for private keys and ONLY if it is requested */ + if(((keyInfoCtx->keyReq.keyType & xmlSecKeyDataTypePrivate) != 0) && (rsa->d != NULL)) { + cur = xmlSecAddChild(node, xmlSecNodeRSAPrivateExponent, xmlSecNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAPrivateExponent)); + return(-1); + } + ret = xmlSecOpenSSLNodeSetBNValue(cur, rsa->d, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLNodeSetBNValue", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRSAPrivateExponent)); + return(-1); + } + } + + return(0); +} + +static int +xmlSecOpenSSLKeyDataRsaGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + RSA* rsa; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), -1); + xmlSecAssert2(sizeBits > 0, -1); + + rsa = RSA_generate_key(sizeBits, 3, NULL, NULL); + if(rsa == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "RSA_generate_key", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "sizeBits=%d", sizeBits); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataRsaAdoptRsa(data, rsa); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataRsaAdoptRsa", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + RSA_free(rsa); + return(-1); + } + + return(0); +} + +static xmlSecKeyDataType +xmlSecOpenSSLKeyDataRsaGetType(xmlSecKeyDataPtr data) { + RSA* rsa; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), xmlSecKeyDataTypeUnknown); + + rsa = xmlSecOpenSSLKeyDataRsaGetRsa(data); + if((rsa != NULL) && (rsa->n != NULL) && (rsa->e != NULL)) { + if(rsa->d != NULL) { + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else if(rsa->engine != NULL) { + /* + * !!! HACK !!! Also see DSA key + * We assume here that engine *always* has private key. + * This might be incorrect but it seems that there is no + * way to ask engine if given key is private or not. + */ + return(xmlSecKeyDataTypePrivate | xmlSecKeyDataTypePublic); + } else { + return(xmlSecKeyDataTypePublic); + } + } + + return(xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecOpenSSLKeyDataRsaGetSize(xmlSecKeyDataPtr data) { + RSA* rsa; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId), 0); + + rsa = xmlSecOpenSSLKeyDataRsaGetRsa(data); + if((rsa != NULL) && (rsa->n != NULL)) { + return(BN_num_bits(rsa->n)); + } + return(0); +} + +static void +xmlSecOpenSSLKeyDataRsaDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== rsa key: size = %d\n", + xmlSecOpenSSLKeyDataRsaGetSize(data)); +} + +static void +xmlSecOpenSSLKeyDataRsaDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataRsaId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<RSAKeyValue size=\"%d\" />\n", + xmlSecOpenSSLKeyDataRsaGetSize(data)); +} + +#endif /* XMLSEC_NO_RSA */ + + + diff --git a/src/openssl/globals.h b/src/openssl/globals.h new file mode 100644 index 00000000..272a27b8 --- /dev/null +++ b/src/openssl/globals.h @@ -0,0 +1,24 @@ +/* + * XML Security Library + * + * globals.h: internal header only used during the compilation + * + * 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_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 + +#endif /* ! __XMLSEC_GLOBALS_H__ */ diff --git a/src/openssl/hmac.c b/src/openssl/hmac.c new file mode 100644 index 00000000..0b6605b8 --- /dev/null +++ b/src/openssl/hmac.c @@ -0,0 +1,841 @@ +/** + * + * 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 <openssl/hmac.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/openssl/crypto.h> + +/* sizes in bits */ +#define XMLSEC_OPENSSL_MIN_HMAC_SIZE 80 +#define XMLSEC_OPENSSL_MAX_HMAC_SIZE (EVP_MAX_MD_SIZE * 8) + +/************************************************************************** + * + * Configuration + * + *****************************************************************************/ +static int g_xmlsec_openssl_hmac_min_length = XMLSEC_OPENSSL_MIN_HMAC_SIZE; + +/** + * xmlSecOpenSSLHmacGetMinOutputLength: + * + * Gets the value of min HMAC length. + * + * Returns: the min HMAC output length + */ +int xmlSecOpenSSLHmacGetMinOutputLength(void) +{ + return g_xmlsec_openssl_hmac_min_length; +} + +/** + * xmlSecOpenSSLHmacSetMinOutputLength: + * @min_length: the new min length + * + * Sets the min HMAC output length + */ +void xmlSecOpenSSLHmacSetMinOutputLength(int min_length) +{ + g_xmlsec_openssl_hmac_min_length = min_length; +} + +/************************************************************************** + * + * Internal OpenSSL HMAC CTX + * + *****************************************************************************/ +typedef struct _xmlSecOpenSSLHmacCtx xmlSecOpenSSLHmacCtx, *xmlSecOpenSSLHmacCtxPtr; +struct _xmlSecOpenSSLHmacCtx { + const EVP_MD* hmacDgst; + HMAC_CTX hmacCtx; + int ctxInitialized; + xmlSecByte dgst[XMLSEC_OPENSSL_MAX_HMAC_SIZE]; + xmlSecSize dgstSize; /* dgst size in bits */ +}; + +/************************************************************************** + * + * HMAC transforms + * + * xmlSecOpenSSLHmacCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecOpenSSLHmacGetCtx(transform) \ + ((xmlSecOpenSSLHmacCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecOpenSSLHmacSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLHmacCtx)) + +static int xmlSecOpenSSLHmacCheckId (xmlSecTransformPtr transform); +static int xmlSecOpenSSLHmacInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLHmacFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLHmacNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLHmacSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLHmacSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLHmacVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLHmacExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + + +static int +xmlSecOpenSSLHmacCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha1Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha224Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha256Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha384Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha512Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacRipemd160Id)) { + return(1); + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacMd5Id)) { + return(1); + } else +#endif /* XMLSEC_NO_MD5 */ + + { + return(0); + } + + return(0); +} + + + +static int +xmlSecOpenSSLHmacInitialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLHmacCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize), -1); + + ctx = xmlSecOpenSSLHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecOpenSSLHmacCtx)); + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha1Id)) { + ctx->hmacDgst = EVP_sha1(); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha224Id)) { + ctx->hmacDgst = EVP_sha224(); + } else +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha256Id)) { + ctx->hmacDgst = EVP_sha256(); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha384Id)) { + ctx->hmacDgst = EVP_sha384(); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacSha512Id)) { + ctx->hmacDgst = EVP_sha512(); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacRipemd160Id)) { + ctx->hmacDgst = EVP_ripemd160(); + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformHmacMd5Id)) { + ctx->hmacDgst = EVP_md5(); + } else +#endif /* XMLSEC_NO_MD5 */ + + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_OPENSSL_096 + HMAC_CTX_init(&(ctx->hmacCtx)); +#endif /* XMLSEC_OPENSSL_096 */ + return(0); +} + +static void +xmlSecOpenSSLHmacFinalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLHmacCtxPtr ctx; + + xmlSecAssert(xmlSecOpenSSLHmacCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize)); + + ctx = xmlSecOpenSSLHmacGetCtx(transform); + xmlSecAssert(ctx != NULL); + +#ifndef XMLSEC_OPENSSL_096 + HMAC_CTX_cleanup(&(ctx->hmacCtx)); +#endif /* XMLSEC_OPENSSL_096 */ + memset(ctx, 0, sizeof(xmlSecOpenSSLHmacCtx)); +} + +static int +xmlSecOpenSSLHmacNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLHmacCtxPtr ctx; + xmlNodePtr cur; + + xmlSecAssert2(xmlSecOpenSSLHmacCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize), -1); + xmlSecAssert2(node!= NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLHmacGetCtx(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 lenght to 0 or very + small value + */ + if((int)ctx->dgstSize < xmlSecOpenSSLHmacGetMinOutputLength()) { + 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 +xmlSecOpenSSLHmacSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecOpenSSLHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecOpenSSLKeyDataHmacId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationSign) { + keyReq->keyUsage = xmlSecKeyUsageSign; + } else { + keyReq->keyUsage = xmlSecKeyUsageVerify; + } + + return(0); +} + +static int +xmlSecOpenSSLHmacSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecOpenSSLHmacCtxPtr ctx; + xmlSecKeyDataPtr value; + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecOpenSSLHmacCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecOpenSSLHmacGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->hmacDgst != NULL, -1); + xmlSecAssert2(ctx->ctxInitialized == 0, -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(xmlSecKeyDataCheckId(value, xmlSecOpenSSLKeyDataHmacId), -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); + HMAC_Init(&(ctx->hmacCtx), + xmlSecBufferGetData(buffer), + xmlSecBufferGetSize(buffer), + ctx->hmacDgst); + ctx->ctxInitialized = 1; + return(0); +} + +static int +xmlSecOpenSSLHmacVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + static xmlSecByte last_byte_masks[] = + { 0xFF, 0x80, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC, 0xFE }; + + xmlSecOpenSSLHmacCtxPtr ctx; + xmlSecByte mask; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLHmacGetCtx(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 +xmlSecOpenSSLHmacExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLHmacCtxPtr ctx; + xmlSecBufferPtr in, out; + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLHmacSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + + ctx = xmlSecOpenSSLHmacGetCtx(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) { + HMAC_Update(&(ctx->hmacCtx), xmlSecBufferGetData(in), inSize); + + 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) { + xmlSecSize dgstSize; + + HMAC_Final(&(ctx->hmacCtx), ctx->dgst, &dgstSize); + xmlSecAssert2(dgstSize > 0, -1); + + /* check/set the result digest size */ + if(ctx->dgstSize == 0) { + ctx->dgstSize = dgstSize * 8; /* no dgst size specified, use all we have */ + } else if(ctx->dgstSize <= 8 * dgstSize) { + dgstSize = ((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 * dgstSize, ctx->dgstSize); + return(-1); + } + + /* finally write result to output */ + if(transform->operation == xmlSecTransformOperationSign) { + ret = xmlSecBufferAppend(out, ctx->dgst, dgstSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", 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 xmlSecOpenSSLHmacMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacMd5, /* const xmlChar* name; */ + xmlSecHrefHmacMd5, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacMd5GetKlass: + * + * The HMAC-MD5 transform klass. + * + * Returns: the HMAC-MD5 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacMd5GetKlass(void) { + return(&xmlSecOpenSSLHmacMd5Klass); +} + +#endif /* XMLSEC_NO_MD5 */ + + +#ifndef XMLSEC_NO_RIPEMD160 +/** + * HMAC RIPEMD160 + */ +static xmlSecTransformKlass xmlSecOpenSSLHmacRipemd160Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacRipemd160, /* const xmlChar* name; */ + xmlSecHrefHmacRipemd160, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacRipemd160GetKlass: + * + * The HMAC-RIPEMD160 transform klass. + * + * Returns: the HMAC-RIPEMD160 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacRipemd160GetKlass(void) { + return(&xmlSecOpenSSLHmacRipemd160Klass); +} +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 +/** + * HMAC SHA1 + */ +static xmlSecTransformKlass xmlSecOpenSSLHmacSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha1, /* const xmlChar* name; */ + xmlSecHrefHmacSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacSha1GetKlass: + * + * The HMAC-SHA1 transform klass. + * + * Returns: the HMAC-SHA1 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacSha1GetKlass(void) { + return(&xmlSecOpenSSLHmacSha1Klass); +} + +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 +/** + * HMAC SHA224 + */ +static xmlSecTransformKlass xmlSecOpenSSLHmacSha224Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha224, /* const xmlChar* name; */ + xmlSecHrefHmacSha224, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacSha224GetKlass: + * + * The HMAC-SHA224 transform klass. + * + * Returns: the HMAC-SHA224 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacSha224GetKlass(void) { + return(&xmlSecOpenSSLHmacSha224Klass); +} + +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 +/** + * HMAC SHA256 + */ +static xmlSecTransformKlass xmlSecOpenSSLHmacSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha256, /* const xmlChar* name; */ + xmlSecHrefHmacSha256, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacSha256GetKlass: + * + * The HMAC-SHA256 transform klass. + * + * Returns: the HMAC-SHA256 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacSha256GetKlass(void) { + return(&xmlSecOpenSSLHmacSha256Klass); +} + +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/** + * HMAC SHA384 + */ +static xmlSecTransformKlass xmlSecOpenSSLHmacSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha384, /* const xmlChar* name; */ + xmlSecHrefHmacSha384, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacSha384GetKlass: + * + * The HMAC-SHA384 transform klass. + * + * Returns: the HMAC-SHA384 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacSha384GetKlass(void) { + return(&xmlSecOpenSSLHmacSha384Klass); +} + +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/** + * HMAC SHA512 + */ +static xmlSecTransformKlass xmlSecOpenSSLHmacSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha512, /* const xmlChar* name; */ + xmlSecHrefHmacSha512, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLHmacInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLHmacFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLHmacNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLHmacSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLHmacSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLHmacVerify, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLHmacExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformHmacSha512GetKlass: + * + * The HMAC-SHA512 transform klass. + * + * Returns: the HMAC-SHA512 transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformHmacSha512GetKlass(void) { + return(&xmlSecOpenSSLHmacSha512Klass); +} + +#endif /* XMLSEC_NO_SHA512 */ + + +#endif /* XMLSEC_NO_HMAC */ + diff --git a/src/openssl/kt_rsa.c b/src/openssl/kt_rsa.c new file mode 100644 index 00000000..1ed3685e --- /dev/null +++ b/src/openssl/kt_rsa.c @@ -0,0 +1,877 @@ +/** + * + * XMLSec library + * + * RSA Algorithms support + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_RSA + +#include <stdlib.h> +#include <string.h> + +#include <openssl/rsa.h> +#include <openssl/evp.h> +#include <openssl/sha.h> +#include <openssl/objects.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/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> +#include <xmlsec/openssl/bn.h> + +/************************************************************************** + * + * Internal OpenSSL RSA PKCS1 CTX + * + *************************************************************************/ +typedef struct _xmlSecOpenSSLRsaPkcs1Ctx xmlSecOpenSSLRsaPkcs1Ctx, + *xmlSecOpenSSLRsaPkcs1CtxPtr; +struct _xmlSecOpenSSLRsaPkcs1Ctx { + EVP_PKEY* pKey; +}; + +/********************************************************************* + * + * RSA PKCS1 key transport transform + * + * xmlSecOpenSSLRsaPkcs1Ctx is located after xmlSecTransform + * + ********************************************************************/ +#define xmlSecOpenSSLRsaPkcs1Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLRsaPkcs1Ctx)) +#define xmlSecOpenSSLRsaPkcs1GetCtx(transform) \ + ((xmlSecOpenSSLRsaPkcs1CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecOpenSSLRsaPkcs1Initialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLRsaPkcs1Finalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLRsaPkcs1SetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLRsaPkcs1SetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLRsaPkcs1Execute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLRsaPkcs1Process (xmlSecTransformPtr transform, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecOpenSSLRsaPkcs1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLRsaPkcs1Size, /* xmlSecSize objSize */ + + xmlSecNameRsaPkcs1, /* const xmlChar* name; */ + xmlSecHrefRsaPkcs1, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLRsaPkcs1Initialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLRsaPkcs1Finalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLRsaPkcs1SetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLRsaPkcs1SetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLRsaPkcs1Execute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaPkcs1GetKlass: + * + * The RSA-PKCS1 key transport transform klass. + * + * Returns: RSA-PKCS1 key transport transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaPkcs1GetKlass(void) { + return(&xmlSecOpenSSLRsaPkcs1Klass); +} + +static int +xmlSecOpenSSLRsaPkcs1Initialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLRsaPkcs1CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaPkcs1Id), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaPkcs1Size), -1); + + ctx = xmlSecOpenSSLRsaPkcs1GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLRsaPkcs1Ctx)); + return(0); +} + +static void +xmlSecOpenSSLRsaPkcs1Finalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLRsaPkcs1CtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaPkcs1Id)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaPkcs1Size)); + + ctx = xmlSecOpenSSLRsaPkcs1GetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->pKey != NULL) { + EVP_PKEY_free(ctx->pKey); + } + memset(ctx, 0, sizeof(xmlSecOpenSSLRsaPkcs1Ctx)); +} + +static int +xmlSecOpenSSLRsaPkcs1SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecOpenSSLRsaPkcs1CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaPkcs1Size), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecOpenSSLRsaPkcs1GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecOpenSSLKeyDataRsaId; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyType = xmlSecKeyDataTypePublic; + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyType = xmlSecKeyDataTypePrivate; + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + return(0); +} + +static int +xmlSecOpenSSLRsaPkcs1SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecOpenSSLRsaPkcs1CtxPtr ctx; + EVP_PKEY* pKey; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaPkcs1Size), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataRsaId), -1); + + ctx = xmlSecOpenSSLRsaPkcs1GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pKey == NULL, -1); + + pKey = xmlSecOpenSSLKeyDataRsaGetEvp(xmlSecKeyGetValue(key)); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKeyDataRsaGetEvp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(pKey->type == EVP_PKEY_RSA, -1); + xmlSecAssert2(pKey->pkey.rsa != NULL, -1); + + ctx->pKey = xmlSecOpenSSLEvpKeyDup(pKey); + if(ctx->pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpKeyDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLRsaPkcs1Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLRsaPkcs1CtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaPkcs1Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLRsaPkcs1GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pKey != 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 = xmlSecOpenSSLRsaPkcs1Process(transform, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLRsaPkcs1Process", + 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 +xmlSecOpenSSLRsaPkcs1Process(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLRsaPkcs1CtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaPkcs1Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaPkcs1Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLRsaPkcs1GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pKey != NULL, -1); + xmlSecAssert2(ctx->pKey->type == EVP_PKEY_RSA, -1); + xmlSecAssert2(ctx->pKey->pkey.rsa != NULL, -1); + + keySize = RSA_size(ctx->pKey->pkey.rsa); + 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) { + ret = RSA_public_encrypt(inSize, xmlSecBufferGetData(in), + xmlSecBufferGetData(out), + ctx->pKey->pkey.rsa, RSA_PKCS1_PADDING); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_public_encrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", inSize); + return(-1); + } + outSize = ret; + } else { + ret = RSA_private_decrypt(inSize, xmlSecBufferGetData(in), + xmlSecBufferGetData(out), + ctx->pKey->pkey.rsa, RSA_PKCS1_PADDING); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_private_decrypt", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", inSize); + 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); + } + + return(0); +} + +/************************************************************************** + * + * Internal OpenSSL RSA OAPE CTX + * + *************************************************************************/ +typedef struct _xmlSecOpenSSLRsaOaepCtx xmlSecOpenSSLRsaOaepCtx, + *xmlSecOpenSSLRsaOaepCtxPtr; +struct _xmlSecOpenSSLRsaOaepCtx { + EVP_PKEY* pKey; + xmlSecBuffer oaepParams; +}; + +/********************************************************************* + * + * RSA OAEP key transport transform + * + * xmlSecOpenSSLRsaOaepCtx is located after xmlSecTransform + * + ********************************************************************/ +#define xmlSecOpenSSLRsaOaepSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLRsaOaepCtx)) +#define xmlSecOpenSSLRsaOaepGetCtx(transform) \ + ((xmlSecOpenSSLRsaOaepCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecOpenSSLRsaOaepInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLRsaOaepFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLRsaOaepNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLRsaOaepSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLRsaOaepSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLRsaOaepExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLRsaOaepProcess (xmlSecTransformPtr transform, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecOpenSSLRsaOaepKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLRsaOaepSize, /* xmlSecSize objSize */ + + xmlSecNameRsaOaep, /* const xmlChar* name; */ + xmlSecHrefRsaOaep, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLRsaOaepInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLRsaOaepFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecOpenSSLRsaOaepNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLRsaOaepSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLRsaOaepSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLRsaOaepExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaOaepGetKlass: + * + * The RSA-OAEP key transport transform klass. + * + * Returns: RSA-OAEP key transport transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaOaepGetKlass(void) { + return(&xmlSecOpenSSLRsaOaepKlass); +} + +static int +xmlSecOpenSSLRsaOaepInitialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize), -1); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLRsaOaepCtx)); + + 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); + } + return(0); +} + +static void +xmlSecOpenSSLRsaOaepFinalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize)); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->pKey != NULL) { + EVP_PKEY_free(ctx->pKey); + } + xmlSecBufferFinalize(&(ctx->oaepParams)); + memset(ctx, 0, sizeof(xmlSecOpenSSLRsaOaepCtx)); +} + +static int +xmlSecOpenSSLRsaOaepNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecBufferGetSize(&(ctx->oaepParams)) == 0, -1); + + cur = xmlSecGetNextElementNode(node->children); + if((cur != NULL) && 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); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + if((cur != NULL) && 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); + + 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 +xmlSecOpenSSLRsaOaepSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecOpenSSLKeyDataRsaId; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyType = xmlSecKeyDataTypePublic; + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyType = xmlSecKeyDataTypePrivate; + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + + return(0); +} + +static int +xmlSecOpenSSLRsaOaepSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + EVP_PKEY* pKey; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataRsaId), -1); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pKey == NULL, -1); + + pKey = xmlSecOpenSSLKeyDataRsaGetEvp(xmlSecKeyGetValue(key)); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKeyDataRsaGetEvp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(pKey->type == EVP_PKEY_RSA, -1); + xmlSecAssert2(pKey->pkey.rsa != NULL, -1); + + ctx->pKey = xmlSecOpenSSLEvpKeyDup(pKey); + if(ctx->pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpKeyDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLRsaOaepExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pKey != 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 = xmlSecOpenSSLRsaOaepProcess(transform, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLRsaOaepProcess", + 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 +xmlSecOpenSSLRsaOaepProcess(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLRsaOaepCtxPtr ctx; + xmlSecSize paramsSize; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaOaepId), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLRsaOaepSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLRsaOaepGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->pKey != NULL, -1); + xmlSecAssert2(ctx->pKey->type == EVP_PKEY_RSA, -1); + xmlSecAssert2(ctx->pKey->pkey.rsa != NULL, -1); + + keySize = RSA_size(ctx->pKey->pkey.rsa); + 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); + } + + paramsSize = xmlSecBufferGetSize(&(ctx->oaepParams)); + if((transform->operation == xmlSecTransformOperationEncrypt) && (paramsSize == 0)) { + /* encode w/o OAEPParams --> simple */ + ret = RSA_public_encrypt(inSize, xmlSecBufferGetData(in), + xmlSecBufferGetData(out), + ctx->pKey->pkey.rsa, RSA_PKCS1_OAEP_PADDING); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_public_encrypt(RSA_PKCS1_OAEP_PADDING)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else if((transform->operation == xmlSecTransformOperationEncrypt) && (paramsSize > 0)) { + xmlSecAssert2(xmlSecBufferGetData(&(ctx->oaepParams)) != NULL, -1); + + /* add space for padding */ + ret = xmlSecBufferSetMaxSize(in, keySize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", keySize); + return(-1); + } + + /* add padding */ + ret = RSA_padding_add_PKCS1_OAEP(xmlSecBufferGetData(in), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(&(ctx->oaepParams)), + paramsSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_padding_add_PKCS1_OAEP", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + inSize = keySize; + + /* encode with OAEPParams */ + ret = RSA_public_encrypt(inSize, xmlSecBufferGetData(in), + xmlSecBufferGetData(out), + ctx->pKey->pkey.rsa, RSA_NO_PADDING); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_public_encrypt(RSA_NO_PADDING)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else if((transform->operation == xmlSecTransformOperationDecrypt) && (paramsSize == 0)) { + ret = RSA_private_decrypt(inSize, xmlSecBufferGetData(in), + xmlSecBufferGetData(out), + ctx->pKey->pkey.rsa, RSA_PKCS1_OAEP_PADDING); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_private_decrypt(RSA_PKCS1_OAEP_PADDING)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else if((transform->operation == xmlSecTransformOperationDecrypt) && (paramsSize != 0)) { + BIGNUM bn; + + ret = RSA_private_decrypt(inSize, xmlSecBufferGetData(in), + xmlSecBufferGetData(out), + ctx->pKey->pkey.rsa, RSA_NO_PADDING); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_private_decrypt(RSA_NO_PADDING)", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + + /* + * the private decrypt w/o padding adds '0's at the begginning. + * it's not clear for me can I simply skip all '0's from the + * beggining so I have to do decode it back to BIGNUM and dump + * buffer again + */ + BN_init(&bn); + if(BN_bin2bn(xmlSecBufferGetData(out), outSize, &bn) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "BN_bin2bn", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", outSize); + BN_clear_free(&bn); + return(-1); + } + + ret = BN_bn2bin(&bn, xmlSecBufferGetData(out)); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "BN_bn2bin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BN_clear_free(&bn); + return(-1); + } + BN_clear_free(&bn); + outSize = ret; + + ret = RSA_padding_check_PKCS1_OAEP(xmlSecBufferGetData(out), outSize, + xmlSecBufferGetData(out), outSize, + keySize, + xmlSecBufferGetData(&(ctx->oaepParams)), + paramsSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "RSA_padding_check_PKCS1_OAEP", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else { + xmlSecAssert2("we could not be here" == NULL, -1); + return(-1); + } + + 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); +} + +#endif /* XMLSEC_NO_RSA */ + diff --git a/src/openssl/kw_aes.c b/src/openssl/kw_aes.c new file mode 100644 index 00000000..94cfeddb --- /dev/null +++ b/src/openssl/kw_aes.c @@ -0,0 +1,622 @@ +/** + * + * XMLSec library + * + * AES 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_AES +#ifndef XMLSEC_OPENSSL_096 +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <openssl/aes.h> +#include <openssl/rand.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> + +#define XMLSEC_OPENSSL_AES128_KEY_SIZE 16 +#define XMLSEC_OPENSSL_AES192_KEY_SIZE 24 +#define XMLSEC_OPENSSL_AES256_KEY_SIZE 32 +#define XMLSEC_OPENSSL_AES_IV_SIZE 16 +#define XMLSEC_OPENSSL_AES_BLOCK_SIZE 16 + + +/********************************************************************* + * + * AES KW transforms + * + * key (xmlSecBuffer) is located after xmlSecTransform structure + * + ********************************************************************/ +#define xmlSecOpenSSLKWAesGetKey(transform) \ + ((xmlSecBufferPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecOpenSSLKWAesSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer)) + +static int xmlSecOpenSSLKWAesInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLKWAesFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLKWAesSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLKWAesSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLKWAesExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static xmlSecSize xmlSecOpenSSLKWAesGetKeySize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLKWAesEncode (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte* in, + xmlSecSize inSize, + xmlSecByte* out, + xmlSecSize outSize); +static int xmlSecOpenSSLKWAesDecode (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte* in, + xmlSecSize inSize, + xmlSecByte* out, + xmlSecSize outSize); + +static xmlSecTransformKlass xmlSecOpenSSLKWAes128Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes128, /* const xmlChar* name; */ + xmlSecHrefKWAes128, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static xmlSecTransformKlass xmlSecOpenSSLKWAes192Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes192, /* const xmlChar* name; */ + xmlSecHrefKWAes192, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static xmlSecTransformKlass xmlSecOpenSSLKWAes256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLKWAesSize, /* xmlSecSize objSize */ + + xmlSecNameKWAes256, /* const xmlChar* name; */ + xmlSecHrefKWAes256, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLKWAesInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLKWAesFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLKWAesSetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLKWAesSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLKWAesExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +#define XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE 8 + +#define xmlSecOpenSSLKWAesCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecOpenSSLTransformKWAes128Id) || \ + xmlSecTransformCheckId((transform), xmlSecOpenSSLTransformKWAes192Id) || \ + xmlSecTransformCheckId((transform), xmlSecOpenSSLTransformKWAes256Id)) + +/** + * xmlSecOpenSSLTransformKWAes128GetKlass: + * + * The AES-128 kew wrapper transform klass. + * + * Returns: AES-128 kew wrapper transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformKWAes128GetKlass(void) { + return(&xmlSecOpenSSLKWAes128Klass); +} + +/** + * xmlSecOpenSSLTransformKWAes192GetKlass: + * + * The AES-192 kew wrapper transform klass. + * + * Returns: AES-192 kew wrapper transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformKWAes192GetKlass(void) { + return(&xmlSecOpenSSLKWAes192Klass); +} + +/** + * xmlSecOpenSSLTransformKWAes256GetKlass: + * + * The AES-256 kew wrapper transform klass. + * + * Returns: AES-256 kew wrapper transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformKWAes256GetKlass(void) { + return(&xmlSecOpenSSLKWAes256Klass); +} + +static int +xmlSecOpenSSLKWAesInitialize(xmlSecTransformPtr transform) { + int ret; + + xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1); + + ret = xmlSecBufferInitialize(xmlSecOpenSSLKWAesGetKey(transform), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKWAesGetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecOpenSSLKWAesFinalize(xmlSecTransformPtr transform) { + xmlSecAssert(xmlSecOpenSSLKWAesCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize)); + + if(xmlSecOpenSSLKWAesGetKey(transform) != NULL) { + xmlSecBufferFinalize(xmlSecOpenSSLKWAesGetKey(transform)); + } +} + +static int +xmlSecOpenSSLKWAesSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecOpenSSLKeyDataAesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * xmlSecOpenSSLKWAesGetKeySize(transform); + + return(0); +} + +static int +xmlSecOpenSSLKWAesSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecBufferPtr buffer; + xmlSecSize keySize; + xmlSecSize expectedKeySize; + int ret; + + xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1); + xmlSecAssert2(xmlSecOpenSSLKWAesGetKey(transform) != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataAesId), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + expectedKeySize = xmlSecOpenSSLKWAesGetKeySize(transform); + if(keySize < expectedKeySize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "key=%d;expected=%d", + keySize, expectedKeySize); + return(-1); + } + + ret = xmlSecBufferSetData(xmlSecOpenSSLKWAesGetKey(transform), + xmlSecBufferGetData(buffer), + expectedKeySize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "expected-size=%d", expectedKeySize); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLKWAesExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr in, out, key; + xmlSecSize inSize, outSize, keySize, expectedKeySize; + int ret; + + xmlSecAssert2(xmlSecOpenSSLKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWAesSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + key = xmlSecOpenSSLKWAesGetKey(transform); + xmlSecAssert2(key != NULL, -1); + + keySize = xmlSecBufferGetSize(key); + expectedKeySize = xmlSecOpenSSLKWAesGetKeySize(transform); + xmlSecAssert2(keySize == expectedKeySize, -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_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE + + XMLSEC_OPENSSL_AES_BLOCK_SIZE; + } else { + outSize = inSize + XMLSEC_OPENSSL_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 = xmlSecOpenSSLKWAesEncode(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKWAesEncode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecOpenSSLKWAesDecode(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKWAesDecode", + 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); +} + +static xmlSecSize +xmlSecOpenSSLKWAesGetKeySize(xmlSecTransformPtr transform) { + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWAes128Id)) { + return(XMLSEC_OPENSSL_AES128_KEY_SIZE); + } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWAes192Id)) { + return(XMLSEC_OPENSSL_AES192_KEY_SIZE); + } else if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWAes256Id)) { + return(XMLSEC_OPENSSL_AES256_KEY_SIZE); + } + return(0); +} + +/** + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap: + * + * Assume that the data to be wrapped consists of N 64-bit data blocks + * denoted P(1), P(2), P(3) ... P(N). The result of wrapping will be N+1 + * 64-bit blocks denoted C(0), C(1), C(2), ... C(N). The key encrypting + * key is represented by K. Assume integers i, j, and t and intermediate + * 64-bit register A, 128-bit register B, and array of 64-bit quantities + * R(1) through R(N). + * + * "|" represents concatentation so x|y, where x and y and 64-bit quantities, + * is the 128-bit quantity with x in the most significant bits and y in the + * least significant bits. AES(K)enc(x) is the operation of AES encrypting + * the 128-bit quantity x under the key K. AES(K)dec(x) is the corresponding + * decryption opteration. XOR(x,y) is the bitwise exclusive or of x and y. + * MSB(x) and LSB(y) are the most significant 64 bits and least significant + * 64 bits of x and y respectively. + * + * If N is 1, a single AES operation is performed for wrap or unwrap. + * If N>1, then 6*N AES operations are performed for wrap or unwrap. + * + * The key wrap algorithm is as follows: + * + * 1. If N is 1: + * * B=AES(K)enc(0xA6A6A6A6A6A6A6A6|P(1)) + * * C(0)=MSB(B) + * * C(1)=LSB(B) + * If N>1, perform the following steps: + * 2. Initialize variables: + * * Set A to 0xA6A6A6A6A6A6A6A6 + * * Fori=1 to N, + * R(i)=P(i) + * 3. Calculate intermediate values: + * * Forj=0 to 5, + * o For i=1 to N, + * t= i + j*N + * B=AES(K)enc(A|R(i)) + * A=XOR(t,MSB(B)) + * R(i)=LSB(B) + * 4. Output the results: + * * Set C(0)=A + * * For i=1 to N, + * C(i)=R(i) + * + * The key unwrap algorithm is as follows: + * + * 1. If N is 1: + * * B=AES(K)dec(C(0)|C(1)) + * * P(1)=LSB(B) + * * If MSB(B) is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, + * return an integrity check failure error. + * If N>1, perform the following steps: + * 2. Initialize the variables: + * * A=C(0) + * * For i=1 to N, + * R(i)=C(i) + * 3. Calculate intermediate values: + * * For j=5 to 0, + * o For i=N to 1, + * t= i + j*N + * B=AES(K)dec(XOR(t,A)|R(i)) + * A=MSB(B) + * R(i)=LSB(B) + * 4. Output the results: + * * For i=1 to N, + * P(i)=R(i) + * * If A is 0xA6A6A6A6A6A6A6A6, return success. Otherwise, return + * an integrity check failure error. + */ +static const xmlSecByte xmlSecOpenSSLKWAesMagicBlock[XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE] = { + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 +}; + +static int +xmlSecOpenSSLKWAesEncode(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + AES_KEY aesKey; + xmlSecByte block[XMLSEC_OPENSSL_AES_BLOCK_SIZE]; + xmlSecByte *p; + int N, i, j, t; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize > 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize + 8, -1); + + ret = AES_set_encrypt_key(key, 8 * keySize, &aesKey); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "AES_set_encrypt_key", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* prepend magic block */ + if(in != out) { + memcpy(out + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE, in, inSize); + } else { + memmove(out + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE, out, inSize); + } + memcpy(out, xmlSecOpenSSLKWAesMagicBlock, XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE); + + N = (inSize / 8); + if(N == 1) { + AES_encrypt(out, out, &aesKey); + } else { + for(j = 0; j <= 5; ++j) { + for(i = 1; i <= N; ++i) { + t = i + (j * N); + p = out + i * 8; + + memcpy(block, out, 8); + memcpy(block + 8, p, 8); + + AES_encrypt(block, block, &aesKey); + block[7] ^= t; + memcpy(out, block, 8); + memcpy(p, block + 8, 8); + } + } + } + + return(inSize + 8); +} + +static int +xmlSecOpenSSLKWAesDecode(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + AES_KEY aesKey; + xmlSecByte block[XMLSEC_OPENSSL_AES_BLOCK_SIZE]; + xmlSecByte *p; + int N, i, j, t; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize > 0, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + ret = AES_set_decrypt_key(key, 8 * keySize, &aesKey); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "AES_set_decrypt_key", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* copy input */ + if(in != out) { + memcpy(out, in, inSize); + } + + N = (inSize / 8) - 1; + if(N == 1) { + AES_decrypt(out, out, &aesKey); + } else { + for(j = 5; j >= 0; --j) { + for(i = N; i > 0; --i) { + t = i + (j * N); + p = out + i * 8; + + memcpy(block, out, 8); + memcpy(block + 8, p, 8); + block[7] ^= t; + + AES_decrypt(block, block, &aesKey); + memcpy(out, block, 8); + memcpy(p, block + 8, 8); + } + } + } + /* do not left data in memory */ + memset(block, 0, sizeof(block)); + + if(memcmp(xmlSecOpenSSLKWAesMagicBlock, out, XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "bad magic block"); + return(-1); + } + + memmove(out, out + XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE, inSize - XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE); + return(inSize - XMLSEC_OPENSSL_KW_AES_MAGIC_BLOCK_SIZE); +} + +#endif /* XMLSEC_OPENSSL_096 */ +#endif /* XMLSEC_NO_AES */ diff --git a/src/openssl/kw_des.c b/src/openssl/kw_des.c new file mode 100644 index 00000000..f5ebf435 --- /dev/null +++ b/src/openssl/kw_des.c @@ -0,0 +1,628 @@ +/** + * + * 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 <openssl/des.h> +#include <openssl/rand.h> +#include <openssl/sha.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> + +#define XMLSEC_OPENSSL_DES3_KEY_LENGTH 24 +#define XMLSEC_OPENSSL_DES3_IV_LENGTH 8 +#define XMLSEC_OPENSSL_DES3_BLOCK_LENGTH 8 + +/********************************************************************* + * + * Triple DES Key Wrap transform + * + * key (xmlSecBuffer) is located after xmlSecTransform structure + * + ********************************************************************/ +#define xmlSecOpenSSLKWDes3GetKey(transform) \ + ((xmlSecBufferPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) +#define xmlSecOpenSSLKWDes3Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecBuffer)) + +static int xmlSecOpenSSLKWDes3Initialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLKWDes3Finalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLKWDes3SetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLKWDes3SetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLKWDes3Execute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLKWDes3Encode (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize); +static int xmlSecOpenSSLKWDes3Decode (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize); +static int xmlSecOpenSSLKWDes3Encrypt (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *iv, + xmlSecSize ivSize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize, + int enc); +static int xmlSecOpenSSLKWDes3BufferReverse (xmlSecByte *buf, + xmlSecSize size); + +static xmlSecTransformKlass xmlSecOpenSSLKWDes3Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLKWDes3Size, /* xmlSecSize objSize */ + + xmlSecNameKWDes3, /* const xmlChar* name; */ + xmlSecHrefKWDes3, /* const xmlChar* href; */ + xmlSecTransformUsageEncryptionMethod, /* xmlSecAlgorithmUsage usage; */ + + xmlSecOpenSSLKWDes3Initialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLKWDes3Finalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLKWDes3SetKeyReq, /* xmlSecTransformSetKeyMethod setKeyReq; */ + xmlSecOpenSSLKWDes3SetKey, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLKWDes3Execute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformKWDes3GetKlass: + * + * The Triple DES key wrapper transform klass. + * + * Returns: Triple DES key wrapper transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformKWDes3GetKlass(void) { + return(&xmlSecOpenSSLKWDes3Klass); +} + +static int +xmlSecOpenSSLKWDes3Initialize(xmlSecTransformPtr transform) { + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1); + + ret = xmlSecBufferInitialize(xmlSecOpenSSLKWDes3GetKey(transform), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecOpenSSLKWDes3Finalize(xmlSecTransformPtr transform) { + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size)); + + if(xmlSecOpenSSLKWDes3GetKey(transform) != NULL) { + xmlSecBufferFinalize(xmlSecOpenSSLKWDes3GetKey(transform)); + } +} + +static int +xmlSecOpenSSLKWDes3SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecOpenSSLKeyDataDesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage= xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage= xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * XMLSEC_OPENSSL_DES3_KEY_LENGTH; + return(0); +} + +static int +xmlSecOpenSSLKWDes3SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecBufferPtr buffer; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1); + xmlSecAssert2(xmlSecOpenSSLKWDes3GetKey(transform) != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecOpenSSLKeyDataDesId), -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + if(keySize < XMLSEC_OPENSSL_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_OPENSSL_DES3_KEY_LENGTH); + return(-1); + } + + ret = xmlSecBufferSetData(xmlSecOpenSSLKWDes3GetKey(transform), + xmlSecBufferGetData(buffer), + XMLSEC_OPENSSL_DES3_KEY_LENGTH); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", XMLSEC_OPENSSL_DES3_KEY_LENGTH); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLKWDes3Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecBufferPtr in, out, key; + xmlSecSize inSize, outSize, keySize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLKWDes3Size), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + key = xmlSecOpenSSLKWDes3GetKey(transform); + xmlSecAssert2(key != NULL, -1); + + keySize = xmlSecBufferGetSize(key); + xmlSecAssert2(keySize == XMLSEC_OPENSSL_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_OPENSSL_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_OPENSSL_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_OPENSSL_DES3_IV_LENGTH + + XMLSEC_OPENSSL_DES3_BLOCK_LENGTH + + XMLSEC_OPENSSL_DES3_BLOCK_LENGTH; + } else { + outSize = inSize + XMLSEC_OPENSSL_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 = xmlSecOpenSSLKWDes3Encode(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKWDes3Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "key=%d,in=%d,out=%d", + keySize, inSize, outSize); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecOpenSSLKWDes3Decode(xmlSecBufferGetData(key), keySize, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLKWDes3Decode", + 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); +} + +static xmlSecByte xmlSecOpenSSLKWDes3Iv[XMLSEC_OPENSSL_DES3_IV_LENGTH] = { + 0x4a, 0xdd, 0xa2, 0x2c, 0x79, 0xe8, 0x21, 0x05 +}; +/** + * CMS Triple DES Key Wrap + * + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap + * + * The following algorithm wraps (encrypts) a key (the wrapped key, WK) + * under a TRIPLEDES key-encryption-key (KEK) as specified in [CMS-Algorithms]: + * + * 1. Represent the key being wrapped as an octet sequence. If it is a + * TRIPLEDES key, this is 24 octets (192 bits) with odd parity bit as + * the bottom bit of each octet. + * 2. Compute the CMS key checksum (section 5.6.1) call this CKS. + * 3. Let WKCKS = WK || CKS, where || is concatenation. + * 4. Generate 8 random octets [RANDOM] and call this IV. + * 5. Encrypt WKCKS in CBC mode using KEK as the key and IV as the + * initialization vector. Call the results TEMP1. + * 6. Left TEMP2 = IV || TEMP1. + * 7. Reverse the order of the octets in TEMP2 and call the result TEMP3. + * 8. Encrypt TEMP3 in CBC mode using the KEK and an initialization vector + * of 0x4adda22c79e82105. The resulting cipher text is the desired result. + * It is 40 octets long if a 168 bit key is being wrapped. + * + */ +static int +xmlSecOpenSSLKWDes3Encode(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + xmlSecByte sha1[SHA_DIGEST_LENGTH]; + xmlSecByte iv[XMLSEC_OPENSSL_DES3_IV_LENGTH]; + xmlSecSize s; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == XMLSEC_OPENSSL_DES3_KEY_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize + 16, -1); + + /* step 2: calculate sha1 and CMS */ + if(SHA1(in, inSize, sha1) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SHA1", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 3: construct WKCKS */ + memcpy(out, in, inSize); + memcpy(out + inSize, sha1, XMLSEC_OPENSSL_DES3_BLOCK_LENGTH); + + /* step 4: generate random iv */ + ret = RAND_bytes(iv, XMLSEC_OPENSSL_DES3_IV_LENGTH); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "RAND_bytes", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ret=%d", ret); + return(-1); + } + + /* step 5: first encryption, result is TEMP1 */ + ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize, + iv, XMLSEC_OPENSSL_DES3_IV_LENGTH, + out, inSize + XMLSEC_OPENSSL_DES3_BLOCK_LENGTH, + out, outSize, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 6: construct TEMP2=IV || TEMP1 */ + memmove(out + XMLSEC_OPENSSL_DES3_IV_LENGTH, out, + inSize + XMLSEC_OPENSSL_DES3_IV_LENGTH); + memcpy(out, iv, XMLSEC_OPENSSL_DES3_IV_LENGTH); + s = ret + XMLSEC_OPENSSL_DES3_IV_LENGTH; + + /* step 7: reverse octets order, result is TEMP3 */ + ret = xmlSecOpenSSLKWDes3BufferReverse(out, s); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKWDes3BufferReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* step 8: second encryption with static IV */ + ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize, + xmlSecOpenSSLKWDes3Iv, XMLSEC_OPENSSL_DES3_IV_LENGTH, + out, s, out, outSize, 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + s = ret; + return(s); +} + +/** + * CMS Triple DES Key Wrap + * + * http://www.w3.org/TR/xmlenc-core/#sec-Alg-SymmetricKeyWrap + * + * The following algorithm unwraps (decrypts) a key as specified in + * [CMS-Algorithms]: + * + * 1. Check if the length of the cipher text is reasonable given the key type. + * It must be 40 bytes for a 168 bit key and either 32, 40, or 48 bytes for + * a 128, 192, or 256 bit key. If the length is not supported or inconsistent + * with the algorithm for which the key is intended, return error. + * 2. Decrypt the cipher text with TRIPLEDES in CBC mode using the KEK and + * an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3. + * 3. Reverse the order of the octets in TEMP3 and call the result TEMP2. + * 4. Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining + * octets. + * 5. Decrypt TEMP1 using TRIPLEDES in CBC mode using the KEK and the IV found + * in the previous step. Call the result WKCKS. + * 6. Decompose WKCKS. CKS is the last 8 octets and WK, the wrapped key, are + * those octets before the CKS. + * 7. Calculate a CMS key checksum (section 5.6.1) over the WK and compare + * with the CKS extracted in the above step. If they are not equal, return + * error. + * 8. WK is the wrapped key, now extracted for use in data decryption. + */ +static int +xmlSecOpenSSLKWDes3Decode(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize) { + xmlSecByte sha1[SHA_DIGEST_LENGTH]; + xmlSecSize s; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == XMLSEC_OPENSSL_DES3_KEY_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + /* step 2: first decryption with static IV, result is TEMP3 */ + ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize, + xmlSecOpenSSLKWDes3Iv, XMLSEC_OPENSSL_DES3_IV_LENGTH, + in, inSize, out, outSize, 0); + if((ret < 0) || (ret < XMLSEC_OPENSSL_DES3_IV_LENGTH)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + s = ret; + + /* step 3: reverse octets order in TEMP3, result is TEMP2 */ + ret = xmlSecOpenSSLKWDes3BufferReverse(out, s); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKWDes3BufferReverse", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* steps 4 and 5: get IV and decrypt second time, result is WKCKS */ + ret = xmlSecOpenSSLKWDes3Encrypt(key, keySize, + out, XMLSEC_OPENSSL_DES3_IV_LENGTH, + out + XMLSEC_OPENSSL_DES3_IV_LENGTH, + s - XMLSEC_OPENSSL_DES3_IV_LENGTH, + out, outSize, 0); + if((ret < 0) || (ret < XMLSEC_OPENSSL_DES3_BLOCK_LENGTH)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + s = ret - XMLSEC_OPENSSL_DES3_BLOCK_LENGTH; + + /* steps 6 and 7: calculate SHA1 and validate it */ + if(SHA1(out, s, sha1) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "SHA1", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(memcmp(sha1, out + s, XMLSEC_OPENSSL_DES3_BLOCK_LENGTH) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "SHA1 does not match"); + return(-1); + } + + return(s); +} + +static int +xmlSecOpenSSLKWDes3Encrypt(const xmlSecByte *key, xmlSecSize keySize, + const xmlSecByte *iv, xmlSecSize ivSize, + const xmlSecByte *in, xmlSecSize inSize, + xmlSecByte *out, xmlSecSize outSize, int enc) { + EVP_CIPHER_CTX cipherCtx; + int updateLen; + int finalLen; + int ret; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == (xmlSecSize)EVP_CIPHER_key_length(EVP_des_ede3_cbc()), -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize == (xmlSecSize)EVP_CIPHER_iv_length(EVP_des_ede3_cbc()), -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + EVP_CIPHER_CTX_init(&cipherCtx); + ret = EVP_CipherInit(&cipherCtx, EVP_des_ede3_cbc(), key, iv, enc); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "EVP_CipherInit", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_OPENSSL_096 + EVP_CIPHER_CTX_set_padding(&cipherCtx, 0); +#endif /* XMLSEC_OPENSSL_096 */ + + ret = EVP_CipherUpdate(&cipherCtx, out, &updateLen, in, inSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "EVP_CipherUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = EVP_CipherFinal(&cipherCtx, out + updateLen, &finalLen); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "EVP_CipherFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + EVP_CIPHER_CTX_cleanup(&cipherCtx); + + return(updateLen + finalLen); +} + +static int +xmlSecOpenSSLKWDes3BufferReverse(xmlSecByte *buf, xmlSecSize size) { + xmlSecSize s; + xmlSecSize i; + xmlSecByte c; + + xmlSecAssert2(buf != NULL, -1); + + s = size / 2; + --size; + for(i = 0; i < s; ++i) { + c = buf[i]; + buf[i] = buf[size - i]; + buf[size - i] = c; + } + return(0); +} + +#endif /* XMLSEC_NO_DES */ + diff --git a/src/openssl/signatures.c b/src/openssl/signatures.c new file mode 100644 index 00000000..2a16983a --- /dev/null +++ b/src/openssl/signatures.c @@ -0,0 +1,1061 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +#include <openssl/evp.h> +#include <openssl/rand.h> +#include <openssl/sha.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> + +#ifndef XMLSEC_NO_DSA +#define XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE 40 +static const EVP_MD *xmlSecOpenSSLDsaSha1Evp (void); +#endif /* XMLSEC_NO_DSA */ + + +/************************************************************************** + * + * Internal OpenSSL evp signatures ctx + * + *****************************************************************************/ +typedef struct _xmlSecOpenSSLEvpSignatureCtx xmlSecOpenSSLEvpSignatureCtx, + *xmlSecOpenSSLEvpSignatureCtxPtr; +struct _xmlSecOpenSSLEvpSignatureCtx { + const EVP_MD* digest; + EVP_MD_CTX digestCtx; + xmlSecKeyDataId keyId; + EVP_PKEY* pKey; +}; + +/****************************************************************************** + * + * EVP Signature transforms + * + * xmlSecOpenSSLEvpSignatureCtx is located after xmlSecTransform + * + *****************************************************************************/ +#define xmlSecOpenSSLEvpSignatureSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecOpenSSLEvpSignatureCtx)) +#define xmlSecOpenSSLEvpSignatureGetCtx(transform) \ + ((xmlSecOpenSSLEvpSignatureCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecOpenSSLEvpSignatureCheckId (xmlSecTransformPtr transform); +static int xmlSecOpenSSLEvpSignatureInitialize (xmlSecTransformPtr transform); +static void xmlSecOpenSSLEvpSignatureFinalize (xmlSecTransformPtr transform); +static int xmlSecOpenSSLEvpSignatureSetKeyReq (xmlSecTransformPtr transform, + xmlSecKeyReqPtr keyReq); +static int xmlSecOpenSSLEvpSignatureSetKey (xmlSecTransformPtr transform, + xmlSecKeyPtr key); +static int xmlSecOpenSSLEvpSignatureVerify (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecOpenSSLEvpSignatureExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static int +xmlSecOpenSSLEvpSignatureCheckId(xmlSecTransformPtr transform) { +#ifndef XMLSEC_NO_DSA + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformDsaSha1Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaMd5Id)) { + return(1); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaRipemd160Id)) { + return(1); + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha1Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha224Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha256Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha384Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha512Id)) { + return(1); + } else +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + + { + return(0); + } + + return(0); +} + +static int +xmlSecOpenSSLEvpSignatureInitialize(xmlSecTransformPtr transform) { + xmlSecOpenSSLEvpSignatureCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLEvpSignatureCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpSignatureSize), -1); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpSignatureCtx)); + +#ifndef XMLSEC_NO_DSA + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformDsaSha1Id)) { + ctx->digest = xmlSecOpenSSLDsaSha1Evp(); + ctx->keyId = xmlSecOpenSSLKeyDataDsaId; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaMd5Id)) { + ctx->digest = EVP_md5(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaRipemd160Id)) { + ctx->digest = EVP_ripemd160(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha1Id)) { + ctx->digest = EVP_sha1(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha224Id)) { + ctx->digest = EVP_sha224(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha256Id)) { + ctx->digest = EVP_sha256(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha384Id)) { + ctx->digest = EVP_sha384(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecOpenSSLTransformRsaSha512Id)) { + ctx->digest = EVP_sha512(); + ctx->keyId = xmlSecOpenSSLKeyDataRsaId; + } else +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + + if(1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_OPENSSL_096 + EVP_MD_CTX_init(&(ctx->digestCtx)); +#endif /* XMLSEC_OPENSSL_096 */ + return(0); +} + +static void +xmlSecOpenSSLEvpSignatureFinalize(xmlSecTransformPtr transform) { + xmlSecOpenSSLEvpSignatureCtxPtr ctx; + + xmlSecAssert(xmlSecOpenSSLEvpSignatureCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpSignatureSize)); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->pKey != NULL) { + EVP_PKEY_free(ctx->pKey); + } + +#ifndef XMLSEC_OPENSSL_096 + EVP_MD_CTX_cleanup(&(ctx->digestCtx)); +#endif /* XMLSEC_OPENSSL_096 */ + memset(ctx, 0, sizeof(xmlSecOpenSSLEvpSignatureCtx)); +} + +static int +xmlSecOpenSSLEvpSignatureSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecOpenSSLEvpSignatureCtxPtr ctx; + xmlSecKeyDataPtr value; + EVP_PKEY* pKey; + + xmlSecAssert2(xmlSecOpenSSLEvpSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpSignatureSize), -1); + xmlSecAssert2(key != NULL, -1); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digest != NULL, -1); + xmlSecAssert2(ctx->keyId != NULL, -1); + xmlSecAssert2(xmlSecKeyCheckId(key, ctx->keyId), -1); + + value = xmlSecKeyGetValue(key); + xmlSecAssert2(value != NULL, -1); + + pKey = xmlSecOpenSSLEvpKeyDataGetEvp(value); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpKeyDataGetEvp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(ctx->pKey != NULL) { + EVP_PKEY_free(ctx->pKey); + } + + ctx->pKey = xmlSecOpenSSLEvpKeyDup(pKey); + if(ctx->pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecOpenSSLEvpKeyDup", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecOpenSSLEvpSignatureSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecOpenSSLEvpSignatureCtxPtr ctx; + + xmlSecAssert2(xmlSecOpenSSLEvpSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpSignatureSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(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 +xmlSecOpenSSLEvpSignatureVerify(xmlSecTransformPtr transform, + const xmlSecByte* data, xmlSecSize dataSize, + xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLEvpSignatureCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecOpenSSLEvpSignatureCheckId(transform), -1); + xmlSecAssert2(transform->operation == xmlSecTransformOperationVerify, -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpSignatureSize), -1); + xmlSecAssert2(transform->status == xmlSecTransformStatusFinished, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + ret = EVP_VerifyFinal(&(ctx->digestCtx), (xmlSecByte*)data, dataSize, ctx->pKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_VerifyFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } else if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_VerifyFinal", + XMLSEC_ERRORS_R_DATA_NOT_MATCH, + "signature do not match"); + transform->status = xmlSecTransformStatusFail; + return(0); + } + + transform->status = xmlSecTransformStatusOk; + return(0); +} + +static int +xmlSecOpenSSLEvpSignatureExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecOpenSSLEvpSignatureCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + int ret; + + xmlSecAssert2(xmlSecOpenSSLEvpSignatureCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationSign) || (transform->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecOpenSSLEvpSignatureSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + ctx = xmlSecOpenSSLEvpSignatureGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->digest != NULL, -1); + xmlSecAssert2(ctx->pKey != NULL, -1); + + if(transform->status == xmlSecTransformStatusNone) { + xmlSecAssert2(outSize == 0, -1); + + if(transform->operation == xmlSecTransformOperationSign) { +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_SignInit(&(ctx->digestCtx), ctx->digest); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_SignInit", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_SignInit(&(ctx->digestCtx), ctx->digest); +#endif /* XMLSEC_OPENSSL_096 */ + } else { +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_VerifyInit(&(ctx->digestCtx), ctx->digest); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_VerifyInit", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_VerifyInit(&(ctx->digestCtx), ctx->digest); +#endif /* XMLSEC_OPENSSL_096 */ + } + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (inSize > 0)) { + xmlSecAssert2(outSize == 0, -1); + + if(transform->operation == xmlSecTransformOperationSign) { +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_SignUpdate(&(ctx->digestCtx), xmlSecBufferGetData(in), inSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_SignUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_SignUpdate(&(ctx->digestCtx), xmlSecBufferGetData(in), inSize); +#endif /* XMLSEC_OPENSSL_096 */ + } else { +#ifndef XMLSEC_OPENSSL_096 + ret = EVP_VerifyUpdate(&(ctx->digestCtx), xmlSecBufferGetData(in), inSize); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_VerifyUpdate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#else /* XMLSEC_OPENSSL_096 */ + EVP_VerifyUpdate(&(ctx->digestCtx), xmlSecBufferGetData(in), inSize); +#endif /* XMLSEC_OPENSSL_096 */ + } + + 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)) { + xmlSecAssert2(outSize == 0, -1); + if(transform->operation == xmlSecTransformOperationSign) { + /* this is a hack: for rsa signatures + * we get size from EVP_PKEY_size(), + * for dsa signature we use a fixed constant */ + outSize = EVP_PKEY_size(ctx->pKey); +#ifndef XMLSEC_NO_DSA + if(outSize < XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE) { + outSize = XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE; + } +#endif /* XMLSEC_NO_DSA */ + + 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); + } + + ret = EVP_SignFinal(&(ctx->digestCtx), xmlSecBufferGetData(out), &outSize, ctx->pKey); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "EVP_SignFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + 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); + } + } + 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_DSA + +#ifndef XMLSEC_NO_SHA1 +/**************************************************************************** + * + * DSA-SHA1 signature transform + * + ***************************************************************************/ + +static xmlSecTransformKlass xmlSecOpenSSLDsaSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameDsaSha1, /* const xmlChar* name; */ + xmlSecHrefDsaSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformDsaSha1GetKlass: + * + * The DSA-SHA1 signature transform klass. + * + * Returns: DSA-SHA1 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformDsaSha1GetKlass(void) { + return(&xmlSecOpenSSLDsaSha1Klass); +} + +/**************************************************************************** + * + * DSA-SHA1 EVP + * + * XMLDSig specifies dsa signature packing not supported by OpenSSL so + * we created our own EVP_MD. + * + * http://www.w3.org/TR/xmldsig-core/#sec-SignatureAlg: + * + * The output of the DSA algorithm consists of a pair of integers + * usually referred by the pair (r, s). The signature value consists of + * the base64 encoding of the concatenation of two octet-streams that + * respectively result from the octet-encoding of the values r and s in + * that order. Integer to octet-stream conversion must be done according + * to the I2OSP operation defined in the RFC 2437 [PKCS1] specification + * with a l parameter equal to 20. For example, the SignatureValue element + * for a DSA signature (r, s) with values specified in hexadecimal: + * + * r = 8BAC1AB6 6410435C B7181F95 B16AB97C 92B341C0 + * s = 41E2345F 1F56DF24 58F426D1 55B4BA2D B6DCD8C8 + * + * from the example in Appendix 5 of the DSS standard would be + * + * <SignatureValue>i6watmQQQ1y3GB+VsWq5fJKzQcBB4jRfH1bfJFj0JtFVtLotttzYyA==</SignatureValue> + * + ***************************************************************************/ +#ifndef XMLSEC_OPENSSL_096 +static int +xmlSecOpenSSLDsaSha1EvpInit(EVP_MD_CTX *ctx) +{ + return SHA1_Init(ctx->md_data); +} + +static int +xmlSecOpenSSLDsaSha1EvpUpdate(EVP_MD_CTX *ctx,const void *data,unsigned long count) +{ + return SHA1_Update(ctx->md_data,data,count); +} + +static int +xmlSecOpenSSLDsaSha1EvpFinal(EVP_MD_CTX *ctx,xmlSecByte *md) +{ + return SHA1_Final(md,ctx->md_data); +} +#endif /* XMLSEC_OPENSSL_096 */ + +static int +xmlSecOpenSSLDsaSha1EvpSign(int type ATTRIBUTE_UNUSED, + const xmlSecByte *dgst, int dlen, + xmlSecByte *sig, unsigned int *siglen, DSA *dsa) { + DSA_SIG *s; + int rSize, sSize; + + s = DSA_do_sign(dgst, dlen, dsa); + if(s == NULL) { + *siglen=0; + return(0); + } + + rSize = BN_num_bytes(s->r); + sSize = BN_num_bytes(s->s); + if((rSize > (XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2)) || + (sSize > (XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2))) { + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "size(r)=%d or size(s)=%d > %d", + rSize, sSize, XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2); + DSA_SIG_free(s); + return(0); + } + + memset(sig, 0, XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE); + BN_bn2bin(s->r, sig + (XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2) - rSize); + BN_bn2bin(s->s, sig + XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE - sSize); + *siglen = XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE; + + DSA_SIG_free(s); + return(1); +} + +static int +xmlSecOpenSSLDsaSha1EvpVerify(int type ATTRIBUTE_UNUSED, + const xmlSecByte *dgst, int dgst_len, + const xmlSecByte *sigbuf, int siglen, DSA *dsa) { + DSA_SIG *s; + int ret = -1; + + s = DSA_SIG_new(); + if (s == NULL) { + return(ret); + } + + if(siglen != XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "invalid length %d (%d expected)", + siglen, XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE); + goto err; + } + + s->r = BN_bin2bn(sigbuf, XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2, NULL); + s->s = BN_bin2bn(sigbuf + (XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2), + XMLSEC_OPENSSL_DSA_SIGNATURE_SIZE / 2, NULL); + if((s->r == NULL) || (s->s == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_bin2bn", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto err; + } + + ret = DSA_do_verify(dgst, dgst_len, s, dsa); + +err: + DSA_SIG_free(s); + return(ret); +} + +static const EVP_MD xmlSecOpenSSLDsaMdEvp = { + NID_dsaWithSHA, + NID_dsaWithSHA, + SHA_DIGEST_LENGTH, +#ifndef XMLSEC_OPENSSL_096 + 0, + xmlSecOpenSSLDsaSha1EvpInit, + xmlSecOpenSSLDsaSha1EvpUpdate, + xmlSecOpenSSLDsaSha1EvpFinal, + NULL, + NULL, +#else /* XMLSEC_OPENSSL_096 */ + SHA1_Init, + SHA1_Update, + SHA1_Final, +#endif /* XMLSEC_OPENSSL_096 */ + xmlSecOpenSSLDsaSha1EvpSign, + xmlSecOpenSSLDsaSha1EvpVerify, + {EVP_PKEY_DSA,EVP_PKEY_DSA2,EVP_PKEY_DSA3,EVP_PKEY_DSA4,0}, + SHA_CBLOCK, + sizeof(EVP_MD *)+sizeof(SHA_CTX), +}; + +static const EVP_MD *xmlSecOpenSSLDsaSha1Evp(void) +{ + return(&xmlSecOpenSSLDsaMdEvp); +} +#endif /* XMLSEC_NO_SHA1 */ + +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 +/**************************************************************************** + * + * RSA-MD5 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaMd5, /* const xmlChar* name; */ + xmlSecHrefRsaMd5, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaMd5GetKlass: + * + * The RSA-MD5 signature transform klass. + * + * Returns: RSA-MD5 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaMd5GetKlass(void) { + return(&xmlSecOpenSSLRsaMd5Klass); +} + +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 +/**************************************************************************** + * + * RSA-RIPEMD160 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaRipemd160Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaRipemd160, /* const xmlChar* name; */ + xmlSecHrefRsaRipemd160, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaRipemd160GetKlass: + * + * The RSA-RIPEMD160 signature transform klass. + * + * Returns: RSA-RIPEMD160 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaRipemd160GetKlass(void) { + return(&xmlSecOpenSSLRsaRipemd160Klass); +} + +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 +/**************************************************************************** + * + * RSA-SHA1 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaSha1Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha1, /* const xmlChar* name; */ + xmlSecHrefRsaSha1, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaSha1GetKlass: + * + * The RSA-SHA1 signature transform klass. + * + * Returns: RSA-SHA1 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaSha1GetKlass(void) { + return(&xmlSecOpenSSLRsaSha1Klass); +} + +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA224 +/**************************************************************************** + * + * RSA-SHA224 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaSha224Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha224, /* const xmlChar* name; */ + xmlSecHrefRsaSha224, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaSha224GetKlass: + * + * The RSA-SHA224 signature transform klass. + * + * Returns: RSA-SHA224 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaSha224GetKlass(void) { + return(&xmlSecOpenSSLRsaSha224Klass); +} + +#endif /* XMLSEC_NO_SHA224 */ + +#ifndef XMLSEC_NO_SHA256 +/**************************************************************************** + * + * RSA-SHA256 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha256, /* const xmlChar* name; */ + xmlSecHrefRsaSha256, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaSha256GetKlass: + * + * The RSA-SHA256 signature transform klass. + * + * Returns: RSA-SHA256 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaSha256GetKlass(void) { + return(&xmlSecOpenSSLRsaSha256Klass); +} + +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/**************************************************************************** + * + * RSA-SHA384 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha384, /* const xmlChar* name; */ + xmlSecHrefRsaSha384, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaSha384GetKlass: + * + * The RSA-SHA384 signature transform klass. + * + * Returns: RSA-SHA384 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaSha384GetKlass(void) { + return(&xmlSecOpenSSLRsaSha384Klass); +} + +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/**************************************************************************** + * + * RSA-SHA512 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecOpenSSLRsaSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecOpenSSLEvpSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha512, /* const xmlChar* name; */ + xmlSecHrefRsaSha512, /* const xmlChar* href; */ + xmlSecTransformUsageSignatureMethod, /* xmlSecTransformUsage usage; */ + + xmlSecOpenSSLEvpSignatureInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecOpenSSLEvpSignatureFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + xmlSecOpenSSLEvpSignatureSetKeyReq, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + xmlSecOpenSSLEvpSignatureSetKey, /* xmlSecTransformSetKeyMethod setKey; */ + xmlSecOpenSSLEvpSignatureVerify, /* xmlSecTransformVerifyMethod verify; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecTransformDefaultPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecOpenSSLEvpSignatureExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLTransformRsaSha512GetKlass: + * + * The RSA-SHA512 signature transform klass. + * + * Returns: RSA-SHA512 signature transform klass. + */ +xmlSecTransformId +xmlSecOpenSSLTransformRsaSha512GetKlass(void) { + return(&xmlSecOpenSSLRsaSha512Klass); +} + +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + + + diff --git a/src/openssl/symkeys.c b/src/openssl/symkeys.c new file mode 100644 index 00000000..fdcf2876 --- /dev/null +++ b/src/openssl/symkeys.c @@ -0,0 +1,447 @@ +/** + * + * 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> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <openssl/rand.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/openssl/crypto.h> + +/***************************************************************************** + * + * Symmetic (binary) keys - just a wrapper for xmlSecKeyDataBinary + * + ****************************************************************************/ +static int xmlSecOpenSSLSymKeyDataInitialize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLSymKeyDataDuplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecOpenSSLSymKeyDataFinalize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLSymKeyDataXmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLSymKeyDataXmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLSymKeyDataBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const xmlSecByte* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLSymKeyDataBinWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlSecByte** buf, + xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLSymKeyDataGenerate (xmlSecKeyDataPtr data, + xmlSecSize sizeBits, + xmlSecKeyDataType type); + +static xmlSecKeyDataType xmlSecOpenSSLSymKeyDataGetType (xmlSecKeyDataPtr data); +static xmlSecSize xmlSecOpenSSLSymKeyDataGetSize (xmlSecKeyDataPtr data); +static void xmlSecOpenSSLSymKeyDataDebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecOpenSSLSymKeyDataDebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); +static int xmlSecOpenSSLSymKeyDataKlassCheck (xmlSecKeyDataKlass* klass); + +#define xmlSecOpenSSLSymKeyDataCheckId(data) \ + (xmlSecKeyDataIsValid((data)) && \ + xmlSecOpenSSLSymKeyDataKlassCheck((data)->id)) + +static int +xmlSecOpenSSLSymKeyDataInitialize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataCheckId(data), -1); + + return(xmlSecKeyDataBinaryValueInitialize(data)); +} + +static int +xmlSecOpenSSLSymKeyDataDuplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataCheckId(dst), -1); + xmlSecAssert2(xmlSecOpenSSLSymKeyDataCheckId(src), -1); + xmlSecAssert2(dst->id == src->id, -1); + + return(xmlSecKeyDataBinaryValueDuplicate(dst, src)); +} + +static void +xmlSecOpenSSLSymKeyDataFinalize(xmlSecKeyDataPtr data) { + xmlSecAssert(xmlSecOpenSSLSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueFinalize(data); +} + +static int +xmlSecOpenSSLSymKeyDataXmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlRead(id, key, node, keyInfoCtx)); +} + +static int +xmlSecOpenSSLSymKeyDataXmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueXmlWrite(id, key, node, keyInfoCtx)); +} + +static int +xmlSecOpenSSLSymKeyDataBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinRead(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecOpenSSLSymKeyDataBinWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlSecByte** buf, xmlSecSize* bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataKlassCheck(id), -1); + + return(xmlSecKeyDataBinaryValueBinWrite(id, key, buf, bufSize, keyInfoCtx)); +} + +static int +xmlSecOpenSSLSymKeyDataGenerate(xmlSecKeyDataPtr data, xmlSecSize sizeBits, xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecOpenSSLSymKeyDataCheckId(data), -1); + xmlSecAssert2(sizeBits > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecOpenSSLGenerateRandom(buffer, (sizeBits + 7) / 8)); +} + +static xmlSecKeyDataType +xmlSecOpenSSLSymKeyDataGetType(xmlSecKeyDataPtr data) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecOpenSSLSymKeyDataCheckId(data), xmlSecKeyDataTypeUnknown); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, xmlSecKeyDataTypeUnknown); + + return((xmlSecBufferGetSize(buffer) > 0) ? xmlSecKeyDataTypeSymmetric : xmlSecKeyDataTypeUnknown); +} + +static xmlSecSize +xmlSecOpenSSLSymKeyDataGetSize(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecOpenSSLSymKeyDataCheckId(data), 0); + + return(xmlSecKeyDataBinaryValueGetSize(data)); +} + +static void +xmlSecOpenSSLSymKeyDataDebugDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecOpenSSLSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugDump(data, output); +} + +static void +xmlSecOpenSSLSymKeyDataDebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + xmlSecAssert(xmlSecOpenSSLSymKeyDataCheckId(data)); + + xmlSecKeyDataBinaryValueDebugXmlDump(data, output); +} + +static int +xmlSecOpenSSLSymKeyDataKlassCheck(xmlSecKeyDataKlass* klass) { +#ifndef XMLSEC_NO_DES + if(klass == xmlSecOpenSSLKeyDataDesId) { + return(1); + } +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_AES +#ifndef XMLSEC_OPENSSL_096 + if(klass == xmlSecOpenSSLKeyDataAesId) { + return(1); + } +#endif /* XMLSEC_OPENSSL_096 */ +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_HMAC + if(klass == xmlSecOpenSSLKeyDataHmacId) { + return(1); + } +#endif /* XMLSEC_NO_HMAC */ + + return(0); +} + +#ifndef XMLSEC_NO_AES +#ifndef XMLSEC_OPENSSL_096 +/************************************************************************** + * + * <xmlsec:AESKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataAesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameAESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefAESKeyValue, /* const xmlChar* href; */ + xmlSecNodeAESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecOpenSSLSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecOpenSSLSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecOpenSSLSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecOpenSSLSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecOpenSSLSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecOpenSSLSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecOpenSSLSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecOpenSSLSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecOpenSSLSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecOpenSSLSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecOpenSSLSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecOpenSSLSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataAesGetKlass: + * + * The AES key data klass. + * + * Returns: AES key data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataAesGetKlass(void) { + return(&xmlSecOpenSSLKeyDataAesKlass); +} + +/** + * xmlSecOpenSSLKeyDataAesSet: + * @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 +xmlSecOpenSSLKeyDataAesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataAesId), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} + +#endif /* XMLSEC_OPENSSL_096 */ +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES +/************************************************************************** + * + * <xmlsec:DESKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataDesKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameDESKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefDESKeyValue, /* const xmlChar* href; */ + xmlSecNodeDESKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecOpenSSLSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecOpenSSLSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecOpenSSLSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecOpenSSLSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecOpenSSLSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecOpenSSLSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecOpenSSLSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecOpenSSLSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecOpenSSLSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecOpenSSLSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecOpenSSLSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecOpenSSLSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataDesGetKlass: + * + * The DES key data klass. + * + * Returns: DES key data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataDesGetKlass(void) { + return(&xmlSecOpenSSLKeyDataDesKlass); +} + +/** + * xmlSecOpenSSLKeyDataDesSet: + * @data: the pointer to DES key data. + * @buf: the pointer to key value. + * @bufSize: the key value size (in bytes). + * + * Sets the value of DES key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecOpenSSLKeyDataDesSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataDesId), -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(data); + xmlSecAssert2(buffer != NULL, -1); + + return(xmlSecBufferSetData(buffer, buf, bufSize)); +} + +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_HMAC +/************************************************************************** + * + * <xmlsec:HMACKeyValue> processing + * + *************************************************************************/ +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataHmacKlass = { + sizeof(xmlSecKeyDataKlass), + xmlSecKeyDataBinarySize, + + /* data */ + xmlSecNameHMACKeyValue, + xmlSecKeyDataUsageKeyValueNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefHMACKeyValue, /* const xmlChar* href; */ + xmlSecNodeHMACKeyValue, /* const xmlChar* dataNodeName; */ + xmlSecNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecOpenSSLSymKeyDataInitialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecOpenSSLSymKeyDataDuplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecOpenSSLSymKeyDataFinalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + xmlSecOpenSSLSymKeyDataGenerate, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecOpenSSLSymKeyDataGetType, /* xmlSecKeyDataGetTypeMethod getType; */ + xmlSecOpenSSLSymKeyDataGetSize, /* xmlSecKeyDataGetSizeMethod getSize; */ + NULL, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecOpenSSLSymKeyDataXmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecOpenSSLSymKeyDataXmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + xmlSecOpenSSLSymKeyDataBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + xmlSecOpenSSLSymKeyDataBinWrite, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecOpenSSLSymKeyDataDebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecOpenSSLSymKeyDataDebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataHmacGetKlass: + * + * The HMAC key data klass. + * + * Returns: HMAC key data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataHmacGetKlass(void) { + return(&xmlSecOpenSSLKeyDataHmacKlass); +} + +/** + * xmlSecOpenSSLKeyDataHmacSet: + * @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 +xmlSecOpenSSLKeyDataHmacSet(xmlSecKeyDataPtr data, const xmlSecByte* buf, xmlSecSize bufSize) { + xmlSecBufferPtr buffer; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataHmacId), -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/openssl/x509.c b/src/openssl/x509.c new file mode 100644 index 00000000..74dd4096 --- /dev/null +++ b/src/openssl/x509.c @@ -0,0 +1,2414 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-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 <libxml/tree.h> +#include <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509v3.h> +#include <openssl/asn1.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/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> +#include <xmlsec/openssl/x509.h> + +/************************************************************************* + * + * X509 utility functions + * + ************************************************************************/ +static int xmlSecOpenSSLX509DataNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509CertificateNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509CertificateNodeWrite (X509* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509SubjectNameNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509SubjectNameNodeWrite (X509* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509IssuerSerialNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509IssuerSerialNodeWrite (X509* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509SKINodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509SKINodeWrite (X509* cert, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509CRLNodeRead (xmlSecKeyDataPtr data, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLX509CRLNodeWrite (X509_CRL* crl, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, + xmlSecKeyPtr key, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static X509* xmlSecOpenSSLX509CertDerRead (const xmlSecByte* buf, + xmlSecSize size); +static X509* xmlSecOpenSSLX509CertBase64DerRead (xmlChar* buf); +static xmlChar* xmlSecOpenSSLX509CertBase64DerWrite (X509* cert, + int base64LineWrap); +static X509_CRL* xmlSecOpenSSLX509CrlDerRead (xmlSecByte* buf, + xmlSecSize size); +static X509_CRL* xmlSecOpenSSLX509CrlBase64DerRead (xmlChar* buf); +static xmlChar* xmlSecOpenSSLX509CrlBase64DerWrite (X509_CRL* crl, + int base64LineWrap); +static xmlChar* xmlSecOpenSSLX509NameWrite (X509_NAME* nm); +static xmlChar* xmlSecOpenSSLASN1IntegerWrite (ASN1_INTEGER *asni); +static xmlChar* xmlSecOpenSSLX509SKIWrite (X509* cert); +static void xmlSecOpenSSLX509CertDebugDump (X509* cert, + FILE* output); +static void xmlSecOpenSSLX509CertDebugXmlDump (X509* cert, + FILE* output); +static int xmlSecOpenSSLX509CertGetTime (ASN1_TIME* t, + time_t* res); + +/************************************************************************* + * + * Internal OpenSSL X509 data CTX + * + ************************************************************************/ +typedef struct _xmlSecOpenSSLX509DataCtx xmlSecOpenSSLX509DataCtx, + *xmlSecOpenSSLX509DataCtxPtr; +struct _xmlSecOpenSSLX509DataCtx { + X509* keyCert; + STACK_OF(X509)* certsList; + STACK_OF(X509_CRL)* crlsList; +}; + +/************************************************************************** + * + * <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) > + * + * ----------------------------------------------------------------------- + * + * xmlSecOpenSSLX509DataCtx is located after xmlSecTransform + * + *************************************************************************/ +#define xmlSecOpenSSLX509DataSize \ + (sizeof(xmlSecKeyData) + sizeof(xmlSecOpenSSLX509DataCtx)) +#define xmlSecOpenSSLX509DataGetCtx(data) \ + ((xmlSecOpenSSLX509DataCtxPtr)(((xmlSecByte*)(data)) + sizeof(xmlSecKeyData))) + +static int xmlSecOpenSSLKeyDataX509Initialize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLKeyDataX509Duplicate (xmlSecKeyDataPtr dst, + xmlSecKeyDataPtr src); +static void xmlSecOpenSSLKeyDataX509Finalize (xmlSecKeyDataPtr data); +static int xmlSecOpenSSLKeyDataX509XmlRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static int xmlSecOpenSSLKeyDataX509XmlWrite (xmlSecKeyDataId id, + xmlSecKeyPtr key, + xmlNodePtr node, + xmlSecKeyInfoCtxPtr keyInfoCtx); +static xmlSecKeyDataType xmlSecOpenSSLKeyDataX509GetType (xmlSecKeyDataPtr data); +static const xmlChar* xmlSecOpenSSLKeyDataX509GetIdentifier (xmlSecKeyDataPtr data); + +static void xmlSecOpenSSLKeyDataX509DebugDump (xmlSecKeyDataPtr data, + FILE* output); +static void xmlSecOpenSSLKeyDataX509DebugXmlDump (xmlSecKeyDataPtr data, + FILE* output); + + + +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataX509Klass = { + sizeof(xmlSecKeyDataKlass), + xmlSecOpenSSLX509DataSize, + + /* data */ + xmlSecNameX509Data, + xmlSecKeyDataUsageKeyInfoNode | xmlSecKeyDataUsageRetrievalMethodNodeXml, + /* xmlSecKeyDataUsage usage; */ + xmlSecHrefX509Data, /* const xmlChar* href; */ + xmlSecNodeX509Data, /* const xmlChar* dataNodeName; */ + xmlSecDSigNs, /* const xmlChar* dataNodeNs; */ + + /* constructors/destructor */ + xmlSecOpenSSLKeyDataX509Initialize, /* xmlSecKeyDataInitializeMethod initialize; */ + xmlSecOpenSSLKeyDataX509Duplicate, /* xmlSecKeyDataDuplicateMethod duplicate; */ + xmlSecOpenSSLKeyDataX509Finalize, /* xmlSecKeyDataFinalizeMethod finalize; */ + NULL, /* xmlSecKeyDataGenerateMethod generate; */ + + /* get info */ + xmlSecOpenSSLKeyDataX509GetType, /* xmlSecKeyDataGetTypeMethod getType; */ + NULL, /* xmlSecKeyDataGetSizeMethod getSize; */ + xmlSecOpenSSLKeyDataX509GetIdentifier, /* xmlSecKeyDataGetIdentifier getIdentifier; */ + + /* read/write */ + xmlSecOpenSSLKeyDataX509XmlRead, /* xmlSecKeyDataXmlReadMethod xmlRead; */ + xmlSecOpenSSLKeyDataX509XmlWrite, /* xmlSecKeyDataXmlWriteMethod xmlWrite; */ + NULL, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + xmlSecOpenSSLKeyDataX509DebugDump, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + xmlSecOpenSSLKeyDataX509DebugXmlDump, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataX509GetKlass: + * + * The OpenSSL X509 key data klass (http://www.w3.org/TR/xmldsig-core/#sec-X509Data). + * + * Returns: the X509 data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataX509GetKlass(void) { + return(&xmlSecOpenSSLKeyDataX509Klass); +} + +/** + * xmlSecOpenSSLKeyDataX509GetKeyCert: + * @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. + */ +X509* +xmlSecOpenSSLKeyDataX509GetKeyCert(xmlSecKeyDataPtr data) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), NULL); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + + return(ctx->keyCert); +} + +/** + * xmlSecOpenSSLKeyDataX509AdoptKeyCert: + * @data: the pointer to X509 key data. + * @cert: the pointer to OpenSSL X509 certificate. + * + * Sets the key's certificate in @data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecOpenSSLKeyDataX509AdoptKeyCert(xmlSecKeyDataPtr data, X509* cert) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->keyCert != NULL) { + X509_free(ctx->keyCert); + } + ctx->keyCert = cert; + return(0); +} + +/** + * xmlSecOpenSSLKeyDataX509AdoptCert: + * @data: the pointer to X509 key data. + * @cert: the pointer to OpenSSL X509 certificate. + * + * Adds certificate to the X509 key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecOpenSSLKeyDataX509AdoptCert(xmlSecKeyDataPtr data, X509* cert) { + xmlSecOpenSSLX509DataCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->certsList == NULL) { + ctx->certsList = sk_X509_new_null(); + if(ctx->certsList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "sk_X509_new_null", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ret = sk_X509_push(ctx->certsList, cert); + if(ret < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "sk_X509_push", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLKeyDataX509GetCert: + * @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. + */ +X509* +xmlSecOpenSSLKeyDataX509GetCert(xmlSecKeyDataPtr data, xmlSecSize pos) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), NULL); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->certsList != NULL, NULL); + xmlSecAssert2((int)pos < sk_X509_num(ctx->certsList), NULL); + + return(sk_X509_value(ctx->certsList, pos)); +} + +/** + * xmlSecOpenSSLKeyDataX509GetCertsSize: + * @data: the pointer to X509 key data. + * + * Gets the number of certificates in @data. + * + * Returns: te number of certificates in @data. + */ +xmlSecSize +xmlSecOpenSSLKeyDataX509GetCertsSize(xmlSecKeyDataPtr data) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), 0); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return((ctx->certsList != NULL) ? sk_X509_num(ctx->certsList) : 0); +} + +/** + * xmlSecOpenSSLKeyDataX509AdoptCrl: + * @data: the pointer to X509 key data. + * @crl: the pointer to OpenSSL X509 CRL. + * + * Adds CRL to the X509 key data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecOpenSSLKeyDataX509AdoptCrl(xmlSecKeyDataPtr data, X509_CRL* crl) { + xmlSecOpenSSLX509DataCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(crl != NULL, -1); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->crlsList == NULL) { + ctx->crlsList = sk_X509_CRL_new_null(); + if(ctx->crlsList == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "sk_X509_CRL_new_null", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ret = sk_X509_CRL_push(ctx->crlsList, crl); + if(ret < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "sk_X509_CRL_push", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecOpenSSLKeyDataX509GetCrl: + * @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. + */ +X509_CRL* +xmlSecOpenSSLKeyDataX509GetCrl(xmlSecKeyDataPtr data, xmlSecSize pos) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), NULL); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, NULL); + + xmlSecAssert2(ctx->crlsList != NULL, NULL); + xmlSecAssert2((int)pos < sk_X509_CRL_num(ctx->crlsList), NULL); + + return(sk_X509_CRL_value(ctx->crlsList, pos)); +} + +/** + * xmlSecOpenSSLKeyDataX509GetCrlsSize: + * @data: the pointer to X509 key data. + * + * Gets the number of CRLs in @data. + * + * Returns: te number of CRLs in @data. + */ +xmlSecSize +xmlSecOpenSSLKeyDataX509GetCrlsSize(xmlSecKeyDataPtr data) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), 0); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, 0); + + return((ctx->crlsList != NULL) ? sk_X509_CRL_num(ctx->crlsList) : 0); +} + +static int +xmlSecOpenSSLKeyDataX509Initialize(xmlSecKeyDataPtr data) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLX509DataCtx)); + return(0); +} + +static int +xmlSecOpenSSLKeyDataX509Duplicate(xmlSecKeyDataPtr dst, xmlSecKeyDataPtr src) { + X509* certSrc; + X509* certDst; + X509_CRL* crlSrc; + X509_CRL* crlDst; + xmlSecSize size, pos; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(dst, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(xmlSecKeyDataCheckId(src, xmlSecOpenSSLKeyDataX509Id), -1); + + /* copy certsList */ + size = xmlSecOpenSSLKeyDataX509GetCertsSize(src); + for(pos = 0; pos < size; ++pos) { + certSrc = xmlSecOpenSSLKeyDataX509GetCert(src, pos); + if(certSrc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)), + "xmlSecOpenSSLKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + certDst = X509_dup(certSrc); + if(certDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(dst, certDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(certDst); + return(-1); + } + } + + /* copy crls */ + size = xmlSecOpenSSLKeyDataX509GetCrlsSize(src); + for(pos = 0; pos < size; ++pos) { + crlSrc = xmlSecOpenSSLKeyDataX509GetCrl(src, pos); + if(crlSrc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(src)), + "xmlSecOpenSSLKeyDataX509GetCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + crlDst = X509_CRL_dup(crlSrc); + if(crlDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "X509_CRL_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCrl(dst, crlDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecOpenSSLKeyDataX509AdoptCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_CRL_free(crlDst); + return(-1); + } + } + + /* copy key cert if exist */ + certSrc = xmlSecOpenSSLKeyDataX509GetKeyCert(src); + if(certSrc != NULL) { + certDst = X509_dup(certSrc); + if(certDst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ret = xmlSecOpenSSLKeyDataX509AdoptKeyCert(dst, certDst); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(dst)), + "xmlSecOpenSSLKeyDataX509AdoptKeyCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(certDst); + return(-1); + } + } + return(0); +} + +static void +xmlSecOpenSSLKeyDataX509Finalize(xmlSecKeyDataPtr data) { + xmlSecOpenSSLX509DataCtxPtr ctx; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id)); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert(ctx != NULL); + + if(ctx->certsList != NULL) { + sk_X509_pop_free(ctx->certsList, X509_free); + } + if(ctx->crlsList != NULL) { + sk_X509_CRL_pop_free(ctx->crlsList, X509_CRL_free); + } + if(ctx->keyCert != NULL) { + X509_free(ctx->keyCert); + } + memset(ctx, 0, sizeof(xmlSecOpenSSLX509DataCtx)); +} + +static int +xmlSecOpenSSLKeyDataX509XmlRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataX509Id, -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 = xmlSecOpenSSLX509DataNodeRead(data, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLX509DataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_X509DATA_DONT_VERIFY_CERTS) == 0) { + ret = xmlSecOpenSSLKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLKeyDataX509VerifyAndExtractKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +static int +xmlSecOpenSSLKeyDataX509XmlWrite(xmlSecKeyDataId id, xmlSecKeyPtr key, + xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + X509* cert; + X509_CRL* crl; + xmlSecSize size, pos; + int content; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataX509Id, -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 = xmlSecOpenSSLKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecOpenSSLKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + if((content & XMLSEC_X509DATA_CERTIFICATE_NODE) != 0) { + ret = xmlSecOpenSSLX509CertificateNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLX509CertificateNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_SUBJECTNAME_NODE) != 0) { + ret = xmlSecOpenSSLX509SubjectNameNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLX509SubjectNameNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_ISSUERSERIAL_NODE) != 0) { + ret = xmlSecOpenSSLX509IssuerSerialNodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLX509IssuerSerialNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + + if((content & XMLSEC_X509DATA_SKI_NODE) != 0) { + ret = xmlSecOpenSSLX509SKINodeWrite(cert, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLX509SKINodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + } + + /* write crls if needed */ + if((content & XMLSEC_X509DATA_CRL_NODE) != 0) { + size = xmlSecOpenSSLKeyDataX509GetCrlsSize(data); + for(pos = 0; pos < size; ++pos) { + crl = xmlSecOpenSSLKeyDataX509GetCrl(data, pos); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLKeyDataX509GetCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + + ret = xmlSecOpenSSLX509CRLNodeWrite(crl, node, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLX509CRLNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return(-1); + } + } + } + + return(0); +} + + +static xmlSecKeyDataType +xmlSecOpenSSLKeyDataX509GetType(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), xmlSecKeyDataTypeUnknown); + + /* TODO: return verified/not verified status */ + return(xmlSecKeyDataTypeUnknown); +} + +static const xmlChar* +xmlSecOpenSSLKeyDataX509GetIdentifier(xmlSecKeyDataPtr data) { + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), NULL); + + /* TODO */ + return(NULL); +} + +static void +xmlSecOpenSSLKeyDataX509DebugDump(xmlSecKeyDataPtr data, FILE* output) { + X509* cert; + xmlSecSize size, pos; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== X509 Data:\n"); + cert = xmlSecOpenSSLKeyDataX509GetKeyCert(data); + if(cert != NULL) { + fprintf(output, "==== Key Certificate:\n"); + xmlSecOpenSSLX509CertDebugDump(cert, output); + } + + size = xmlSecOpenSSLKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecOpenSSLKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return; + } + fprintf(output, "==== Certificate:\n"); + xmlSecOpenSSLX509CertDebugDump(cert, output); + } + + /* we don't print out crls */ +} + +static void +xmlSecOpenSSLKeyDataX509DebugXmlDump(xmlSecKeyDataPtr data, FILE* output) { + X509* cert; + xmlSecSize size, pos; + + xmlSecAssert(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id)); + xmlSecAssert(output != NULL); + + fprintf(output, "<X509Data>\n"); + cert = xmlSecOpenSSLKeyDataX509GetKeyCert(data); + if(cert != NULL) { + fprintf(output, "<KeyCertificate>\n"); + xmlSecOpenSSLX509CertDebugXmlDump(cert, output); + fprintf(output, "</KeyCertificate>\n"); + } + + size = xmlSecOpenSSLKeyDataX509GetCertsSize(data); + for(pos = 0; pos < size; ++pos) { + cert = xmlSecOpenSSLKeyDataX509GetCert(data, pos); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509GetCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + return; + } + fprintf(output, "<Certificate>\n"); + xmlSecOpenSSLX509CertDebugXmlDump(cert, output); + fprintf(output, "</Certificate>\n"); + } + + /* we don't print out crls */ + fprintf(output, "</X509Data>\n"); +} + +static int +xmlSecOpenSSLX509DataNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -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 = xmlSecOpenSSLX509CertificateNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) { + ret = xmlSecOpenSSLX509SubjectNameNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) { + ret = xmlSecOpenSSLX509IssuerSerialNodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) { + ret = xmlSecOpenSSLX509SKINodeRead(data, cur, keyInfoCtx); + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) { + ret = xmlSecOpenSSLX509CRLNodeRead(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 +xmlSecOpenSSLX509CertificateNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar *content; + X509* cert; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -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 = xmlSecOpenSSLX509CertBase64DerRead(content); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLX509CertBase64DerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert); + xmlFree(content); + return(-1); + } + + xmlFree(content); + return(0); +} + +static int +xmlSecOpenSSLX509CertificateNodeWrite(X509* 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 = xmlSecOpenSSLX509CertBase64DerWrite(cert, keyInfoCtx->base64LineSize); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509CertBase64DerWrite", + 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 +xmlSecOpenSSLX509SubjectNameNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlChar* subject; + X509* cert; + X509* cert2; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecOpenSSLX509StoreId); + 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 = xmlSecOpenSSLX509StoreFindCert(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); + } + + cert2 = X509_dup(cert); + if(cert2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + + xmlFree(subject); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(data, cert2); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert2); + xmlFree(subject); + return(-1); + } + + xmlFree(subject); + return(0); +} + +static int +xmlSecOpenSSLX509SubjectNameNodeWrite(X509* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlChar* buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + buf = xmlSecOpenSSLX509NameWrite(X509_get_subject_name(cert)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameWrite(X509_get_subject_name)", + 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 +xmlSecOpenSSLX509IssuerSerialNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlNodePtr cur; + xmlChar *issuerName; + xmlChar *issuerSerial; + X509* cert; + X509* cert2; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecOpenSSLX509StoreId); + 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 = xmlSecOpenSSLX509StoreFindCert(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); + } + + cert2 = X509_dup(cert); + if(cert2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(issuerSerial); + xmlFree(issuerName); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(data, cert2); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert2); + xmlFree(issuerSerial); + xmlFree(issuerName); + return(-1); + } + + xmlFree(issuerSerial); + xmlFree(issuerName); + return(0); +} + +static int +xmlSecOpenSSLX509IssuerSerialNodeWrite(X509* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlNodePtr cur; + xmlNodePtr issuerNameNode; + xmlNodePtr issuerNumberNode; + xmlChar* buf; + + 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 = xmlSecOpenSSLX509NameWrite(X509_get_issuer_name(cert)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameWrite(X509_get_issuer_name)", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecNodeEncodeAndSetContent(issuerNameNode, buf); + xmlFree(buf); + + buf = xmlSecOpenSSLASN1IntegerWrite(X509_get_serialNumber(cert)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLASN1IntegerWrite(X509_get_serialNumber)", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecNodeEncodeAndSetContent(issuerNumberNode, buf); + xmlFree(buf); + + return(0); +} + + +static int +xmlSecOpenSSLX509SKINodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataStorePtr x509Store; + xmlChar* ski; + X509* cert; + X509* cert2; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecOpenSSLX509StoreId); + 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 = xmlSecOpenSSLX509StoreFindCert(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); + } + + cert2 = X509_dup(cert); + if(cert2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(ski); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(data, cert2); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert2); + xmlFree(ski); + return(-1); + } + + xmlFree(ski); + return(0); +} + +static int +xmlSecOpenSSLX509SKINodeWrite(X509* cert, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx ATTRIBUTE_UNUSED) { + xmlChar *buf = NULL; + xmlNodePtr cur = NULL; + + xmlSecAssert2(cert != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + buf = xmlSecOpenSSLX509SKIWrite(cert); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509SKIWrite", + 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 +xmlSecOpenSSLX509CRLNodeRead(xmlSecKeyDataPtr data, xmlNodePtr node, xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlChar *content; + X509_CRL* crl; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -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 = xmlSecOpenSSLX509CrlBase64DerRead(content); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLX509CrlBase64DerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(content); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCrl(data, crl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLKeyDataX509AdoptCrl", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_CRL_free(crl); + xmlFree(content); + return(-1); + } + + xmlFree(content); + return(0); +} + +static int +xmlSecOpenSSLX509CRLNodeWrite(X509_CRL* 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 = xmlSecOpenSSLX509CrlBase64DerWrite(crl, keyInfoCtx->base64LineSize); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509CrlBase64DerWrite", + 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 +xmlSecOpenSSLKeyDataX509VerifyAndExtractKey(xmlSecKeyDataPtr data, xmlSecKeyPtr key, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecOpenSSLX509DataCtxPtr ctx; + xmlSecKeyDataStorePtr x509Store; + int ret; + + xmlSecAssert2(xmlSecKeyDataCheckId(data, xmlSecOpenSSLKeyDataX509Id), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + xmlSecAssert2(keyInfoCtx->keysMngr != NULL, -1); + + ctx = xmlSecOpenSSLX509DataGetCtx(data); + xmlSecAssert2(ctx != NULL, -1); + + x509Store = xmlSecKeysMngrGetDataStore(keyInfoCtx->keysMngr, xmlSecOpenSSLX509StoreId); + 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) && (ctx->certsList != NULL) && (xmlSecKeyGetValue(key) == NULL)) { + X509* cert; + + cert = xmlSecOpenSSLX509StoreVerify(x509Store, ctx->certsList, ctx->crlsList, keyInfoCtx); + if(cert != NULL) { + xmlSecKeyDataPtr keyValue; + + ctx->keyCert = X509_dup(cert); + if(ctx->keyCert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + keyValue = xmlSecOpenSSLX509CertGetKey(ctx->keyCert); + if(keyValue == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLX509CertGetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* 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); + } + + if((X509_get_notBefore(ctx->keyCert) != NULL) && (X509_get_notAfter(ctx->keyCert) != NULL)) { + ret = xmlSecOpenSSLX509CertGetTime(X509_get_notBefore(ctx->keyCert), &(key->notValidBefore)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLX509CertGetTime", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "notValidBefore"); + return(-1); + } + ret = xmlSecOpenSSLX509CertGetTime(X509_get_notAfter(ctx->keyCert), &(key->notValidAfter)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataGetName(data)), + "xmlSecOpenSSLX509CertGetTime", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "notValidAfter"); + return(-1); + } + } else { + key->notValidBefore = key->notValidAfter = 0; + } + } 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); +} + +#ifdef HAVE_TIMEGM +extern time_t timegm (struct tm *tm); +#else /* HAVE_TIMEGM */ +#ifdef WIN32 +#define timegm(tm) (mktime(tm) - _timezone) +#else /* WIN32 */ +/* Absolutely not the best way but it's the only ANSI compatible way I know. + * If you system has a native struct tm --> GMT time_t conversion function + * (like timegm) use it instead. + */ +static time_t +my_timegm(struct tm *t) { + time_t tl, tb; + struct tm *tg; + + tl = mktime (t); + if(tl == -1) { + t->tm_hour--; + tl = mktime (t); + if (tl == -1) { + return -1; + } + tl += 3600; + } + tg = gmtime (&tl); + tg->tm_isdst = 0; + tb = mktime (tg); + if (tb == -1) { + tg->tm_hour--; + tb = mktime (tg); + if (tb == -1) { + return -1; + } + tb += 3600; + } + return (tl - (tb - tl)); +} + +#define timegm(tm) my_timegm(tm) +#endif /* WIN32 */ +#endif /* HAVE_TIMEGM */ + +static int +xmlSecOpenSSLX509CertGetTime(ASN1_TIME* t, time_t* res) { + struct tm tm; + int offset; + + xmlSecAssert2(t != NULL, -1); + xmlSecAssert2(res != NULL, -1); + + (*res) = 0; +#ifndef XMLSEC_OPENSSL_096 + if(!ASN1_TIME_check(t)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "ASN1_TIME_check", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#endif /* XMLSEC_OPENSSL_096 */ + + memset(&tm, 0, sizeof(tm)); + +#define g2(p) (((p)[0]-'0')*10+(p)[1]-'0') + if(t->type == V_ASN1_UTCTIME) { + xmlSecAssert2(t->length > 12, -1); + + + /* this code is copied from OpenSSL asn1/a_utctm.c file */ + tm.tm_year = g2(t->data); + if(tm.tm_year < 50) { + tm.tm_year += 100; + } + tm.tm_mon = g2(t->data + 2) - 1; + tm.tm_mday = g2(t->data + 4); + tm.tm_hour = g2(t->data + 6); + tm.tm_min = g2(t->data + 8); + tm.tm_sec = g2(t->data + 10); + if(t->data[12] == 'Z') { + offset = 0; + } else { + xmlSecAssert2(t->length > 16, -1); + + offset = g2(t->data + 13) * 60 + g2(t->data + 15); + if(t->data[12] == '-') { + offset = -offset; + } + } + tm.tm_isdst = -1; + } else { + xmlSecAssert2(t->length > 14, -1); + + tm.tm_year = g2(t->data) * 100 + g2(t->data + 2); + tm.tm_mon = g2(t->data + 4) - 1; + tm.tm_mday = g2(t->data + 6); + tm.tm_hour = g2(t->data + 8); + tm.tm_min = g2(t->data + 10); + tm.tm_sec = g2(t->data + 12); + if(t->data[14] == 'Z') { + offset = 0; + } else { + xmlSecAssert2(t->length > 18, -1); + + offset = g2(t->data + 15) * 60 + g2(t->data + 17); + if(t->data[14] == '-') { + offset = -offset; + } + } + tm.tm_isdst = -1; + } +#undef g2 + (*res) = timegm(&tm) - offset * 60; + return(0); +} + +/** + * xmlSecOpenSSLX509CertGetKey: + * @cert: the certificate. + * + * Extracts public key from the @cert. + * + * Returns: public key value or NULL if an error occurs. + */ +xmlSecKeyDataPtr +xmlSecOpenSSLX509CertGetKey(X509* cert) { + xmlSecKeyDataPtr data; + EVP_PKEY *pKey = NULL; + + xmlSecAssert2(cert != NULL, NULL); + + pKey = X509_get_pubkey(cert); + if(pKey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_get_pubkey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + data = xmlSecOpenSSLEvpKeyAdopt(pKey); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLEvpKeyAdopt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + EVP_PKEY_free(pKey); + return(NULL); + } + + return(data); +} + +static X509* +xmlSecOpenSSLX509CertBase64DerRead(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(xmlSecOpenSSLX509CertDerRead((xmlSecByte*)buf, ret)); +} + +static X509* +xmlSecOpenSSLX509CertDerRead(const xmlSecByte* buf, xmlSecSize size) { + X509 *cert = NULL; + BIO *mem = NULL; + int ret; + + xmlSecAssert2(buf != NULL, NULL); + xmlSecAssert2(size > 0, NULL); + + mem = BIO_new(BIO_s_mem()); + if(mem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "BIO_s_mem"); + return(NULL); + } + + ret = BIO_write(mem, buf, size); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_write", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", size); + BIO_free_all(mem); + return(NULL); + } + + cert = d2i_X509_bio(mem, NULL); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "d2i_X509_bio", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free_all(mem); + return(NULL); + } + + BIO_free_all(mem); + return(cert); +} + +static xmlChar* +xmlSecOpenSSLX509CertBase64DerWrite(X509* cert, int base64LineWrap) { + xmlChar *res = NULL; + BIO *mem = NULL; + xmlSecByte *p = NULL; + long size; + + xmlSecAssert2(cert != NULL, NULL); + + mem = BIO_new(BIO_s_mem()); + if(mem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "BIO_s_mem"); + return(NULL); + } + + /* todo: add error checks */ + i2d_X509_bio(mem, cert); + BIO_flush(mem); + + size = BIO_get_mem_data(mem, &p); + if((size <= 0) || (p == NULL)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_get_mem_data", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free_all(mem); + 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); + BIO_free_all(mem); + return(NULL); + } + + BIO_free_all(mem); + return(res); +} + +static X509_CRL* +xmlSecOpenSSLX509CrlBase64DerRead(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(xmlSecOpenSSLX509CrlDerRead((xmlSecByte*)buf, ret)); +} + +static X509_CRL* +xmlSecOpenSSLX509CrlDerRead(xmlSecByte* buf, xmlSecSize size) { + X509_CRL *crl = NULL; + BIO *mem = NULL; + int ret; + + xmlSecAssert2(buf != NULL, NULL); + xmlSecAssert2(size > 0, NULL); + + mem = BIO_new(BIO_s_mem()); + if(mem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "BIO_s_mem"); + return(NULL); + } + + ret = BIO_write(mem, buf, size); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_write", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "size=%d", size); + BIO_free_all(mem); + return(NULL); + } + + crl = d2i_X509_CRL_bio(mem, NULL); + if(crl == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "d2i_X509_CRL_bio", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free_all(mem); + return(NULL); + } + + BIO_free_all(mem); + return(crl); +} + +static xmlChar* +xmlSecOpenSSLX509CrlBase64DerWrite(X509_CRL* crl, int base64LineWrap) { + xmlChar *res = NULL; + BIO *mem = NULL; + xmlSecByte *p = NULL; + long size; + + xmlSecAssert2(crl != NULL, NULL); + + mem = BIO_new(BIO_s_mem()); + if(mem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "BIO_s_mem"); + return(NULL); + } + + /* todo: add error checks */ + i2d_X509_CRL_bio(mem, crl); + BIO_flush(mem); + + size = BIO_get_mem_data(mem, &p); + if((size <= 0) || (p == NULL)){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_get_mem_data", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free_all(mem); + 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); + BIO_free_all(mem); + return(NULL); + } + + BIO_free_all(mem); + return(res); +} + +static xmlChar* +xmlSecOpenSSLX509NameWrite(X509_NAME* nm) { + xmlChar *res = NULL; + BIO *mem = NULL; + long size; + + xmlSecAssert2(nm != NULL, NULL); + + mem = BIO_new(BIO_s_mem()); + if(mem == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BIO_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "BIO_s_mem"); + return(NULL); + } + + if (X509_NAME_print_ex(mem, nm, 0, XN_FLAG_RFC2253) <=0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_NAME_print_ex", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free_all(mem); + return(NULL); + } + + BIO_flush(mem); /* should call flush ? */ + + size = BIO_pending(mem); + res = xmlMalloc(size + 1); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BIO_free_all(mem); + return(NULL); + } + + size = BIO_read(mem, res, size); + res[size] = '\0'; + + BIO_free_all(mem); + return(res); +} + +static xmlChar* +xmlSecOpenSSLASN1IntegerWrite(ASN1_INTEGER *asni) { + xmlChar *res = NULL; + BIGNUM *bn; + char *p; + + xmlSecAssert2(asni != NULL, NULL); + + bn = ASN1_INTEGER_to_BN(asni, NULL); + if(bn == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "ASN1_INTEGER_to_BN", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + p = BN_bn2dec(bn); + if (p == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_bn2dec", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BN_free(bn); + return(NULL); + } + BN_free(bn); + bn = NULL; + + /* OpenSSL and LibXML2 can have different memory callbacks, i.e. + when data is allocated in OpenSSL should be freed with OpenSSL + method, not with LibXML2 method. + */ + res = xmlCharStrdup(p); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlCharStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + OPENSSL_free(p); + return(NULL); + } + OPENSSL_free(p); + p = NULL; + return(res); +} + +static xmlChar* +xmlSecOpenSSLX509SKIWrite(X509* cert) { + xmlChar *res = NULL; + int index; + X509_EXTENSION *ext; + ASN1_OCTET_STRING *keyId; + + xmlSecAssert2(cert != NULL, NULL); + + index = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); + if (index < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "Certificate without SubjectKeyIdentifier extension", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + ext = X509_get_ext(cert, index); + if (ext == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_get_ext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + keyId = X509V3_EXT_d2i(ext); + if (keyId == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509V3_EXT_d2i", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + M_ASN1_OCTET_STRING_free(keyId); + return(NULL); + } + + res = xmlSecBase64Encode(M_ASN1_STRING_data(keyId), M_ASN1_STRING_length(keyId), 0); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + M_ASN1_OCTET_STRING_free(keyId); + return(NULL); + } + M_ASN1_OCTET_STRING_free(keyId); + + return(res); +} + +static void +xmlSecOpenSSLX509CertDebugDump(X509* cert, FILE* output) { + char buf[1024]; + BIGNUM *bn = NULL; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "==== Subject Name: %s\n", + X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf))); + fprintf(output, "==== Issuer Name: %s\n", + X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf))); + fprintf(output, "==== Issuer Serial: "); + bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert),NULL); + if(bn != NULL) { + BN_print_fp(output, bn); + BN_free(bn); + fprintf(output, "\n"); + } else { + fprintf(output, "unknown\n"); + } +} + + +static void +xmlSecOpenSSLX509CertDebugXmlDump(X509* cert, FILE* output) { + char buf[1024]; + BIGNUM *bn = NULL; + + xmlSecAssert(cert != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "<SubjectName>"); + xmlSecPrintXmlString(output, + BAD_CAST X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)) + ); + fprintf(output, "</SubjectName>\n"); + + + fprintf(output, "<IssuerName>"); + xmlSecPrintXmlString(output, + BAD_CAST X509_NAME_oneline(X509_get_issuer_name(cert), buf, sizeof(buf))); + fprintf(output, "</IssuerName>\n"); + + fprintf(output, "<SerialNumber>"); + bn = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert),NULL); + if(bn != NULL) { + BN_print_fp(output, bn); + BN_free(bn); + } + fprintf(output, "</SerialNumber>\n"); +} + + +/************************************************************************** + * + * Raw X509 Certificate processing + * + * + *************************************************************************/ +static int xmlSecOpenSSLKeyDataRawX509CertBinRead (xmlSecKeyDataId id, + xmlSecKeyPtr key, + const xmlSecByte* buf, + xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx); + +static xmlSecKeyDataKlass xmlSecOpenSSLKeyDataRawX509CertKlass = { + 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; */ + xmlSecOpenSSLKeyDataRawX509CertBinRead, /* xmlSecKeyDataBinReadMethod binRead; */ + NULL, /* xmlSecKeyDataBinWriteMethod binWrite; */ + + /* debug */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugDump; */ + NULL, /* xmlSecKeyDataDebugDumpMethod debugXmlDump; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecOpenSSLKeyDataRawX509CertGetKlass: + * + * The raw X509 certificates key data klass. + * + * Returns: raw X509 certificates key data klass. + */ +xmlSecKeyDataId +xmlSecOpenSSLKeyDataRawX509CertGetKlass(void) { + return(&xmlSecOpenSSLKeyDataRawX509CertKlass); +} + +static int +xmlSecOpenSSLKeyDataRawX509CertBinRead(xmlSecKeyDataId id, xmlSecKeyPtr key, + const xmlSecByte* buf, xmlSecSize bufSize, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlSecKeyDataPtr data; + X509* cert; + int ret; + + xmlSecAssert2(id == xmlSecOpenSSLKeyDataRawX509CertId, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(bufSize > 0, -1); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + cert = xmlSecOpenSSLX509CertDerRead(buf, bufSize); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509CertDerRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + data = xmlSecKeyEnsureData(key, xmlSecOpenSSLKeyDataX509Id); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecKeyEnsureData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509AdoptCert(data, cert); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLKeyDataX509AdoptCert", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_free(cert); + return(-1); + } + + ret = xmlSecOpenSSLKeyDataX509VerifyAndExtractKey(data, key, keyInfoCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataKlassGetName(id)), + "xmlSecOpenSSLKeyDataX509VerifyAndExtractKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +#endif /* XMLSEC_NO_X509 */ diff --git a/src/openssl/x509vfy.c b/src/openssl/x509vfy.c new file mode 100644 index 00000000..3b6c6af8 --- /dev/null +++ b/src/openssl/x509vfy.c @@ -0,0 +1,1286 @@ +/** + * XMLSec library + * + * X509 support + * + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-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 <openssl/evp.h> +#include <openssl/x509.h> +#include <openssl/x509_vfy.h> +#include <openssl/x509v3.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/errors.h> + +#include <xmlsec/openssl/crypto.h> +#include <xmlsec/openssl/evp.h> +#include <xmlsec/openssl/x509.h> + +/************************************************************************** + * + * Internal OpenSSL X509 store CTX + * + *************************************************************************/ +typedef struct _xmlSecOpenSSLX509StoreCtx xmlSecOpenSSLX509StoreCtx, + *xmlSecOpenSSLX509StoreCtxPtr; +struct _xmlSecOpenSSLX509StoreCtx { + X509_STORE* xst; + STACK_OF(X509)* untrusted; + STACK_OF(X509_CRL)* crls; + +#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) + X509_VERIFY_PARAM * vpm; +#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ +}; + +/**************************************************************************** + * + * xmlSecOpenSSLKeyDataStoreX509Id: + * + * xmlSecOpenSSLX509StoreCtx is located after xmlSecTransform + * + ***************************************************************************/ +#define xmlSecOpenSSLX509StoreGetCtx(store) \ + ((xmlSecOpenSSLX509StoreCtxPtr)(((xmlSecByte*)(store)) + \ + sizeof(xmlSecKeyDataStoreKlass))) +#define xmlSecOpenSSLX509StoreSize \ + (sizeof(xmlSecKeyDataStoreKlass) + sizeof(xmlSecOpenSSLX509StoreCtx)) + +static int xmlSecOpenSSLX509StoreInitialize (xmlSecKeyDataStorePtr store); +static void xmlSecOpenSSLX509StoreFinalize (xmlSecKeyDataStorePtr store); + +static xmlSecKeyDataStoreKlass xmlSecOpenSSLX509StoreKlass = { + sizeof(xmlSecKeyDataStoreKlass), + xmlSecOpenSSLX509StoreSize, + + /* data */ + xmlSecNameX509Store, /* const xmlChar* name; */ + + /* constructors/destructor */ + xmlSecOpenSSLX509StoreInitialize, /* xmlSecKeyDataStoreInitializeMethod initialize; */ + xmlSecOpenSSLX509StoreFinalize, /* xmlSecKeyDataStoreFinalizeMethod finalize; */ + + /* reserved for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static int xmlSecOpenSSLX509VerifyCRL (X509_STORE* xst, + X509_CRL *crl ); +static X509* xmlSecOpenSSLX509FindCert (STACK_OF(X509) *certs, + xmlChar *subjectName, + xmlChar *issuerName, + xmlChar *issuerSerial, + xmlChar *ski); +static X509* xmlSecOpenSSLX509FindNextChainCert (STACK_OF(X509) *chain, + X509 *cert); +static int xmlSecOpenSSLX509VerifyCertAgainstCrls (STACK_OF(X509_CRL) *crls, + X509* cert); +static X509_NAME* xmlSecOpenSSLX509NameRead (xmlSecByte *str, + int len); +static int xmlSecOpenSSLX509NameStringRead (xmlSecByte **str, + int *strLen, + xmlSecByte *res, + int resLen, + xmlSecByte delim, + int ingoreTrailingSpaces); +static int xmlSecOpenSSLX509NamesCompare (X509_NAME *a, + X509_NAME *b); +static int xmlSecOpenSSLX509_NAME_cmp (const X509_NAME *a, + const X509_NAME *b); +static int xmlSecOpenSSLX509_NAME_ENTRY_cmp (const X509_NAME_ENTRY **a, + const X509_NAME_ENTRY **b); + +/** + * xmlSecOpenSSLX509StoreGetKlass: + * + * The OpenSSL X509 certificates key data store klass. + * + * Returns: pointer to OpenSSL X509 certificates key data store klass. + */ +xmlSecKeyDataStoreId +xmlSecOpenSSLX509StoreGetKlass(void) { + return(&xmlSecOpenSSLX509StoreKlass); +} + +/** + * xmlSecOpenSSLX509StoreFindCert: + * @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. + */ +X509* +xmlSecOpenSSLX509StoreFindCert(xmlSecKeyDataStorePtr store, xmlChar *subjectName, + xmlChar *issuerName, xmlChar *issuerSerial, + xmlChar *ski, xmlSecKeyInfoCtx* keyInfoCtx) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + X509* res = NULL; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, NULL); + + if((res == NULL) && (ctx->untrusted != NULL)) { + res = xmlSecOpenSSLX509FindCert(ctx->untrusted, subjectName, issuerName, issuerSerial, ski); + } + return(res); +} + +/** + * xmlSecOpenSSLX509StoreVerify: + * @store: the pointer to X509 key data store klass. + * @certs: the untrusted certificates stack. + * @crls: the crls stack. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. + * + * Verifies @certs list. + * + * Returns: pointer to the first verified certificate from @certs. + */ +X509* +xmlSecOpenSSLX509StoreVerify(xmlSecKeyDataStorePtr store, XMLSEC_STACK_OF_X509* certs, + XMLSEC_STACK_OF_X509_CRL* crls, xmlSecKeyInfoCtx* keyInfoCtx) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + STACK_OF(X509)* certs2 = NULL; + STACK_OF(X509_CRL)* crls2 = NULL; + X509* res = NULL; + X509* cert; + X509 *err_cert = NULL; + char buf[256]; + int err = 0, depth; + int i; + int ret; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), NULL); + xmlSecAssert2(certs != NULL, NULL); + xmlSecAssert2(keyInfoCtx != NULL, NULL); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->xst != NULL, NULL); + + /* dup certs */ + certs2 = sk_X509_dup(certs); + if(certs2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* add untrusted certs from the store */ + if(ctx->untrusted != NULL) { + for(i = 0; i < sk_X509_num(ctx->untrusted); ++i) { + ret = sk_X509_push(certs2, sk_X509_value(ctx->untrusted, i)); + if(ret < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_push", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + } + + /* dup crls but remove all non-verified */ + if(crls != NULL) { + crls2 = sk_X509_CRL_dup(crls); + if(crls2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_CRL_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + for(i = 0; i < sk_X509_CRL_num(crls2); ) { + ret = xmlSecOpenSSLX509VerifyCRL(ctx->xst, sk_X509_CRL_value(crls2, i)); + if(ret == 1) { + ++i; + } else if(ret == 0) { + sk_X509_CRL_delete(crls2, i); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "xmlSecOpenSSLX509VerifyCRL", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + } + + /* remove all revoked certs */ + for(i = 0; i < sk_X509_num(certs2);) { + cert = sk_X509_value(certs2, i); + + if(crls2 != NULL) { + ret = xmlSecOpenSSLX509VerifyCertAgainstCrls(crls2, cert); + if(ret == 0) { + sk_X509_delete(certs2, i); + continue; + } else if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "xmlSecOpenSSLX509VerifyCertAgainstCrls", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + + if(ctx->crls != NULL) { + ret = xmlSecOpenSSLX509VerifyCertAgainstCrls(ctx->crls, cert); + if(ret == 0) { + sk_X509_delete(certs2, i); + continue; + } else if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "xmlSecOpenSSLX509VerifyCertAgainstCrls", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + } + ++i; + } + + /* get one cert after another and try to verify */ + for(i = 0; i < sk_X509_num(certs2); ++i) { + cert = sk_X509_value(certs2, i); + if(xmlSecOpenSSLX509FindNextChainCert(certs2, cert) == NULL) { + X509_STORE_CTX xsc; + +#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) + X509_VERIFY_PARAM * vpm = NULL; + unsigned long vpm_flags = 0; + + vpm = X509_VERIFY_PARAM_new(); + if(vpm == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_VERIFY_PARAM_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + vpm_flags = vpm->flags; +/* + vpm_flags &= (~X509_V_FLAG_X509_STRICT); +*/ + vpm_flags &= (~X509_V_FLAG_CRL_CHECK); + + X509_VERIFY_PARAM_set_depth(vpm, 9); + X509_VERIFY_PARAM_set_flags(vpm, vpm_flags); +#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ + + X509_STORE_CTX_init (&xsc, ctx->xst, cert, certs2); + + if(keyInfoCtx->certsVerificationTime > 0) { +#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) + vpm_flags |= X509_V_FLAG_USE_CHECK_TIME; + X509_VERIFY_PARAM_set_time(vpm, keyInfoCtx->certsVerificationTime); +#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ + X509_STORE_CTX_set_time(&xsc, 0, keyInfoCtx->certsVerificationTime); + } + +#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) + X509_STORE_CTX_set0_param(&xsc, vpm); +#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ + + ret = X509_verify_cert(&xsc); + err_cert = X509_STORE_CTX_get_current_cert(&xsc); + err = X509_STORE_CTX_get_error(&xsc); + depth = X509_STORE_CTX_get_error_depth(&xsc); + X509_STORE_CTX_cleanup (&xsc); + + if(ret != 1 && keyInfoCtx->flags & XMLSEC_KEYINFO_FLAGS_ALLOW_BROKEN_CHAIN){ + ret = 1; + keyInfoCtx->flags2 |= XMLSEC_KEYINFO_ERROR_FLAGS_BROKEN_CHAIN; + } + + if(ret == 1) { + res = cert; + goto done; + } else if(ret < 0) { + const char* err_msg; + + buf[0] = '\0'; + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf); + err_msg = X509_verify_cert_error_string(err); + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_verify_cert", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "subj=%s;err=%d;msg=%s", + xmlSecErrorsSafeString(buf), + err, + xmlSecErrorsSafeString(err_msg)); + goto done; + } else if(ret == 0) { + const char* err_msg; + + buf[0] = '\0'; + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf); + err_msg = X509_verify_cert_error_string(err); + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_verify_cert", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "subj=%s;err=%d;msg=%s", + xmlSecErrorsSafeString(buf), + err, + xmlSecErrorsSafeString(err_msg)); + } + } + } + + /* if we came here then we found nothing. do we have any error? */ + if((err != 0) && (err_cert != NULL)) { + const char* err_msg; + + err_msg = X509_verify_cert_error_string(err); + switch (err) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, sizeof buf); + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_ISSUER_FAILED, + "err=%d;msg=%s;issuer=%s", + err, + xmlSecErrorsSafeString(err_msg), + xmlSecErrorsSafeString(buf)); + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_NOT_YET_VALID, + "err=%d;msg=%s", err, + xmlSecErrorsSafeString(err_msg)); + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, + "err=%d;msg=%s", err, + xmlSecErrorsSafeString(err_msg)); + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + NULL, + XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, + "err=%d;msg=%s", err, + xmlSecErrorsSafeString(err_msg)); + } + } + +done: + if(certs2 != NULL) { + sk_X509_free(certs2); + } + if(crls2 != NULL) { + sk_X509_CRL_free(crls2); + } + return(res); +} + +/** + * xmlSecOpenSSLX509StoreAdoptCert: + * @store: the pointer to X509 key data store klass. + * @cert: the pointer to OpenSSL 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 +xmlSecOpenSSLX509StoreAdoptCert(xmlSecKeyDataStorePtr store, X509* cert, xmlSecKeyDataType type) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), -1); + xmlSecAssert2(cert != NULL, -1); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + + if((type & xmlSecKeyDataTypeTrusted) != 0) { + xmlSecAssert2(ctx->xst != NULL, -1); + + ret = X509_STORE_add_cert(ctx->xst, cert); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_STORE_add_cert", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + /* add cert increments the reference */ + X509_free(cert); + } else { + xmlSecAssert2(ctx->untrusted != NULL, -1); + + ret = sk_X509_push(ctx->untrusted, cert); + if(ret < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_push", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +/** + * xmlSecOpenSSLX509StoreAdoptCrl: + * @store: the pointer to X509 key data store klass. + * @crl: the pointer to OpenSSL X509_CRL. + * + * Adds X509 CRL to the store. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecOpenSSLX509StoreAdoptCrl(xmlSecKeyDataStorePtr store, X509_CRL* crl) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), -1); + xmlSecAssert2(crl != NULL, -1); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->crls != NULL, -1); + + ret = sk_X509_CRL_push(ctx->crls, crl); + if(ret < 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_CRL_push", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return (0); +} + +/** + * xmlSecOpenSSLX509StoreAddCertsPath: + * @store: the pointer to OpenSSL x509 store. + * @path: the path to the certs dir. + * + * Adds all certs in the @path to the list of trusted certs + * in @store. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLX509StoreAddCertsPath(xmlSecKeyDataStorePtr store, const char *path) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + X509_LOOKUP *lookup = NULL; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), -1); + xmlSecAssert2(path != NULL, -1); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xst != NULL, -1); + + lookup = X509_STORE_add_lookup(ctx->xst, X509_LOOKUP_hash_dir()); + if(lookup == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_STORE_add_lookup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(!X509_LOOKUP_add_dir(lookup, path, X509_FILETYPE_PEM)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_LOOKUP_add_dir", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "path='%s'", + xmlSecErrorsSafeString(path) + ); + return(-1); + } + return(0); +} + +/** + * xmlSecOpenSSLX509StoreAddCertsFile: + * @store: the pointer to OpenSSL x509 store. + * @file: the certs file. + * + * Adds all certs in @file to the list of trusted certs + * in @store. It is possible for @file to contain multiple certs. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecOpenSSLX509StoreAddCertsFile(xmlSecKeyDataStorePtr store, const char *file) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + X509_LOOKUP *lookup = NULL; + + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), -1); + xmlSecAssert2(file != NULL, -1); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xst != NULL, -1); + + lookup = X509_STORE_add_lookup(ctx->xst, X509_LOOKUP_file()); + if(lookup == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_STORE_add_lookup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(!X509_LOOKUP_load_file(lookup, file, X509_FILETYPE_PEM)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_LOOKUP_load_file", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "file='%s'", + xmlSecErrorsSafeString(file) + ); + return(-1); + } + return(0); +} + +static int +xmlSecOpenSSLX509StoreInitialize(xmlSecKeyDataStorePtr store) { + const xmlChar* path; + X509_LOOKUP *lookup = NULL; + + xmlSecOpenSSLX509StoreCtxPtr ctx; + xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), -1); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecOpenSSLX509StoreCtx)); + + ctx->xst = X509_STORE_new(); + if(ctx->xst == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_STORE_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(!X509_STORE_set_default_paths(ctx->xst)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_STORE_set_default_paths", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + + lookup = X509_STORE_add_lookup(ctx->xst, X509_LOOKUP_hash_dir()); + if(lookup == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_STORE_add_lookup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + path = xmlSecOpenSSLGetDefaultTrustedCertsFolder(); + if(path != NULL) { + if(!X509_LOOKUP_add_dir(lookup, (char*)path, X509_FILETYPE_PEM)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_LOOKUP_add_dir", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "path='%s'", + xmlSecErrorsSafeString(path) + ); + return(-1); + } + } else { + if(!X509_LOOKUP_add_dir(lookup, NULL, X509_FILETYPE_DEFAULT)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_LOOKUP_add_dir", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE + ); + return(-1); + } + } + + ctx->untrusted = sk_X509_new_null(); + if(ctx->untrusted == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_new_null", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->crls = sk_X509_CRL_new_null(); + if(ctx->crls == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "sk_X509_CRL_new_null", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) + ctx->vpm = X509_VERIFY_PARAM_new(); + if(ctx->vpm == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), + "X509_VERIFY_PARAM_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + X509_VERIFY_PARAM_set_depth(ctx->vpm, 9); /* the default cert verification path in openssl */ + X509_STORE_set1_param(ctx->xst, ctx->vpm); + +#else /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ + ctx->xst->depth = 9; /* the default cert verification path in openssl */ +#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ + + return(0); +} + +static void +xmlSecOpenSSLX509StoreFinalize(xmlSecKeyDataStorePtr store) { + xmlSecOpenSSLX509StoreCtxPtr ctx; + xmlSecAssert(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId)); + + ctx = xmlSecOpenSSLX509StoreGetCtx(store); + xmlSecAssert(ctx != NULL); + + + if(ctx->xst != NULL) { + X509_STORE_free(ctx->xst); + } + if(ctx->untrusted != NULL) { + sk_X509_pop_free(ctx->untrusted, X509_free); + } + if(ctx->crls != NULL) { + sk_X509_CRL_pop_free(ctx->crls, X509_CRL_free); + } +#if !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) + if(ctx->vpm != NULL) { + X509_VERIFY_PARAM_free(ctx->vpm); + } +#endif /* !defined(XMLSEC_OPENSSL_096) && !defined(XMLSEC_OPENSSL_097) */ + + memset(ctx, 0, sizeof(xmlSecOpenSSLX509StoreCtx)); +} + + +/***************************************************************************** + * + * Low-level x509 functions + * + *****************************************************************************/ +static int +xmlSecOpenSSLX509VerifyCRL(X509_STORE* xst, X509_CRL *crl ) { + X509_STORE_CTX xsc; + X509_OBJECT xobj; + EVP_PKEY *pkey; + int ret; + + xmlSecAssert2(xst != NULL, -1); + xmlSecAssert2(crl != NULL, -1); + + X509_STORE_CTX_init(&xsc, xst, NULL, NULL); + ret = X509_STORE_get_by_subject(&xsc, X509_LU_X509, + X509_CRL_get_issuer(crl), &xobj); + if(ret <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_STORE_get_by_subject", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + pkey = X509_get_pubkey(xobj.data.x509); + X509_OBJECT_free_contents(&xobj); + if(pkey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_get_pubkey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ret = X509_CRL_verify(crl, pkey); + EVP_PKEY_free(pkey); + if(ret != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_CRL_verify", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + } + X509_STORE_CTX_cleanup (&xsc); + return((ret == 1) ? 1 : 0); +} + +static X509* +xmlSecOpenSSLX509FindCert(STACK_OF(X509) *certs, xmlChar *subjectName, + xmlChar *issuerName, xmlChar *issuerSerial, + xmlChar *ski) { + X509 *cert = NULL; + int i; + + xmlSecAssert2(certs != NULL, NULL); + + /* todo: may be this is not the fastest way to search certs */ + if(subjectName != NULL) { + X509_NAME *nm; + X509_NAME *subj; + + nm = xmlSecOpenSSLX509NameRead(subjectName, xmlStrlen(subjectName)); + if(nm == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "subject=%s", + xmlSecErrorsSafeString(subjectName)); + return(NULL); + } + + for(i = 0; i < sk_X509_num(certs); ++i) { + cert = sk_X509_value(certs, i); + subj = X509_get_subject_name(cert); + if(xmlSecOpenSSLX509NamesCompare(nm, subj) == 0) { + X509_NAME_free(nm); + return(cert); + } + } + X509_NAME_free(nm); + } else if((issuerName != NULL) && (issuerSerial != NULL)) { + X509_NAME *nm; + X509_NAME *issuer; + BIGNUM *bn; + ASN1_INTEGER *serial; + + nm = xmlSecOpenSSLX509NameRead(issuerName, xmlStrlen(issuerName)); + if(nm == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "issuer=%s", + xmlSecErrorsSafeString(issuerName)); + return(NULL); + } + + bn = BN_new(); + if(bn == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_NAME_free(nm); + return(NULL); + } + if(BN_dec2bn(&bn, (char*)issuerSerial) == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_dec2bn", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BN_free(bn); + X509_NAME_free(nm); + return(NULL); + } + + serial = BN_to_ASN1_INTEGER(bn, NULL); + if(serial == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "BN_to_ASN1_INTEGER", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + BN_free(bn); + X509_NAME_free(nm); + return(NULL); + } + BN_free(bn); + + + for(i = 0; i < sk_X509_num(certs); ++i) { + cert = sk_X509_value(certs, i); + if(ASN1_INTEGER_cmp(X509_get_serialNumber(cert), serial) != 0) { + continue; + } + issuer = X509_get_issuer_name(cert); + if(xmlSecOpenSSLX509NamesCompare(nm, issuer) == 0) { + ASN1_INTEGER_free(serial); + X509_NAME_free(nm); + return(cert); + } + } + + X509_NAME_free(nm); + ASN1_INTEGER_free(serial); + } else if(ski != NULL) { + int len; + int index; + X509_EXTENSION *ext; + ASN1_OCTET_STRING *keyId; + + /* our usual trick with base64 decode */ + len = xmlSecBase64Decode(ski, (xmlSecByte*)ski, xmlStrlen(ski)); + if(len < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ski=%s", + xmlSecErrorsSafeString(ski)); + return(NULL); + } + for(i = 0; i < sk_X509_num(certs); ++i) { + cert = sk_X509_value(certs, i); + index = X509_get_ext_by_NID(cert, NID_subject_key_identifier, -1); + if((index >= 0) && (ext = X509_get_ext(cert, index))) { + keyId = X509V3_EXT_d2i(ext); + if((keyId != NULL) && (keyId->length == len) && + (memcmp(keyId->data, ski, len) == 0)) { + M_ASN1_OCTET_STRING_free(keyId); + return(cert); + } + M_ASN1_OCTET_STRING_free(keyId); + } + } + } + + return(NULL); +} + +static X509* +xmlSecOpenSSLX509FindNextChainCert(STACK_OF(X509) *chain, X509 *cert) { + unsigned long certSubjHash; + int i; + + xmlSecAssert2(chain != NULL, NULL); + xmlSecAssert2(cert != NULL, NULL); + + certSubjHash = X509_subject_name_hash(cert); + for(i = 0; i < sk_X509_num(chain); ++i) { + if((sk_X509_value(chain, i) != cert) && + (X509_issuer_name_hash(sk_X509_value(chain, i)) == certSubjHash)) { + + return(sk_X509_value(chain, i)); + } + } + return(NULL); +} + +static int +xmlSecOpenSSLX509VerifyCertAgainstCrls(STACK_OF(X509_CRL) *crls, X509* cert) { + X509_NAME *issuer; + X509_CRL *crl = NULL; + X509_REVOKED *revoked; + int i, n; + int ret; + + xmlSecAssert2(crls != NULL, -1); + xmlSecAssert2(cert != NULL, -1); + + /* + * Try to retrieve a CRL corresponding to the issuer of + * the current certificate + */ + n = sk_X509_CRL_num(crls); + for(i = 0; i < n; i++) { + crl = sk_X509_CRL_value(crls, i); + if(crl == NULL) { + continue; + } + + issuer = X509_CRL_get_issuer(crl); + if(xmlSecOpenSSLX509NamesCompare(X509_CRL_get_issuer(crl), issuer) == 0) { + break; + } + } + if((i >= n) || (crl == NULL)){ + /* no crls for this issuer */ + return(1); + } + + /* + * Check date of CRL to make sure it's not expired + */ + ret = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); + if (ret == 0) { + /* crl expired */ + return(1); + } + + /* + * Check if the current certificate is revoked by this CRL + */ + n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); + for (i = 0; i < n; i++) { + revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); + if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(cert)) == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_CERT_REVOKED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + } + return(1); +} + +static X509_NAME * +xmlSecOpenSSLX509NameRead(xmlSecByte *str, int len) { + xmlSecByte name[256]; + xmlSecByte value[256]; + int nameLen, valueLen; + X509_NAME *nm; + int type = MBSTRING_ASC; + + xmlSecAssert2(str != NULL, NULL); + + nm = X509_NAME_new(); + if(nm == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_NAME_new", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + while(len > 0) { + /* skip spaces after comma or semicolon */ + while((len > 0) && isspace(*str)) { + ++str; --len; + } + + nameLen = xmlSecOpenSSLX509NameStringRead(&str, &len, name, sizeof(name), '=', 0); + if(nameLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameStringRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_NAME_free(nm); + return(NULL); + } + name[nameLen] = '\0'; + if(len > 0) { + ++str; --len; + if((*str) == '\"') { + ++str; --len; + valueLen = xmlSecOpenSSLX509NameStringRead(&str, &len, + value, sizeof(value), '"', 1); + if(valueLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameStringRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_NAME_free(nm); + return(NULL); + } + + /* skip quote */ + if((len <= 0) || ((*str) != '\"')) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "quote is expected:%s", + xmlSecErrorsSafeString(str)); + X509_NAME_free(nm); + return(NULL); + } + ++str; --len; + + /* skip spaces before comma or semicolon */ + while((len > 0) && isspace(*str)) { + ++str; --len; + } + if((len > 0) && ((*str) != ',')) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "comma is expected:%s", + xmlSecErrorsSafeString(str)); + X509_NAME_free(nm); + return(NULL); + } + if(len > 0) { + ++str; --len; + } + type = MBSTRING_ASC; + } else if((*str) == '#') { + /* TODO: read octect values */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "reading octect values is not implemented yet"); + X509_NAME_free(nm); + return(NULL); + } else { + valueLen = xmlSecOpenSSLX509NameStringRead(&str, &len, + value, sizeof(value), ',', 1); + if(valueLen < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecOpenSSLX509NameStringRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + X509_NAME_free(nm); + return(NULL); + } + type = MBSTRING_ASC; + } + } else { + valueLen = 0; + } + value[valueLen] = '\0'; + if(len > 0) { + ++str; --len; + } + X509_NAME_add_entry_by_txt(nm, (char*)name, type, value, valueLen, -1, 0); + } + + return(nm); +} + +static int +xmlSecOpenSSLX509NameStringRead(xmlSecByte **str, int *strLen, + xmlSecByte *res, int resLen, + xmlSecByte delim, int ingoreTrailingSpaces) { + xmlSecByte *p, *q, *nonSpace; + + xmlSecAssert2(str != NULL, -1); + xmlSecAssert2(strLen != NULL, -1); + xmlSecAssert2(res != NULL, -1); + + p = (*str); + nonSpace = q = res; + while(((p - (*str)) < (*strLen)) && ((*p) != delim) && ((q - res) < resLen)) { + if((*p) != '\\') { + if(ingoreTrailingSpaces && !isspace(*p)) nonSpace = q; + *(q++) = *(p++); + } else { + ++p; + nonSpace = q; + if(xmlSecIsHex((*p))) { + if((p - (*str) + 1) >= (*strLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "two hex digits expected"); + return(-1); + } + *(q++) = xmlSecGetHex(p[0]) * 16 + xmlSecGetHex(p[1]); + p += 2; + } else { + if(((++p) - (*str)) >= (*strLen)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "escaped symbol missed"); + return(-1); + } + *(q++) = *(p++); + } + } + } + if(((p - (*str)) < (*strLen)) && ((*p) != delim)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "buffer is too small"); + return(-1); + } + (*strLen) -= (p - (*str)); + (*str) = p; + return((ingoreTrailingSpaces) ? nonSpace - res + 1 : q - res); +} + +static +int xmlSecOpenSSLX509_NAME_cmp(const X509_NAME *a, const X509_NAME *b) { + int i,ret; + const X509_NAME_ENTRY *na,*nb; + + xmlSecAssert2(a != NULL, -1); + xmlSecAssert2(b != NULL, 1); + + if (sk_X509_NAME_ENTRY_num(a->entries) != sk_X509_NAME_ENTRY_num(b->entries)) { + return sk_X509_NAME_ENTRY_num(a->entries) - sk_X509_NAME_ENTRY_num(b->entries); + } + + for (i=sk_X509_NAME_ENTRY_num(a->entries)-1; i>=0; i--) { + na=sk_X509_NAME_ENTRY_value(a->entries,i); + nb=sk_X509_NAME_ENTRY_value(b->entries,i); + + ret = xmlSecOpenSSLX509_NAME_ENTRY_cmp(&na, &nb); + if(ret != 0) { + return(ret); + } + } + + return(0); +} + + +/** + * xmlSecOpenSSLX509NamesCompare: + * + * We have to sort X509_NAME entries to get correct results. + * This is ugly but OpenSSL does not support it + */ +static int +xmlSecOpenSSLX509NamesCompare(X509_NAME *a, X509_NAME *b) { + X509_NAME *a1 = NULL; + X509_NAME *b1 = NULL; + int ret; + + xmlSecAssert2(a != NULL, -1); + xmlSecAssert2(b != NULL, 1); + + a1 = X509_NAME_dup(a); + if(a1 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_NAME_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + b1 = X509_NAME_dup(b); + if(b1 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "X509_NAME_dup", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(1); + } + + /* sort both */ + sk_X509_NAME_ENTRY_set_cmp_func(a1->entries, xmlSecOpenSSLX509_NAME_ENTRY_cmp); + sk_X509_NAME_ENTRY_sort(a1->entries); + sk_X509_NAME_ENTRY_set_cmp_func(b1->entries, xmlSecOpenSSLX509_NAME_ENTRY_cmp); + sk_X509_NAME_ENTRY_sort(b1->entries); + + /* actually compare */ + ret = xmlSecOpenSSLX509_NAME_cmp(a1, b1); + + /* cleanup */ + X509_NAME_free(a1); + X509_NAME_free(b1); + return(ret); +} + +static int +xmlSecOpenSSLX509_NAME_ENTRY_cmp(const X509_NAME_ENTRY **a, const X509_NAME_ENTRY **b) { + int ret; + + xmlSecAssert2(a != NULL, -1); + xmlSecAssert2(b != NULL, 1); + xmlSecAssert2((*a) != NULL, -1); + xmlSecAssert2((*b) != NULL, 1); + + /* first compare values */ + if(((*a)->value == NULL) && ((*b)->value != NULL)) { + return(-1); + } else if(((*a)->value != NULL) && ((*b)->value == NULL)) { + return(1); + } else if(((*a)->value == NULL) && ((*b)->value == NULL)) { + return(0); + } + + ret = (*a)->value->length - (*b)->value->length; + if(ret != 0) { + return(ret); + } + + ret = memcmp((*a)->value->data, (*b)->value->data, (*a)->value->length); + if(ret != 0) { + return(ret); + } + + /* next compare names */ + return(OBJ_cmp((*a)->object, (*b)->object)); +} + + +#endif /* XMLSEC_NO_X509 */ + + diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 00000000..74c15229 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,571 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * XML Parser transform and utility functions. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <libxml/parserInternals.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/parser.h> +#include <xmlsec/errors.h> + +/************************************************************************** + * + * Internal parser + * + *****************************************************************************/ +typedef struct _xmlSecParserCtx xmlSecParserCtx, + *xmlSecParserCtxPtr; +struct _xmlSecParserCtx { + xmlParserCtxtPtr parserCtx; +}; + +/************************************************************************** + * + * XML Parser transform + * + * xmlSecParserCtx is located after xmlSecTransform + * + ***************************************************************************/ +#define xmlSecParserSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecParserCtx)) +#define xmlSecParserGetCtx(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecParserSize)) ? \ + ((xmlSecParserCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) : \ + (xmlSecParserCtxPtr)NULL) + +static int xmlSecParserInitialize (xmlSecTransformPtr transform); +static void xmlSecParserFinalize (xmlSecTransformPtr transform); +static int xmlSecParserPushBin (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + int final, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecParserPopXml (xmlSecTransformPtr transform, + xmlSecNodeSetPtr* nodes, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecParserKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecParserSize, /* xmlSecSize objSize */ + + BAD_CAST "xml-parser", /* const xmlChar* name; */ + NULL, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + xmlSecParserInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecParserFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecParserPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + NULL, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + xmlSecParserPopXml, /* xmlSecTransformPopXmlMethod popXml; */ + NULL, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformXmlParserGetKlass: + * + * The XML parser transform. + * + * Returns: XML parser transform klass. + */ +xmlSecTransformId +xmlSecTransformXmlParserGetKlass(void) { + return(&xmlSecParserKlass); +} + +static int +xmlSecParserInitialize(xmlSecTransformPtr transform) { + xmlSecParserCtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecParserSize), -1); + + ctx = xmlSecParserGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecParserCtx)); + return(0); +} + +static void +xmlSecParserFinalize(xmlSecTransformPtr transform) { + xmlSecParserCtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecParserSize)); + + ctx = xmlSecParserGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->parserCtx != NULL) { + xmlFreeParserCtxt(ctx->parserCtx); + } + memset(ctx, 0, sizeof(xmlSecParserCtx)); +} + +static int +xmlSecParserPushBin(xmlSecTransformPtr transform, const xmlSecByte* data, + xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) { + xmlSecParserCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecParserGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* check/update current transform status */ + if(transform->status == xmlSecTransformStatusNone) { + xmlSecAssert2(ctx->parserCtx == NULL, -1); + + ctx->parserCtx = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); + if(ctx->parserCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlCreatePushParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* required for c14n! */ + ctx->parserCtx->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctx->parserCtx->replaceEntities = 1; + + transform->status = xmlSecTransformStatusWorking; + } else if(transform->status == xmlSecTransformStatusFinished) { + return(0); + } else if(transform->status != xmlSecTransformStatusWorking) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1); + xmlSecAssert2(ctx->parserCtx != NULL, -1); + + /* push data to the input buffer */ + if((data != NULL) && (dataSize > 0)) { + ret = xmlParseChunk(ctx->parserCtx, (const char*)data, dataSize, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + "size=%d", dataSize); + return(-1); + } + } + + /* finish parsing and push to next in the chain */ + if(final != 0) { + ret = xmlParseChunk(ctx->parserCtx, NULL, 0, 1); + if((ret != 0) || (ctx->parserCtx->myDoc == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* todo: check that document is well formed? */ + transform->outNodes = xmlSecNodeSetCreate(ctx->parserCtx->myDoc, + NULL, xmlSecNodeSetTree); + if(transform->outNodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNodeSetCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(ctx->parserCtx->myDoc); + ctx->parserCtx->myDoc = NULL; + return(-1); + } + xmlSecNodeSetDocDestroy(transform->outNodes); /* this node set "owns" the doc pointer */ + ctx->parserCtx->myDoc = NULL; + + /* push result to the next transform (if exist) */ + if(transform->next != NULL) { + ret = xmlSecTransformPushXml(transform->next, transform->outNodes, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformPushXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + transform->status = xmlSecTransformStatusFinished; + } + + return(0); +} + +static int +xmlSecParserPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes, + xmlSecTransformCtxPtr transformCtx) { + xmlSecParserCtxPtr ctx; + xmlParserInputBufferPtr buf; + xmlParserInputPtr input; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXmlParserId), -1); + xmlSecAssert2(nodes != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecParserGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* check/update current transform status */ + switch(transform->status) { + case xmlSecTransformStatusNone: + transform->status = xmlSecTransformStatusWorking; + break; + case xmlSecTransformStatusWorking: + /* just do nothing */ + break; + case xmlSecTransformStatusFinished: + (*nodes) = NULL; + return(0); + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1); + + /* prepare parser context */ + if(transform->prev == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + "prev transform is null"); + return(-1); + } + + buf = xmlSecTransformCreateInputBuffer(transform->prev, transformCtx); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformCreateInputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctxt = xmlNewParserCtxt(); + if (ctxt == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlNewParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeParserInputBuffer(buf); + return(-1); + } + + input = xmlNewIOInputStream(ctxt, buf, XML_CHAR_ENCODING_NONE); + if(input == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlNewParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeParserCtxt(ctxt); + xmlFreeParserInputBuffer(buf); + return(-1); + } + + ret = inputPush(ctxt, input); + if(input == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "inputPush", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeInputStream(input); + xmlFreeParserCtxt(ctxt); + return(-1); + } + + /* required for c14n! */ + ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctxt->replaceEntities = 1; + + /* finaly do the parsing */ + ret = xmlParseDocument(ctxt); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseDocument", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + if(ctxt->myDoc != NULL) { + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + xmlFreeParserCtxt(ctxt); + return(-1); + } + + /* remember the result and free parsing context */ + doc = ctxt->myDoc; + ctxt->myDoc = NULL; + xmlFreeParserCtxt(ctxt); + + /* return result to the caller */ + (*nodes) = xmlSecNodeSetCreate(doc, NULL, xmlSecNodeSetTree); + if((*nodes) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNodeSetCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(doc); + return(-1); + } + xmlSecNodeSetDocDestroy((*nodes)); /* this node set "owns" the doc pointer */ + transform->status = xmlSecTransformStatusFinished; + return(0); +} + +/************************************************************************** + * + * XML Parser functions + * + *************************************************************************/ +typedef struct _xmlSecExtMemoryParserCtx { + const xmlSecByte *prefix; + xmlSecSize prefixSize; + const xmlSecByte *buffer; + xmlSecSize bufferSize; + const xmlSecByte *postfix; + xmlSecSize postfixSize; +} xmlSecExtMemoryParserCtx, *xmlSecExtMemoryParserCtxPtr; + +/** + * xmlSecParseFile: + * @filename: the filename. + * + * Loads XML Doc from file @filename. We need a special version because of + * c14n issue. The code is copied from xmlSAXParseFileWithData() function. + * + * Returns: pointer to the loaded XML document or NULL if an error occurs. + */ +xmlDocPtr +xmlSecParseFile(const char *filename) { + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + char *directory = NULL; + + xmlSecAssert2(filename != NULL, NULL); + + xmlInitParser(); + ctxt = xmlCreateFileParserCtxt(filename); + if (ctxt == NULL) { + return(NULL); + } + + /* todo: set directories from current doc? */ + if ((ctxt->directory == NULL) && (directory == NULL)) + directory = xmlParserGetDirectory(filename); + if ((ctxt->directory == NULL) && (directory != NULL)) + ctxt->directory = (char *) xmlStrdup((xmlChar *) directory); + + /* required for c14n! */ + ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctxt->replaceEntities = 1; + + xmlParseDocument(ctxt); + + if(ctxt->wellFormed) { + ret = ctxt->myDoc; + } else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + xmlFreeParserCtxt(ctxt); + return(ret); + +} + +/** + * xmlSecParseMemoryExt: + * @prefix: the first part of the input. + * @prefixSize: the size of the first part of the input. + * @buffer: the second part of the input. + * @bufferSize: the size of the second part of the input. + * @postfix: the third part of the input. + * @postfixSize: the size of the third part of the input. + * + * Loads XML Doc from 3 chunks of memory: @prefix, @buffer and @postfix. + * + * Returns: pointer to the loaded XML document or NULL if an error occurs. + */ +xmlDocPtr +xmlSecParseMemoryExt(const xmlSecByte *prefix, xmlSecSize prefixSize, + const xmlSecByte *buffer, xmlSecSize bufferSize, + const xmlSecByte *postfix, xmlSecSize postfixSize) { + xmlParserCtxtPtr ctxt = NULL; + xmlDocPtr doc = NULL; + int ret; + + /* create context */ + ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); + if(ctxt == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlCreatePushParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + /* required for c14n! */ + ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctxt->replaceEntities = 1; + + /* prefix */ + if((prefix != NULL) && (prefixSize > 0)) { + ret = xmlParseChunk(ctxt, (const char*)prefix, prefixSize, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + "prefixSize=%d", prefixSize); + goto done; + } + } + + /* buffer */ + if((buffer != NULL) && (bufferSize > 0)) { + ret = xmlParseChunk(ctxt, (const char*)buffer, bufferSize, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + "bufferSize=%d", bufferSize); + goto done; + } + } + + /* postfix */ + if((postfix != NULL) && (postfixSize > 0)) { + ret = xmlParseChunk(ctxt, (const char*)postfix, postfixSize, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + "postfixSize=%d", postfixSize); + goto done; + } + } + + /* finishing */ + ret = xmlParseChunk(ctxt, NULL, 0, 1); + if((ret != 0) || (ctxt->myDoc == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + doc = ctxt->myDoc; + +done: + if(ctxt != NULL) { + xmlFreeParserCtxt(ctxt); + } + return(doc); +} + + +/** + * xmlSecParseMemory: + * @buffer: the input buffer. + * @size: the input buffer size. + * @recovery: the flag. + * + * Loads XML Doc from memory. We need a special version because of + * c14n issue. The code is copied from xmlSAXParseMemory() function. + * + * Returns: pointer to the loaded XML document or NULL if an error occurs. + */ +xmlDocPtr +xmlSecParseMemory(const xmlSecByte *buffer, xmlSecSize size, int recovery) { + xmlDocPtr ret; + xmlParserCtxtPtr ctxt; + + xmlSecAssert2(buffer != NULL, NULL); + + ctxt = xmlCreateMemoryParserCtxt((char*)buffer, size); + if (ctxt == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlCreateMemoryParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* required for c14n! */ + ctxt->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctxt->replaceEntities = 1; + + xmlParseDocument(ctxt); + + if((ctxt->wellFormed) || recovery) { + ret = ctxt->myDoc; + } else { + ret = NULL; + xmlFreeDoc(ctxt->myDoc); + ctxt->myDoc = NULL; + } + xmlFreeParserCtxt(ctxt); + return(ret); +} + diff --git a/src/skeleton/Makefile.am b/src/skeleton/Makefile.am new file mode 100644 index 00000000..8e2e910b --- /dev/null +++ b/src/skeleton/Makefile.am @@ -0,0 +1,45 @@ +NULL = + +EXTRA_DIST = \ + README \ + $(NULL) + +lib_LTLIBRARIES = \ + libxmlsec1-skeleton.la \ + $(NULL) + +libxmlsec1_skeleton_la_CPPFLAGS = \ + -DPACKAGE=\"@PACKAGE@\" \ + -I../../include \ + -I$(top_srcdir)/include \ + $(XMLSEC_DEFINES) \ + $(XMLSEC_SKELETON_DEFINES) \ + $(SKELETON_CFLAGS) \ + $(LIBXSLT_CFLAGS) \ + $(LIBXML_CFLAGS) \ + $(NULL) + +libxmlsec1_skeleton_la_SOURCES =\ + app.c \ + crypto.c \ + globals.h \ + $(NULL) + +if SHAREDLIB_HACK +libxmlsec1_skeleton_la_SOURCES += ../strings.c +endif + +libxmlsec1_skeleton_la_LIBADD = \ + ../libxmlsec1.la \ + $(SKELETON_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + $(NULL) + +libxmlsec1_skeleton_la_DEPENDENCIES = \ + $(NULL) + +libxmlsec1_skeleton_la_LDFLAGS = \ + @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ \ + -version-info @XMLSEC_VERSION_INFO@ \ + $(NULL) diff --git a/src/skeleton/README b/src/skeleton/README new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/skeleton/README diff --git a/src/skeleton/app.c b/src/skeleton/app.c new file mode 100644 index 00000000..e229ab34 --- /dev/null +++ b/src/skeleton/app.c @@ -0,0 +1,499 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +/* TODO: aadd Skeleton include files */ + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + +#include <xmlsec/skeleton/app.h> +#include <xmlsec/skeleton/crypto.h> + +/** + * xmlSecSkeletonAppInit: + * @config: the path to Skeleton configuration (unused). + * + * 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 +xmlSecSkeletonAppInit(const char* config ATTRIBUTE_UNUSED) { + /* TODO: initialize Skeleton crypto engine */ + return(0); +} + +/** + * xmlSecSkeletonAppShutdown: + * + * 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 +xmlSecSkeletonAppShutdown(void) { + /* TODO: shutdown Skeleton crypto engine */ + + return(0); +} + +/** + * xmlSecSkeletonAppKeyLoad: + * @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 (not implemented yet). + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecSkeletonAppKeyLoad(const char *filename, xmlSecKeyDataFormat format, + const char *pwd, + void* pwdCallback, + void* pwdCallbackCtx) { + xmlSecAssert2(filename != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + /* TODO: load key */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppKeyLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +/** + * xmlSecSkeletonAppKeyLoadMemory: + * @data: the key binary data. + * @dataSize: the key binary data size. + * @format: the key data format. + * @pwd: the key data2 password. + * @pwdCallback: the key password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key from a binary @data. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecSkeletonAppKeyLoadMemory(const xmlSecByte* data, xmlSecSize dataSize, xmlSecKeyDataFormat format, + const char *pwd, void* pwdCallback, void* pwdCallbackCtx) { + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, NULL); + + /* TODO: load key */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppKeyLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + + +#ifndef XMLSEC_NO_X509 +/** + * xmlSecSkeletonAppKeyCertLoad: + * @key: the pointer to key. + * @filename: the certificate filename. + * @format: the certificate file format. + * + * Reads the certificate from $@filename and adds it to key + * (not implemented yet). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonAppKeyCertLoad(xmlSecKeyPtr key, const char* filename, + xmlSecKeyDataFormat format) { + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppKeyCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +/** + * xmlSecSkeletonAppKeyCertLoadMemory: + * @key: the pointer to key. + * @data: the certificate binary data. + * @dataSize: the certificate binary data size. + * @format: the certificate file format. + * + * Reads the certificate from memory buffer and adds it to key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonAppKeyCertLoadMemory(xmlSecKeyPtr key, const xmlSecByte* data, xmlSecSize dataSize, + xmlSecKeyDataFormat format) { + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppKeyCertLoadMemory", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +/** + * xmlSecSkeletonAppPkcs12Load: + * @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 + * (not implemented yet). + * For uniformity, call xmlSecSkeletonAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecSkeletonAppPkcs12Load(const char *filename, + const char *pwd ATTRIBUTE_UNUSED, + void* pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + xmlSecAssert2(filename != NULL, NULL); + + /* TODO: load pkcs12 file */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppPkcs12Load", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + +/** + * xmlSecSkeletonAppPkcs12LoadMemory: + * @data: the key binary data. + * @dataSize: the key binary data size. + * @pwd: the PKCS12 password. + * @pwdCallback: the password callback. + * @pwdCallbackCtx: the user context for password callback. + * + * Reads key and all associated certificates from the PKCS12 binary data. + * For uniformity, call xmlSecSkeletonAppKeyLoad instead of this function. Pass + * in format=xmlSecKeyDataFormatPkcs12. + * + * Returns: pointer to the key or NULL if an error occurs. + */ +xmlSecKeyPtr +xmlSecSkeletonAppPkcs12LoadMemory(const xmlSecByte* data, xmlSecSize dataSize, const char *pwd, + void *pwdCallback ATTRIBUTE_UNUSED, + void* pwdCallbackCtx ATTRIBUTE_UNUSED) { + xmlSecAssert2(data != NULL, NULL); + + /* TODO: load pkcs12 file */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppPkcs12Load", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); +} + + + +/** + * xmlSecSkeletonAppKeysMngrCertLoad: + * @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 +xmlSecSkeletonAppKeysMngrCertLoad(xmlSecKeysMngrPtr mngr, const char *filename, + xmlSecKeyDataFormat format, + xmlSecKeyDataType type ATTRIBUTE_UNUSED) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO: load cert and add to keys manager */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppKeysMngrCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +/** + * xmlSecSkeletonAppKeysMngrCertLoadMemory: + * @mngr: the pointer to keys manager. + * @data: the key binary data. + * @dataSize: the key binary data size. + * @format: the certificate format (PEM or DER). + * @type: the certificate type (trusted/untrusted). + * + * 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 +xmlSecSkeletonAppKeysMngrCertLoadMemory(xmlSecKeysMngrPtr mngr, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecKeyDataFormat format, + xmlSecKeyDataType type) { + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(format != xmlSecKeyDataFormatUnknown, -1); + + /* TODO: load cert and add to keys manager */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonAppKeysMngrCertLoad", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); +} + +#endif /* XMLSEC_NO_X509 */ + +/** + * xmlSecSkeletonAppDefaultKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Initializes @mngr with simple keys store #xmlSecSimpleKeysStoreId + * and a default Skeleton crypto key data stores. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonAppDefaultKeysMngrInit(xmlSecKeysMngrPtr mngr) { + int ret; + + xmlSecAssert2(mngr != NULL, -1); + + /* TODO: if Skeleton crypto engine has another default + * keys storage then use it! + */ + + /* create simple keys store if needed */ + if(xmlSecKeysMngrGetKeysStore(mngr) == NULL) { + xmlSecKeyStorePtr keysStore; + + keysStore = xmlSecKeyStoreCreate(xmlSecSimpleKeysStoreId); + if(keysStore == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyStoreCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecSimpleKeysStoreId"); + 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 = xmlSecSkeletonKeysMngrInit(mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSkeletonKeysMngrInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + mngr->getKey = xmlSecKeysMngrGetKey; + return(0); +} + +/** + * xmlSecSkeletonAppDefaultKeysMngrAdoptKey: + * @mngr: the pointer to keys manager. + * @key: the pointer to key. + * + * Adds @key to the keys manager @mngr created with #xmlSecSkeletonAppDefaultKeysMngrInit + * function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr mngr, xmlSecKeyPtr key) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(key != NULL, -1); + + /* TODO: if Skeleton crypto engine has another default + * keys storage then use it! + */ + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecSimpleKeysStoreAdoptKey(store, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreAdoptKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecSkeletonAppDefaultKeysMngrLoad: + * @mngr: the pointer to keys manager. + * @uri: the uri. + * + * Loads XML keys file from @uri to the keys manager @mngr created + * with #xmlSecSkeletonAppDefaultKeysMngrInit function. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonAppDefaultKeysMngrLoad(xmlSecKeysMngrPtr mngr, const char* uri) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(uri != NULL, -1); + + /* TODO: if Skeleton crypto engine has another default + * keys storage then use it! + */ + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecSimpleKeysStoreLoad(store, uri, mngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreLoad", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", xmlSecErrorsSafeString(uri)); + return(-1); + } + + return(0); +} + +/** + * xmlSecSkeletonAppDefaultKeysMngrSave: + * @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 +xmlSecSkeletonAppDefaultKeysMngrSave(xmlSecKeysMngrPtr mngr, const char* filename, xmlSecKeyDataType type) { + xmlSecKeyStorePtr store; + int ret; + + xmlSecAssert2(mngr != NULL, -1); + xmlSecAssert2(filename != NULL, -1); + + /* TODO: if Skeleton crypto engine has another default + * keys storage then use it! + */ + + store = xmlSecKeysMngrGetKeysStore(mngr); + if(store == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeysMngrGetKeysStore", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecSimpleKeysStoreSave(store, filename, type); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSimpleKeysStoreSave", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "filename=%s", + xmlSecErrorsSafeString(filename)); + return(-1); + } + + return(0); +} + +/** + * xmlSecSkeletonAppGetDefaultPwdCallback: + * + * Gets default password callback. + * + * Returns: default password callback. + */ +void* +xmlSecSkeletonAppGetDefaultPwdCallback(void) { + /* TODO */ + return(NULL); +} + diff --git a/src/skeleton/crypto.c b/src/skeleton/crypto.c new file mode 100644 index 00000000..aff0945a --- /dev/null +++ b/src/skeleton/crypto.c @@ -0,0 +1,227 @@ +/** + * XMLSec library + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <string.h> + +/* TODO: add Skeleton include files */ + +#include <xmlsec/xmlsec.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> +#include <xmlsec/dl.h> +#include <xmlsec/private.h> + +#include <xmlsec/skeleton/app.h> +#include <xmlsec/skeleton/crypto.h> + +static xmlSecCryptoDLFunctionsPtr gXmlSecSkeletonFunctions = NULL; + +/** + * xmlSecCryptoGetFunctions_skeleton: + * + * Gets the pointer to xmlsec-skeleton functions table. + * + * Returns: the xmlsec-skeleton functions table or NULL if an error occurs. + */ +xmlSecCryptoDLFunctionsPtr +xmlSecCryptoGetFunctions_skeleton(void) { + static xmlSecCryptoDLFunctions functions; + + if(gXmlSecSkeletonFunctions != NULL) { + return(gXmlSecSkeletonFunctions); + } + + memset(&functions, 0, sizeof(functions)); + gXmlSecSkeletonFunctions = &functions; + + /** + * Crypto Init/shutdown + */ + gXmlSecSkeletonFunctions->cryptoInit = xmlSecSkeletonInit; + gXmlSecSkeletonFunctions->cryptoShutdown = xmlSecSkeletonShutdown; + gXmlSecSkeletonFunctions->cryptoKeysMngrInit = xmlSecSkeletonKeysMngrInit; + + /** + * Key data ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecSkeletonFunctions->keyDataAesGetKlass = xmlSecSkeletonKeyDataAesGetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecSkeletonFunctions->keyDataDesGetKlass = xmlSecSkeletonKeyDataDesGetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_DSA + gXmlSecSkeletonFunctions->keyDataDsaGetKlass = xmlSecSkeletonKeyDataDsaGetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + gXmlSecSkeletonFunctions->keyDataGost2001GetKlass = xmlSecSkeletonKeyDataGost2001GetKlass; +#endif /* XMLSEC_NO_GOST */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecSkeletonFunctions->keyDataHmacGetKlass = xmlSecSkeletonKeyDataHmacGetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_RSA + gXmlSecSkeletonFunctions->keyDataRsaGetKlass = xmlSecSkeletonKeyDataRsaGetKlass; +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_X509 + gXmlSecSkeletonFunctions->keyDataX509GetKlass = xmlSecSkeletonKeyDataX509GetKlass; + gXmlSecSkeletonFunctions->keyDataRawX509CertGetKlass = xmlSecSkeletonKeyDataRawX509CertGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /** + * Key data store ids + */ +#ifndef XMLSEC_NO_X509 + gXmlSecSkeletonFunctions->x509StoreGetKlass = xmlSecSkeletonX509StoreGetKlass; +#endif /* XMLSEC_NO_X509 */ + + /** + * Crypto transforms ids + */ +#ifndef XMLSEC_NO_AES + gXmlSecSkeletonFunctions->transformAes128CbcGetKlass = xmlSecSkeletonTransformAes128CbcGetKlass; + gXmlSecSkeletonFunctions->transformAes192CbcGetKlass = xmlSecSkeletonTransformAes192CbcGetKlass; + gXmlSecSkeletonFunctions->transformAes256CbcGetKlass = xmlSecSkeletonTransformAes256CbcGetKlass; + gXmlSecSkeletonFunctions->transformKWAes128GetKlass = xmlSecSkeletonTransformKWAes128GetKlass; + gXmlSecSkeletonFunctions->transformKWAes192GetKlass = xmlSecSkeletonTransformKWAes192GetKlass; + gXmlSecSkeletonFunctions->transformKWAes256GetKlass = xmlSecSkeletonTransformKWAes256GetKlass; +#endif /* XMLSEC_NO_AES */ + +#ifndef XMLSEC_NO_DES + gXmlSecSkeletonFunctions->transformDes3CbcGetKlass = xmlSecSkeletonTransformDes3CbcGetKlass; + gXmlSecSkeletonFunctions->transformKWDes3GetKlass = xmlSecSkeletonTransformKWDes3GetKlass; +#endif /* XMLSEC_NO_DES */ + +#ifndef XMLSEC_NO_DSA + gXmlSecSkeletonFunctions->transformDsaSha1GetKlass = xmlSecSkeletonTransformDsaSha1GetKlass; +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_GOST + gXmlSecSkeletonFunctions->transformGost2001GostR3411_94GetKlass = xmlSecSkeletonTransformGost2001GostR3411_94GetKlass; +#endif /* XMLSEC_GOST */ + +#ifndef XMLSEC_NO_HMAC + gXmlSecSkeletonFunctions->transformHmacSha1GetKlass = xmlSecSkeletonTransformHmacSha1GetKlass; + gXmlSecSkeletonFunctions->transformHmacRipemd160GetKlass = xmlSecSkeletonTransformHmacRipemd160GetKlass; + gXmlSecSkeletonFunctions->transformHmacMd5GetKlass = xmlSecSkeletonTransformHmacMd5GetKlass; +#endif /* XMLSEC_NO_HMAC */ + +#ifndef XMLSEC_NO_RIPEMD160 + gXmlSecSkeletonFunctions->transformRipemd160GetKlass = xmlSecSkeletonTransformRipemd160GetKlass; +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_RSA + gXmlSecSkeletonFunctions->transformRsaSha1GetKlass = xmlSecSkeletonTransformRsaSha1GetKlass; + gXmlSecSkeletonFunctions->transformRsaPkcs1GetKlass = xmlSecSkeletonTransformRsaPkcs1GetKlass; + gXmlSecSkeletonFunctions->transformRsaOaepGetKlass = xmlSecSkeletonTransformRsaOaepGetKlass; +#endif /* XMLSEC_NO_RSA */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecSkeletonFunctions->transformSha1GetKlass = xmlSecSkeletonTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_GOST + gXmlSecSkeletonFunctions->transformGostR3411_94GetKlass = xmlSecSkeletonTransformGostR3411_94GetKlass; +#endif /* XMLSEC_NO_GOST */ + + /** + * High level routines form xmlsec command line utility + */ + gXmlSecSkeletonFunctions->cryptoAppInit = xmlSecSkeletonAppInit; + gXmlSecSkeletonFunctions->cryptoAppShutdown = xmlSecSkeletonAppShutdown; + gXmlSecSkeletonFunctions->cryptoAppDefaultKeysMngrInit = xmlSecSkeletonAppDefaultKeysMngrInit; + gXmlSecSkeletonFunctions->cryptoAppDefaultKeysMngrAdoptKey = xmlSecSkeletonAppDefaultKeysMngrAdoptKey; + gXmlSecSkeletonFunctions->cryptoAppDefaultKeysMngrLoad = xmlSecSkeletonAppDefaultKeysMngrLoad; + gXmlSecSkeletonFunctions->cryptoAppDefaultKeysMngrSave = xmlSecSkeletonAppDefaultKeysMngrSave; +#ifndef XMLSEC_NO_X509 + gXmlSecSkeletonFunctions->cryptoAppKeysMngrCertLoad = xmlSecSkeletonAppKeysMngrCertLoad; + gXmlSecSkeletonFunctions->cryptoAppKeysMngrCertLoadMemory = xmlSecSkeletonAppKeysMngrCertLoadMemory; + gXmlSecSkeletonFunctions->cryptoAppPkcs12Load = xmlSecSkeletonAppPkcs12Load; + gXmlSecSkeletonFunctions->cryptoAppPkcs12LoadMemory = xmlSecSkeletonAppPkcs12LoadMemory; + gXmlSecSkeletonFunctions->cryptoAppKeyCertLoad = xmlSecSkeletonAppKeyCertLoad; + gXmlSecSkeletonFunctions->cryptoAppKeyCertLoadMemory = xmlSecSkeletonAppKeyCertLoadMemory; +#endif /* XMLSEC_NO_X509 */ + gXmlSecSkeletonFunctions->cryptoAppKeyLoad = xmlSecSkeletonAppKeyLoad; + gXmlSecSkeletonFunctions->cryptoAppKeyLoadMemory = xmlSecSkeletonAppKeyLoadMemory; + gXmlSecSkeletonFunctions->cryptoAppDefaultPwdCallback = (void*)xmlSecSkeletonAppGetDefaultPwdCallback(); + + return(gXmlSecSkeletonFunctions); +} + + +/** + * xmlSecSkeletonInit: + * + * XMLSec library specific crypto engine initialization. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonInit (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); + } + + /* register our klasses */ + if(xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms(xmlSecCryptoGetFunctions_skeleton()) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLFunctionsRegisterKeyDataAndTransforms", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); + + /* TODO: if necessary do, additional initialization here */ +} + +/** + * xmlSecSkeletonShutdown: + * + * XMLSec library specific crypto engine shutdown. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonShutdown(void) { + /* TODO: if necessary, do additional shutdown here */ + return(0); +} + +/** + * xmlSecSkeletonKeysMngrInit: + * @mngr: the pointer to keys manager. + * + * Adds Skeleton specific key data stores in keys manager. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecSkeletonKeysMngrInit(xmlSecKeysMngrPtr mngr) { + xmlSecAssert2(mngr != NULL, -1); + + /* TODO: add key data stores */ + return(0); +} + + diff --git a/src/skeleton/globals.h b/src/skeleton/globals.h new file mode 100644 index 00000000..272a27b8 --- /dev/null +++ b/src/skeleton/globals.h @@ -0,0 +1,24 @@ +/* + * XML Security Library + * + * globals.h: internal header only used during the compilation + * + * 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_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 + +#endif /* ! __XMLSEC_GLOBALS_H__ */ diff --git a/src/soap.c b/src/soap.c new file mode 100644 index 00000000..84512b23 --- /dev/null +++ b/src/soap.c @@ -0,0 +1,1322 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Simple SOAP messages parsing/creation. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_SOAP + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/soap.h> +#include <xmlsec/errors.h> + +/*********************************************************************** + * + * SOAP 1.1 + * + **********************************************************************/ +/** + * xmlSecSoap11CreateEnvelope: + * @doc: the parent doc (might be NULL). + * + * Creates a new SOAP Envelope node. Caller is responsible for + * adding the returned node to the XML document. + * + * XML Schema (http://schemas.xmlsoap.org/soap/envelope/): + * + * <xs:element name="Envelope" type="tns:Envelope"/> + * <xs:complexType name="Envelope"> + * <xs:sequence> + * <xs:element ref="tns:Header" minOccurs="0"/> + * <xs:element ref="tns:Body" minOccurs="1"/> + * <xs:any namespace="##other" minOccurs="0" + * maxOccurs="unbounded" processContents="lax"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##other" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to newly created <soap:Envelope> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecSoap11CreateEnvelope(xmlDocPtr doc) { + xmlNodePtr envNode; + xmlNodePtr bodyNode; + xmlNsPtr ns; + + /* create Envelope node */ + envNode = xmlNewDocNode(doc, NULL, xmlSecNodeEnvelope, NULL); + if(envNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDocNode", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEnvelope)); + return(NULL); + } + + ns = xmlNewNs(envNode, xmlSecSoap11Ns, NULL) ; + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(xmlSecSoap11Ns)); + xmlFreeNode(envNode); + return(NULL); + } + xmlSetNs(envNode, ns); + + /* add required Body node */ + bodyNode = xmlSecAddChild(envNode, xmlSecNodeBody, xmlSecSoap11Ns); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeBody)); + xmlFreeNode(envNode); + return(NULL); + } + + return(envNode); +} + +/** + * xmlSecSoap11EnsureHeader: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets the pointer to <soap:Header> node (if necessary, the node + * is created). + * + * XML Schema (http://schemas.xmlsoap.org/soap/envelope/): + * + * <xs:element name="Header" type="tns:Header"/> + * <xs:complexType name="Header"> + * <xs:sequence> + * <xs:any namespace="##other" minOccurs="0" + * maxOccurs="unbounded" processContents="lax"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##other" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to <soap:Header> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap11EnsureHeader(xmlNodePtr envNode) { + xmlNodePtr hdrNode; + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* try to find Header node first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) { + return(cur); + } + + /* if the first element child is not Header then it is Body */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap11Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* finally add Header node before body */ + hdrNode = xmlSecAddPrevSibling(cur, xmlSecNodeHeader, xmlSecSoap11Ns); + if(hdrNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddPrevSibling", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(hdrNode); +} + +/** + * xmlSecSoap11AddBodyEntry: + * @envNode: the pointer to <soap:Envelope> node. + * @entryNode: the pointer to body entry node. + * + * Adds a new entry to <soap:Body> node. + * + * Returns: pointer to the added entry (@contentNode) or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap11AddBodyEntry(xmlNodePtr envNode, xmlNodePtr entryNode) { + xmlNodePtr bodyNode; + + xmlSecAssert2(envNode != NULL, NULL); + xmlSecAssert2(entryNode != NULL, NULL); + + bodyNode = xmlSecSoap11GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecAddChildNode(bodyNode, entryNode)); +} + +/** + * xmlSecSoap11AddFaultEntry: + * @envNode: the pointer to <soap:Envelope> node. + * @faultCodeHref: the fault code QName href (must be known in th context of + * <soap:Body> node). + * @faultCodeLocalPart: the fault code QName LocalPart. + * @faultString: the human readable explanation of the fault. + * @faultActor: the information about who caused the fault (might be NULL). + * + * Adds <soap:Fault> entry to the @envNode. Note that only one <soap:Fault> + * entry is allowed. + * + * XML Schema (http://schemas.xmlsoap.org/soap/envelope/): + * + * <xs:element name="Fault" type="tns:Fault"/> + * <xs:complexType name="Fault" final="extension"> + * <xs:sequence> + * <xs:element name="faultcode" type="xs:QName"/> + * <xs:element name="faultstring" type="xs:string"/> + * <xs:element name="faultactor" type="xs:anyURI" minOccurs="0"/> + * <xs:element name="detail" type="tns:detail" minOccurs="0"/> + * </xs:sequence> + * </xs:complexType> + * <xs:complexType name="detail"> + * <xs:sequence> + * <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" + * processContents="lax"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##any" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to the added entry or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap11AddFaultEntry(xmlNodePtr envNode, const xmlChar* faultCodeHref, + const xmlChar* faultCodeLocalPart, + const xmlChar* faultString, const xmlChar* faultActor) { + xmlNodePtr bodyNode; + xmlNodePtr faultNode; + xmlNodePtr cur; + xmlChar* qname; + + xmlSecAssert2(envNode != NULL, NULL); + xmlSecAssert2(faultCodeLocalPart != NULL, NULL); + xmlSecAssert2(faultString != NULL, NULL); + + /* get Body node */ + bodyNode = xmlSecSoap11GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* check that we don't have Fault node already */ + faultNode = xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap11Ns); + if(faultNode != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* add Fault node */ + faultNode = xmlSecAddChild(bodyNode, xmlSecNodeFault, xmlSecSoap11Ns); + if(faultNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeFault)); + return(NULL); + } + + /* add faultcode node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeFaultCode, xmlSecSoap11Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeFaultCode)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* create qname for fault code */ + qname = xmlSecGetQName(cur, faultCodeHref, faultCodeLocalPart); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGetQName", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(cur->name)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* set faultcode value */ + xmlNodeSetContent(cur, qname); + xmlFree(qname); + + /* add faultstring node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeFaultString, xmlSecSoap11Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeFaultString)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* set faultstring node */ + xmlNodeSetContent(cur, faultString); + + if(faultActor != NULL) { + /* add faultactor node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeFaultActor, xmlSecSoap11Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeFaultActor)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* set faultactor node */ + xmlNodeSetContent(cur, faultActor); + } + + return(faultNode); +} + +/** + * xmlSecSoap11CheckEnvelope: + * @envNode: the pointer to <soap:Envelope> node. + * + * Validates <soap:Envelope> node structure. + * + * Returns: 1 if @envNode has a valid <soap:Envelope> element, 0 if it is + * not valid or a negative value if an error occurs. + */ +int +xmlSecSoap11CheckEnvelope(xmlNodePtr envNode) { + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, -1); + + /* verify envNode itself */ + if(!xmlSecCheckNodeName(envNode, xmlSecNodeEnvelope, xmlSecSoap11Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeEnvelope), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + + /* optional Header node first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* required Body node is next */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap11Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + + return(1); +} + +/** + * xmlSecSoap11GetHeader: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets pointer to the <soap:Header> node. + * + * Returns: pointer to <soap:Header> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap11GetHeader(xmlNodePtr envNode) { + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* optional Header node is first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) { + return(cur); + } + + return(NULL); +} + +/** + * xmlSecSoap11GetBody: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets pointer to the <soap:Body> node. + * + * Returns: pointer to <soap:Body> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap11GetBody(xmlNodePtr envNode) { + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* optional Header node first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap11Ns)) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* Body node is next */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap11Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(cur); +} + +/** + * xmlSecSoap11GetBodyEntriesNumber: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets the number of body entries. + * + * Returns: the number of body entries. + */ +xmlSecSize +xmlSecSoap11GetBodyEntriesNumber(xmlNodePtr envNode) { + xmlSecSize number = 0; + xmlNodePtr bodyNode; + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, 0); + + /* get Body node */ + bodyNode = xmlSecSoap11GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + + cur = xmlSecGetNextElementNode(bodyNode->children); + while(cur != NULL) { + number++; + cur = xmlSecGetNextElementNode(cur->next); + } + + return(number); +} + +/** + * xmlSecSoap11GetBodyEntry: + * @envNode: the pointer to <soap:Envelope> node. + * @pos: the body entry number. + * + * Gets the body entry number @pos. + * + * Returns: pointer to body entry node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap11GetBodyEntry(xmlNodePtr envNode, xmlSecSize pos) { + xmlNodePtr bodyNode; + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* get Body node */ + bodyNode = xmlSecSoap11GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecGetNextElementNode(bodyNode->children); + while((cur != NULL) && (pos > 0)) { + pos--; + cur = xmlSecGetNextElementNode(cur->next); + } + + return(cur); +} + +/** + * xmlSecSoap11GetFaultEntry: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets the Fault entry (if any). + * + * Returns: pointer to Fault entry or NULL if it does not exist. + */ +xmlNodePtr +xmlSecSoap11GetFaultEntry(xmlNodePtr envNode) { + xmlNodePtr bodyNode; + + xmlSecAssert2(envNode != NULL, NULL); + + /* get Body node */ + bodyNode = xmlSecSoap11GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap11Ns)); +} + + +/*********************************************************************** + * + * SOAP 1.2 + * + **********************************************************************/ +static const xmlSecQName2IntegerInfo gXmlSecSoap12FaultCodeInfo[] = +{ + { xmlSecSoap12Ns, xmlSecSoapFaultCodeVersionMismatch, + xmlSecSoap12FaultCodeVersionMismatch }, + { xmlSecSoap12Ns, xmlSecSoapFaultCodeMustUnderstand, + xmlSecSoap12FaultCodeMustUnderstand }, + { xmlSecSoap12Ns, xmlSecSoapFaultDataEncodningUnknown, + xmlSecSoap12FaultCodeDataEncodingUnknown }, + { xmlSecSoap12Ns, xmlSecSoapFaultCodeSender, + xmlSecSoap12FaultCodeSender }, + { xmlSecSoap12Ns, xmlSecSoapFaultCodeReceiver, + xmlSecSoap12FaultCodeReceiver }, + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +/** + * xmlSecSoap12CreateEnvelope: + * @doc: the parent doc (might be NULL). + * + * Creates a new SOAP 1.2 Envelope node. Caller is responsible for + * adding the returned node to the XML document. + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * <xs:element name="Envelope" type="tns:Envelope"/> + * <xs:complexType name="Envelope"> + * <xs:sequence> + * <xs:element ref="tns:Header" minOccurs="0"/> + * <xs:element ref="tns:Body" minOccurs="1"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##other" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to newly created <soap:Envelope> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecSoap12CreateEnvelope(xmlDocPtr doc) { + xmlNodePtr envNode; + xmlNodePtr bodyNode; + xmlNsPtr ns; + + /* create Envelope node */ + envNode = xmlNewDocNode(doc, NULL, xmlSecNodeEnvelope, NULL); + if(envNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDocNode", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEnvelope)); + return(NULL); + } + + ns = xmlNewNs(envNode, xmlSecSoap12Ns, NULL) ; + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(xmlSecSoap12Ns)); + xmlFreeNode(envNode); + return(NULL); + } + xmlSetNs(envNode, ns); + + /* add required Body node */ + bodyNode = xmlSecAddChild(envNode, xmlSecNodeBody, xmlSecSoap12Ns); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeBody)); + xmlFreeNode(envNode); + return(NULL); + } + + return(envNode); +} + +/** + * xmlSecSoap12EnsureHeader: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets the pointer to <soap:Header> node (if necessary, the node + * is created). + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * <xs:element name="Header" type="tns:Header"/> + * <xs:complexType name="Header"> + * <xs:sequence> + * <xs:any namespace="##any" processContents="lax" + * minOccurs="0" maxOccurs="unbounded"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##other" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to <soap:Header> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap12EnsureHeader(xmlNodePtr envNode) { + xmlNodePtr hdrNode; + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* try to find Header node first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) { + return(cur); + } + + /* if the first element child is not Header then it is Body */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap12Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* finally add Header node before body */ + hdrNode = xmlSecAddPrevSibling(cur, xmlSecNodeHeader, xmlSecSoap12Ns); + if(hdrNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddPrevSibling", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(hdrNode); +} + +/** + * xmlSecSoap12AddBodyEntry: + * @envNode: the pointer to <soap:Envelope> node. + * @entryNode: the pointer to body entry node. + * + * Adds a new entry to <soap:Body> node. + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * <xs:element name="Body" type="tns:Body"/> + * <xs:complexType name="Body"> + * <xs:sequence> + * <xs:any namespace="##any" processContents="lax" + * minOccurs="0" maxOccurs="unbounded"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##other" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to the added entry (@contentNode) or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap12AddBodyEntry(xmlNodePtr envNode, xmlNodePtr entryNode) { + xmlNodePtr bodyNode; + + xmlSecAssert2(envNode != NULL, NULL); + xmlSecAssert2(entryNode != NULL, NULL); + + bodyNode = xmlSecSoap12GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecAddChildNode(bodyNode, entryNode)); +} + +/** + * xmlSecSoap12AddFaultEntry: + * @envNode: the pointer to <soap:Envelope> node. + * @faultCode: the fault code. + * @faultReasonText: the human readable explanation of the fault. + * @faultReasonLang: the language (xml:lang) for @faultReason string. + * @faultNodeURI: the more preciese information about fault source + * (might be NULL). + * @faultRole: the role the node was operating in at the point + * the fault occurred (might be NULL). + * + * Adds <soap:Fault> entry to the @envNode. Note that only one <soap:Fault> + * entry is allowed. + * + * XML Schema (http://www.w3.org/2003/05/soap-envelope): + * + * <xs:element name="Fault" type="tns:Fault"/> + * <xs:complexType name="Fault" final="extension"> + * <xs:sequence> + * <xs:element name="Code" type="tns:faultcode"/> + * <xs:element name="Reason" type="tns:faultreason"/> + * <xs:element name="Node" type="xs:anyURI" minOccurs="0"/> + * <xs:element name="Role" type="xs:anyURI" minOccurs="0"/> + * <xs:element name="Detail" type="tns:detail" minOccurs="0"/> + * </xs:sequence> + * </xs:complexType> + * + * <xs:complexType name="faultcode"> + * <xs:sequence> + * <xs:element name="Value" type="tns:faultcodeEnum"/> + * <xs:element name="Subcode" type="tns:subcode" minOccurs="0"/> + * </xs:sequence> + * </xs:complexType> + * + * <xs:complexType name="faultreason"> + * <xs:sequence> + * <xs:element name="Text" type="tns:reasontext" + * minOccurs="1" maxOccurs="unbounded"/> + * </xs:sequence> + * </xs:complexType> + * + * <xs:complexType name="reasontext"> + * <xs:simpleContent> + * <xs:extension base="xs:string"> + * <xs:attribute ref="xml:lang" use="required"/> + * </xs:extension> + * </xs:simpleContent> + * </xs:complexType> + * + * <xs:simpleType name="faultcodeEnum"> + * <xs:restriction base="xs:QName"> + * <xs:enumeration value="tns:DataEncodingUnknown"/> + * <xs:enumeration value="tns:MustUnderstand"/> + * <xs:enumeration value="tns:Receiver"/> + * <xs:enumeration value="tns:Sender"/> + * <xs:enumeration value="tns:VersionMismatch"/> + * </xs:restriction> + * </xs:simpleType> + * + * <xs:complexType name="subcode"> + * <xs:sequence> + * <xs:element name="Value" type="xs:QName"/> + * <xs:element name="Subcode" type="tns:subcode" minOccurs="0"/> + * </xs:sequence> + * </xs:complexType> + * + * <xs:complexType name="detail"> + * <xs:sequence> + * <xs:any namespace="##any" processContents="lax" + * minOccurs="0" maxOccurs="unbounded"/> + * </xs:sequence> + * <xs:anyAttribute namespace="##other" processContents="lax"/> + * </xs:complexType> + * + * Returns: pointer to the added entry or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap12AddFaultEntry(xmlNodePtr envNode, xmlSecSoap12FaultCode faultCode, + const xmlChar* faultReasonText, const xmlChar* faultReasonLang, + const xmlChar* faultNodeURI, const xmlChar* faultRole) { + xmlNodePtr bodyNode; + xmlNodePtr faultNode; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(envNode != NULL, NULL); + xmlSecAssert2(faultCode != xmlSecSoap12FaultCodeUnknown, NULL); + xmlSecAssert2(faultReasonText != NULL, NULL); + xmlSecAssert2(faultReasonLang != NULL, NULL); + + /* get Body node */ + bodyNode = xmlSecSoap12GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* check that we don't have Fault node already */ + faultNode = xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap12Ns); + if(faultNode != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* add Fault node */ + faultNode = xmlSecAddChild(bodyNode, xmlSecNodeFault, xmlSecSoap12Ns); + if(faultNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeFault)); + return(NULL); + } + + /* add Code node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeCode, xmlSecSoap12Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCode)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* write the fault code in Value child */ + ret = xmlSecQName2IntegerNodeWrite(gXmlSecSoap12FaultCodeInfo, cur, + xmlSecNodeValue, xmlSecSoap12Ns, + faultCode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "faultCode=%d", + faultCode); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* add Reason node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeReason, xmlSecSoap12Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeReason)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + /* Add Reason/Text node */ + if(xmlSecSoap12AddFaultReasonText(faultNode, faultReasonText, faultReasonLang) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12AddFaultReasonText", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "text=%s", + xmlSecErrorsSafeString(faultReasonText)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + + if(faultNodeURI != NULL) { + /* add Node node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeNode, xmlSecSoap12Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeNode)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + xmlNodeSetContent(cur, faultNodeURI); + } + + if(faultRole != NULL) { + /* add Role node */ + cur = xmlSecAddChild(faultNode, xmlSecNodeRole, xmlSecSoap12Ns); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRole)); + xmlUnlinkNode(faultNode); + xmlFreeNode(faultNode); + return(NULL); + } + xmlNodeSetContent(cur, faultRole); + } + + return(faultNode); +} + +/** + * xmlSecSoap12AddFaultSubcode: + * @faultNode: the pointer to <Fault> node. + * @subCodeHref: the subcode href. + * @subCodeName: the subcode name. + * + * Adds a new <Subcode> node to the <Code> node or the last <Subcode> node. + * + * Returns: a pointer to the newly created <Subcode> node or NULL if an error + * occurs. + */ +xmlNodePtr +xmlSecSoap12AddFaultSubcode(xmlNodePtr faultNode, const xmlChar* subCodeHref, const xmlChar* subCodeName) { + xmlNodePtr cur, subcodeNode, valueNode; + xmlChar* qname; + + xmlSecAssert2(faultNode != NULL, NULL); + xmlSecAssert2(subCodeHref != NULL, NULL); + xmlSecAssert2(subCodeName != NULL, NULL); + + /* Code node is the first childern in Fault node */ + cur = xmlSecGetNextElementNode(faultNode->children); + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeCode, xmlSecSoap12Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCode)); + return(NULL); + } + + /* find the Code or Subcode node that does not have Subcode child */ + while(1) { + xmlNodePtr tmp; + + tmp = xmlSecFindChild(cur, xmlSecNodeSubcode, xmlSecSoap12Ns); + if(tmp != NULL) { + cur = tmp; + } else { + break; + } + } + xmlSecAssert2(cur != NULL, NULL); + + /* add Subcode node */ + subcodeNode = xmlSecAddChild(cur, xmlSecNodeSubcode, xmlSecSoap12Ns); + if(subcodeNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeSubcode)); + return(NULL); + } + + /* add Value node */ + valueNode = xmlSecAddChild(subcodeNode, xmlSecNodeValue, xmlSecSoap12Ns); + if(valueNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeValue)); + xmlUnlinkNode(subcodeNode); + xmlFreeNode(subcodeNode); + return(NULL); + } + + /* create qname for fault code */ + qname = xmlSecGetQName(cur, subCodeHref, subCodeName); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGetQName", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(cur->name)); + xmlUnlinkNode(subcodeNode); + xmlFreeNode(subcodeNode); + return(NULL); + } + + /* set result qname in Value node */ + xmlNodeSetContent(cur, qname); + if(qname != subCodeName) { + xmlFree(qname); + } + + return(subcodeNode); +} + +/** + * xmlSecSoap12AddFaultReasonText: + * @faultNode: the pointer to <Fault> node. + * @faultReasonText: the new reason text. + * @faultReasonLang: the new reason xml:lang attribute. + * + * Adds a new Text node to the Fault/Reason node. + * + * Returns: a pointer to the newly created <Text> node or NULL if an error + * occurs. + */ +xmlNodePtr +xmlSecSoap12AddFaultReasonText(xmlNodePtr faultNode, const xmlChar* faultReasonText, + const xmlChar* faultReasonLang) { + xmlNodePtr reasonNode; + xmlNodePtr textNode; + + xmlSecAssert2(faultNode != NULL, NULL); + xmlSecAssert2(faultReasonText != NULL, NULL); + xmlSecAssert2(faultReasonLang != NULL, NULL); + + /* find Reason node */ + reasonNode = xmlSecFindChild(faultNode, xmlSecNodeReason, xmlSecSoap12Ns); + if(reasonNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecFindChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeReason)); + return(NULL); + } + + /* add Text node */ + textNode = xmlSecAddChild(reasonNode, xmlSecNodeText, xmlSecSoap12Ns); + if(textNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeText)); + return(NULL); + } + xmlNodeSetContent(textNode, faultReasonText); + xmlNodeSetLang(textNode, faultReasonLang); + + return(textNode); +} + +/** + * xmlSecSoap12AddFaultDetailEntry: + * @faultNode: the pointer to <Fault> node. + * @detailEntryNode: the pointer to detail entry node. + * + * Adds a new child to the Detail child element of @faultNode. + * + * Returns: pointer to the added child (@detailEntryNode) or NULL if an error + * occurs. + */ +xmlNodePtr +xmlSecSoap12AddFaultDetailEntry(xmlNodePtr faultNode, xmlNodePtr detailEntryNode) { + xmlNodePtr detailNode; + + xmlSecAssert2(faultNode != NULL, NULL); + xmlSecAssert2(detailEntryNode != NULL, NULL); + + /* find Detail node and add it if needed */ + detailNode = xmlSecFindChild(faultNode, xmlSecNodeDetail, xmlSecSoap12Ns); + if(detailNode == NULL) { + detailNode = xmlSecAddChild(faultNode, xmlSecNodeDetail, xmlSecSoap12Ns); + if(detailNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDetail)); + return(NULL); + } + } + + return(xmlSecAddChildNode(detailNode, detailEntryNode)); +} + +/** + * xmlSecSoap12CheckEnvelope: + * @envNode: the pointer to <soap:Envelope> node. + * + * Validates <soap:Envelope> node structure. + * + * Returns: 1 if @envNode has a valid <soap:Envelope> element, 0 if it is + * not valid or a negative value if an error occurs. + */ +int +xmlSecSoap12CheckEnvelope(xmlNodePtr envNode) { + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, -1); + + /* verify envNode itself */ + if(!xmlSecCheckNodeName(envNode, xmlSecNodeEnvelope, xmlSecSoap12Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeEnvelope), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + + /* optional Header node first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* required Body node is next */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap12Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + + return(1); +} + +/** + * xmlSecSoap12GetHeader: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets pointer to the <soap:Header> node. + * + * Returns: pointer to <soap:Header> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap12GetHeader(xmlNodePtr envNode) { + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* optional Header node is first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) { + return(cur); + } + + return(NULL); +} + +/** + * xmlSecSoap12GetBody: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets pointer to the <soap:Body> node. + * + * Returns: pointer to <soap:Body> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap12GetBody(xmlNodePtr envNode) { + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* optional Header node first */ + cur = xmlSecGetNextElementNode(envNode->children); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeHeader, xmlSecSoap12Ns)) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* Body node is next */ + if((cur == NULL) || !xmlSecCheckNodeName(cur, xmlSecNodeBody, xmlSecSoap12Ns)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeBody), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(cur); +} + +/** + * xmlSecSoap12GetBodyEntriesNumber: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets the number of body entries. + * + * Returns: the number of body entries. + */ +xmlSecSize +xmlSecSoap12GetBodyEntriesNumber(xmlNodePtr envNode) { + xmlSecSize number = 0; + xmlNodePtr bodyNode; + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, 0); + + /* get Body node */ + bodyNode = xmlSecSoap12GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(0); + } + + cur = xmlSecGetNextElementNode(bodyNode->children); + while(cur != NULL) { + number++; + cur = xmlSecGetNextElementNode(cur->next); + } + + return(number); +} + +/** + * xmlSecSoap12GetBodyEntry: + * @envNode: the pointer to <soap:Envelope> node. + * @pos: the body entry number. + * + * Gets the body entry number @pos. + * + * Returns: pointer to body entry node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecSoap12GetBodyEntry(xmlNodePtr envNode, xmlSecSize pos) { + xmlNodePtr bodyNode; + xmlNodePtr cur; + + xmlSecAssert2(envNode != NULL, NULL); + + /* get Body node */ + bodyNode = xmlSecSoap12GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecGetNextElementNode(bodyNode->children); + while((cur != NULL) && (pos > 0)) { + pos--; + cur = xmlSecGetNextElementNode(cur->next); + } + + return(cur); +} + +/** + * xmlSecSoap12GetFaultEntry: + * @envNode: the pointer to <soap:Envelope> node. + * + * Gets the Fault entry (if any). + * + * Returns: pointer to Fault entry or NULL if it does not exist. + */ +xmlNodePtr +xmlSecSoap12GetFaultEntry(xmlNodePtr envNode) { + xmlNodePtr bodyNode; + + xmlSecAssert2(envNode != NULL, NULL); + + /* get Body node */ + bodyNode = xmlSecSoap12GetBody(envNode); + if(bodyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBody", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecFindChild(bodyNode, xmlSecNodeFault, xmlSecSoap12Ns)); +} + +#endif /* XMLSEC_NO_SOAP */ + + diff --git a/src/strings.c b/src/strings.c new file mode 100644 index 00000000..98971986 --- /dev/null +++ b/src/strings.c @@ -0,0 +1,601 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * All the string constants. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> + +/************************************************************************* + * + * Global Namespaces + * + ************************************************************************/ +const xmlChar xmlSecNs[] = "http://www.aleksey.com/xmlsec/2002"; +const xmlChar xmlSecDSigNs[] = "http://www.w3.org/2000/09/xmldsig#"; +const xmlChar xmlSecEncNs[] = "http://www.w3.org/2001/04/xmlenc#"; +const xmlChar xmlSecXkmsNs[] = "http://www.w3.org/2002/03/xkms#"; +const xmlChar xmlSecXPathNs[] = "http://www.w3.org/TR/1999/REC-xpath-19991116"; +const xmlChar xmlSecXPath2Ns[] = "http://www.w3.org/2002/06/xmldsig-filter2"; +const xmlChar xmlSecXPointerNs[] = "http://www.w3.org/2001/04/xmldsig-more/xptr"; +const xmlChar xmlSecSoap11Ns[] = "http://schemas.xmlsoap.org/soap/envelope/"; +const xmlChar xmlSecSoap12Ns[] = "http://www.w3.org/2002/06/soap-envelope"; + +/************************************************************************* + * + * DSig Nodes + * + ************************************************************************/ +const xmlChar xmlSecNodeSignature[] = "Signature"; +const xmlChar xmlSecNodeSignedInfo[] = "SignedInfo"; +const xmlChar xmlSecNodeCanonicalizationMethod[]= "CanonicalizationMethod"; +const xmlChar xmlSecNodeSignatureMethod[] = "SignatureMethod"; +const xmlChar xmlSecNodeSignatureValue[] = "SignatureValue"; +const xmlChar xmlSecNodeDigestMethod[] = "DigestMethod"; +const xmlChar xmlSecNodeDigestValue[] = "DigestValue"; +const xmlChar xmlSecNodeObject[] = "Object"; +const xmlChar xmlSecNodeManifest[] = "Manifest"; +const xmlChar xmlSecNodeSignatureProperties[] = "SignatureProperties"; + +/************************************************************************* + * + * Encryption Nodes + * + ************************************************************************/ +const xmlChar xmlSecNodeEncryptedData[] = "EncryptedData"; +const xmlChar xmlSecNodeEncryptionMethod[] = "EncryptionMethod"; +const xmlChar xmlSecNodeEncryptionProperties[] = "EncryptionProperties"; +const xmlChar xmlSecNodeEncryptionProperty[] = "EncryptionProperty"; +const xmlChar xmlSecNodeCipherData[] = "CipherData"; +const xmlChar xmlSecNodeCipherValue[] = "CipherValue"; +const xmlChar xmlSecNodeCipherReference[] = "CipherReference"; +const xmlChar xmlSecNodeReferenceList[] = "ReferenceList"; +const xmlChar xmlSecNodeDataReference[] = "DataReference"; +const xmlChar xmlSecNodeKeyReference[] = "KeyReference"; + +const xmlChar xmlSecNodeCarriedKeyName[] = "CarriedKeyName"; + +const xmlChar xmlSecTypeEncContent[] = "http://www.w3.org/2001/04/xmlenc#Content"; +const xmlChar xmlSecTypeEncElement[] = "http://www.w3.org/2001/04/xmlenc#Element"; + +/************************************************************************* + * + * XKMS Nodes + * + ************************************************************************/ +#ifndef XMLSEC_NO_XKMS +const xmlChar xmlSecXkmsServerRequestResultName[] = "result-response"; +const xmlChar xmlSecXkmsServerRequestStatusName[] = "status-request"; +const xmlChar xmlSecXkmsServerRequestLocateName[] = "locate-request"; +const xmlChar xmlSecXkmsServerRequestValidateName[] = "validate-request"; +const xmlChar xmlSecXkmsServerRequestCompoundName[] = "compound-request"; + +const xmlChar xmlSecNodeResult[] = "Result"; +const xmlChar xmlSecNodeStatusRequest[] = "StatusRequest"; +const xmlChar xmlSecNodeStatusResult[] = "StatusResult"; +const xmlChar xmlSecNodeLocateRequest[] = "LocateRequest"; +const xmlChar xmlSecNodeLocateResult[] = "LocateResult"; +const xmlChar xmlSecNodeValidateRequest[] = "ValidateRequest"; +const xmlChar xmlSecNodeValidateResult[] = "ValidateResult"; +const xmlChar xmlSecNodeCompoundRequest[] = "CompoundRequest"; +const xmlChar xmlSecNodeCompoundResult[] = "CompoundResult"; + +const xmlChar xmlSecNodeMessageExtension[] = "MessageExtension"; +const xmlChar xmlSecNodeOpaqueClientData[] = "OpaqueClientData"; +const xmlChar xmlSecNodeResponseMechanism[] = "ResponseMechanism"; +const xmlChar xmlSecNodeRespondWith[] = "RespondWith"; +const xmlChar xmlSecNodePendingNotification[] = "PendingNotification"; +const xmlChar xmlSecNodeQueryKeyBinding[] = "QueryKeyBinding"; +const xmlChar xmlSecNodeKeyUsage[] = "KeyUsage"; +const xmlChar xmlSecNodeUseKeyWith[] = "UseKeyWith"; +const xmlChar xmlSecNodeTimeInstant[] = "TimeInstant"; +const xmlChar xmlSecNodeRequestSignatureValue[] = "RequestSignatureValue"; +const xmlChar xmlSecNodeUnverifiedKeyBinding[] = "UnverifiedKeyBinding"; +const xmlChar xmlSecNodeValidityInterval[] = "ValidityInterval"; +const xmlChar xmlSecNodeStatus[] = "Status"; +const xmlChar xmlSecNodeValidReason[] = "ValidReason"; +const xmlChar xmlSecNodeInvalidReason[] = "InvalidReason"; +const xmlChar xmlSecNodeIndeterminateReason[] = "IndeterminateReason"; + +const xmlChar xmlSecAttrService[] = "Service"; +const xmlChar xmlSecAttrNonce[] = "Nonce"; +const xmlChar xmlSecAttrOriginalRequestId[] = "OriginalRequestId"; +const xmlChar xmlSecAttrResponseLimit[] = "ResponseLimit"; +const xmlChar xmlSecAttrMechanism[] = "Mechanism["; +const xmlChar xmlSecAttrIdentifier[] = "Identifier"; +const xmlChar xmlSecAttrApplication[] = "Application"; +const xmlChar xmlSecAttrResultMajor[] = "ResultMajor"; +const xmlChar xmlSecAttrResultMinor[] = "ResultMinor"; +const xmlChar xmlSecAttrRequestId[] = "RequestId"; +const xmlChar xmlSecAttrNotBefore[] = "NotBefore"; +const xmlChar xmlSecAttrNotOnOrAfter[] = "NotOnOrAfter"; +const xmlChar xmlSecAttrTime[] = "Time"; +const xmlChar xmlSecAttrStatusValue[] = "StatusValue"; + +const xmlChar xmlSecResponseMechanismPending[] = "Pending"; +const xmlChar xmlSecResponseMechanismRepresent[]= "Represent"; +const xmlChar xmlSecResponseMechanismRequestSignatureValue[] = "RequestSignatureValue"; + +const xmlChar xmlSecRespondWithKeyName[] = "KeyName"; +const xmlChar xmlSecRespondWithKeyValue[] = "KeyValue"; +const xmlChar xmlSecRespondWithX509Cert[] = "X509Cert"; +const xmlChar xmlSecRespondWithX509Chain[] = "X509Chain"; +const xmlChar xmlSecRespondWithX509CRL[] = "X509CRL"; +const xmlChar xmlSecRespondWithOCSP[] = "OCSP"; +const xmlChar xmlSecRespondWithRetrievalMethod[]= "RetrievalMethod"; +const xmlChar xmlSecRespondWithPGP[] = "PGP"; +const xmlChar xmlSecRespondWithPGPWeb[] = "PGPWeb"; +const xmlChar xmlSecRespondWithSPKI[] = "SPKI"; +const xmlChar xmlSecRespondWithPrivateKey[] = "PrivateKey"; + +const xmlChar xmlSecStatusResultSuccess[] = "Success"; +const xmlChar xmlSecStatusResultFailed[] = "Failed"; +const xmlChar xmlSecStatusResultPending[] = "Pending"; + +const xmlChar xmlSecKeyUsageEncryption[] = "Encryption"; +const xmlChar xmlSecKeyUsageSignature[] = "Signature"; +const xmlChar xmlSecKeyUsageExchange[] = "Exchange"; + +const xmlChar xmlSecKeyBindingStatusValid[] = "Valid"; +const xmlChar xmlSecKeyBindingStatusInvalid[] = "Invalid"; +const xmlChar xmlSecKeyBindingStatusIndeterminate[] = "Indeterminate"; + +const xmlChar xmlSecKeyBindingReasonIssuerTrust[] = "IssuerTrust"; +const xmlChar xmlSecKeyBindingReasonRevocationStatus[] = "RevocationStatus"; +const xmlChar xmlSecKeyBindingReasonValidityInterval[] = "ValidityInterval"; +const xmlChar xmlSecKeyBindingReasonSignature[] = "Signature"; + +const xmlChar xmlSecResultMajorCodeSuccess[] = "Success"; +const xmlChar xmlSecResultMajorCodeVersionMismatch[] = "VersionMismatch"; +const xmlChar xmlSecResultMajorCodeSender[] = "Sender"; +const xmlChar xmlSecResultMajorCodeReceiver[] = "Receiver"; +const xmlChar xmlSecResultMajorCodeRepresent[] = "Represent"; +const xmlChar xmlSecResultMajorCodePending[] = "Pending"; + +const xmlChar xmlSecResultMinorCodeNoMatch[] = "NoMatch"; +const xmlChar xmlSecResultMinorCodeTooManyResponses[] = "TooManyResponses"; +const xmlChar xmlSecResultMinorCodeIncomplete[] = "Incomplete"; +const xmlChar xmlSecResultMinorCodeFailure[] = "Failure"; +const xmlChar xmlSecResultMinorCodeRefused[] = "Refused"; +const xmlChar xmlSecResultMinorCodeNoAuthentication[] = "NoAuthentication"; +const xmlChar xmlSecResultMinorCodeMessageNotSupported[]= "MessageNotSupported"; +const xmlChar xmlSecResultMinorCodeUnknownResponseId[] = "UnknownResponseId"; +const xmlChar xmlSecResultMinorCodeNotSynchronous[] = "NotSynchronous"; + +const xmlChar xmlSecXkmsSoapSubcodeValueMessageNotSupported[] = "MessageNotSupported"; +const xmlChar xmlSecXkmsSoapSubcodeValueBadMessage[] = "BadMessage"; + +const xmlChar xmlSecXkmsSoapFaultReasonLang[] = "en"; +const xmlChar xmlSecXkmsSoapFaultReasonUnsupportedVersion[] = "Unsupported SOAP version"; +const xmlChar xmlSecXkmsSoapFaultReasonUnableToProcess[] = "Unable to process %s"; +const xmlChar xmlSecXkmsSoapFaultReasonServiceUnavailable[] = "Service temporarily unable"; +const xmlChar xmlSecXkmsSoapFaultReasonMessageNotSupported[]= "%s message not supported"; +const xmlChar xmlSecXkmsSoapFaultReasonMessageInvalid[] = "%s message invalid"; + +const xmlChar xmlSecXkmsFormatStrPlain[] = "plain"; +const xmlChar xmlSecXkmsFormatStrSoap11[] = "soap-1.1"; +const xmlChar xmlSecXkmsFormatStrSoap12[] = "soap-1.2"; + +#endif /* XMLSEC_NO_XKMS */ + +/************************************************************************* + * + * KeyInfo Nodes + * + ************************************************************************/ +const xmlChar xmlSecNodeKeyInfo[] = "KeyInfo"; +const xmlChar xmlSecNodeReference[] = "Reference"; +const xmlChar xmlSecNodeTransforms[] = "Transforms"; +const xmlChar xmlSecNodeTransform[] = "Transform"; + +/************************************************************************* + * + * Attributes + * + ************************************************************************/ +const xmlChar xmlSecAttrId[] = "Id"; +const xmlChar xmlSecAttrURI[] = "URI"; +const xmlChar xmlSecAttrType[] = "Type"; +const xmlChar xmlSecAttrMimeType[] = "MimeType"; +const xmlChar xmlSecAttrEncoding[] = "Encoding"; +const xmlChar xmlSecAttrAlgorithm[] = "Algorithm"; +const xmlChar xmlSecAttrFilter[] = "Filter"; +const xmlChar xmlSecAttrRecipient[] = "Recipient"; +const xmlChar xmlSecAttrTarget[] = "Target"; + +/************************************************************************* + * + * AES strings + * + ************************************************************************/ +const xmlChar xmlSecNameAESKeyValue[] = "aes"; +const xmlChar xmlSecNodeAESKeyValue[] = "AESKeyValue"; +const xmlChar xmlSecHrefAESKeyValue[] = "http://www.aleksey.com/xmlsec/2002#AESKeyValue"; + +const xmlChar xmlSecNameAes128Cbc[] = "aes128-cbc"; +const xmlChar xmlSecHrefAes128Cbc[] = "http://www.w3.org/2001/04/xmlenc#aes128-cbc"; + +const xmlChar xmlSecNameAes192Cbc[] = "aes192-cbc"; +const xmlChar xmlSecHrefAes192Cbc[] = "http://www.w3.org/2001/04/xmlenc#aes192-cbc"; + +const xmlChar xmlSecNameAes256Cbc[] = "aes256-cbc"; +const xmlChar xmlSecHrefAes256Cbc[] = "http://www.w3.org/2001/04/xmlenc#aes256-cbc"; + +const xmlChar xmlSecNameKWAes128[] = "kw-aes128"; +const xmlChar xmlSecHrefKWAes128[] = "http://www.w3.org/2001/04/xmlenc#kw-aes128"; + +const xmlChar xmlSecNameKWAes192[] = "kw-aes192"; +const xmlChar xmlSecHrefKWAes192[] = "http://www.w3.org/2001/04/xmlenc#kw-aes192"; + +const xmlChar xmlSecNameKWAes256[] = "kw-aes256"; +const xmlChar xmlSecHrefKWAes256[] = "http://www.w3.org/2001/04/xmlenc#kw-aes256"; + +/************************************************************************* + * + * BASE64 strings + * + ************************************************************************/ +const xmlChar xmlSecNameBase64[] = "base64"; +const xmlChar xmlSecHrefBase64[] = "http://www.w3.org/2000/09/xmldsig#base64"; + +/************************************************************************* + * + * C14N strings + * + ************************************************************************/ +const xmlChar xmlSecNameC14N[] = "c14n"; +const xmlChar xmlSecHrefC14N[] = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"; + +const xmlChar xmlSecNameC14NWithComments[] = "c14n-with-comments"; +const xmlChar xmlSecHrefC14NWithComments[] = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"; + +const xmlChar xmlSecNameC14N11[] = "c14n11"; +const xmlChar xmlSecHrefC14N11[] = "http://www.w3.org/2006/12/xml-c14n11"; + +const xmlChar xmlSecNameC14N11WithComments[] = "c14n11-with-comments"; +const xmlChar xmlSecHrefC14N11WithComments[] = "http://www.w3.org/2006/12/xml-c14n11#WithComments"; + +const xmlChar xmlSecNameExcC14N[] = "exc-c14n"; +const xmlChar xmlSecHrefExcC14N[] = "http://www.w3.org/2001/10/xml-exc-c14n#"; + +const xmlChar xmlSecNameExcC14NWithComments[] = "exc-c14n-with-comments"; +const xmlChar xmlSecHrefExcC14NWithComments[] = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; + +const xmlChar xmlSecNsExcC14N[] = "http://www.w3.org/2001/10/xml-exc-c14n#"; +const xmlChar xmlSecNsExcC14NWithComments[] = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"; + +const xmlChar xmlSecNodeInclusiveNamespaces[] = "InclusiveNamespaces"; +const xmlChar xmlSecAttrPrefixList[] = "PrefixList"; + +/************************************************************************* + * + * DES strings + * + ************************************************************************/ +const xmlChar xmlSecNameDESKeyValue[] = "des"; +const xmlChar xmlSecNodeDESKeyValue[] = "DESKeyValue"; +const xmlChar xmlSecHrefDESKeyValue[] = "http://www.aleksey.com/xmlsec/2002#DESKeyValue"; + +const xmlChar xmlSecNameDes3Cbc[] = "tripledes-cbc"; +const xmlChar xmlSecHrefDes3Cbc[] = "http://www.w3.org/2001/04/xmlenc#tripledes-cbc"; + +const xmlChar xmlSecNameKWDes3[] = "kw-tripledes"; +const xmlChar xmlSecHrefKWDes3[] = "http://www.w3.org/2001/04/xmlenc#kw-tripledes"; + +/************************************************************************* + * + * GOST2001 strings + * + ************************************************************************/ +const xmlChar xmlSecNameGOST2001KeyValue[] = "gost2001"; +const xmlChar xmlSecNodeGOST2001KeyValue[] = "gostr34102001-gostr3411"; +const xmlChar xmlSecHrefGOST2001KeyValue[] = "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"; + +const xmlChar xmlSecNameGost2001GostR3411_94[] = "gostr34102001-gostr3411"; +const xmlChar xmlSecHrefGost2001GostR3411_94[] = "http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"; + +/************************************************************************* + * + * DSA strings + * + ************************************************************************/ +const xmlChar xmlSecNameDSAKeyValue[] = "dsa"; +const xmlChar xmlSecNodeDSAKeyValue[] = "DSAKeyValue"; +const xmlChar xmlSecHrefDSAKeyValue[] = "http://www.w3.org/2000/09/xmldsig#DSAKeyValue"; +const xmlChar xmlSecNodeDSAP[] = "P"; +const xmlChar xmlSecNodeDSAQ[] = "Q"; +const xmlChar xmlSecNodeDSAG[] = "G"; +const xmlChar xmlSecNodeDSAJ[] = "J"; +const xmlChar xmlSecNodeDSAX[] = "X"; +const xmlChar xmlSecNodeDSAY[] = "Y"; +const xmlChar xmlSecNodeDSASeed[] = "Seed"; +const xmlChar xmlSecNodeDSAPgenCounter[] = "PgenCounter"; + +const xmlChar xmlSecNameDsaSha1[] = "dsa-sha1"; +const xmlChar xmlSecHrefDsaSha1[] = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; + +/************************************************************************* + * + * EncryptedKey + * + ************************************************************************/ +const xmlChar xmlSecNameEncryptedKey[] = "enc-key"; +const xmlChar xmlSecNodeEncryptedKey[] = "EncryptedKey"; +const xmlChar xmlSecHrefEncryptedKey[] = "http://www.w3.org/2001/04/xmlenc#EncryptedKey"; + +/************************************************************************* + * + * Enveloped transform strings + * + ************************************************************************/ +const xmlChar xmlSecNameEnveloped[] = "enveloped-signature"; +const xmlChar xmlSecHrefEnveloped[] = "http://www.w3.org/2000/09/xmldsig#enveloped-signature"; + +/************************************************************************* + * + * HMAC strings + * + ************************************************************************/ +const xmlChar xmlSecNameHMACKeyValue[] = "hmac"; +const xmlChar xmlSecNodeHMACKeyValue[] = "HMACKeyValue"; +const xmlChar xmlSecHrefHMACKeyValue[] = "http://www.aleksey.com/xmlsec/2002#HMACKeyValue"; + +const xmlChar xmlSecNodeHMACOutputLength[] = "HMACOutputLength"; + +const xmlChar xmlSecNameHmacMd5[] = "hmac-md5"; +const xmlChar xmlSecHrefHmacMd5[] = "http://www.w3.org/2001/04/xmldsig-more#hmac-md5"; + +const xmlChar xmlSecNameHmacRipemd160[] = "hmac-ripemd160"; +const xmlChar xmlSecHrefHmacRipemd160[] = "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160"; + +const xmlChar xmlSecNameHmacSha1[] = "hmac-sha1"; +const xmlChar xmlSecHrefHmacSha1[] = "http://www.w3.org/2000/09/xmldsig#hmac-sha1"; + +const xmlChar xmlSecNameHmacSha224[] = "hmac-sha224"; +const xmlChar xmlSecHrefHmacSha224[] = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha224"; + +const xmlChar xmlSecNameHmacSha256[] = "hmac-sha256"; +const xmlChar xmlSecHrefHmacSha256[] = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"; + +const xmlChar xmlSecNameHmacSha384[] = "hmac-sha384"; +const xmlChar xmlSecHrefHmacSha384[] = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha384"; + +const xmlChar xmlSecNameHmacSha512[] = "hmac-sha512"; +const xmlChar xmlSecHrefHmacSha512[] = "http://www.w3.org/2001/04/xmldsig-more#hmac-sha512"; + +/************************************************************************* + * + * KeyName strings + * + ************************************************************************/ +const xmlChar xmlSecNameKeyName[] = "key-name"; +const xmlChar xmlSecNodeKeyName[] = "KeyName"; + +/************************************************************************* + * + * KeyValue strings + * + ************************************************************************/ +const xmlChar xmlSecNameKeyValue[] = "key-value"; +const xmlChar xmlSecNodeKeyValue[] = "KeyValue"; + +/************************************************************************* + * + * Memory Buffer strings + * + ************************************************************************/ +const xmlChar xmlSecNameMemBuf[] = "membuf-transform"; + +/************************************************************************* + * + * MD5 strings + * + ************************************************************************/ +const xmlChar xmlSecNameMd5[] = "md5"; +const xmlChar xmlSecHrefMd5[] = "http://www.w3.org/2001/04/xmldsig-more#md5"; + +/************************************************************************* + * + * RetrievalMethod + * + ************************************************************************/ +const xmlChar xmlSecNameRetrievalMethod[] = "retrieval-method"; +const xmlChar xmlSecNodeRetrievalMethod[] = "RetrievalMethod"; + +/************************************************************************* + * + * RIPEMD160 strings + * + ************************************************************************/ +const xmlChar xmlSecNameRipemd160[] = "ripemd160"; +const xmlChar xmlSecHrefRipemd160[] = "http://www.w3.org/2001/04/xmlenc#ripemd160"; + +/************************************************************************* + * + * RSA strings + * + ************************************************************************/ +const xmlChar xmlSecNameRSAKeyValue[] = "rsa"; +const xmlChar xmlSecNodeRSAKeyValue[] = "RSAKeyValue"; +const xmlChar xmlSecHrefRSAKeyValue[] = "http://www.w3.org/2000/09/xmldsig#RSAKeyValue"; +const xmlChar xmlSecNodeRSAModulus[] = "Modulus"; +const xmlChar xmlSecNodeRSAExponent[] = "Exponent"; +const xmlChar xmlSecNodeRSAPrivateExponent[] = "PrivateExponent"; + +const xmlChar xmlSecNameRsaMd5[] = "rsa-md5"; +const xmlChar xmlSecHrefRsaMd5[] = "http://www.w3.org/2001/04/xmldsig-more#rsa-md5"; + +const xmlChar xmlSecNameRsaRipemd160[] = "rsa-ripemd160"; +const xmlChar xmlSecHrefRsaRipemd160[] = "http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160"; + +const xmlChar xmlSecNameRsaSha1[] = "rsa-sha1"; +const xmlChar xmlSecHrefRsaSha1[] = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; + +const xmlChar xmlSecNameRsaSha224[] = "rsa-sha224"; +const xmlChar xmlSecHrefRsaSha224[] = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224"; + +const xmlChar xmlSecNameRsaSha256[] = "rsa-sha256"; +const xmlChar xmlSecHrefRsaSha256[] = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; + +const xmlChar xmlSecNameRsaSha384[] = "rsa-sha384"; +const xmlChar xmlSecHrefRsaSha384[] = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"; + +const xmlChar xmlSecNameRsaSha512[] = "rsa-sha512"; +const xmlChar xmlSecHrefRsaSha512[] = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"; + +const xmlChar xmlSecNameRsaPkcs1[] = "rsa-1_5"; +const xmlChar xmlSecHrefRsaPkcs1[] = "http://www.w3.org/2001/04/xmlenc#rsa-1_5"; + +const xmlChar xmlSecNameRsaOaep[] = "rsa-oaep-mgf1p"; +const xmlChar xmlSecHrefRsaOaep[] = "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"; +const xmlChar xmlSecNodeRsaOAEPparams[] = "OAEPparams"; + +/************************************************************************* + * + * GOSTR3411_94 strings + * + ************************************************************************/ +const xmlChar xmlSecNameGostR3411_94[] = "gostr3411"; +const xmlChar xmlSecHrefGostR3411_94[] = "http://www.w3.org/2001/04/xmldsig-more#gostr3411"; + +/************************************************************************* + * + * SHA1 strings + * + ************************************************************************/ +const xmlChar xmlSecNameSha1[] = "sha1"; +const xmlChar xmlSecHrefSha1[] = "http://www.w3.org/2000/09/xmldsig#sha1"; + +const xmlChar xmlSecNameSha224[] = "sha224"; +const xmlChar xmlSecHrefSha224[] = "http://www.w3.org/2001/04/xmldsig-more#sha224"; + +const xmlChar xmlSecNameSha256[] = "sha256"; +const xmlChar xmlSecHrefSha256[] = "http://www.w3.org/2001/04/xmlenc#sha256"; + +const xmlChar xmlSecNameSha384[] = "sha384"; +const xmlChar xmlSecHrefSha384[] = "http://www.w3.org/2001/04/xmldsig-more#sha384"; + +const xmlChar xmlSecNameSha512[] = "sha512"; +const xmlChar xmlSecHrefSha512[] = "http://www.w3.org/2001/04/xmlenc#sha512"; + +/************************************************************************* + * + * X509 strings + * + ************************************************************************/ +const xmlChar xmlSecNameX509Data[] = "x509"; +const xmlChar xmlSecNodeX509Data[] = "X509Data"; +const xmlChar xmlSecHrefX509Data[] = "http://www.w3.org/2000/09/xmldsig#X509Data"; + +const xmlChar xmlSecNodeX509Certificate[] = "X509Certificate"; +const xmlChar xmlSecNodeX509CRL[] = "X509CRL"; +const xmlChar xmlSecNodeX509SubjectName[] = "X509SubjectName"; +const xmlChar xmlSecNodeX509IssuerSerial[] = "X509IssuerSerial"; +const xmlChar xmlSecNodeX509IssuerName[] = "X509IssuerName"; +const xmlChar xmlSecNodeX509SerialNumber[] = "X509SerialNumber"; +const xmlChar xmlSecNodeX509SKI[] = "X509SKI"; + +const xmlChar xmlSecNameRawX509Cert[] = "raw-x509-cert"; +const xmlChar xmlSecHrefRawX509Cert[] = "http://www.w3.org/2000/09/xmldsig#rawX509Certificate"; + +const xmlChar xmlSecNameX509Store[] = "x509-store"; + +/************************************************************************* + * + * PGP strings + * + ************************************************************************/ +const xmlChar xmlSecNamePGPData[] = "pgp"; +const xmlChar xmlSecNodePGPData[] = "PGPData"; +const xmlChar xmlSecHrefPGPData[] = "http://www.w3.org/2000/09/xmldsig#PGPData"; + +/************************************************************************* + * + * SPKI strings + * + ************************************************************************/ +const xmlChar xmlSecNameSPKIData[] = "spki"; +const xmlChar xmlSecNodeSPKIData[] = "SPKIData"; +const xmlChar xmlSecHrefSPKIData[] = "http://www.w3.org/2000/09/xmldsig#SPKIData"; + +/************************************************************************* + * + * XPath/XPointer strings + * + ************************************************************************/ +const xmlChar xmlSecNameXPath[] = "xpath"; +const xmlChar xmlSecNodeXPath[] = "XPath"; + +const xmlChar xmlSecNameXPath2[] = "xpath2"; +const xmlChar xmlSecNodeXPath2[] = "XPath"; +const xmlChar xmlSecXPath2FilterIntersect[] = "intersect"; +const xmlChar xmlSecXPath2FilterSubtract[] = "subtract"; +const xmlChar xmlSecXPath2FilterUnion[] = "union"; + +const xmlChar xmlSecNameXPointer[] = "xpointer"; +const xmlChar xmlSecNodeXPointer[] = "XPointer"; + +/************************************************************************* + * + * Xslt strings + * + ************************************************************************/ +const xmlChar xmlSecNameXslt[] = "xslt"; +const xmlChar xmlSecHrefXslt[] = "http://www.w3.org/TR/1999/REC-xslt-19991116"; + +#ifndef XMLSEC_NO_SOAP +/************************************************************************* + * + * SOAP 1.1/1.2 strings + * + ************************************************************************/ +const xmlChar xmlSecNodeEnvelope[] = "Envelope"; +const xmlChar xmlSecNodeHeader[] = "Header"; +const xmlChar xmlSecNodeBody[] = "Body"; +const xmlChar xmlSecNodeFault[] = "Fault"; +const xmlChar xmlSecNodeFaultCode[] = "faultcode"; +const xmlChar xmlSecNodeFaultString[] = "faultstring"; +const xmlChar xmlSecNodeFaultActor[] = "faultactor"; +const xmlChar xmlSecNodeFaultDetail[] = "detail"; +const xmlChar xmlSecNodeCode[] = "Code"; +const xmlChar xmlSecNodeReason[] = "Reason"; +const xmlChar xmlSecNodeNode[] = "Node"; +const xmlChar xmlSecNodeRole[] = "Role"; +const xmlChar xmlSecNodeDetail[] = "Detail"; +const xmlChar xmlSecNodeValue[] = "Value"; +const xmlChar xmlSecNodeSubcode[] = "Subcode"; +const xmlChar xmlSecNodeText[] = "Text"; + + +const xmlChar xmlSecSoapFaultCodeVersionMismatch[] = "VersionMismatch"; +const xmlChar xmlSecSoapFaultCodeMustUnderstand[] = "MustUnderstand"; +const xmlChar xmlSecSoapFaultCodeClient[] = "Client"; +const xmlChar xmlSecSoapFaultCodeServer[] = "Server"; +const xmlChar xmlSecSoapFaultCodeReceiver[] = "Receiver"; +const xmlChar xmlSecSoapFaultCodeSender[] = "Sender"; +const xmlChar xmlSecSoapFaultDataEncodningUnknown[] = "DataEncodingUnknown"; + + +#endif /* XMLSEC_NO_SOAP */ + +/************************************************************************* + * + * Utility strings + * + ************************************************************************/ +const xmlChar xmlSecStringEmpty[] = ""; +const xmlChar xmlSecStringCR[] = "\n"; + + + + + + diff --git a/src/templates.c b/src/templates.c new file mode 100644 index 00000000..67cadb14 --- /dev/null +++ b/src/templates.c @@ -0,0 +1,2091 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Creating signature and encryption templates. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/transforms.h> +#include <xmlsec/strings.h> +#include <xmlsec/base64.h> +#include <xmlsec/templates.h> +#include <xmlsec/errors.h> + + +static xmlNodePtr xmlSecTmplAddReference (xmlNodePtr parentNode, + xmlSecTransformId digestMethodId, + const xmlChar *id, + const xmlChar *uri, + const xmlChar *type); +static int xmlSecTmplPrepareEncData (xmlNodePtr parentNode, + xmlSecTransformId encMethodId); +static int xmlSecTmplNodeWriteNsList (xmlNodePtr parentNode, + const xmlChar** namespaces); +/************************************************************************** + * + * <dsig:Signature/> node + * + **************************************************************************/ +/** + * xmlSecTmplSignatureCreate: + * @doc: the pointer to signature document or NULL; in the + * second case, application must later call @xmlSetTreeDoc + * to ensure that all the children nodes have correct + * pointer to XML document. + * @c14nMethodId: the signature canonicalization method. + * @signMethodId: the signature method. + * @id: the node id (may be NULL). + * + * Creates new <dsig:Signature/> node with the mandatory <dsig:SignedInfo/>, + * <dsig:CanonicalizationMethod/>, <dsig:SignatureMethod/> and + * <dsig:SignatureValue/> children and sub-children. + * The application is responsible for inserting the returned node + * in the XML document. + * + * Returns: the pointer to newly created <dsig:Signature/> node or NULL if an + * error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureCreate(xmlDocPtr doc, xmlSecTransformId c14nMethodId, + xmlSecTransformId signMethodId, const xmlChar *id) { + return xmlSecTmplSignatureCreateNsPref(doc, c14nMethodId, signMethodId, id, NULL); +} + +/** + * xmlSecTmplSignatureCreateNsPref: + * @doc: the pointer to signature document or NULL; in the + * second case, application must later call @xmlSetTreeDoc + * to ensure that all the children nodes have correct + * pointer to XML document. + * @c14nMethodId: the signature canonicalization method. + * @signMethodId: the signature method. + * @id: the node id (may be NULL). + * @nsPrefix: the namespace prefix for the signature element (e.g. "dsig"), or NULL + * + * Creates new <dsig:Signature/> node with the mandatory + * <dsig:SignedInfo/>, <dsig:CanonicalizationMethod/>, + * <dsig:SignatureMethod/> and <dsig:SignatureValue/> children and + * sub-children. This method differs from xmlSecTmplSignatureCreate in + * that it will define the http://www.w3.org/2000/09/xmldsig# + * namespace with the given prefix that will be used for all of the + * appropriate child nodes. The application is responsible for + * inserting the returned node in the XML document. + * + * Returns: the pointer to newly created <dsig:Signature/> node or NULL if an + * error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureCreateNsPref(xmlDocPtr doc, xmlSecTransformId c14nMethodId, + xmlSecTransformId signMethodId, const xmlChar *id, + const xmlChar* nsPrefix) { + xmlNodePtr signNode; + xmlNodePtr signedInfoNode; + xmlNodePtr cur; + xmlNsPtr ns; + + xmlSecAssert2(c14nMethodId != NULL, NULL); + xmlSecAssert2(c14nMethodId->href != NULL, NULL); + xmlSecAssert2(signMethodId != NULL, NULL); + xmlSecAssert2(signMethodId->href != NULL, NULL); + + /* create Signature node itself */ + signNode = xmlNewDocNode(doc, NULL, xmlSecNodeSignature, NULL); + if(signNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDocNode", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeSignature)); + return(NULL); + } + + ns = xmlNewNs(signNode, xmlSecDSigNs, nsPrefix); + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(xmlSecDSigNs)); + xmlFreeNode(signNode); + return(NULL); + } + xmlSetNs(signNode, ns); + + if(id != NULL) { + xmlSetProp(signNode, BAD_CAST "Id", id); + } + + /* add SignedInfo node */ + signedInfoNode = xmlSecAddChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs); + if(signedInfoNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeSignedInfo)); + xmlFreeNode(signNode); + return(NULL); + } + + /* add SignatureValue node */ + cur = xmlSecAddChild(signNode, xmlSecNodeSignatureValue, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeSignatureValue)); + xmlFreeNode(signNode); + return(NULL); + } + + /* add CanonicaizationMethod node to SignedInfo */ + cur = xmlSecAddChild(signedInfoNode, xmlSecNodeCanonicalizationMethod, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCanonicalizationMethod)); + xmlFreeNode(signNode); + return(NULL); + } + if(xmlSetProp(cur, xmlSecAttrAlgorithm, c14nMethodId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(c14nMethodId->href)); + xmlFreeNode(signNode); + return(NULL); + } + + /* add SignatureMethod node to SignedInfo */ + cur = xmlSecAddChild(signedInfoNode, xmlSecNodeSignatureMethod, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeSignatureMethod)); + xmlFreeNode(signNode); + return(NULL); + } + if(xmlSetProp(cur, xmlSecAttrAlgorithm, signMethodId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(signMethodId->href)); + xmlFreeNode(signNode); + return(NULL); + } + + return(signNode); +} + +/** + * xmlSecTmplSignatureEnsureKeyInfo: + * @signNode: the pointer to <dsig:Signature/> node. + * @id: the node id (may be NULL). + * + * Adds (if necessary) <dsig:KeyInfo/> node to the <dsig:Signature/> + * node @signNode. + * + * Returns: the pointer to newly created <dsig:KeyInfo/> node or NULL if an + * error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureEnsureKeyInfo(xmlNodePtr signNode, const xmlChar *id) { + xmlNodePtr res; + + xmlSecAssert2(signNode != NULL, NULL); + + res = xmlSecFindChild(signNode, xmlSecNodeKeyInfo, xmlSecDSigNs); + if(res == NULL) { + xmlNodePtr signValueNode; + + signValueNode = xmlSecFindChild(signNode, xmlSecNodeSignatureValue, xmlSecDSigNs); + if(signValueNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeSignatureValue), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecAddNextSibling(signValueNode, xmlSecNodeKeyInfo, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddNextSibling", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyInfo)); + return(NULL); + } + } + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + return(res); +} + +/** + * xmlSecTmplSignatureAddReference: + * @signNode: the pointer to <dsig:Signature/> node. + * @digestMethodId: the reference digest method. + * @id: the node id (may be NULL). + * @uri: the reference node uri (may be NULL). + * @type: the reference node type (may be NULL). + * + * Adds <dsig:Reference/> node with given URI (@uri), Id (@id) and + * Type (@type) attributes and the required children <dsig:DigestMethod/> and + * <dsig:DigestValue/> to the <dsig:SignedInfo/> child of @signNode. + * + * Returns: the pointer to newly created <dsig:Reference/> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureAddReference(xmlNodePtr signNode, xmlSecTransformId digestMethodId, + const xmlChar *id, const xmlChar *uri, const xmlChar *type) { + xmlNodePtr signedInfoNode; + + xmlSecAssert2(signNode != NULL, NULL); + xmlSecAssert2(digestMethodId != NULL, NULL); + xmlSecAssert2(digestMethodId->href != NULL, NULL); + + signedInfoNode = xmlSecFindChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs); + if(signedInfoNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeSignedInfo), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + return(xmlSecTmplAddReference(signedInfoNode, digestMethodId, id, uri, type)); +} + +static xmlNodePtr +xmlSecTmplAddReference(xmlNodePtr parentNode, xmlSecTransformId digestMethodId, + const xmlChar *id, const xmlChar *uri, const xmlChar *type) { + xmlNodePtr res; + xmlNodePtr cur; + + xmlSecAssert2(parentNode != NULL, NULL); + xmlSecAssert2(digestMethodId != NULL, NULL); + xmlSecAssert2(digestMethodId->href != NULL, NULL); + + /* add Reference node */ + res = xmlSecAddChild(parentNode, xmlSecNodeReference, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeReference)); + return(NULL); + } + + /* set Reference node attributes */ + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + if(type != NULL) { + xmlSetProp(res, xmlSecAttrType, type); + } + if(uri != NULL) { + xmlSetProp(res, xmlSecAttrURI, uri); + } + + /* add DigestMethod node and set algorithm */ + cur = xmlSecAddChild(res, xmlSecNodeDigestMethod, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDigestMethod)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + if(xmlSetProp(cur, xmlSecAttrAlgorithm, digestMethodId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(digestMethodId->href)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + + /* add DigestValue node */ + cur = xmlSecAddChild(res, xmlSecNodeDigestValue, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDigestValue)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + + return(res); +} + +/** + * xmlSecTmplSignatureAddObject: + * @signNode: the pointer to <dsig:Signature/> node. + * @id: the node id (may be NULL). + * @mimeType: the object mime type (may be NULL). + * @encoding: the object encoding (may be NULL). + * + * Adds <dsig:Object/> node to the <dsig:Signature/> node @signNode. + * + * Returns: the pointer to newly created <dsig:Object/> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureAddObject(xmlNodePtr signNode, const xmlChar *id, + const xmlChar *mimeType, const xmlChar *encoding) { + xmlNodePtr res; + + xmlSecAssert2(signNode != NULL, NULL); + + res = xmlSecAddChild(signNode, xmlSecNodeObject, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeObject)); + return(NULL); + } + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + if(mimeType != NULL) { + xmlSetProp(res, xmlSecAttrMimeType, mimeType); + } + if(encoding != NULL) { + xmlSetProp(res, xmlSecAttrEncoding, encoding); + } + return(res); +} + +/** + * xmlSecTmplSignatureGetSignMethodNode: + * @signNode: the pointer to <dsig:Signature /> node. + * + * Gets pointer to <dsig:SignatureMethod/> child of <dsig:KeyInfo/> node. + * + * Returns: pointer to <dsig:SignatureMethod /> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureGetSignMethodNode(xmlNodePtr signNode) { + xmlNodePtr signedInfoNode; + + xmlSecAssert2(signNode != NULL, NULL); + + signedInfoNode = xmlSecFindChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs); + if(signedInfoNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeSignedInfo), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + return(xmlSecFindChild(signedInfoNode, xmlSecNodeSignatureMethod, xmlSecDSigNs)); +} + +/** + * xmlSecTmplSignatureGetC14NMethodNode: + * @signNode: the pointer to <dsig:Signature /> node. + * + * Gets pointer to <dsig:CanonicalizationMethod/> child of <dsig:KeyInfo/> node. + * + * Returns: pointer to <dsig:CanonicalizationMethod /> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplSignatureGetC14NMethodNode(xmlNodePtr signNode) { + xmlNodePtr signedInfoNode; + + xmlSecAssert2(signNode != NULL, NULL); + + signedInfoNode = xmlSecFindChild(signNode, xmlSecNodeSignedInfo, xmlSecDSigNs); + if(signedInfoNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeSignedInfo), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + return(xmlSecFindChild(signedInfoNode, xmlSecNodeCanonicalizationMethod, xmlSecDSigNs)); +} + +/** + * xmlSecTmplReferenceAddTransform: + * @referenceNode: the pointer to <dsig:Reference/> node. + * @transformId: the transform method id. + * + * Adds <dsig:Transform/> node to the <dsig:Reference/> node @referenceNode. + * + * Returns: the pointer to newly created <dsig:Transform/> node or NULL if an + * error occurs. + */ +xmlNodePtr +xmlSecTmplReferenceAddTransform(xmlNodePtr referenceNode, xmlSecTransformId transformId) { + xmlNodePtr transformsNode; + xmlNodePtr res; + + xmlSecAssert2(referenceNode != NULL, NULL); + xmlSecAssert2(transformId != NULL, NULL); + xmlSecAssert2(transformId->href != NULL, NULL); + + /* do we need to create Transforms node first */ + transformsNode = xmlSecFindChild(referenceNode, xmlSecNodeTransforms, xmlSecDSigNs); + if(transformsNode == NULL) { + xmlNodePtr tmp; + + tmp = xmlSecGetNextElementNode(referenceNode->children); + if(tmp == NULL) { + transformsNode = xmlSecAddChild(referenceNode, xmlSecNodeTransforms, xmlSecDSigNs); + } else { + transformsNode = xmlSecAddPrevSibling(tmp, xmlSecNodeTransforms, xmlSecDSigNs); + } + if(transformsNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild or xmlSecAddPrevSibling", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeTransforms)); + return(NULL); + } + } + + res = xmlSecAddChild(transformsNode, xmlSecNodeTransform, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeTransform)); + return(NULL); + } + + if(xmlSetProp(res, xmlSecAttrAlgorithm, transformId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(transformId->href)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + + return(res); +} + +/** + * xmlSecTmplObjectAddSignProperties: + * @objectNode: the pointer to <dsig:Object/> node. + * @id: the node id (may be NULL). + * @target: the Target (may be NULL). + * + * Adds <dsig:SignatureProperties/> node to the <dsig:Object/> node @objectNode. + * + * Returns: the pointer to newly created <dsig:SignatureProperties/> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecTmplObjectAddSignProperties(xmlNodePtr objectNode, const xmlChar *id, const xmlChar *target) { + xmlNodePtr res; + + xmlSecAssert2(objectNode != NULL, NULL); + + res = xmlSecAddChild(objectNode, xmlSecNodeSignatureProperties, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeSignatureProperties)); + return(NULL); + } + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + if(target != NULL) { + xmlSetProp(res, xmlSecAttrTarget, target); + } + return(res); +} + +/** + * xmlSecTmplObjectAddManifest: + * @objectNode: the pointer to <dsig:Object/> node. + * @id: the node id (may be NULL). + * + * Adds <dsig:Manifest/> node to the <dsig:Object/> node @objectNode. + * + * Returns: the pointer to newly created <dsig:Manifest/> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecTmplObjectAddManifest(xmlNodePtr objectNode, const xmlChar *id) { + xmlNodePtr res; + + xmlSecAssert2(objectNode != NULL, NULL); + + res = xmlSecAddChild(objectNode, xmlSecNodeManifest, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeManifest)); + return(NULL); + } + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + return(res); +} + +/** + * xmlSecTmplManifestAddReference: + * @manifestNode: the pointer to <dsig:Manifest/> node. + * @digestMethodId: the reference digest method. + * @id: the node id (may be NULL). + * @uri: the reference node uri (may be NULL). + * @type: the reference node type (may be NULL). + * + * Adds <dsig:Reference/> node with specified URI (@uri), Id (@id) and + * Type (@type) attributes and the required children <dsig:DigestMethod/> and + * <dsig:DigestValue/> to the <dsig:Manifest/> node @manifestNode. + * + * Returns: the pointer to newly created <dsig:Reference/> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecTmplManifestAddReference(xmlNodePtr manifestNode, xmlSecTransformId digestMethodId, + const xmlChar *id, const xmlChar *uri, const xmlChar *type) { + return(xmlSecTmplAddReference(manifestNode, digestMethodId, id, uri, type)); +} + +/************************************************************************** + * + * <enc:EncryptedData/> node + * + **************************************************************************/ +/** + * xmlSecTmplEncDataCreate: + * @doc: the pointer to signature document or NULL; in the later + * case, application must later call @xmlSetTreeDoc to ensure + * that all the children nodes have correct pointer to XML document. + * @encMethodId: the encryption method (may be NULL). + * @id: the Id attribute (optional). + * @type: the Type attribute (optional) + * @mimeType: the MimeType attribute (optional) + * @encoding: the Encoding attribute (optional) + * + * Creates new <enc:EncryptedData /> node for encryption template. + * + * Returns: the pointer newly created <enc:EncryptedData/> node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataCreate(xmlDocPtr doc, xmlSecTransformId encMethodId, + const xmlChar *id, const xmlChar *type, + const xmlChar *mimeType, const xmlChar *encoding) { + xmlNodePtr encNode; + xmlNsPtr ns; + + encNode = xmlNewDocNode(doc, NULL, xmlSecNodeEncryptedData, NULL); + if(encNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDocNode", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptedData)); + return(NULL); + } + + ns = xmlNewNs(encNode, xmlSecEncNs, NULL); + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(xmlSecEncNs)); + return(NULL); + } + xmlSetNs(encNode, ns); + + if(id != NULL) { + xmlSetProp(encNode, xmlSecAttrId, id); + } + if(type != NULL) { + xmlSetProp(encNode, xmlSecAttrType, type); + } + if(mimeType != NULL) { + xmlSetProp(encNode, xmlSecAttrMimeType, mimeType); + } + if(encoding != NULL) { + xmlSetProp(encNode, xmlSecAttrEncoding, encoding); + } + + if(xmlSecTmplPrepareEncData(encNode, encMethodId) < 0) { + xmlFreeNode(encNode); + return(NULL); + } + return(encNode); +} + +static int +xmlSecTmplPrepareEncData(xmlNodePtr parentNode, xmlSecTransformId encMethodId) { + xmlNodePtr cur; + + xmlSecAssert2(parentNode != NULL, -1); + xmlSecAssert2((encMethodId == NULL) || (encMethodId->href != NULL), -1); + + /* add EncryptionMethod node if requested */ + if(encMethodId != NULL) { + cur = xmlSecAddChild(parentNode, xmlSecNodeEncryptionMethod, xmlSecEncNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptionMethod)); + return(-1); + } + if(xmlSetProp(cur, xmlSecAttrAlgorithm, encMethodId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(encMethodId->href)); + return(-1); + } + } + + /* and CipherData node */ + cur = xmlSecAddChild(parentNode, xmlSecNodeCipherData, xmlSecEncNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCipherData)); + return(-1); + } + + return(0); +} + + +/** + * xmlSecTmplEncDataEnsureKeyInfo: + * @encNode: the pointer to <enc:EncryptedData/> node. + * @id: the Id attrbibute (optional). + * + * Adds <dsig:KeyInfo/> to the <enc:EncryptedData/> node @encNode. + * + * Returns: the pointer to newly created <dsig:KeyInfo/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataEnsureKeyInfo(xmlNodePtr encNode, const xmlChar* id) { + xmlNodePtr res; + + xmlSecAssert2(encNode != NULL, NULL); + + res = xmlSecFindChild(encNode, xmlSecNodeKeyInfo, xmlSecDSigNs); + if(res == NULL) { + xmlNodePtr cipherDataNode; + + cipherDataNode = xmlSecFindChild(encNode, xmlSecNodeCipherData, xmlSecEncNs); + if(cipherDataNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeCipherData), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecAddPrevSibling(cipherDataNode, xmlSecNodeKeyInfo, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddPrevSibling", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyInfo)); + return(NULL); + } + } + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + return(res); +} + +/** + * xmlSecTmplEncDataEnsureEncProperties: + * @encNode: the pointer to <enc:EncryptedData/> node. + * @id: the Id attribute (optional). + * + * Adds <enc:EncryptionProperties/> node to the <enc:EncryptedData/> + * node @encNode. + * + * Returns: the pointer to newly created <enc:EncryptionProperties/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataEnsureEncProperties(xmlNodePtr encNode, const xmlChar *id) { + xmlNodePtr res; + + xmlSecAssert2(encNode != NULL, NULL); + + res = xmlSecFindChild(encNode, xmlSecNodeEncryptionProperties, xmlSecEncNs); + if(res == NULL) { + res = xmlSecAddChild(encNode, xmlSecNodeEncryptionProperties, xmlSecEncNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptionProperties)); + return(NULL); + } + } + + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + + return(res); +} + +/** + * xmlSecTmplEncDataAddEncProperty: + * @encNode: the pointer to <enc:EncryptedData/> node. + * @id: the Id attribute (optional). + * @target: the Target attribute (optional). + * + * Adds <enc:EncryptionProperty/> node (and the parent + * <enc:EncryptionProperties/> node if required) to the + * <enc:EncryptedData/> node @encNode. + * + * Returns: the pointer to newly created <enc:EncryptionProperty/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataAddEncProperty(xmlNodePtr encNode, const xmlChar *id, const xmlChar *target) { + xmlNodePtr encProps; + xmlNodePtr res; + + xmlSecAssert2(encNode != NULL, NULL); + + encProps = xmlSecTmplEncDataEnsureEncProperties(encNode, NULL); + if(encProps == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTmplEncDataEnsureEncProperties", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecAddChild(encProps, xmlSecNodeEncryptionProperty, xmlSecEncNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptionProperty)); + return(NULL); + } + if(id != NULL) { + xmlSetProp(res, xmlSecAttrId, id); + } + if(target != NULL) { + xmlSetProp(res, xmlSecAttrTarget, target); + } + + return(res); +} + +/** + * xmlSecTmplEncDataEnsureCipherValue: + * @encNode: the pointer to <enc:EncryptedData/> node. + * + * Adds <enc:CipherValue/> to the <enc:EncryptedData/> node @encNode. + * + * Returns: the pointer to newly created <enc:CipherValue/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataEnsureCipherValue(xmlNodePtr encNode) { + xmlNodePtr cipherDataNode; + xmlNodePtr res, tmp; + + xmlSecAssert2(encNode != NULL, NULL); + + cipherDataNode = xmlSecFindChild(encNode, xmlSecNodeCipherData, xmlSecEncNs); + if(cipherDataNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeCipherData), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* check that we don;t have CipherReference node */ + tmp = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherReference, xmlSecEncNs); + if(tmp != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeCipherReference), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherValue, xmlSecEncNs); + if(res == NULL) { + res = xmlSecAddChild(cipherDataNode, xmlSecNodeCipherValue, xmlSecEncNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCipherValue)); + return(NULL); + } + } + + return(res); +} + +/** + * xmlSecTmplEncDataEnsureCipherReference: + * @encNode: the pointer to <enc:EncryptedData/> node. + * @uri: the URI attribute (may be NULL). + * + * Adds <enc:CipherReference/> node with specified URI attribute @uri + * to the <enc:EncryptedData/> node @encNode. + * + * Returns: the pointer to newly created <enc:CipherReference/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataEnsureCipherReference(xmlNodePtr encNode, const xmlChar *uri) { + xmlNodePtr cipherDataNode; + xmlNodePtr res, tmp; + + xmlSecAssert2(encNode != NULL, NULL); + + cipherDataNode = xmlSecFindChild(encNode, xmlSecNodeCipherData, xmlSecEncNs); + if(cipherDataNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeCipherData), + XMLSEC_ERRORS_R_NODE_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* check that we don;t have CipherValue node */ + tmp = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherValue, xmlSecEncNs); + if(tmp != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeCipherValue), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecFindChild(cipherDataNode, xmlSecNodeCipherReference, xmlSecEncNs); + if(res == NULL) { + res = xmlSecAddChild(cipherDataNode, xmlSecNodeCipherReference, xmlSecEncNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCipherReference)); + return(NULL); + } + } + + if(uri != NULL) { + xmlSetProp(res, xmlSecAttrURI, uri); + } + + return(res); +} + +/** + * xmlSecTmplEncDataGetEncMethodNode: + * @encNode: the pointer to <enc:EcnryptedData /> node. + * + * Gets pointer to <enc:EncrytpionMethod/> node. + * + * Returns: pointer to <enc:EncryptionMethod /> node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplEncDataGetEncMethodNode(xmlNodePtr encNode) { + xmlSecAssert2(encNode != NULL, NULL); + + return(xmlSecFindChild(encNode, xmlSecNodeEncryptionMethod, xmlSecEncNs)); +} + +/** + * xmlSecTmplCipherReferenceAddTransform: + * @cipherReferenceNode: the pointer to <enc:CipherReference/> node. + * @transformId: the transform id. + * + * Adds <dsig:Transform/> node (and the parent <dsig:Transforms/> node) + * with specified transform methods @transform to the <enc:CipherReference/> + * child node of the <enc:EncryptedData/> node @encNode. + * + * Returns: the pointer to newly created <dsig:Transform/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplCipherReferenceAddTransform(xmlNodePtr cipherReferenceNode, + xmlSecTransformId transformId) { + xmlNodePtr transformsNode; + xmlNodePtr res; + + xmlSecAssert2(cipherReferenceNode != NULL, NULL); + xmlSecAssert2(transformId != NULL, NULL); + xmlSecAssert2(transformId->href != NULL, NULL); + + transformsNode = xmlSecFindChild(cipherReferenceNode, xmlSecNodeTransforms, xmlSecEncNs); + if(transformsNode == NULL) { + transformsNode = xmlSecAddChild(cipherReferenceNode, xmlSecNodeTransforms, xmlSecEncNs); + if(transformsNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeTransforms)); + return(NULL); + } + } + + res = xmlSecAddChild(transformsNode, xmlSecNodeTransform, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeTransform)); + return(NULL); + } + + if(xmlSetProp(res, xmlSecAttrAlgorithm, transformId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(transformId->href)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + + return(res); +} + + +/*********************************************************************** + * + * <enc:EncryptedKey> node + * + **********************************************************************/ + +/** + * xmlSecTmplReferenceListAddDataReference: + * @encNode: the pointer to <enc:EncryptedKey/> node. + * @uri: uri to reference (optional) + * + * Adds <enc:DataReference/> and the parent <enc:ReferenceList/> node (if needed). + * + * Returns: the pointer to newly created <enc:DataReference/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplReferenceListAddDataReference(xmlNodePtr encNode, const xmlChar *uri) { + xmlNodePtr refListNode, res; + + xmlSecAssert2(encNode != NULL, NULL); + + refListNode = xmlSecFindChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs); + if(refListNode == NULL) { + refListNode = xmlSecAddChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs); + if(refListNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeReferenceList)); + return(NULL); + } + } + + res = xmlSecAddChild(refListNode, xmlSecNodeDataReference, xmlSecEncNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDataReference)); + return(NULL); + } + + if(uri != NULL) { + if(xmlSetProp(res, xmlSecAttrURI, uri) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrURI), + xmlSecErrorsSafeString(uri)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + } + + return(res); +} + +/** + * xmlSecTmplReferenceListAddKeyReference: + * @encNode: the pointer to <enc:EncryptedKey/> node. + * @uri: uri to reference (optional) + * + * Adds <enc:KeyReference/> and the parent <enc:ReferenceList/> node (if needed). + * + * Returns: the pointer to newly created <enc:KeyReference/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplReferenceListAddKeyReference(xmlNodePtr encNode, const xmlChar *uri) { + xmlNodePtr refListNode, res; + + xmlSecAssert2(encNode != NULL, NULL); + + refListNode = xmlSecFindChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs); + if(refListNode == NULL) { + refListNode = xmlSecAddChild(encNode, xmlSecNodeReferenceList, xmlSecEncNs); + if(refListNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeReferenceList)); + return(NULL); + } + } + + res = xmlSecAddChild(refListNode, xmlSecNodeKeyReference, xmlSecEncNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyReference)); + return(NULL); + } + + if(uri != NULL) { + if(xmlSetProp(res, xmlSecAttrURI, uri) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrURI), + xmlSecErrorsSafeString(uri)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + } + + return(res); +} + + +/************************************************************************** + * + * <dsig:KeyInfo/> node + * + **************************************************************************/ + +/** + * xmlSecTmplKeyInfoAddKeyName: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * @name: the key name (optional). + * + * Adds <dsig:KeyName/> node to the <dsig:KeyInfo/> node @keyInfoNode. + * + * Returns: the pointer to the newly created <dsig:KeyName/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplKeyInfoAddKeyName(xmlNodePtr keyInfoNode, const xmlChar* name) { + xmlNodePtr res; + + xmlSecAssert2(keyInfoNode != NULL, NULL); + + res = xmlSecAddChild(keyInfoNode, xmlSecNodeKeyName, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyName)); + return(NULL); + } + if(name != NULL) { + xmlSecNodeEncodeAndSetContent(res, name); + } + return(res); +} + +/** + * xmlSecTmplKeyInfoAddKeyValue: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * + * Adds <dsig:KeyValue/> node to the <dsig:KeyInfo/> node @keyInfoNode. + * + * Returns: the pointer to the newly created <dsig:KeyValue/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplKeyInfoAddKeyValue(xmlNodePtr keyInfoNode) { + xmlNodePtr res; + + xmlSecAssert2(keyInfoNode != NULL, NULL); + + res = xmlSecAddChild(keyInfoNode, xmlSecNodeKeyValue, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyValue)); + return(NULL); + } + + return(res); +} + +/** + * xmlSecTmplKeyInfoAddX509Data: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * + * Adds <dsig:X509Data/> node to the <dsig:KeyInfo/> node @keyInfoNode. + * + * Returns: the pointer to the newly created <dsig:X509Data/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplKeyInfoAddX509Data(xmlNodePtr keyInfoNode) { + xmlNodePtr res; + + xmlSecAssert2(keyInfoNode != NULL, NULL); + + res = xmlSecAddChild(keyInfoNode, xmlSecNodeX509Data, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509Data)); + return(NULL); + } + + return(res); +} + +/** + * xmlSecTmplKeyInfoAddRetrievalMethod: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * @uri: the URI attribute (optional). + * @type: the Type attribute(optional). + * + * Adds <dsig:RetrievalMethod/> node to the <dsig:KeyInfo/> node @keyInfoNode. + * + * Returns: the pointer to the newly created <dsig:RetrievalMethod/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplKeyInfoAddRetrievalMethod(xmlNodePtr keyInfoNode, const xmlChar *uri, + const xmlChar *type) { + xmlNodePtr res; + + xmlSecAssert2(keyInfoNode != NULL, NULL); + + res = xmlSecAddChild(keyInfoNode, xmlSecNodeRetrievalMethod, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRetrievalMethod)); + return(NULL); + } + + if(uri != NULL) { + xmlSetProp(res, xmlSecAttrURI, uri); + } + if(type != NULL) { + xmlSetProp(res, xmlSecAttrType, type); + } + return(res); +} + +/** + * xmlSecTmplRetrievalMethodAddTransform: + * @retrMethodNode: the pointer to <dsig:RetrievalMethod/> node. + * @transformId: the transform id. + * + * Adds <dsig:Transform/> node (and the parent <dsig:Transforms/> node + * if required) to the <dsig:RetrievalMethod/> node @retrMethod. + * + * Returns: the pointer to the newly created <dsig:Transforms/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplRetrievalMethodAddTransform(xmlNodePtr retrMethodNode, xmlSecTransformId transformId) { + xmlNodePtr transformsNode; + xmlNodePtr res; + + xmlSecAssert2(retrMethodNode != NULL, NULL); + xmlSecAssert2(transformId != NULL, NULL); + xmlSecAssert2(transformId->href != NULL, NULL); + + transformsNode = xmlSecFindChild(retrMethodNode, xmlSecNodeTransforms, xmlSecDSigNs); + if(transformsNode == NULL) { + transformsNode = xmlSecAddChild(retrMethodNode, xmlSecNodeTransforms, xmlSecDSigNs); + if(transformsNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeTransforms)); + return(NULL); + } + } + + res = xmlSecAddChild(transformsNode, xmlSecNodeTransform, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeTransform)); + return(NULL); + } + + if(xmlSetProp(res, xmlSecAttrAlgorithm, transformId->href) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + xmlSecErrorsSafeString(transformId->href)); + xmlUnlinkNode(res); + xmlFreeNode(res); + return(NULL); + } + + return(res); +} + + +/** + * xmlSecTmplKeyInfoAddEncryptedKey: + * @keyInfoNode: the pointer to <dsig:KeyInfo/> node. + * @encMethodId: the encryption method (optional). + * @id: the Id attribute (optional). + * @type: the Type attribute (optional). + * @recipient: the Recipient attribute (optional). + * + * Adds <enc:EncryptedKey/> node with given attributes to + * the <dsig:KeyInfo/> node @keyInfoNode. + * + * Returns: the pointer to the newly created <enc:EncryptedKey/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplKeyInfoAddEncryptedKey(xmlNodePtr keyInfoNode, xmlSecTransformId encMethodId, + const xmlChar* id, const xmlChar* type, const xmlChar* recipient) { + xmlNodePtr encKeyNode; + + xmlSecAssert2(keyInfoNode != NULL, NULL); + + /* we allow multiple encrypted key elements */ + encKeyNode = xmlSecAddChild(keyInfoNode, xmlSecNodeEncryptedKey, xmlSecEncNs); + if(encKeyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptedKey)); + return(NULL); + } + + if(id != NULL) { + xmlSetProp(encKeyNode, xmlSecAttrId, id); + } + if(type != NULL) { + xmlSetProp(encKeyNode, xmlSecAttrType, type); + } + if(recipient != NULL) { + xmlSetProp(encKeyNode, xmlSecAttrRecipient, recipient); + } + + if(xmlSecTmplPrepareEncData(encKeyNode, encMethodId) < 0) { + xmlUnlinkNode(encKeyNode); + xmlFreeNode(encKeyNode); + return(NULL); + } + return(encKeyNode); +} + +/*********************************************************************** + * + * <dsig:X509Data> node + * + **********************************************************************/ +/** + * xmlSecTmplX509DataAddIssuerSerial: + * @x509DataNode: the pointer to <dsig:X509Data/> node. + * + * Adds <dsig:X509IssuerSerial/> node to the given <dsig:X509Data/> node. + * + * Returns: the pointer to the newly created <dsig:X509IssuerSerial/> node or + * NULL if an error occurs. + */ + +xmlNodePtr +xmlSecTmplX509DataAddIssuerSerial(xmlNodePtr x509DataNode) { + xmlNodePtr cur; + + xmlSecAssert2(x509DataNode != NULL, NULL); + + cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509IssuerSerial, xmlSecDSigNs); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509IssuerSerial, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509IssuerSerial)); + return(NULL); + } + + return (cur); +} + +/** + * xmlSecTmplX509IssuerSerialAddIssuerName: + * @x509IssuerSerialNode: the pointer to <dsig:X509IssuerSerial/> node. + * @issuerName: the issuer name (optional). + * + * Adds <dsig:X509IssuerName/> node to the <dsig:X509IssuerSerial/> node @x509IssuerSerialNode. + * + * Returns: the pointer to the newly created <dsig:X509IssuerName/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplX509IssuerSerialAddIssuerName(xmlNodePtr x509IssuerSerialNode, const xmlChar* issuerName) { + xmlNodePtr res; + + xmlSecAssert2(x509IssuerSerialNode != NULL, NULL); + + if(xmlSecFindChild(x509IssuerSerialNode, xmlSecNodeX509IssuerName, + xmlSecDSigNs) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509IssuerName), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecAddChild(x509IssuerSerialNode, xmlSecNodeX509IssuerName, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509IssuerName)); + return(NULL); + } + + if (issuerName != NULL) { + xmlSecNodeEncodeAndSetContent(res, issuerName); + } + return(res); +} + +/** + * xmlSecTmplX509IssuerSerialAddSerialNumber: + * @x509IssuerSerialNode: the pointer to <dsig:X509IssuerSerial/> node. + * @serial: the serial number (optional). + * + * Adds <dsig:X509SerialNumber/> node to the <dsig:X509IssuerSerial/> node @x509IssuerSerialNode. + * + * Returns: the pointer to the newly created <dsig:X509SerialNumber/> node or + * NULL if an error occurs. + */ +xmlNodePtr +xmlSecTmplX509IssuerSerialAddSerialNumber(xmlNodePtr x509IssuerSerialNode, const xmlChar* serial) { + xmlNodePtr res; + + xmlSecAssert2(x509IssuerSerialNode != NULL, NULL); + + if(xmlSecFindChild(x509IssuerSerialNode, xmlSecNodeX509SerialNumber, + xmlSecDSigNs) != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + res = xmlSecAddChild(x509IssuerSerialNode, xmlSecNodeX509SerialNumber, xmlSecDSigNs); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SerialNumber)); + return(NULL); + } + + if (serial != NULL) { + xmlSecNodeEncodeAndSetContent(res, serial); + } + return(res); +} + +/** + * xmlSecTmplX509DataAddSubjectName: + * @x509DataNode: the pointer to <dsig:X509Data/> node. + * + * Adds <dsig:X509SubjectName/> node to the given <dsig:X509Data/> node. + * + * Returns: the pointer to the newly created <dsig:X509SubjectName/> node or + * NULL if an error occurs. + */ + +xmlNodePtr +xmlSecTmplX509DataAddSubjectName(xmlNodePtr x509DataNode) { + xmlNodePtr cur; + + xmlSecAssert2(x509DataNode != NULL, NULL); + + cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509SubjectName, xmlSecDSigNs); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509SubjectName), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509SubjectName, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SubjectName)); + return(NULL); + } + + return (cur); +} + +/** + * xmlSecTmplX509DataAddSKI: + * @x509DataNode: the pointer to <dsig:X509Data/> node. + * + * Adds <dsig:X509SKI/> node to the given <dsig:X509Data/> node. + * + * Returns: the pointer to the newly created <dsig:X509SKI/> node or + * NULL if an error occurs. + */ + +xmlNodePtr +xmlSecTmplX509DataAddSKI(xmlNodePtr x509DataNode) { + xmlNodePtr cur; + + xmlSecAssert2(x509DataNode != NULL, NULL); + + cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509SKI, xmlSecDSigNs); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509SKI), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509SKI, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509SKI)); + return(NULL); + } + + return (cur); +} + + +/** + * xmlSecTmplX509DataAddCertificate: + * @x509DataNode: the pointer to <dsig:X509Data/> node. + * + * Adds <dsig:X509Certificate/> node to the given <dsig:X509Data/> node. + * + * Returns: the pointer to the newly created <dsig:X509Certificate/> node or + * NULL if an error occurs. + */ + +xmlNodePtr +xmlSecTmplX509DataAddCertificate(xmlNodePtr x509DataNode) { + xmlNodePtr cur; + + xmlSecAssert2(x509DataNode != NULL, NULL); + + cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509Certificate, xmlSecDSigNs); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509Certificate), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509Certificate, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509Certificate)); + return(NULL); + } + + return (cur); +} + +/** + * xmlSecTmplX509DataAddCRL: + * @x509DataNode: the pointer to <dsig:X509Data/> node. + * + * Adds <dsig:X509CRL/> node to the given <dsig:X509Data/> node. + * + * Returns: the pointer to the newly created <dsig:X509CRL/> node or + * NULL if an error occurs. + */ + +xmlNodePtr +xmlSecTmplX509DataAddCRL(xmlNodePtr x509DataNode) { + xmlNodePtr cur; + + xmlSecAssert2(x509DataNode != NULL, NULL); + + cur = xmlSecFindChild(x509DataNode, xmlSecNodeX509CRL, xmlSecDSigNs); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeX509CRL), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + cur = xmlSecAddChild(x509DataNode, xmlSecNodeX509CRL, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeX509CRL)); + return(NULL); + } + + return (cur); +} + +/************************************************************************* + * + * <dsig:Transform/> node + * + ************************************************************************/ + +/** + * xmlSecTmplTransformAddHmacOutputLength: + * @transformNode: the pointer to <dsig:Transform/> node + * @bitsLen: the required length in bits + * + * Creates <dsig:HMACOutputLength/> child for the HMAC transform + * node @node. + * + * Returns: 0 on success and a negatie value otherwise. + */ +int +xmlSecTmplTransformAddHmacOutputLength(xmlNodePtr transformNode, xmlSecSize bitsLen) { + xmlNodePtr cur; + char buf[32]; + + xmlSecAssert2(transformNode != NULL, -1); + xmlSecAssert2(bitsLen > 0, -1); + + cur = xmlSecFindChild(transformNode, xmlSecNodeHMACOutputLength, xmlSecDSigNs); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeHMACOutputLength), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecAddChild(transformNode, xmlSecNodeHMACOutputLength, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeHMACOutputLength)); + return(-1); + } + + sprintf(buf, "%u", bitsLen); + xmlNodeSetContent(cur, BAD_CAST buf); + return(0); +} + +/** + * xmlSecTmplTransformAddRsaOaepParam: + * @transformNode: the pointer to <dsig:Transform/> node. + * @buf: the OAEP param buffer. + * @size: the OAEP param buffer size. + * + * Creates <enc:OAEPParam/> child node in the @node. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTmplTransformAddRsaOaepParam(xmlNodePtr transformNode, + const xmlSecByte *buf, xmlSecSize size) { + xmlNodePtr oaepParamNode; + xmlChar *base64; + + xmlSecAssert2(transformNode != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + xmlSecAssert2(size > 0, -1); + + oaepParamNode = xmlSecFindChild(transformNode, xmlSecNodeRsaOAEPparams, xmlSecEncNs); + if(oaepParamNode != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeRsaOAEPparams), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + oaepParamNode = xmlSecAddChild(transformNode, xmlSecNodeRsaOAEPparams, xmlSecEncNs); + if(oaepParamNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeRsaOAEPparams)); + return(-1); + } + + base64 = xmlSecBase64Encode(buf, size, 0); + if(base64 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", size); + return(-1); + } + + xmlNodeSetContent(oaepParamNode, base64); + xmlFree(base64); + return(0); +} + +/** + * xmlSecTmplTransformAddXsltStylesheet: + * @transformNode: the pointer to <dsig:Transform/> node. + * @xslt: the XSLT transform exspression. + * + * Writes the XSLT transform expression to the @node. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTmplTransformAddXsltStylesheet(xmlNodePtr transformNode, const xmlChar *xslt) { + xmlDocPtr xsltDoc; + int ret; + + xmlSecAssert2(transformNode != NULL, -1); + xmlSecAssert2(xslt != NULL, -1); + + xsltDoc = xmlParseMemory((const char*)xslt, xmlStrlen(xslt)); + if(xsltDoc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlParseMemory", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecReplaceContent(transformNode, xmlDocGetRootElement(xsltDoc)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceContent", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(xsltDoc); + return(-1); + } + + xmlFreeDoc(xsltDoc); + return(0); +} + +/** + * xmlSecTmplTransformAddC14NInclNamespaces: + * @transformNode: the pointer to <dsig:Transform/> node. + * @prefixList: the white space delimited list of namespace prefixes, + * where "#default" indicates the default namespace + * (optional). + * + * Adds "inclusive" namespaces to the ExcC14N transform node @node. + * + * Returns: 0 if success or a negative value otherwise. + */ +int +xmlSecTmplTransformAddC14NInclNamespaces(xmlNodePtr transformNode, + const xmlChar *prefixList) { + xmlNodePtr cur; + + xmlSecAssert2(transformNode != NULL, -1); + xmlSecAssert2(prefixList != NULL, -1); + + cur = xmlSecFindChild(transformNode, xmlSecNodeInclusiveNamespaces, xmlSecNsExcC14N); + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeInclusiveNamespaces), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecAddChild(transformNode, xmlSecNodeInclusiveNamespaces, xmlSecNsExcC14N); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecNodeGetName(transformNode)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeInclusiveNamespaces)); + return(-1); + } + + xmlSetProp(cur, xmlSecAttrPrefixList, prefixList); + return(0); +} + +/** + * xmlSecTmplTransformAddXPath: + * @transformNode: the pointer to the <dsig:Transform/> node. + * @expression: the XPath expression. + * @nsList: the NULL terminated list of namespace prefix/href pairs + * (optional). + * + * Writes XPath transform infromation to the <dsig:Transform/> node + * @node. + * + * Returns: 0 for success or a negative value otherwise. + */ +int +xmlSecTmplTransformAddXPath(xmlNodePtr transformNode, const xmlChar *expression, + const xmlChar **nsList) { + xmlNodePtr xpathNode; + + xmlSecAssert2(transformNode != NULL, -1); + xmlSecAssert2(expression != NULL, -1); + + xpathNode = xmlSecFindChild(transformNode, xmlSecNodeXPath, xmlSecDSigNs); + if(xpathNode != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeXPath), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + xpathNode = xmlSecAddChild(transformNode, xmlSecNodeXPath, xmlSecDSigNs); + if(xpathNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeXPath)); + return(-1); + } + + xmlSecNodeEncodeAndSetContent(xpathNode, expression); + return((nsList != NULL) ? xmlSecTmplNodeWriteNsList(xpathNode, nsList) : 0); +} + +/** + * xmlSecTmplTransformAddXPath2: + * @transformNode: the pointer to the <dsig:Transform/> node. + * @type: the XPath2 transform type ("union", "intersect" or "subtract"). + * @expression: the XPath expression. + * @nsList: the NULL terminated list of namespace prefix/href pairs. + * (optional). + * + * Writes XPath2 transform infromation to the <dsig:Transform/> node + * @node. + * + * Returns: 0 for success or a negative value otherwise. + */ +int +xmlSecTmplTransformAddXPath2(xmlNodePtr transformNode, const xmlChar* type, + const xmlChar *expression, const xmlChar **nsList) { + xmlNodePtr xpathNode; + + xmlSecAssert2(transformNode != NULL, -1); + xmlSecAssert2(type != NULL, -1); + xmlSecAssert2(expression != NULL, -1); + + xpathNode = xmlSecAddChild(transformNode, xmlSecNodeXPath, xmlSecXPath2Ns); + if(xpathNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeXPath)); + return(-1); + } + xmlSetProp(xpathNode, xmlSecAttrFilter, type); + + xmlSecNodeEncodeAndSetContent(xpathNode, expression); + return((nsList != NULL) ? xmlSecTmplNodeWriteNsList(xpathNode, nsList) : 0); +} + +/** + * xmlSecTmplTransformAddXPointer: + * @transformNode: the pointer to the <dsig:Transform/> node. + * @expression: the XPath expression. + * @nsList: the NULL terminated list of namespace prefix/href pairs. + * (optional). + * + * Writes XPoniter transform infromation to the <dsig:Transform/> node + * @node. + * + * Returns: 0 for success or a negative value otherwise. + */ +int +xmlSecTmplTransformAddXPointer(xmlNodePtr transformNode, const xmlChar *expression, + const xmlChar **nsList) { + xmlNodePtr xpointerNode; + + xmlSecAssert2(expression != NULL, -1); + xmlSecAssert2(transformNode != NULL, -1); + + xpointerNode = xmlSecFindChild(transformNode, xmlSecNodeXPointer, xmlSecXPointerNs); + if(xpointerNode != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeXPointer), + XMLSEC_ERRORS_R_NODE_ALREADY_PRESENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + xpointerNode = xmlSecAddChild(transformNode, xmlSecNodeXPointer, xmlSecXPointerNs); + if(xpointerNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeXPointer)); + return(-1); + } + + + xmlSecNodeEncodeAndSetContent(xpointerNode, expression); + return((nsList != NULL) ? xmlSecTmplNodeWriteNsList(xpointerNode, nsList) : 0); +} + +static int +xmlSecTmplNodeWriteNsList(xmlNodePtr parentNode, const xmlChar** nsList) { + xmlNsPtr ns; + const xmlChar *prefix; + const xmlChar *href; + const xmlChar **ptr; + + xmlSecAssert2(parentNode != NULL, -1); + xmlSecAssert2(nsList != NULL, -1); + + ptr = nsList; + while((*ptr) != NULL) { + if(xmlStrEqual(BAD_CAST "#default", (*ptr))) { + prefix = NULL; + } else { + prefix = (*ptr); + } + if((++ptr) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "unexpected end of ns list"); + return(-1); + } + href = *(ptr++); + + ns = xmlNewNs(parentNode, href, prefix); + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "href=%s;prefix=%s", + xmlSecErrorsSafeString(href), + xmlSecErrorsSafeString(prefix)); + return(-1); + } + } + return(0); +} diff --git a/src/transforms.c b/src/transforms.c new file mode 100644 index 00000000..2ed3fe88 --- /dev/null +++ b/src/transforms.c @@ -0,0 +1,2892 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * The Transforms Element (http://www.w3.org/TR/xmldsig-core/#sec-Transforms) + * + * The optional Transforms element contains an ordered list of Transform + * elements; these describe how the signer obtained the data object that + * was digested. + * + * Schema Definition: + * + * <element name="Transforms" type="ds:TransformsType"/> + * <complexType name="TransformsType"> + * <sequence> + * <element ref="ds:Transform" maxOccurs="unbounded"/> + * </sequence> + * </complexType> + * + * <element name="Transform" type="ds:TransformType"/> + * <complexType name="TransformType" mixed="true"> + * <choice minOccurs="0" maxOccurs="unbounded"> + * <any namespace="##other" processContents="lax"/> + * <!-- (1,1) elements from (0,unbounded) namespaces --> + * <element name="XPath" type="string"/> + * </choice> + * <attribute name="Algorithm" type="anyURI" use="required"/> + * </complexType> + * + * DTD: + * + * <!ELEMENT Transforms (Transform+)> + * <!ELEMENT Transform (#PCDATA|XPath %Transform.ANY;)* > + * <!ATTLIST Transform Algorithm CDATA #REQUIRED > + * <!ELEMENT XPath (#PCDATA) > + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ + +#include "globals.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xpointer.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keysdata.h> +#include <xmlsec/keys.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/transforms.h> +#include <xmlsec/base64.h> +#include <xmlsec/io.h> +#include <xmlsec/membuf.h> +#include <xmlsec/parser.h> +#include <xmlsec/errors.h> + +/************************************************************************** + * + * Global xmlSecTransformIds list functions + * + *************************************************************************/ +static xmlSecPtrList xmlSecAllTransformIds; + + +/** + * xmlSecTransformIdsGet: + * + * Gets global registered transform klasses list. + * + * Returns: the pointer to list of all registered transform klasses. + */ +xmlSecPtrListPtr +xmlSecTransformIdsGet(void) { + return(&xmlSecAllTransformIds); +} + +/** + * xmlSecTransformIdsInit: + * + * Initializes the transform klasses. This function is called from the + * #xmlSecInit function and the application should not call it directly. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformIdsInit(void) { + int ret; + + ret = xmlSecPtrListInitialize(xmlSecTransformIdsGet(), xmlSecTransformIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListPtrInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecTransformIdListId"); + return(-1); + } + + ret = xmlSecTransformIdsRegisterDefault(); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegisterDefault", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecTransformIdsShutdown: + * + * Shuts down the keys data klasses. This function is called from the + * #xmlSecShutdown function and the application should not call it directly. + */ +void +xmlSecTransformIdsShutdown(void) { + xmlSecPtrListFinalize(xmlSecTransformIdsGet()); +} + +/** + * xmlSecTransformIdsRegister: + * @id: the transform klass. + * + * Registers @id in the global list of transform klasses. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformIdsRegister(xmlSecTransformId id) { + int ret; + + xmlSecAssert2(id != xmlSecTransformIdUnknown, -1); + + ret = xmlSecPtrListAdd(xmlSecTransformIdsGet(), (xmlSecPtr)id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id))); + return(-1); + } + + return(0); +} + +/** + * xmlSecTransformIdsRegisterDefault: + * + * Registers default (implemented by XML Security Library) + * transform klasses: XPath transform, Base64 transform, ... + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformIdsRegisterDefault(void) { + if(xmlSecTransformIdsRegister(xmlSecTransformBase64Id) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformBase64Id))); + return(-1); + } + + if(xmlSecTransformIdsRegister(xmlSecTransformEnvelopedId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformEnvelopedId))); + return(-1); + } + + /* c14n methods */ + if(xmlSecTransformIdsRegister(xmlSecTransformInclC14NId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14NId))); + return(-1); + } + if(xmlSecTransformIdsRegister(xmlSecTransformInclC14NWithCommentsId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14NWithCommentsId))); + return(-1); + } + if(xmlSecTransformIdsRegister(xmlSecTransformInclC14N11Id) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14N11Id))); + return(-1); + } + if(xmlSecTransformIdsRegister(xmlSecTransformInclC14N11WithCommentsId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14N11WithCommentsId))); + return(-1); + } + if(xmlSecTransformIdsRegister(xmlSecTransformExclC14NId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformExclC14NId))); + return(-1); + } + if(xmlSecTransformIdsRegister(xmlSecTransformExclC14NWithCommentsId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformExclC14NWithCommentsId))); + return(-1); + } + + if(xmlSecTransformIdsRegister(xmlSecTransformXPathId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPathId))); + return(-1); + } + + if(xmlSecTransformIdsRegister(xmlSecTransformXPath2Id) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPath2Id))); + return(-1); + } + + if(xmlSecTransformIdsRegister(xmlSecTransformXPointerId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPointerId))); + return(-1); + } + +#ifndef XMLSEC_NO_XSLT + if(xmlSecTransformIdsRegister(xmlSecTransformXsltId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXsltId))); + return(-1); + } +#endif /* XMLSEC_NO_XSLT */ + + return(0); +} + +/************************************************************************** + * + * utils + * + *************************************************************************/ +/** + * xmlSecTransformUriTypeCheck: + * @type: the expected URI type. + * @uri: the uri for checking. + * + * Checks if @uri matches expected type @type. + * + * Returns: 1 if @uri matches @type, 0 if not or a negative value + * if an error occurs. + */ +int +xmlSecTransformUriTypeCheck(xmlSecTransformUriType type, const xmlChar* uri) { + xmlSecTransformUriType uriType = 0; + + if((uri == NULL) || (xmlStrlen(uri) == 0)) { + uriType = xmlSecTransformUriTypeEmpty; + } else if(uri[0] == '#') { + uriType = xmlSecTransformUriTypeSameDocument; + } else if(xmlStrncmp(uri, BAD_CAST "file://", 7) == 0) { + uriType = xmlSecTransformUriTypeLocal; + } else { + uriType = xmlSecTransformUriTypeRemote; + } + return(((uriType & type) != 0) ? 1 : 0); +} + +/************************************************************************** + * + * xmlSecTransformCtx + * + *************************************************************************/ + +/** + * xmlSecTransformCtxCreate: + * + * Creates transforms chain processing context. + * The caller is responsible for destroying returend object by calling + * #xmlSecTransformCtxDestroy function. + * + * Returns: pointer to newly allocated context object or NULL if an error + * occurs. + */ +xmlSecTransformCtxPtr +xmlSecTransformCtxCreate(void) { + xmlSecTransformCtxPtr ctx; + int ret; + + /* Allocate a new xmlSecTransform and fill the fields. */ + ctx = (xmlSecTransformCtxPtr)xmlMalloc(sizeof(xmlSecTransformCtx)); + if(ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(xmlSecTransformCtx)); + return(NULL); + } + + ret = xmlSecTransformCtxInitialize(ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecTransformCtxDestroy(ctx); + return(NULL); + } + + return(ctx); +} + +/** + * xmlSecTransformCtxDestroy: + * @ctx: the pointer to transforms chain processing context. + * + * Destroy context object created with #xmlSecTransformCtxCreate function. + */ +void +xmlSecTransformCtxDestroy(xmlSecTransformCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + xmlSecTransformCtxFinalize(ctx); + xmlFree(ctx); +} + +/** + * xmlSecTransformCtxInitialize: + * @ctx: the pointer to transforms chain processing context. + * + * Initializes transforms chain processing context. + * The caller is responsible for cleaing up returend object by calling + * #xmlSecTransformCtxFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformCtxInitialize(xmlSecTransformCtxPtr ctx) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecTransformCtx)); + + ret = xmlSecPtrListInitialize(&(ctx->enabledTransforms), xmlSecTransformIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ctx->enabledUris = xmlSecTransformUriTypeAny; + return(0); +} + +/** + * xmlSecTransformCtxFinalize: + * @ctx: the pointer to transforms chain processing context. + * + * Cleans up @ctx object initialized with #xmlSecTransformCtxInitialize function. + */ +void +xmlSecTransformCtxFinalize(xmlSecTransformCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + xmlSecTransformCtxReset(ctx); + xmlSecPtrListFinalize(&(ctx->enabledTransforms)); + memset(ctx, 0, sizeof(xmlSecTransformCtx)); +} + +/** + * xmlSecTransformCtxReset: + * @ctx: the pointer to transforms chain processing context. + * + * Resets transfroms context for new processing. + */ +void +xmlSecTransformCtxReset(xmlSecTransformCtxPtr ctx) { + xmlSecTransformPtr transform, tmp; + + xmlSecAssert(ctx != NULL); + + ctx->result = NULL; + ctx->status = xmlSecTransformStatusNone; + + /* destroy uri */ + if(ctx->uri != NULL) { + xmlFree(ctx->uri); + ctx->uri = NULL; + } + if(ctx->xptrExpr != NULL) { + xmlFree(ctx->xptrExpr); + ctx->xptrExpr = NULL; + } + + /* destroy transforms chain */ + for(transform = ctx->first; transform != NULL; transform = tmp) { + tmp = transform->next; + xmlSecTransformDestroy(transform); + } + ctx->first = ctx->last = NULL; +} + +/** + * xmlSecTransformCtxCopyUserPref: + * @dst: the pointer to destination transforms chain processing context. + * @src: the pointer to source transforms chain processing context. + * + * Copies user settings from @src context to @dst. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxCopyUserPref(xmlSecTransformCtxPtr dst, xmlSecTransformCtxPtr src) { + int ret; + + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(src != NULL, -1); + + dst->userData = src->userData; + dst->flags = src->flags; + dst->flags2 = src->flags2; + dst->enabledUris = src->enabledUris; + dst->preExecCallback = src->preExecCallback; + + ret = xmlSecPtrListCopy(&(dst->enabledTransforms), &(src->enabledTransforms)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecTransformCtxAppend: + * @ctx: the pointer to transforms chain processing context. + * @transform: the pointer to new transform. + * + * Connects the @transform to the end of the chain of transforms in the @ctx + * (see #xmlSecTransformConnect function for details). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxAppend(xmlSecTransformCtxPtr ctx, xmlSecTransformPtr transform) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + + if(ctx->last != NULL) { + ret = xmlSecTransformConnect(ctx->last, transform, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformConnect", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + return(-1); + } + } else { + xmlSecAssert2(ctx->first == NULL, -1); + ctx->first = transform; + } + ctx->last = transform; + + return(0); +} + +/** + * xmlSecTransformCtxPrepend: + * @ctx: the pointer to transforms chain processing context. + * @transform: the pointer to new transform. + * + * Connects the @transform to the beggining of the chain of transforms in the @ctx + * (see #xmlSecTransformConnect function for details). + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxPrepend(xmlSecTransformCtxPtr ctx, xmlSecTransformPtr transform) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + + if(ctx->first != NULL) { + ret = xmlSecTransformConnect(transform, ctx->first, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformConnect", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + return(-1); + } + } else { + xmlSecAssert2(ctx->last == NULL, -1); + ctx->last = transform; + } + ctx->first = transform; + + return(0); +} + +/** + * xmlSecTransformCtxCreateAndAppend: + * @ctx: the pointer to transforms chain processing context. + * @id: the new transform klass. + * + * Creaeates new transform and connects it to the end of the chain of + * transforms in the @ctx (see #xmlSecTransformConnect function for details). + * + * Returns: pointer to newly created transform or NULL if an error occurs. + */ +xmlSecTransformPtr +xmlSecTransformCtxCreateAndAppend(xmlSecTransformCtxPtr ctx, xmlSecTransformId id) { + xmlSecTransformPtr transform; + int ret; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL); + xmlSecAssert2(id != xmlSecTransformIdUnknown, NULL); + + transform = xmlSecTransformCreate(id); + if(!xmlSecTransformIsValid(transform)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id))); + return(NULL); + } + + ret = xmlSecTransformCtxAppend(ctx, transform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + xmlSecTransformDestroy(transform); + return(NULL); + } + + return(transform); +} + +/** + * xmlSecTransformCtxCreateAndPrepend: + * @ctx: the pointer to transforms chain processing context. + * @id: the new transform klass. + * + * Creaeates new transform and connects it to the end of the chain of + * transforms in the @ctx (see #xmlSecTransformConnect function for details). + * + * Returns: pointer to newly created transform or NULL if an error occurs. + */ +xmlSecTransformPtr +xmlSecTransformCtxCreateAndPrepend(xmlSecTransformCtxPtr ctx, xmlSecTransformId id) { + xmlSecTransformPtr transform; + int ret; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL); + xmlSecAssert2(id != xmlSecTransformIdUnknown, NULL); + + transform = xmlSecTransformCreate(id); + if(!xmlSecTransformIsValid(transform)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id))); + return(NULL); + } + + ret = xmlSecTransformCtxPrepend(ctx, transform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + xmlSecTransformDestroy(transform); + return(NULL); + } + + return(transform); +} + +/** + * xmlSecTransformCtxNodeRead: + * @ctx: the pointer to transforms chain processing context. + * @node: the pointer to transform's node. + * @usage: the transform's usage (signature, encryption, etc.). + * + * Reads the transform from the @node and appends it to the current chain + * of transforms in @ctx. + * + * Returns: pointer to newly created transform or NULL if an error occurs. + */ +xmlSecTransformPtr +xmlSecTransformCtxNodeRead(xmlSecTransformCtxPtr ctx, xmlNodePtr node, + xmlSecTransformUsage usage) { + xmlSecTransformPtr transform; + int ret; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, NULL); + xmlSecAssert2(node != NULL, NULL); + + transform = xmlSecTransformNodeRead(node, usage, ctx); + if(transform == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(NULL); + } + + ret = xmlSecTransformCtxAppend(ctx, transform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + xmlSecTransformDestroy(transform); + return(NULL); + } + + return(transform); +} + +/** + * xmlSecTransformCtxNodesListRead: + * @ctx: the pointer to transforms chain processing context. + * @node: the pointer to <dsig:Transform/> nodes parent node. + * @usage: the transform's usage (signature, encryption, etc.). + * + * Reads transforms from the <dsig:Transform/> children of the @node and + * appends them to the current transforms chain in @ctx object. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxNodesListRead(xmlSecTransformCtxPtr ctx, xmlNodePtr node, xmlSecTransformUsage usage) { + xmlSecTransformPtr transform; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(node != NULL, -1); + + cur = xmlSecGetNextElementNode(node->children); + while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeTransform, xmlSecDSigNs)) { + transform = xmlSecTransformNodeRead(cur, usage, ctx); + if(transform == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + ret = xmlSecTransformCtxAppend(ctx, transform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + xmlSecTransformDestroy(transform); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecTransformCtxSetUri: + * @ctx: the pointer to transforms chain processing context. + * @uri: the URI. + * @hereNode: the pointer to "here" node required by some + * XML transforms (may be NULL). + * + * Parses uri and adds xpointer transforms if required. + * + * The following examples demonstrate what the URI attribute identifies and + * how it is dereferenced + * (http://www.w3.org/TR/xmldsig-core/#sec-ReferenceProcessingModel): + * + * - URI="http://example.com/bar.xml" + * identifies the octets that represent the external resource + * 'http://example.com/bar.xml', that is probably an XML document given + * its file extension. + * + * - URI="http://example.com/bar.xml#chapter1" + * identifies the element with ID attribute value 'chapter1' of the + * external XML resource 'http://example.com/bar.xml', provided as an + * octet stream. Again, for the sake of interoperability, the element + * identified as 'chapter1' should be obtained using an XPath transform + * rather than a URI fragment (barename XPointer resolution in external + * resources is not REQUIRED in this specification). + * + * - URI="" + * identifies the node-set (minus any comment nodes) of the XML resource + * containing the signature + * + * - URI="#chapter1" + * identifies a node-set containing the element with ID attribute value + * 'chapter1' of the XML resource containing the signature. XML Signature + * (and its applications) modify this node-set to include the element plus + * all descendents including namespaces and attributes -- but not comments. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxSetUri(xmlSecTransformCtxPtr ctx, const xmlChar* uri, xmlNodePtr hereNode) { + xmlSecNodeSetType nodeSetType = xmlSecNodeSetTree; + const xmlChar* xptr; + xmlChar* buf = NULL; + int useVisa3DHack = 0; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->uri == NULL, -1); + xmlSecAssert2(ctx->xptrExpr == NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(hereNode != NULL, -1); + + /* check uri */ + if(xmlSecTransformUriTypeCheck(ctx->enabledUris, uri) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_URI_TYPE, + "uri=%s", + xmlSecErrorsSafeString(uri)); + return(-1); + } + + /* is it an empty uri? */ + if((uri == NULL) || (xmlStrlen(uri) == 0)) { + return(0); + } + + /* do we have barename or full xpointer? */ + xptr = xmlStrchr(uri, '#'); + if(xptr == NULL){ + ctx->uri = xmlStrdup(uri); + if(ctx->uri == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "size=%d", xmlStrlen(uri)); + return(-1); + } + /* we are done */ + return(0); + } else if(xmlStrcmp(uri, BAD_CAST "#xpointer(/)") == 0) { + ctx->xptrExpr = xmlStrdup(uri); + if(ctx->xptrExpr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "size=%d", xmlStrlen(uri)); + return(-1); + } + /* we are done */ + return(0); + } + + ctx->uri = xmlStrndup(uri, xptr - uri); + if(ctx->uri == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "size=%d", xptr - uri); + return(-1); + } + + ctx->xptrExpr = xmlStrdup(xptr); + if(ctx->xptrExpr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + "size=%d", xmlStrlen(xptr)); + return(-1); + } + + /* do we have barename or full xpointer? */ + xmlSecAssert2(xptr != NULL, -1); + if((xmlStrncmp(xptr, BAD_CAST "#xpointer(", 10) == 0) || (xmlStrncmp(xptr, BAD_CAST "#xmlns(", 7) == 0)) { + ++xptr; + nodeSetType = xmlSecNodeSetTree; + } else if((ctx->flags & XMLSEC_TRANSFORMCTX_FLAGS_USE_VISA3D_HACK) != 0) { + ++xptr; + nodeSetType = xmlSecNodeSetTreeWithoutComments; + useVisa3DHack = 1; + } else { + static const char tmpl[] = "xpointer(id(\'%s\'))"; + xmlSecSize size; + + /* we need to add "xpointer(id('..')) because otherwise we have + * problems with numeric ("111" and so on) and other "strange" ids */ + size = xmlStrlen(BAD_CAST tmpl) + xmlStrlen(xptr) + 2; + buf = (xmlChar*)xmlMalloc(size * sizeof(xmlChar)); + if(buf == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", size); + return(-1); + } + sprintf((char*)buf, tmpl, xptr + 1); + xptr = buf; + nodeSetType = xmlSecNodeSetTreeWithoutComments; + } + + if(useVisa3DHack == 0) { + xmlSecTransformPtr transform; + + /* we need to create XPonter transform to execute expr */ + transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformXPointerId); + if(!xmlSecTransformIsValid(transform)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXPointerId))); + return(-1); + } + + ret = xmlSecTransformXPointerSetExpr(transform, xptr, nodeSetType, hereNode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformXPointerSetExpr", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + if(buf != NULL) { + xmlFree(buf); + } + return(-1); + } + } else { + /* Visa3D protocol doesn't follow XML/XPointer/XMLDSig specs + * and allows invalid XPointer expressions (e.g. "#12345") in + * the URI attribute. + * Since we couldn't evaluate such expressions thru XPath/XPointer + * engine, we need to have this hack here + */ + xmlSecTransformPtr transform; + + transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformVisa3DHackId); + if(!xmlSecTransformIsValid(transform)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformVisa3DHackId))); + return(-1); + } + + ret = xmlSecTransformVisa3DHackSetID(transform, xptr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformVisa3DHackSetID", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + if(buf != NULL) { + xmlFree(buf); + } + return(-1); + } + } + if(buf != NULL) { + xmlFree(buf); + } + + return(0); +} + +/** + * xmlSecTransformCtxPrepare: + * @ctx: the pointer to transforms chain processing context. + * @inputDataType: the expected input type. + * + * Prepares the transform context for processing data of @inputDataType. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxPrepare(xmlSecTransformCtxPtr ctx, xmlSecTransformDataType inputDataType) { + xmlSecTransformDataType firstType; + xmlSecTransformPtr transform; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->result == NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + + /* add binary buffer to store result */ + transform = xmlSecTransformCtxCreateAndAppend(ctx, xmlSecTransformMemBufId); + if(!xmlSecTransformIsValid(transform)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId))); + return(-1); + } + ctx->result = xmlSecTransformMemBufGetBuffer(transform); + if(ctx->result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformMemBufGetBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId))); + return(-1); + } + + firstType = xmlSecTransformGetDataType(ctx->first, xmlSecTransformModePush, ctx); + if(((firstType & xmlSecTransformDataTypeBin) == 0) && + ((inputDataType & xmlSecTransformDataTypeBin) != 0)) { + + /* need to add parser transform */ + transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformXmlParserId); + if(transform == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformXmlParserId))); + return(-1); + } + } else if(((firstType & xmlSecTransformDataTypeXml) == 0) && + ((inputDataType & xmlSecTransformDataTypeXml) != 0)) { + + /* need to add c14n transform */ + transform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformInclC14NId); + if(transform == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInclC14NId))); + return(-1); + } + } + + /* finally let application a chance to verify that it's ok to execte + * this transforms chain */ + if(ctx->preExecCallback != NULL) { + ret = (ctx->preExecCallback)(ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "ctx->preExecCallback", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ctx->status = xmlSecTransformStatusWorking; + return(0); +} + +/** + * xmlSecTransformCtxBinaryExecute: + * @ctx: the pointer to transforms chain processing context. + * @data: the input binary data buffer. + * @dataSize: the input data size. + * + * Processes binary data using transforms chain in the @ctx. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxBinaryExecute(xmlSecTransformCtxPtr ctx, + const xmlSecByte* data, xmlSecSize dataSize) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->result == NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize > 0, -1); + + /* we should not have uri stored in ctx */ + xmlSecAssert2(ctx->uri == NULL, -1); + + ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeBin); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxPrepare", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "type=bin"); + return(-1); + } + + ret = xmlSecTransformPushBin(ctx->first, data, dataSize, 1, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxPushBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "dataSize=%d", dataSize); + return(-1); + } + + ctx->status = xmlSecTransformStatusFinished; + return(0); +} + +/** + * xmlSecTransformCtxUriExecute: + * @ctx: the pointer to transforms chain processing context. + * @uri: the URI. + * + * Process binary data from the URI using transforms chain in @ctx. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxUriExecute(xmlSecTransformCtxPtr ctx, const xmlChar* uri) { + xmlSecTransformPtr uriTransform; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(uri != NULL, -1); + + /* we should not execute transform for a different uri */ + xmlSecAssert2((ctx->uri == NULL) || (uri == ctx->uri) || xmlStrEqual(uri, ctx->uri), -1); + + uriTransform = xmlSecTransformCtxCreateAndPrepend(ctx, xmlSecTransformInputURIId); + if(uriTransform == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformInputURIId))); + return(-1); + } + + ret = xmlSecTransformInputURIOpen(uriTransform, uri); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformInputURIOpen", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", + xmlSecErrorsSafeString(uri)); + return(-1); + } + + /* we do not need to do something special for this transform */ + ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeUnknown); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxPrepare", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "type=bin"); + return(-1); + } + + /* Now we have a choice: we either can push from first transform or pop + * from last. Our C14N transforms prefers push, so push data! + */ + ret = xmlSecTransformPump(uriTransform, uriTransform->next, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformPump", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", + xmlSecErrorsSafeString(uri)); + return(-1); + } + + ctx->status = xmlSecTransformStatusFinished; + return(0); +} + +/** + * xmlSecTransformCtxXmlExecute: + * @ctx: the pointer to transforms chain processing context. + * @nodes: the input node set. + * + * Process @nodes using transforms in the transforms chain in @ctx. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxXmlExecute(xmlSecTransformCtxPtr ctx, xmlSecNodeSetPtr nodes) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->result == NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(nodes != NULL, -1); + + xmlSecAssert2((ctx->uri == NULL) || (xmlStrlen(ctx->uri) == 0), -1); + + ret = xmlSecTransformCtxPrepare(ctx, xmlSecTransformDataTypeXml); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxPrepare", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "type=xml"); + return(-1); + } + + /* it's better to do push than pop because all XML transform + * just don't care and c14n likes push more than pop */ + ret = xmlSecTransformPushXml(ctx->first, nodes, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformPushXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(ctx->first))); + return(-1); + } + + ctx->status = xmlSecTransformStatusFinished; + return(0); +} + +/** + * xmlSecTransformCtxExecute: + * @ctx: the pointer to transforms chain processing context. + * @doc: the pointer to input document. + * + * Executes transforms chain in @ctx. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformCtxExecute(xmlSecTransformCtxPtr ctx, xmlDocPtr doc) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->result == NULL, -1); + xmlSecAssert2(ctx->status == xmlSecTransformStatusNone, -1); + xmlSecAssert2(doc != NULL, -1); + + if((ctx->uri == NULL) || (xmlStrlen(ctx->uri) == 0)) { + xmlSecNodeSetPtr nodes; + + if((ctx->xptrExpr != NULL) && (xmlStrlen(ctx->xptrExpr) > 0)){ + /* our xpointer transform takes care of providing correct nodes set */ + nodes = xmlSecNodeSetCreate(doc, NULL, xmlSecNodeSetNormal); + if(nodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + } else { + /* we do not want to have comments for empty URI */ + nodes = xmlSecNodeSetGetChildren(doc, NULL, 0, 0); + if(nodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetGetChildren", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + ret = xmlSecTransformCtxXmlExecute(ctx, nodes); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxXmlExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecNodeSetDestroy(nodes); + return(-1); + } + /* TODO: don't destroy nodes here */ + xmlSecNodeSetDestroy(nodes); + } else { + ret = xmlSecTransformCtxUriExecute(ctx, ctx->uri); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxUriExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +/** + * xmlSecTransformCtxDebugDump: + * @ctx: the pointer to transforms chain processing context. + * @output: the pointer to output FILE. + * + * Prints transforms context debug information to @output. + */ +void +xmlSecTransformCtxDebugDump(xmlSecTransformCtxPtr ctx, FILE* output) { + xmlSecTransformPtr transform; + + xmlSecAssert(ctx != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "== TRANSFORMS CTX (status=%d)\n", ctx->status); + + fprintf(output, "== flags: 0x%08x\n", ctx->flags); + fprintf(output, "== flags2: 0x%08x\n", ctx->flags2); + if(xmlSecPtrListGetSize(&(ctx->enabledTransforms)) > 0) { + fprintf(output, "== enabled transforms: "); + xmlSecTransformIdListDebugDump(&(ctx->enabledTransforms), output); + } else { + fprintf(output, "== enabled transforms: all\n"); + } + + fprintf(output, "=== uri: %s\n", + (ctx->uri != NULL) ? ctx->uri : BAD_CAST "NULL"); + fprintf(output, "=== uri xpointer expr: %s\n", + (ctx->xptrExpr != NULL) ? ctx->xptrExpr : BAD_CAST "NULL"); + for(transform = ctx->first; transform != NULL; transform = transform->next) { + xmlSecTransformDebugDump(transform, output); + } +} + +/** + * xmlSecTransformCtxDebugXmlDump: + * @ctx: the pointer to transforms chain processing context. + * @output: the pointer to output FILE. + * + * Prints transforms context debug information to @output in XML format. + */ +void +xmlSecTransformCtxDebugXmlDump(xmlSecTransformCtxPtr ctx, FILE* output) { + xmlSecTransformPtr transform; + + xmlSecAssert(ctx != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "<TransformCtx status=\"%d\">\n", ctx->status); + + fprintf(output, "<Flags>%08x</Flags>\n", ctx->flags); + fprintf(output, "<Flags2>%08x</Flags2>\n", ctx->flags2); + if(xmlSecPtrListGetSize(&(ctx->enabledTransforms)) > 0) { + fprintf(output, "<EnabledTransforms>\n"); + xmlSecTransformIdListDebugXmlDump(&(ctx->enabledTransforms), output); + fprintf(output, "</EnabledTransforms>\n"); + } else { + fprintf(output, "<EnabledTransforms>all</EnabledTransforms>\n"); + } + + + fprintf(output, "<Uri>"); + xmlSecPrintXmlString(output, ctx->uri); + fprintf(output, "</Uri>\n"); + + fprintf(output, "<UriXPointer>"); + xmlSecPrintXmlString(output, ctx->xptrExpr); + fprintf(output, "</UriXPointer>\n"); + + for(transform = ctx->first; transform != NULL; transform = transform->next) { + xmlSecTransformDebugXmlDump(transform, output); + } + fprintf(output, "</TransformCtx>\n"); +} + +/************************************************************************** + * + * xmlSecTransform + * + *************************************************************************/ +/** + * xmlSecTransformCreate: + * @id: the transform id to create. + * + * Creates new transform of the @id klass. The caller is responsible for + * destroying returned tansform using #xmlSecTransformDestroy function. + * + * Returns: pointer to newly created transform or NULL if an error occurs. + */ +xmlSecTransformPtr +xmlSecTransformCreate(xmlSecTransformId id) { + xmlSecTransformPtr transform; + int ret; + + xmlSecAssert2(id != NULL, NULL); + xmlSecAssert2(id->klassSize >= sizeof(xmlSecTransformKlass), NULL); + xmlSecAssert2(id->objSize >= sizeof(xmlSecTransform), NULL); + xmlSecAssert2(id->name != NULL, NULL); + + /* Allocate a new xmlSecTransform and fill the fields. */ + transform = (xmlSecTransformPtr)xmlMalloc(id->objSize); + if(transform == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", id->objSize); + return(NULL); + } + memset(transform, 0, id->objSize); + transform->id = id; + + if(id->initialize != NULL) { + ret = (id->initialize)(transform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "id->initialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecTransformDestroy(transform); + return(NULL); + } + } + + ret = xmlSecBufferInitialize(&(transform->inBuf), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", 0); + xmlSecTransformDestroy(transform); + return(NULL); + } + + ret = xmlSecBufferInitialize(&(transform->outBuf), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", 0); + xmlSecTransformDestroy(transform); + return(NULL); + } + + return(transform); +} + +/** + * xmlSecTransformDestroy: + * @transform: the pointer to transform. + * + * Destroys transform created with #xmlSecTransformCreate function. + */ +void +xmlSecTransformDestroy(xmlSecTransformPtr transform) { + xmlSecAssert(xmlSecTransformIsValid(transform)); + xmlSecAssert(transform->id->objSize > 0); + + /* first need to remove ourselves from chain */ + xmlSecTransformRemove(transform); + + xmlSecBufferFinalize(&(transform->inBuf)); + xmlSecBufferFinalize(&(transform->outBuf)); + + /* we never destroy input nodes, output nodes + * are destroyed if and only if they are different + * from input nodes + */ + if((transform->outNodes != NULL) && (transform->outNodes != transform->inNodes)) { + xmlSecNodeSetDestroy(transform->outNodes); + } + if(transform->id->finalize != NULL) { + (transform->id->finalize)(transform); + } + memset(transform, 0, transform->id->objSize); + xmlFree(transform); +} + +/** + * xmlSecTransformNodeRead: + * @node: the pointer to the transform's node. + * @usage: the transform usage (signature, encryption, ...). + * @transformCtx: the transform's chaing processing context. + * + * Reads transform from the @node as follows: + * + * 1) reads "Algorithm" attribute; + * + * 2) checks the lists of known and allowed transforms; + * + * 3) calls transform's create method; + * + * 4) calls transform's read transform node method. + * + * Returns: pointer to newly created transform or NULL if an error occurs. + */ +xmlSecTransformPtr +xmlSecTransformNodeRead(xmlNodePtr node, xmlSecTransformUsage usage, xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformPtr transform; + xmlSecTransformId id; + xmlChar *href; + int ret; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(transformCtx != NULL, NULL); + + href = xmlGetProp(node, xmlSecAttrAlgorithm); + if(href == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecAttrAlgorithm), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(NULL); + } + + id = xmlSecTransformIdListFindByHref(xmlSecTransformIdsGet(), href, usage); + if(id == xmlSecTransformIdUnknown) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdListFindByHref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "href=%s", + xmlSecErrorsSafeString(href)); + xmlFree(href); + return(NULL); + } + + /* check with enabled transforms list */ + if((xmlSecPtrListGetSize(&(transformCtx->enabledTransforms)) > 0) && + (xmlSecTransformIdListFind(&(transformCtx->enabledTransforms), id) != 1)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id)), + XMLSEC_ERRORS_R_TRANSFORM_DISABLED, + "href=%s", + xmlSecErrorsSafeString(href)); + xmlFree(href); + return(NULL); + } + + transform = xmlSecTransformCreate(id); + if(!xmlSecTransformIsValid(transform)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(id))); + xmlFree(href); + return(NULL); + } + + if(transform->id->readNode != NULL) { + ret = transform->id->readNode(transform, node, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "id->readNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(transform))); + xmlSecTransformDestroy(transform); + xmlFree(href); + return(NULL); + } + } + + /* finally remember the transform node */ + transform->hereNode = node; + xmlFree(href); + return(transform); +} + +/** + * xmlSecTransformPump: + * @left: the source pumping transform. + * @right: the destination pumping transform. + * @transformCtx: the transform's chaing processing context. + * + * Pops data from @left transform and pushes to @right transform until + * no more data is available. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformPump(xmlSecTransformPtr left, xmlSecTransformPtr right, xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformDataType leftType; + xmlSecTransformDataType rightType; + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(left), -1); + xmlSecAssert2(xmlSecTransformIsValid(right), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + leftType = xmlSecTransformGetDataType(left, xmlSecTransformModePop, transformCtx); + rightType = xmlSecTransformGetDataType(right, xmlSecTransformModePush, transformCtx); + + if(((leftType & xmlSecTransformDataTypeXml) != 0) && + ((rightType & xmlSecTransformDataTypeXml) != 0)) { + + xmlSecNodeSetPtr nodes = NULL; + + ret = xmlSecTransformPopXml(left, &nodes, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(left)), + "xmlSecTransformPopXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecTransformPushXml(right, nodes, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(right)), + "xmlSecTransformPushXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else if(((leftType & xmlSecTransformDataTypeBin) != 0) && + ((rightType & xmlSecTransformDataTypeBin) != 0)) { + xmlSecByte buf[XMLSEC_TRANSFORM_BINARY_CHUNK]; + xmlSecSize bufSize; + int final; + + do { + ret = xmlSecTransformPopBin(left, buf, sizeof(buf), &bufSize, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(left)), + "xmlSecTransformPopBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + final = (bufSize == 0) ? 1 : 0; + ret = xmlSecTransformPushBin(right, buf, bufSize, final, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(right)), + "xmlSecTransformPushBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } while(final == 0); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(left)), + xmlSecErrorsSafeString(xmlSecTransformGetName(right)), + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + "transforms input/output data formats do not match"); + } + return(0); +} + + +/** + * xmlSecTransformSetKey: + * @transform: the pointer to transform. + * @key: the pointer to key. + * + * Sets the transform's key. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(key != NULL, -1); + + if(transform->id->setKey != NULL) { + return((transform->id->setKey)(transform, key)); + } + return(0); +} + +/** + * xmlSecTransformSetKeyReq: + * @transform: the pointer to transform. + * @keyReq: the pointer to keys requirements object. + * + * Sets the key requirements for @transform in the @keyReq. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecTransformSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(keyReq != NULL, -1); + + keyReq->keyId = xmlSecKeyDataIdUnknown; + keyReq->keyType = xmlSecKeyDataTypeUnknown; + keyReq->keyUsage = xmlSecKeyUsageAny; + keyReq->keyBitsSize = 0; + + if(transform->id->setKeyReq != NULL) { + return((transform->id->setKeyReq)(transform, keyReq)); + } + return(0); +} + +/** + * xmlSecTransformVerify: + * @transform: the pointer to transform. + * @data: the binary data for verification. + * @dataSize: the data size. + * @transformCtx: the transform's chaing processing context. + * + * Verifies the data with transform's processing results + * (for digest, HMAC and signature transforms). The verification + * result is stored in the #status member of #xmlSecTransform object. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformVerify(xmlSecTransformPtr transform, const xmlSecByte* data, + xmlSecSize dataSize, xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->id->verify != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + return((transform->id->verify)(transform, data, dataSize, transformCtx)); +} + +/** + * xmlSecTransformVerifyNodeContent: + * @transform: the pointer to transform. + * @node: the pointer to node. + * @transformCtx: the transform's chaing processing context. + * + * Gets the @node content, base64 decodes it and calls #xmlSecTransformVerify + * function to verify binary results. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformVerifyNodeContent(xmlSecTransformPtr transform, xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx) { + xmlSecBuffer buffer; + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ret = xmlSecBufferInitialize(&buffer, 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferBase64NodeContentRead(&buffer, node); + if((ret < 0) || (xmlSecBufferGetData(&buffer) == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferBase64NodeContentRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(-1); + } + + ret = xmlSecTransformVerify(transform, xmlSecBufferGetData(&buffer), + xmlSecBufferGetSize(&buffer), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformVerify", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(-1); + } + + xmlSecBufferFinalize(&buffer); + return(0); +} + +/** + * xmlSecTransformGetDataType: + * @transform: the pointer to transform. + * @mode: the data mode (push or pop). + * @transformCtx: the transform's chaing processing context. + * + * Gets transform input (@mode is "push") or output (@mode is "pop") data + * type (binary or XML). + * + * Returns: the transform's data type for the @mode operation. + */ +xmlSecTransformDataType +xmlSecTransformGetDataType(xmlSecTransformPtr transform, xmlSecTransformMode mode, + xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), xmlSecTransformDataTypeUnknown); + xmlSecAssert2(transform->id->getDataType != NULL, xmlSecTransformDataTypeUnknown); + + return((transform->id->getDataType)(transform, mode, transformCtx)); +} + +/** + * xmlSecTransformPushBin: + * @transform: the pointer to transform object. + * @data: the input binary data, + * @dataSize: the input data size. + * @final: the flag: if set to 1 then it's the last + * data chunk. + * @transformCtx: the pointer to transform context object. + * + * Process binary @data and pushes results to next transform. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformPushBin(xmlSecTransformPtr transform, const xmlSecByte* data, + xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->id->pushBin != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + return((transform->id->pushBin)(transform, data, dataSize, final, transformCtx)); +} + +/** + * xmlSecTransformPopBin: + * @transform: the pointer to transform object. + * @data: the buffer to store result data. + * @maxDataSize: the size of the buffer #data. + * @dataSize: the pointer to returned data size. + * @transformCtx: the pointer to transform context object. + * + * Pops data from previous transform in the chain, processes data and + * returns result in the @data buffer. The size of returned data is + * placed in the @dataSize. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformPopBin(xmlSecTransformPtr transform, xmlSecByte* data, + xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->id->popBin != NULL, -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + return((transform->id->popBin)(transform, data, maxDataSize, dataSize, transformCtx)); +} + +/** + * xmlSecTransformPushXml: + * @transform: the pointer to transform object. + * @nodes: the input nodes. + * @transformCtx: the pointer to transform context object. + * + * Processes @nodes and pushes result to the next transform in the chain. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes, + xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->id->pushXml != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + return((transform->id->pushXml)(transform, nodes, transformCtx)); +} + +/** + * xmlSecTransformPopXml: + * @transform: the pointer to transform object. + * @nodes: the pointer to store popinter to result nodes. + * @transformCtx: the pointer to transform context object. + * + * Pops data from previous transform in the chain, processes the data and + * returns result in @nodes. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes, + xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->id->popXml != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + return((transform->id->popXml)(transform, nodes, transformCtx)); +} + +/** + * xmlSecTransformExecute: + * @transform: the pointer to transform. + * @last: the flag: if set to 1 then it's the last data chunk. + * @transformCtx: the transform's chaing processing context. + * + * Executes transform (used by default popBin/pushBin/popXml/pushXml methods). + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->id->execute != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + return((transform->id->execute)(transform, last, transformCtx)); +} + +/** + * xmlSecTransformDebugDump: + * @transform: the pointer to transform. + * @output: the pointer to output FILE. + * + * Prints transform's debug information to @output. + */ +void +xmlSecTransformDebugDump(xmlSecTransformPtr transform, FILE* output) { + xmlSecAssert(xmlSecTransformIsValid(transform)); + xmlSecAssert(output != NULL); + + fprintf(output, "=== Transform: %s (href=%s)\n", + xmlSecErrorsSafeString(transform->id->name), + xmlSecErrorsSafeString(transform->id->href)); +} + +/** + * xmlSecTransformDebugXmlDump: + * @transform: the pointer to transform. + * @output: the pointer to output FILE. + * + * Prints transform's debug information to @output in XML format. + */ +void +xmlSecTransformDebugXmlDump(xmlSecTransformPtr transform, FILE* output) { + xmlSecAssert(xmlSecTransformIsValid(transform)); + xmlSecAssert(output != NULL); + + fprintf(output, "<Transform name=\""); + xmlSecPrintXmlString(output,transform->id->name); + fprintf(output, "\" href=\""); + xmlSecPrintXmlString(output, transform->id->href); + fprintf(output, "\" />\n"); +} + +/************************************************************************ + * + * Operations on transforms chain + * + ************************************************************************/ +/** + * xmlSecTransformConnect: + * @left: the pointer to left (prev) transform. + * @right: the pointer to right (next) transform. + * @transformCtx: the transform's chaing processing context. + * + * If the data object is a node-set and the next transform requires octets, + * the signature application MUST attempt to convert the node-set to an octet + * stream using Canonical XML [XML-C14N]. + * + * The story is different if the right transform is base64 decode + * (http://www.w3.org/TR/xmldsig-core/#sec-Base-64): + * + * This transform requires an octet stream for input. If an XPath node-set + * (or sufficiently functional alternative) is given as input, then it is + * converted to an octet stream by performing operations logically equivalent + * to 1) applying an XPath transform with expression self::text(), then 2) + * taking the string-value of the node-set. Thus, if an XML element is + * identified by a barename XPointer in the Reference URI, and its content + * consists solely of base64 encoded character data, then this transform + * automatically strips away the start and end tags of the identified element + * and any of its descendant elements as well as any descendant comments and + * processing instructions. The output of this transform is an octet stream. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformConnect(xmlSecTransformPtr left, xmlSecTransformPtr right, + xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformDataType leftType; + xmlSecTransformDataType rightType; + xmlSecTransformId middleId; + xmlSecTransformPtr middle; + + xmlSecAssert2(xmlSecTransformIsValid(left), -1); + xmlSecAssert2(xmlSecTransformIsValid(right), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + leftType = xmlSecTransformGetDataType(left, xmlSecTransformModePop, transformCtx); + rightType = xmlSecTransformGetDataType(right, xmlSecTransformModePush, transformCtx); + + /* happy case first: nothing need to be done */ + if((((leftType & xmlSecTransformDataTypeBin) != 0) && + ((rightType & xmlSecTransformDataTypeBin) != 0)) || + (((leftType & xmlSecTransformDataTypeXml) != 0) && + ((rightType & xmlSecTransformDataTypeXml) != 0))) { + + left->next = right; + right->prev = left; + return(0); + } + + if(((leftType & xmlSecTransformDataTypeBin) != 0) && + ((rightType & xmlSecTransformDataTypeXml) != 0)) { + + /* need to insert parser */ + middleId = xmlSecTransformXmlParserId; + } else if(((leftType & xmlSecTransformDataTypeXml) != 0) && + ((rightType & xmlSecTransformDataTypeBin) != 0)) { + + /* need to insert c14n or special pre-base64 transform */ + if(xmlSecTransformCheckId(right, xmlSecTransformBase64Id)) { + middleId = xmlSecTransformRemoveXmlTagsC14NId; + } else { + middleId = xmlSecTransformInclC14NId; + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(left)), + xmlSecErrorsSafeString(xmlSecTransformGetName(right)), + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + "leftType=%d;rightType=%d", + leftType, rightType); + return(-1); + } + + /* insert transform */ + middle = xmlSecTransformCreate(middleId); + if(middle == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(left)), + "xmlSecTransformCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(middleId))); + return(-1); + } + left->next = middle; + middle->prev = left; + middle->next = right; + right->prev = middle; + return(0); +} + +/** + * xmlSecTransformRemove: + * @transform: the pointer to #xmlSecTransform structure. + * + * Removes @transform from the chain. + */ +void +xmlSecTransformRemove(xmlSecTransformPtr transform) { + xmlSecAssert(xmlSecTransformIsValid(transform)); + + if(transform->next != NULL) { + transform->next->prev = transform->prev; + } + if(transform->prev != NULL) { + transform->prev->next = transform->next; + } + transform->next = transform->prev = NULL; +} + + +/************************************************************************ + * + * Default callbacks, most of the transforms can use them + * + ************************************************************************/ +/** + * xmlSecTransformDefaultGetDataType: + * @transform: the pointer to transform. + * @mode: the data mode (push or pop). + * @transformCtx: the transform's chaing processing context. + * + * Gets transform input (@mode is "push") or output (@mode is "pop") data + * type (binary or XML) by analyzing available pushBin/popBin/pushXml/popXml + * methods. + * + * Returns: the transform's data type for the @mode operation. + */ +xmlSecTransformDataType +xmlSecTransformDefaultGetDataType(xmlSecTransformPtr transform, xmlSecTransformMode mode, + xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformDataType type = xmlSecTransformDataTypeUnknown; + + xmlSecAssert2(xmlSecTransformIsValid(transform), xmlSecTransformDataTypeUnknown); + xmlSecAssert2(transformCtx != NULL, xmlSecTransformDataTypeUnknown); + + /* we'll try to guess the data type based on the handlers we have */ + switch(mode) { + case xmlSecTransformModePush: + if(transform->id->pushBin != NULL) { + type |= xmlSecTransformDataTypeBin; + } + if(transform->id->pushXml != NULL) { + type |= xmlSecTransformDataTypeXml; + } + break; + case xmlSecTransformModePop: + if(transform->id->popBin != NULL) { + type |= xmlSecTransformDataTypeBin; + } + if(transform->id->popXml != NULL) { + type |= xmlSecTransformDataTypeXml; + } + break; + default: + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "mode=%d", mode); + return(xmlSecTransformDataTypeUnknown); + } + + return(type); +} + +/** + * xmlSecTransformDefaultPushBin: + * @transform: the pointer to transform object. + * @data: the input binary data, + * @dataSize: the input data size. + * @final: the flag: if set to 1 then it's the last + * data chunk. + * @transformCtx: the pointer to transform context object. + * + * Process binary @data by calling transform's execute method and pushes + * results to next transform. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformDefaultPushBin(xmlSecTransformPtr transform, const xmlSecByte* data, + xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) { + xmlSecSize inSize = 0; + xmlSecSize outSize = 0; + int finalData = 0; + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + do { + /* append data to input buffer */ + if(dataSize > 0) { + xmlSecSize chunkSize; + + xmlSecAssert2(data != NULL, -1); + + chunkSize = dataSize; + if(chunkSize > XMLSEC_TRANSFORM_BINARY_CHUNK) { + chunkSize = XMLSEC_TRANSFORM_BINARY_CHUNK; + } + + ret = xmlSecBufferAppend(&(transform->inBuf), data, chunkSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", chunkSize); + return(-1); + } + + dataSize -= chunkSize; + data += chunkSize; + } + + /* process data */ + inSize = xmlSecBufferGetSize(&(transform->inBuf)); + outSize = xmlSecBufferGetSize(&(transform->outBuf)); + finalData = (((dataSize == 0) && (final != 0)) ? 1 : 0); + ret = xmlSecTransformExecute(transform, finalData, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "final=%d", final); + return(-1); + } + + /* push data to the next transform */ + inSize = xmlSecBufferGetSize(&(transform->inBuf)); + outSize = xmlSecBufferGetSize(&(transform->outBuf)); + if(inSize > 0) { + finalData = 0; + } + + /* we don't want to puch too much */ + if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) { + outSize = XMLSEC_TRANSFORM_BINARY_CHUNK; + finalData = 0; + } + if((transform->next != NULL) && ((outSize > 0) || (finalData != 0))) { + ret = xmlSecTransformPushBin(transform->next, + xmlSecBufferGetData(&(transform->outBuf)), + outSize, + finalData, + transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform->next)), + "xmlSecTransformPushBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "final=%d;outSize=%d", final, outSize); + return(-1); + } + } + + /* remove data anyway */ + if(outSize > 0) { + ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + } + } while((dataSize > 0) || (outSize > 0)); + + return(0); +} + +/** + * xmlSecTransformDefaultPopBin: + * @transform: the pointer to transform object. + * @data: the buffer to store result data. + * @maxDataSize: the size of the buffer #data. + * @dataSize: the pointer to returned data size. + * @transformCtx: the pointer to transform context object. + * + * Pops data from previous transform in the chain, processes data by calling + * transform's execute method and returns result in the @data buffer. The + * size of returned data is placed in the @dataSize. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformDefaultPopBin(xmlSecTransformPtr transform, xmlSecByte* data, + xmlSecSize maxDataSize, xmlSecSize* dataSize, xmlSecTransformCtxPtr transformCtx) { + xmlSecSize outSize; + int final = 0; + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(dataSize != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + while((xmlSecBufferGetSize(&(transform->outBuf)) == 0) && (final == 0)) { + /* read data from previous transform if exist */ + if(transform->prev != NULL) { + xmlSecSize inSize, chunkSize; + + inSize = xmlSecBufferGetSize(&(transform->inBuf)); + chunkSize = XMLSEC_TRANSFORM_BINARY_CHUNK; + + /* ensure that we have space for at least one data chunk */ + ret = xmlSecBufferSetMaxSize(&(transform->inBuf), inSize + chunkSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize + chunkSize); + return(-1); + } + + /* get data from previous transform */ + ret = xmlSecTransformPopBin(transform->prev, + xmlSecBufferGetData(&(transform->inBuf)) + inSize, + chunkSize, &chunkSize, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform->prev)), + "xmlSecTransformPopBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* adjust our size if needed */ + if(chunkSize > 0) { + ret = xmlSecBufferSetSize(&(transform->inBuf), inSize + chunkSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize + chunkSize); + return(-1); + } + final = 0; /* the previous transform returned some data..*/ + } else { + final = 1; /* no data returned from previous transform, we are done */ + } + } else { + final = 1; /* no previous transform, we are "permanently final" */ + } + + /* execute our transform */ + ret = xmlSecTransformExecute(transform, final, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* copy result (if any) */ + outSize = xmlSecBufferGetSize(&(transform->outBuf)); + if(outSize > maxDataSize) { + outSize = maxDataSize; + } + + /* we don't want to put too much */ + if(outSize > XMLSEC_TRANSFORM_BINARY_CHUNK) { + outSize = XMLSEC_TRANSFORM_BINARY_CHUNK; + } + if(outSize > 0) { + xmlSecAssert2(xmlSecBufferGetData(&(transform->outBuf)), -1); + + memcpy(data, xmlSecBufferGetData(&(transform->outBuf)), outSize); + + ret = xmlSecBufferRemoveHead(&(transform->outBuf), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + } + + /* set the result size */ + (*dataSize) = outSize; + return(0); +} + +/** + * xmlSecTransformDefaultPushXml: + * @transform: the pointer to transform object. + * @nodes: the input nodes. + * @transformCtx: the pointer to transform context object. + * + * Processes @nodes by calling transform's execute method and pushes + * result to the next transform in the chain. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformDefaultPushXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr nodes, + xmlSecTransformCtxPtr transformCtx) { + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->inNodes == NULL, -1); + xmlSecAssert2(transform->outNodes == NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + /* execute our transform */ + transform->inNodes = nodes; + ret = xmlSecTransformExecute(transform, 1, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* push result to the next transform (if exist) */ + if(transform->next != NULL) { + ret = xmlSecTransformPushXml(transform->next, transform->outNodes, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformPushXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + return(0); +} + +/** + * xmlSecTransformDefaultPopXml: + * @transform: the pointer to transform object. + * @nodes: the pointer to store popinter to result nodes. + * @transformCtx: the pointer to transform context object. + * + * Pops data from previous transform in the chain, processes the data + * by calling transform's execute method and returns result in @nodes. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformDefaultPopXml(xmlSecTransformPtr transform, xmlSecNodeSetPtr* nodes, + xmlSecTransformCtxPtr transformCtx) { + int ret; + + xmlSecAssert2(xmlSecTransformIsValid(transform), -1); + xmlSecAssert2(transform->inNodes == NULL, -1); + xmlSecAssert2(transform->outNodes == NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + /* pop result from the prev transform (if exist) */ + if(transform->prev != NULL) { + ret = xmlSecTransformPopXml(transform->prev, &(transform->inNodes), transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformPopXml", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* execute our transform */ + ret = xmlSecTransformExecute(transform, 1, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* return result if requested */ + if(nodes != NULL) { + (*nodes) = transform->outNodes; + } + + return(0); +} + +/*********************************************************************** + * + * Transform Ids list + * + **********************************************************************/ +static xmlSecPtrListKlass xmlSecTransformIdListKlass = { + BAD_CAST "transform-ids-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + NULL, /* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecTransformIdListGetKlass: + * + * The transform id list klass. + * + * Returns: pointer to the transform id list klass. + */ +xmlSecPtrListId +xmlSecTransformIdListGetKlass(void) { + return(&xmlSecTransformIdListKlass); +} + +/** + * xmlSecTransformIdListFind: + * @list: the pointer to transform ids list. + * @transformId: the transform klass. + * + * Lookups @dataId in @list. + * + * Returns: 1 if @dataId is found in the @list, 0 if not and a negative + * value if an error occurs. + */ +int +xmlSecTransformIdListFind(xmlSecPtrListPtr list, xmlSecTransformId transformId) { + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), -1); + xmlSecAssert2(transformId != NULL, -1); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + if((xmlSecTransformId)xmlSecPtrListGetItem(list, i) == transformId) { + return(1); + } + } + return(0); +} + +/** + * xmlSecTransformIdListFindByHref: + * @list: the pointer to transform ids list. + * @href: the desired transform klass href. + * @usage: the desired transform usage. + * + * Lookups data klass in the list with given @href and @usage in @list. + * + * Returns: transform klass is found and NULL otherwise. + */ +xmlSecTransformId +xmlSecTransformIdListFindByHref(xmlSecPtrListPtr list, const xmlChar* href, + xmlSecTransformUsage usage) { + xmlSecTransformId transformId; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), xmlSecTransformIdUnknown); + xmlSecAssert2(href != NULL, xmlSecTransformIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(transformId != xmlSecTransformIdUnknown, xmlSecTransformIdUnknown); + + if(((usage & transformId->usage) != 0) && (transformId->href != NULL) && + xmlStrEqual(href, transformId->href)) { + return(transformId); + } + } + return(xmlSecTransformIdUnknown); +} + +/** + * xmlSecTransformIdListFindByName: + * @list: the pointer to transform ids list. + * @name: the desired transform klass name. + * @usage: the desired transform usage. + * + * Lookups data klass in the list with given @name and @usage in @list. + * + * Returns: transform klass is found and NULL otherwise. + */ +xmlSecTransformId +xmlSecTransformIdListFindByName(xmlSecPtrListPtr list, const xmlChar* name, + xmlSecTransformUsage usage) { + xmlSecTransformId transformId; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecTransformIdListId), xmlSecTransformIdUnknown); + xmlSecAssert2(name != NULL, xmlSecTransformIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i); + xmlSecAssert2(transformId != xmlSecTransformIdUnknown, xmlSecTransformIdUnknown); + + if(((usage & transformId->usage) != 0) && (transformId->name != NULL) && + xmlStrEqual(name, BAD_CAST transformId->name)) { + + return(transformId); + } + } + return(xmlSecTransformIdUnknown); +} + +/** + * xmlSecTransformIdListDebugDump: + * @list: the pointer to transform ids list. + * @output: the pointer to output FILE. + * + * Prints binary transform debug information to @output. + */ +void +xmlSecTransformIdListDebugDump(xmlSecPtrListPtr list, FILE* output) { + xmlSecTransformId transformId; + xmlSecSize i, size; + + xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecTransformIdListId)); + xmlSecAssert(output != NULL); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i); + xmlSecAssert(transformId != NULL); + xmlSecAssert(transformId->name != NULL); + + if(i > 0) { + fprintf(output, ",\"%s\"", transformId->name); + } else { + fprintf(output, "\"%s\"", transformId->name); + } + } + fprintf(output, "\n"); +} + +/** + * xmlSecTransformIdListDebugXmlDump: + * @list: the pointer to transform ids list. + * @output: the pointer to output FILE. + * + * Prints binary transform debug information to @output in XML format. + */ +void +xmlSecTransformIdListDebugXmlDump(xmlSecPtrListPtr list, FILE* output) { + xmlSecTransformId transformId; + xmlSecSize i, size; + + xmlSecAssert(xmlSecPtrListCheckId(list, xmlSecTransformIdListId)); + xmlSecAssert(output != NULL); + + fprintf(output, "<TransformIdsList>\n"); + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + transformId = (xmlSecTransformId)xmlSecPtrListGetItem(list, i); + xmlSecAssert(transformId != NULL); + xmlSecAssert(transformId->name != NULL); + + fprintf(output, "<TransformId name=\""); + xmlSecPrintXmlString(output, transformId->name); + fprintf(output, "\" />"); + } + fprintf(output, "</TransformIdsList>\n"); +} + +/************************************************************************ + * + * IO buffers for transforms + * + ************************************************************************/ +typedef struct _xmlSecTransformIOBuffer xmlSecTransformIOBuffer, + *xmlSecTransformIOBufferPtr; +typedef enum { + xmlSecTransformIOBufferModeRead, + xmlSecTransformIOBufferModeWrite +} xmlSecTransformIOBufferMode; + +struct _xmlSecTransformIOBuffer { + xmlSecTransformIOBufferMode mode; + xmlSecTransformPtr transform; + xmlSecTransformCtxPtr transformCtx; +}; + +static xmlSecTransformIOBufferPtr xmlSecTransformIOBufferCreate (xmlSecTransformIOBufferMode mode, + xmlSecTransformPtr transform, + xmlSecTransformCtxPtr transformCtx); +static void xmlSecTransformIOBufferDestroy (xmlSecTransformIOBufferPtr buffer); +static int xmlSecTransformIOBufferRead (xmlSecTransformIOBufferPtr buffer, + xmlSecByte *buf, + xmlSecSize size); +static int xmlSecTransformIOBufferWrite (xmlSecTransformIOBufferPtr buffer, + const xmlSecByte *buf, + xmlSecSize size); +static int xmlSecTransformIOBufferClose (xmlSecTransformIOBufferPtr buffer); + + +/** + * xmlSecTransformCreateOutputBuffer: + * @transform: the pointer to transform. + * @transformCtx: the pointer to transform context object. + * + * Creates output buffer to write data to @transform. + * + * Returns: pointer to new output buffer or NULL if an error occurs. + */ +xmlOutputBufferPtr +xmlSecTransformCreateOutputBuffer(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformIOBufferPtr buffer; + xmlSecTransformDataType type; + xmlOutputBufferPtr output; + + xmlSecAssert2(xmlSecTransformIsValid(transform), NULL); + xmlSecAssert2(transformCtx != NULL, NULL); + + /* check that we have binary push method for this transform */ + type = xmlSecTransformDefaultGetDataType(transform, xmlSecTransformModePush, transformCtx); + if((type & xmlSecTransformDataTypeBin) == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + "push binary data not supported"); + return(NULL); + } + + buffer = xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferModeWrite, transform, transformCtx); + if(buffer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformIOBufferCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + output = xmlOutputBufferCreateIO((xmlOutputWriteCallback)xmlSecTransformIOBufferWrite, + (xmlOutputCloseCallback)xmlSecTransformIOBufferClose, + buffer, + NULL); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferCreateIO", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecTransformIOBufferDestroy(buffer); + return(NULL); + } + + return(output); +} + +/** + * xmlSecTransformCreateInputBuffer: + * @transform: the pointer to transform. + * @transformCtx: the pointer to transform context object. + * + * Creates input buffer to read data from @transform. + * + * Returns: pointer to new input buffer or NULL if an error occurs. + */ +xmlParserInputBufferPtr +xmlSecTransformCreateInputBuffer(xmlSecTransformPtr transform, xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformIOBufferPtr buffer; + xmlSecTransformDataType type; + xmlParserInputBufferPtr input; + + xmlSecAssert2(xmlSecTransformIsValid(transform), NULL); + xmlSecAssert2(transformCtx != NULL, NULL); + + /* check that we have binary pop method for this transform */ + type = xmlSecTransformDefaultGetDataType(transform, xmlSecTransformModePop, transformCtx); + if((type & xmlSecTransformDataTypeBin) == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + "pop binary data not supported"); + return(NULL); + } + + buffer = xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferModeRead, transform, transformCtx); + if(buffer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformIOBufferCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + input = xmlParserInputBufferCreateIO((xmlInputReadCallback)xmlSecTransformIOBufferRead, + (xmlInputCloseCallback)xmlSecTransformIOBufferClose, + buffer, + XML_CHAR_ENCODING_NONE); + if(input == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParserInputBufferCreateIO", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecTransformIOBufferDestroy(buffer); + return(NULL); + } + + return(input); +} + +static xmlSecTransformIOBufferPtr +xmlSecTransformIOBufferCreate(xmlSecTransformIOBufferMode mode, xmlSecTransformPtr transform, + xmlSecTransformCtxPtr transformCtx) { + xmlSecTransformIOBufferPtr buffer; + + xmlSecAssert2(xmlSecTransformIsValid(transform), NULL); + xmlSecAssert2(transformCtx != NULL, NULL); + + buffer = (xmlSecTransformIOBufferPtr)xmlMalloc(sizeof(xmlSecTransformIOBuffer)); + if(buffer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", sizeof(xmlSecTransformIOBuffer)); + return(NULL); + } + memset(buffer, 0, sizeof(xmlSecTransformIOBuffer)); + + buffer->mode = mode; + buffer->transform = transform; + buffer->transformCtx = transformCtx; + + return(buffer); +} + +static void +xmlSecTransformIOBufferDestroy(xmlSecTransformIOBufferPtr buffer) { + xmlSecAssert(buffer != NULL); + + memset(buffer, 0, sizeof(xmlSecTransformIOBuffer)); + xmlFree(buffer); +} + +static int +xmlSecTransformIOBufferRead(xmlSecTransformIOBufferPtr buffer, + xmlSecByte *buf, xmlSecSize size) { + int ret; + + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2(buffer->mode == xmlSecTransformIOBufferModeRead, -1); + xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1); + xmlSecAssert2(buffer->transformCtx != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + + ret = xmlSecTransformPopBin(buffer->transform, buf, size, &size, buffer->transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(buffer->transform)), + "xmlSecTransformPopBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(size); +} + +static int +xmlSecTransformIOBufferWrite(xmlSecTransformIOBufferPtr buffer, + const xmlSecByte *buf, xmlSecSize size) { + int ret; + + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2(buffer->mode == xmlSecTransformIOBufferModeWrite, -1); + xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1); + xmlSecAssert2(buffer->transformCtx != NULL, -1); + xmlSecAssert2(buf != NULL, -1); + + ret = xmlSecTransformPushBin(buffer->transform, buf, size, 0, buffer->transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(buffer->transform)), + "xmlSecTransformPushBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(size); +} + +static int +xmlSecTransformIOBufferClose(xmlSecTransformIOBufferPtr buffer) { + int ret; + + xmlSecAssert2(buffer != NULL, -1); + xmlSecAssert2(xmlSecTransformIsValid(buffer->transform), -1); + xmlSecAssert2(buffer->transformCtx != NULL, -1); + + /* need to flush write buffer before destroing */ + if(buffer->mode == xmlSecTransformIOBufferModeWrite) { + ret = xmlSecTransformPushBin(buffer->transform, NULL, 0, 1, buffer->transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(buffer->transform)), + "xmlSecTransformPushBin", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + xmlSecTransformIOBufferDestroy(buffer); + return(0); +} diff --git a/src/x509.c b/src/x509.c new file mode 100644 index 00000000..22f5a196 --- /dev/null +++ b/src/x509.c @@ -0,0 +1,97 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_X509 + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/x509.h> +#include <xmlsec/errors.h> + +/** + * xmlSecX509DataGetNodeContent: + * @node: the pointer to <dsig:X509Data/> node. + * @deleteChildren: the flag that indicates whether to remove node children after reading. + * @keyInfoCtx: the pointer to <dsig:KeyInfo/> node processing context. + * + * Reads the contents of <dsig:X509Data/> node and returns it as + * a bits mask. + * + * Returns: the bit mask representing the <dsig:X509Data/> node content + * or a negative value if an error occurs. + */ +int +xmlSecX509DataGetNodeContent (xmlNodePtr node, int deleteChildren, + xmlSecKeyInfoCtxPtr keyInfoCtx) { + xmlNodePtr cur, next; + int deleteCurNode; + int content = 0; + + xmlSecAssert2(node != NULL, 0); + xmlSecAssert2(keyInfoCtx != NULL, -1); + + /* determine the current node content */ + cur = xmlSecGetNextElementNode(node->children); + while(cur != NULL) { + deleteCurNode = 0; + if(xmlSecCheckNodeName(cur, xmlSecNodeX509Certificate, xmlSecDSigNs)) { + if(xmlSecIsEmptyNode(cur) == 1) { + content |= XMLSEC_X509DATA_CERTIFICATE_NODE; + deleteCurNode = 1; + } + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SubjectName, xmlSecDSigNs)) { + if(xmlSecIsEmptyNode(cur) == 1) { + content |= XMLSEC_X509DATA_SUBJECTNAME_NODE; + deleteCurNode = 1; + } + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509IssuerSerial, xmlSecDSigNs)) { + if(xmlSecIsEmptyNode(cur) == 1) { + content |= XMLSEC_X509DATA_ISSUERSERIAL_NODE; + deleteCurNode = 1; + } + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509SKI, xmlSecDSigNs)) { + if(xmlSecIsEmptyNode(cur) == 1) { + content |= XMLSEC_X509DATA_SKI_NODE; + deleteCurNode = 1; + } + } else if(xmlSecCheckNodeName(cur, xmlSecNodeX509CRL, xmlSecDSigNs)) { + if(xmlSecIsEmptyNode(cur) == 1) { + content |= XMLSEC_X509DATA_CRL_NODE; + deleteCurNode = 1; + } + } else { + /* todo: fail on unknown child node? */ + } + next = xmlSecGetNextElementNode(cur->next); + if((deleteCurNode != 0) && (deleteChildren != 0)) { + /* remove "template" nodes */ + xmlUnlinkNode(cur); + xmlFreeNode(cur); + } + cur = next; + } + + return (content); +} + +#endif /* XMLSEC_NO_X509 */ + diff --git a/src/xkms.c b/src/xkms.c new file mode 100644 index 00000000..7b475301 --- /dev/null +++ b/src/xkms.c @@ -0,0 +1,4981 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * "XML Key Management Specification v 2.0" implementation + * http://www.w3.org/TR/xkms2/ + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_XKMS + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/soap.h> +#include <xmlsec/xkms.h> +#include <xmlsec/private.h> +#include <xmlsec/private/xkms.h> +#include <xmlsec/errors.h> + +#define XMLSEC_XKMS_ID_ATTRIBUTE_LEN 32 + +/* The ID attribute in XKMS is 'Id' */ +static const xmlChar* xmlSecXkmsServerIds[] = { BAD_CAST "Id", NULL }; + +#ifndef XMLSEC_NO_SOAP +static int xmlSecXkmsServerCtxWriteSoap11FatalError (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr envNode); +static int xmlSecXkmsServerCtxWriteSoap12FatalError (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr envNode); +#endif /* XMLSEC_NO_SOAP */ + +static int xmlSecXkmsServerCtxRequestAbstractTypeNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr* node); +static int xmlSecXkmsServerCtxSignatureNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxMessageExtensionNodesRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr* node); +static int xmlSecXkmsServerCtxOpaqueClientDataNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxPendingNotificationNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxRespondWithNodesRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr* node); +static int xmlSecXkmsServerCtxPendingRequestNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr* node); +static int xmlSecXkmsServerCtxQueryKeyBindingNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead(xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr* node); +static int xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite(xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); +static int xmlSecXkmsServerCtxKeyInfoNodeWrite (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); +static int xmlSecXkmsServerCtxUseKeyWithNodesRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr* node); +static int xmlSecXkmsServerCtxUseKeyWithNodesWrite (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); +static int xmlSecXkmsServerCtxTimeInstantNodeRead (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxResultTypeNodeWrite (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxRequestSignatureValueNodeWrite(xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); +static int xmlSecXkmsServerCtxKeyBindingNodeWrite (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); +static int xmlSecXkmsServerCtxValidityIntervalNodeWrite (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); +static int xmlSecXkmsServerCtxKeyBindingStatusNodeWrite (xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node, + xmlSecKeyPtr key); + + +static const xmlSecQName2IntegerInfo gXmlSecXkmsResultMajorInfo[] = +{ + { xmlSecXkmsNs, xmlSecResultMajorCodeSuccess, + xmlSecXkmsResultMajorSuccess }, + { xmlSecXkmsNs, xmlSecResultMajorCodeVersionMismatch, + xmlSecXkmsResultMajorVersionMismatch }, + { xmlSecXkmsNs, xmlSecResultMajorCodeSender, + xmlSecXkmsResultMajorSender }, + { xmlSecXkmsNs, xmlSecResultMajorCodeReceiver, + xmlSecXkmsResultMajorReceiver }, + { xmlSecXkmsNs, xmlSecResultMajorCodeRepresent, + xmlSecXkmsResultMajorRepresent }, + { xmlSecXkmsNs, xmlSecResultMajorCodePending, + xmlSecXkmsResultMajorPending, }, + { NULL , NULL, 0 } /* MUST be last in the list */ +}; + +static const xmlSecQName2IntegerInfo gXmlSecXkmsMinorErrorInfo[] = +{ + { xmlSecXkmsNs, xmlSecResultMinorCodeNoMatch, + xmlSecXkmsResultMinorNoMatch }, + { xmlSecXkmsNs, xmlSecResultMinorCodeTooManyResponses, + xmlSecXkmsResultMinorTooManyResponses }, + { xmlSecXkmsNs, xmlSecResultMinorCodeIncomplete, + xmlSecXkmsResultMinorIncomplete }, + { xmlSecXkmsNs, xmlSecResultMinorCodeFailure, + xmlSecXkmsResultMinorFailure }, + { xmlSecXkmsNs, xmlSecResultMinorCodeRefused, + xmlSecXkmsResultMinorRefused }, + { xmlSecXkmsNs, xmlSecResultMinorCodeNoAuthentication, + xmlSecXkmsResultMinorNoAuthentication }, + { xmlSecXkmsNs, xmlSecResultMinorCodeMessageNotSupported, + xmlSecXkmsResultMinorMessageNotSupported }, + { xmlSecXkmsNs, xmlSecResultMinorCodeUnknownResponseId, + xmlSecXkmsResultMinorUnknownResponseId }, + { xmlSecXkmsNs, xmlSecResultMinorCodeNotSynchronous, + xmlSecXkmsResultMinorSynchronous }, + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +static const xmlSecQName2IntegerInfo gXmlSecXkmsKeyBindingStatusInfo[] = +{ + { xmlSecXkmsNs, xmlSecKeyBindingStatusValid, + xmlSecXkmsKeyBindingStatusValid }, + { xmlSecXkmsNs, xmlSecKeyBindingStatusInvalid, + xmlSecXkmsKeyBindingStatusInvalid }, + { xmlSecXkmsNs, xmlSecKeyBindingStatusIndeterminate, + xmlSecXkmsKeyBindingStatusIndeterminate }, + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +static const xmlSecQName2BitMaskInfo gXmlSecXkmsKeyUsageInfo[] = +{ + { xmlSecXkmsNs, xmlSecKeyUsageEncryption, + xmlSecKeyUsageEncrypt | xmlSecKeyUsageDecrypt }, + { xmlSecXkmsNs, xmlSecKeyUsageSignature, + xmlSecKeyUsageSign | xmlSecKeyUsageVerify }, + { xmlSecXkmsNs, xmlSecKeyUsageExchange, + xmlSecKeyUsageKeyExchange}, + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +static const xmlSecQName2BitMaskInfo gXmlSecXkmsKeyBindingReasonInfo[] = +{ + { xmlSecXkmsNs, xmlSecKeyBindingReasonIssuerTrust, + XMLSEC_XKMS_KEY_BINDING_REASON_MASK_ISSUER_TRAST }, + { xmlSecXkmsNs, xmlSecKeyBindingReasonRevocationStatus, + XMLSEC_XKMS_KEY_BINDING_REASON_MASK_REVOCATION_STATUS }, + { xmlSecXkmsNs, xmlSecKeyBindingReasonValidityInterval, + XMLSEC_XKMS_KEY_BINDING_REASON_MASK_VALIDITY_INTERVAL }, + { xmlSecXkmsNs, xmlSecKeyBindingReasonSignature, + XMLSEC_XKMS_KEY_BINDING_REASON_MASK_SIGNATURE }, + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +static const xmlSecQName2BitMaskInfo gXmlSecXkmsResponseMechanismInfo[] = +{ + { xmlSecXkmsNs, xmlSecResponseMechanismRepresent, + XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_REPRESENT }, + { xmlSecXkmsNs, xmlSecResponseMechanismPending, + XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_PENDING }, + { xmlSecXkmsNs, xmlSecResponseMechanismRequestSignatureValue, + XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_REQUEST_SIGNATURE_VALUE }, + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +static const xmlSecQName2IntegerInfo gXmlSecXkmsFormatInfo[] = +{ + { NULL, xmlSecXkmsFormatStrPlain, + xmlSecXkmsServerFormatPlain }, +#ifndef XMLSEC_NO_SOAP + { NULL, xmlSecXkmsFormatStrSoap11, + xmlSecXkmsServerFormatSoap11 }, + { NULL, xmlSecXkmsFormatStrSoap12, + xmlSecXkmsServerFormatSoap12 }, +#endif /* XMLSEC_NO_SOAP */ + { NULL, NULL, 0 } /* MUST be last in the list */ +}; + +/** + * xmlSecXkmsServerFormatFromString: + * @str the string. + * + * Gets xmlSecXkmsServerFormat from string @str. + * + * Returns: corresponding format or xmlSecXkmsServerFormatUnknown + * if format could not be recognized. + */ +xmlSecXkmsServerFormat +xmlSecXkmsServerFormatFromString(const xmlChar* str) { + int res; + int ret; + + xmlSecAssert2(str != NULL, xmlSecXkmsServerFormatUnknown); + + ret = xmlSecQName2IntegerGetInteger(gXmlSecXkmsFormatInfo, NULL, str, &res); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetInteger", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(xmlSecXkmsServerFormatUnknown); + } + + return((xmlSecXkmsServerFormat)res); +} + +/** + * xmlSecXkmsServerFormatToString: + * @format: the format. + * + * Gets string from @format. + * + * Returns: string corresponding to @format or NULL if an error occurs. + */ +const xmlChar* +xmlSecXkmsServerFormatToString (xmlSecXkmsServerFormat format) { + xmlSecQName2IntegerInfoConstPtr info; + + xmlSecAssert2(format != xmlSecXkmsServerFormatUnknown, NULL); + + info = xmlSecQName2IntegerGetInfo(gXmlSecXkmsFormatInfo, format); + if(info == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetInfo", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + return(info->qnameLocalPart); +} + +/** + * xmlSecXkmsServerCtxCreate: + * @keysMngr: the pointer to keys manager. + * + * Creates XKMS request server side processing context. + * The caller is responsible for destroying returend object by calling + * #xmlSecXkmsServerCtxDestroy function. + * + * Returns: pointer to newly allocated context object or NULL if an error + * occurs. + */ +xmlSecXkmsServerCtxPtr +xmlSecXkmsServerCtxCreate(xmlSecKeysMngrPtr keysMngr) { + xmlSecXkmsServerCtxPtr ctx; + int ret; + + ctx = (xmlSecXkmsServerCtxPtr) xmlMalloc(sizeof(xmlSecXkmsServerCtx)); + if(ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecXkmsServerCtx)=%d", + sizeof(xmlSecXkmsServerCtx)); + return(NULL); + } + + ret = xmlSecXkmsServerCtxInitialize(ctx, keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxDestroy(ctx); + return(NULL); + } + return(ctx); +} + +/** + * xmlSecXkmsServerCtxDestroy: + * @ctx: the pointer to XKMS processing context. + * + * Destroy context object created with #xmlSecXkmsServerCtxCreate function. + */ +void +xmlSecXkmsServerCtxDestroy(xmlSecXkmsServerCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + xmlSecXkmsServerCtxFinalize(ctx); + xmlFree(ctx); +} + +/** + * xmlSecXkmsServerCtxInitialize: + * @ctx: the pointer to XKMS processing context. + * @keysMngr: the pointer to keys manager. + * + * Initializes XKMS element processing context. + * The caller is responsible for cleaing up returend object by calling + * #xmlSecXkmsServerCtxFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerCtxInitialize(xmlSecXkmsServerCtxPtr ctx, xmlSecKeysMngrPtr keysMngr) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + + memset(ctx, 0, sizeof(xmlSecXkmsServerCtx)); + + ctx->resultMajor = xmlSecXkmsResultMajorSuccess; + ctx->resultMinor = xmlSecXkmsResultMinorNone; + ctx->responseLimit = XMLSEC_XKMS_NO_RESPONSE_LIMIT; + ctx->idLen = XMLSEC_XKMS_ID_ATTRIBUTE_LEN; + + /* initialize key info */ + ret = xmlSecKeyInfoCtxInitialize(&(ctx->keyInfoReadCtx), keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ctx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead; + + ret = xmlSecKeyInfoCtxInitialize(&(ctx->keyInfoWriteCtx), keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + ctx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite; + + /* enabled RespondWith */ + ret = xmlSecPtrListInitialize(&(ctx->enabledRespondWithIds), xmlSecXkmsRespondWithIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* enabled ServerRequest */ + ret = xmlSecPtrListInitialize(&(ctx->enabledServerRequestIds), xmlSecXkmsServerRequestIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + + + /* initialize keys list */ + ret = xmlSecPtrListInitialize(&(ctx->keys), xmlSecKeyPtrListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* initialize RespondWith list */ + ret = xmlSecPtrListInitialize(&(ctx->respWithList), xmlSecXkmsRespondWithIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsServerCtxFinalize: + * @ctx: the pointer to XKMS processing context. + * + * Cleans up @ctx object. + */ +void +xmlSecXkmsServerCtxFinalize(xmlSecXkmsServerCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + xmlSecXkmsServerCtxReset(ctx); + + if(ctx->expectedService != NULL) { + xmlFree(ctx->expectedService); + } + if(ctx->idPrefix != NULL) { + xmlFree(ctx->idPrefix); + } + + xmlSecKeyInfoCtxFinalize(&(ctx->keyInfoReadCtx)); + xmlSecKeyInfoCtxFinalize(&(ctx->keyInfoWriteCtx)); + xmlSecPtrListFinalize(&(ctx->enabledRespondWithIds)); + xmlSecPtrListFinalize(&(ctx->enabledServerRequestIds)); + xmlSecPtrListFinalize(&(ctx->keys)); + xmlSecPtrListFinalize(&(ctx->respWithList)); + memset(ctx, 0, sizeof(xmlSecXkmsServerCtx)); +} + +/** + * xmlSecXkmsServerCtxReset: + * @ctx: the pointer to XKMS processing context. + * + * Resets @ctx object, user settings are not touched. + */ +void +xmlSecXkmsServerCtxReset(xmlSecXkmsServerCtxPtr ctx) { + xmlSecAssert(ctx != NULL); + + ctx->resultMajor = xmlSecXkmsResultMajorSuccess; + ctx->resultMinor = xmlSecXkmsResultMinorNone; + xmlSecKeyInfoCtxReset(&(ctx->keyInfoReadCtx)); + xmlSecKeyInfoCtxReset(&(ctx->keyInfoWriteCtx)); + xmlSecPtrListEmpty(&(ctx->keys)); + xmlSecPtrListEmpty(&(ctx->respWithList)); + + ctx->requestNode = NULL; + ctx->opaqueClientDataNode = NULL; + ctx->firtsMsgExtNode = NULL; + ctx->keyInfoNode = NULL; + ctx->requestId = xmlSecXkmsServerRequestIdUnknown; + + if(ctx->id != NULL) { + xmlFree(ctx->id); ctx->id = NULL; + } + if(ctx->service != NULL) { + xmlFree(ctx->service); ctx->service = NULL; + } + if(ctx->nonce != NULL) { + xmlFree(ctx->nonce); ctx->nonce = NULL; + } + if(ctx->originalRequestId != NULL) { + xmlFree(ctx->originalRequestId); ctx->originalRequestId = NULL; + } + if(ctx->pendingNotificationMechanism != NULL) { + xmlFree(ctx->pendingNotificationMechanism); + ctx->pendingNotificationMechanism = NULL; + } + if(ctx->pendingNotificationIdentifier != NULL) { + xmlFree(ctx->pendingNotificationIdentifier); + ctx->pendingNotificationIdentifier = NULL; + } + if(ctx->compoundRequestContexts != NULL) { + xmlSecPtrListDestroy(ctx->compoundRequestContexts); + ctx->compoundRequestContexts = NULL; + } + + ctx->responseLimit = XMLSEC_XKMS_NO_RESPONSE_LIMIT; + ctx->responseMechanismMask = 0; +} + +/** + * xmlSecXkmsServerCtxCopyUserPref: + * @dst: the pointer to destination context. + * @src: the pointer to source context. + * + * Copies user preference from @src context to @dst. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerCtxCopyUserPref(xmlSecXkmsServerCtxPtr dst, xmlSecXkmsServerCtxPtr src) { + int ret; + + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(src != NULL, -1); + + dst->userData = src->userData; + dst->flags = src->flags; + dst->flags2 = src->flags2; + + ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoReadCtx), &(src->keyInfoReadCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoWriteCtx), &(src->keyInfoWriteCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(src->expectedService != NULL) { + dst->expectedService = xmlStrdup(src->expectedService); + if(dst->expectedService == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + if(src->idPrefix != NULL) { + dst->idPrefix = xmlStrdup(src->idPrefix); + if(dst->idPrefix == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + src->idLen = dst->idLen; + + + ret = xmlSecPtrListCopy(&(dst->enabledRespondWithIds), &(src->enabledRespondWithIds)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecPtrListCopy(&(dst->enabledServerRequestIds), &(src->enabledServerRequestIds)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsServerCtxProcess: + * @ctx: the pointer to XKMS processing context. + * @node: the pointer to request node. + * @format: the request/response format. + * @doc: the pointer to response parent XML document (might be NULL). + * + * Reads XKMS request from @node and creates response to a newly created node. + * Caller is responsible for adding the returned node to the XML document. + * + * Returns: pointer to newly created XKMS response node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecXkmsServerCtxProcess(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, + xmlSecXkmsServerFormat format, xmlDocPtr doc) { + int ret; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->requestId == NULL, NULL); + xmlSecAssert2(ctx->requestNode == NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + ctx->requestNode = xmlSecXkmsServerCtxRequestUnwrap(ctx, node, format); + if(ctx->requestNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRequestUnwrap", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + goto done; + } + + ret = xmlSecXkmsServerCtxRequestRead(ctx, ctx->requestNode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdListFindByNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ctx->requestNode=%s", + xmlSecErrorsSafeString(ctx->requestNode->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + goto done; + } + + ret = xmlSecXkmsServerRequestExecute(ctx->requestId, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ctx->requestNode=%s", + xmlSecErrorsSafeString(ctx->requestNode->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + goto done; + } + +done: + /* always try to write response back */ + if(ctx->requestId != NULL) { + xmlNodePtr respNode; + xmlNodePtr wrappedRespNode; + + respNode = xmlSecXkmsServerCtxResponseWrite(ctx, doc); + if(respNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResponseWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ctx->requestNode=%s", + xmlSecErrorsSafeString(ctx->requestNode->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + goto error; + } + + + wrappedRespNode = xmlSecXkmsServerCtxResponseWrap(ctx, respNode, format, doc); + if(wrappedRespNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResponseWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ctx->requestNode=%s", + xmlSecErrorsSafeString(ctx->requestNode->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + xmlFreeNode(respNode); + goto error; + } + + return(wrappedRespNode); + } + +error: + /* last attempt: create fatatl error response */ + return(xmlSecXkmsServerCtxFatalErrorResponseCreate(ctx, format, doc)); +} + +/** + * xmlSecXkmsServerCtxRequestRead: + * @ctx: the pointer to XKMS processing context. + * @node: the pointer to request node. + * + * Reads XKMS request from @node and stores data in @ctx. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerCtxRequestRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->requestId == NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* find out what the request is */ + if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) { + ctx->requestId = xmlSecXkmsServerRequestIdListFindByNode(&(ctx->enabledServerRequestIds), node); + } else { + ctx->requestId = xmlSecXkmsServerRequestIdListFindByNode(xmlSecXkmsServerRequestIdsGet(), node); + } + if(ctx->requestId == xmlSecXkmsServerRequestIdUnknown) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdListFindByNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorMessageNotSupported); + return(-1); + } + + xmlSecAddIDs(node->doc, node, xmlSecXkmsServerIds); + ret = xmlSecXkmsServerRequestNodeRead(ctx->requestId, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "request=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctx->requestId))); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsServerCtxResponseWrite: + * @ctx: the pointer to XKMS processing context. + * @doc: the pointer to response parent XML document (might be NULL). + * + * Writes XKMS response from context to a newly created node. Caller is + * responsible for adding the returned node to the XML document. + * + * Returns: pointer to newly created XKMS response node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecXkmsServerCtxResponseWrite(xmlSecXkmsServerCtxPtr ctx, xmlDocPtr doc) { + xmlNodePtr respNode; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(ctx->requestId != NULL, NULL); + + /* now write results */ + respNode = xmlSecXkmsServerRequestNodeWrite(ctx->requestId, ctx, doc, NULL); + if(respNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "request=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctx->requestId))); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + return(respNode); +} + +/** + * xmlSecXkmsServerCtxRequestUnwrap: + * @ctx: the pointer to XKMS processing context. + * @node: the pointer to request node. + * @format: the request/response format. + * + * Removes SOAP or other envelope from XKMS request. + * + * Returns: pointer to "real" XKMS request node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecXkmsServerCtxRequestUnwrap(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecXkmsServerFormat format) { + xmlNodePtr result = NULL; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + switch(format) { + case xmlSecXkmsServerFormatPlain: + result = node; + break; +#ifndef XMLSEC_NO_SOAP + case xmlSecXkmsServerFormatSoap11: + /* verify that it is actually soap Envelope node */ + if(xmlSecSoap11CheckEnvelope(node) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11CheckEnvelope", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + /* check that Body has exactly one entry */ + if(xmlSecSoap11GetBodyEntriesNumber(node) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBodyEntriesNumber", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + /* this one enntry is our xkms request */ + result = xmlSecSoap11GetBodyEntry(node, 0); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11GetBodyEntry", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + break; + case xmlSecXkmsServerFormatSoap12: + /* verify that it is actually soap Envelope node */ + if(xmlSecSoap12CheckEnvelope(node) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12CheckEnvelope", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + /* check that Body has exactly one entry */ + if(xmlSecSoap12GetBodyEntriesNumber(node) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBodyEntriesNumber", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + /* this one enntry is our xkms request */ + result = xmlSecSoap12GetBodyEntry(node, 0); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12GetBodyEntry", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + break; +#endif /* XMLSEC_NO_SOAP */ + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + "format=%d", + format); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + return(result); +} + +/** + * xmlSecXkmsServerCtxResponseWrap: + * @ctx: the pointer to XKMS processing context. + * @node: the pointer to response node. + * @format: the request/response format. + * @doc: the pointer to response parent XML document (might be NULL). + * + * Creates SOAP or other envelope around XKMS response. + * Caller is responsible for adding the returned node to the XML document. + * + * Returns: pointer to newly created response envelope node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecXkmsServerCtxResponseWrap(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecXkmsServerFormat format, xmlDocPtr doc) { + xmlNodePtr result = NULL; + + xmlSecAssert2(ctx != NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + switch(format) { + case xmlSecXkmsServerFormatPlain: + result = node; /* do nothing */ + break; +#ifndef XMLSEC_NO_SOAP + case xmlSecXkmsServerFormatSoap11: + result = xmlSecSoap11CreateEnvelope(doc); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11CreateEnvelope", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + if(xmlSecSoap11AddBodyEntry(result, node) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11AddBodyEntry", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + break; + case xmlSecXkmsServerFormatSoap12: + result = xmlSecSoap12CreateEnvelope(doc); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12CreateEnvelope", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + if(xmlSecSoap12AddBodyEntry(result, node) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12AddBodyEntry", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + break; +#endif /* XMLSEC_NO_SOAP */ + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + "format=%d", + format); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + return(result); +} + +/** + * xmlSecXkmsServerCtxFatalErrorResponseCreate: + * @ctx: the pointer to XKMS processing context. + * @format: the request/response format. + * @doc: the pointer to response parent XML document (might be NULL). + * + * Creates a "fatal error" SOAP or other envelope respons. Caller is + * responsible for adding the returned node to the XML document. + * + * Returns: pointer to newly created fatal error response (it might be NULL). + */ +xmlNodePtr +xmlSecXkmsServerCtxFatalErrorResponseCreate(xmlSecXkmsServerCtxPtr ctx, xmlSecXkmsServerFormat format, xmlDocPtr doc) { + xmlNodePtr result = NULL; + int ret; + + xmlSecAssert2(ctx != NULL, NULL); + + /* make sure that we have an error */ + if(ctx->resultMajor == xmlSecXkmsResultMajorSuccess) { + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + } + + switch(format) { + case xmlSecXkmsServerFormatPlain: + /* try to create fatal error response with XKMS Status request */ + result = xmlSecXkmsServerRequestNodeWrite(xmlSecXkmsServerRequestResultId, ctx, doc, NULL); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + break; +#ifndef XMLSEC_NO_SOAP + case xmlSecXkmsServerFormatSoap11: + result = xmlSecSoap11CreateEnvelope(doc); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11CreateEnvelope", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + ret = xmlSecXkmsServerCtxWriteSoap11FatalError(ctx, result); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxWriteSoap11FatalError", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + xmlFreeNode(result); + return(NULL); + } + + break; + case xmlSecXkmsServerFormatSoap12: + result = xmlSecSoap12CreateEnvelope(doc); + if(result == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12CreateEnvelope", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + ret = xmlSecXkmsServerCtxWriteSoap12FatalError(ctx, result); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxWriteSoap12FatalError", + XMLSEC_ERRORS_R_INVALID_DATA, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + xmlFreeNode(result); + return(NULL); + } + + break; +#endif /* XMLSEC_NO_SOAP */ + default: + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + "format=%d", + format); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(NULL); + } + + return(result); +} + +#ifndef XMLSEC_NO_SOAP +static int +xmlSecXkmsServerCtxWriteSoap11FatalError(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr envNode) { + const xmlChar* faultCodeHref = NULL; + const xmlChar* faultCodeLocalPart = NULL; + xmlChar* faultString = NULL; + int len; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(envNode != NULL, -1); + + if((ctx->resultMajor == xmlSecXkmsResultMajorVersionMismatch) || + (ctx->requestNode == NULL)) { + /* we were not able to parse the envelope or its general version mismatch error */ + faultCodeHref = xmlSecSoap11Ns; + faultCodeLocalPart = xmlSecSoapFaultCodeVersionMismatch; + faultString = xmlStrdup(xmlSecXkmsSoapFaultReasonUnsupportedVersion); + if(faultString == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + } else if((ctx->resultMajor == xmlSecXkmsResultMajorSender) && + (ctx->requestId == NULL)) { + /* we understood the request but were not able to parse input message */ + faultCodeHref = xmlSecSoap11Ns; + faultCodeLocalPart = xmlSecSoapFaultCodeClient; + + len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) + + xmlStrlen(xmlSecXkmsSoapFaultReasonMessageInvalid) + 1; + faultString = xmlMalloc(len + 1); + if(faultString == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + xmlSecStrPrintf(faultString, len , xmlSecXkmsSoapFaultReasonMessageInvalid, + xmlSecErrorsSafeString(ctx->requestNode->name)); + } else if((ctx->resultMajor == xmlSecXkmsResultMajorReceiver) && + (ctx->requestId == NULL)) { + /* we understood the request but were not able to process it */ + faultCodeHref = xmlSecSoap11Ns; + faultCodeLocalPart = xmlSecSoapFaultCodeServer; + faultString = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable); + if(faultString == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + } else if((ctx->requestId == NULL) && (ctx->requestNode != NULL)) { + /* we parsed the envelope but were not able to understand this request */ + faultCodeHref = xmlSecSoap11Ns; + faultCodeLocalPart = xmlSecSoapFaultCodeClient; + + len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) + + xmlStrlen(xmlSecXkmsSoapFaultReasonMessageNotSupported) + 1; + faultString = xmlMalloc(len + 1); + if(faultString == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + xmlSecStrPrintf(faultString, len , xmlSecXkmsSoapFaultReasonMessageNotSupported, + xmlSecErrorsSafeString(ctx->requestNode->name)); + } else { + /* just some error */ + faultCodeHref = xmlSecSoap11Ns; + faultCodeLocalPart = xmlSecSoapFaultCodeServer; + faultString = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable); + if(faultString == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + } + + if(xmlSecSoap11AddFaultEntry(envNode, faultCodeHref, faultCodeLocalPart, faultString, NULL) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap11AddFaultEntry", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + xmlFree(faultString); + return(-1); + } + + xmlFree(faultString); + return(0); +} + +static int +xmlSecXkmsServerCtxWriteSoap12FatalError(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr envNode) { + xmlSecSoap12FaultCode faultCode = xmlSecSoap12FaultCodeUnknown; + const xmlChar* faultSubCodeHref = NULL; + const xmlChar* faultSubCodeLocalPart = NULL; + xmlChar* faultReason = NULL; + int len; + xmlNodePtr faultNode; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(envNode != NULL, -1); + + if((ctx->resultMajor == xmlSecXkmsResultMajorVersionMismatch) || + (ctx->requestNode == NULL)) { + /* we were not able to parse the envelope or its general version mismatch error */ + faultCode = xmlSecSoap12FaultCodeVersionMismatch; + faultReason = xmlStrdup(xmlSecXkmsSoapFaultReasonUnsupportedVersion); + if(faultReason == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + } else if((ctx->resultMajor == xmlSecXkmsResultMajorSender) && + (ctx->requestId == NULL)) { + /* we understood the request but were not able to parse input message */ + faultCode = xmlSecSoap12FaultCodeSender; + faultSubCodeHref = xmlSecXkmsNs; + faultSubCodeLocalPart = xmlSecXkmsSoapSubcodeValueMessageNotSupported; + + len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) + + xmlStrlen(xmlSecXkmsSoapFaultReasonMessageInvalid) + 1; + faultReason = xmlMalloc(len + 1); + if(faultReason == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + xmlSecStrPrintf(faultReason, len , xmlSecXkmsSoapFaultReasonMessageInvalid, + xmlSecErrorsSafeString(ctx->requestNode->name)); + } else if((ctx->resultMajor == xmlSecXkmsResultMajorReceiver) && + (ctx->requestId == NULL)) { + /* we understood the request but were not able to process it */ + faultCode = xmlSecSoap12FaultCodeReceiver; + faultReason = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable); + if(faultReason == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + } else if((ctx->requestId == NULL) && (ctx->requestNode != NULL)) { + /* we parsed the envelope but were not able to understand this request */ + faultCode = xmlSecSoap12FaultCodeSender; + faultSubCodeHref = xmlSecXkmsNs; + faultSubCodeLocalPart = xmlSecXkmsSoapSubcodeValueBadMessage; + + len = xmlStrlen(BAD_CAST xmlSecErrorsSafeString(ctx->requestNode->name)) + + xmlStrlen(xmlSecXkmsSoapFaultReasonMessageNotSupported) + 1; + faultReason = xmlMalloc(len + 1); + if(faultReason == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + xmlSecStrPrintf(faultReason, len , xmlSecXkmsSoapFaultReasonMessageNotSupported, + xmlSecErrorsSafeString(ctx->requestNode->name)); + } else { + /* just some error */ + faultCode = xmlSecSoap12FaultCodeReceiver; + faultReason = xmlStrdup(xmlSecXkmsSoapFaultReasonServiceUnavailable); + if(faultReason == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + return(-1); + } + } + xmlSecAssert2(faultCode != xmlSecSoap12FaultCodeUnknown, -1); + xmlSecAssert2(faultReason != NULL, -1); + + faultNode = xmlSecSoap12AddFaultEntry(envNode, faultCode, faultReason, + xmlSecXkmsSoapFaultReasonLang, NULL, NULL); + if(faultNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12AddFaultEntry", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + xmlFree(faultReason); + return(-1); + } + xmlFree(faultReason); + + if((faultSubCodeHref != NULL) && (faultSubCodeLocalPart != NULL)) { + /* make sure that we have subcode (xkms) namespace declared */ + if(xmlNewNs(faultNode, faultSubCodeHref, BAD_CAST "xkms") == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(faultSubCodeHref)); + return(-1); + } + if(xmlSecSoap12AddFaultSubcode(faultNode, faultSubCodeHref, faultSubCodeLocalPart) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecSoap12AddFaultSubcode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "href=%s,value=%s", + xmlSecErrorsSafeString(faultSubCodeHref), + xmlSecErrorsSafeString(faultSubCodeLocalPart)); + return(-1); + } + } + + return(0); +} + +#endif /* XMLSEC_NO_SOAP */ + + +/** + * xmlSecXkmsServerCtxSetResult: + * @ctx: the pointer to XKMS processing context. + * @resultMajor: the major result code. + * @resultMinor: the minor result code. + * + * Sets the major/minor result code in the context if no other result is already + * reported. + */ +void +xmlSecXkmsServerCtxSetResult(xmlSecXkmsServerCtxPtr ctx, xmlSecXkmsResultMajor resultMajor, + xmlSecXkmsResultMinor resultMinor) { + xmlSecAssert(ctx != NULL); + + if((ctx->resultMajor == xmlSecXkmsResultMajorSuccess) && + (resultMinor != xmlSecXkmsResultMajorSuccess)) { + ctx->resultMajor = resultMajor; + ctx->resultMinor = resultMinor; + } else if((ctx->resultMajor == xmlSecXkmsResultMajorSuccess) && + (ctx->resultMinor == xmlSecXkmsResultMinorNone)) { + xmlSecAssert(resultMajor == xmlSecXkmsResultMajorSuccess); + + ctx->resultMinor = resultMinor; + } +} + + +/** + * xmlSecXkmsServerCtxDebugDump: + * @ctx: the pointer to XKMS processing context. + * @output: the pointer to output FILE. + * + * Prints the debug information about @ctx to @output. + */ +void +xmlSecXkmsServerCtxDebugDump(xmlSecXkmsServerCtxPtr ctx, FILE* output) { + xmlSecAssert(ctx != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "= XKMS SERVER CONTEXT: %s\n", + (ctx->requestId != xmlSecXkmsServerRequestIdUnknown && + xmlSecXkmsServerRequestKlassGetName(ctx->requestId)) ? + xmlSecXkmsServerRequestKlassGetName(ctx->requestId) : + BAD_CAST "NULL"); + + xmlSecQName2IntegerDebugDump(gXmlSecXkmsResultMajorInfo, + ctx->resultMajor, BAD_CAST "resultMajor", output); + xmlSecQName2IntegerDebugDump(gXmlSecXkmsMinorErrorInfo, + ctx->resultMinor, BAD_CAST "resultMinor", output); + + fprintf(output, "== id: %s\n", + (ctx->id) ? ctx->id : BAD_CAST ""); + fprintf(output, "== service: %s\n", + (ctx->service) ? ctx->service : BAD_CAST ""); + fprintf(output, "== nonce: %s\n", + (ctx->nonce) ? ctx->nonce : BAD_CAST ""); + fprintf(output, "== originalRequestId: %s\n", + (ctx->originalRequestId) ? ctx->originalRequestId : BAD_CAST ""); + fprintf(output, "== pendingNotificationMechanism: %s\n", + (ctx->pendingNotificationMechanism) ? + ctx->pendingNotificationMechanism : + BAD_CAST ""); + fprintf(output, "== pendingNotificationIdentifier: %s\n", + (ctx->pendingNotificationIdentifier) ? + ctx->pendingNotificationIdentifier : + BAD_CAST ""); + if(ctx->responseLimit != XMLSEC_XKMS_NO_RESPONSE_LIMIT) { + fprintf(output, "== ResponseLimit: %d\n", ctx->responseLimit); + } + xmlSecQName2BitMaskDebugDump(gXmlSecXkmsResponseMechanismInfo, + ctx->responseMechanismMask, BAD_CAST "responseMechanism", output); + + if(ctx->expectedService != NULL) { + fprintf(output, "== expected service: %s\n", ctx->expectedService); + } + fprintf(output, "== flags: 0x%08x\n", ctx->flags); + fprintf(output, "== flags2: 0x%08x\n", ctx->flags2); + + fprintf(output, "== Key Info Read Ctx:\n"); + xmlSecKeyInfoCtxDebugDump(&(ctx->keyInfoReadCtx), output); + + fprintf(output, "== Key Info Write Ctx:\n"); + xmlSecKeyInfoCtxDebugDump(&(ctx->keyInfoWriteCtx), output); + + if(xmlSecPtrListGetSize(&(ctx->enabledRespondWithIds)) > 0) { + fprintf(output, "== Enabled RespondWith: "); + xmlSecTransformIdListDebugDump(&(ctx->enabledRespondWithIds), output); + } else { + fprintf(output, "== Enabled RespondWith: all\n"); + } + + if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) { + fprintf(output, "== Enabled ServerRequest: "); + xmlSecTransformIdListDebugDump(&(ctx->enabledServerRequestIds), output); + } else { + fprintf(output, "== Enabled ServerRequest: all\n"); + } + + fprintf(output, "== RespondWith List:\n"); + xmlSecPtrListDebugDump(&(ctx->respWithList), output); + + fprintf(output, "== Keys:\n"); + xmlSecPtrListDebugDump(&(ctx->keys), output); + + if(ctx->compoundRequestContexts != NULL) { + fprintf(output, "== Compound Request:\n"); + xmlSecPtrListDebugDump(ctx->compoundRequestContexts, output); + } +} + +/** + * xmlSecXkmsServerCtxDebugXmlDump: + * @ctx: the pointer to XKMS processing context. + * @output: the pointer to output FILE. + * + * Prints the debug information about @ctx to @output in XML format. + */ +void +xmlSecXkmsServerCtxDebugXmlDump(xmlSecXkmsServerCtxPtr ctx, FILE* output) { + xmlSecAssert(ctx != NULL); + xmlSecAssert(output != NULL); + + fprintf(output, "<XkmsServerRequestContext name=\""); + xmlSecPrintXmlString(output, + (ctx->requestId != xmlSecXkmsServerRequestIdUnknown) ? + xmlSecXkmsServerRequestKlassGetName(ctx->requestId) : + BAD_CAST "NULL" + ); + fprintf(output, "\">\n"); + + xmlSecQName2IntegerDebugXmlDump(gXmlSecXkmsResultMajorInfo, + ctx->resultMajor, BAD_CAST "MajorError", output); + xmlSecQName2IntegerDebugXmlDump(gXmlSecXkmsMinorErrorInfo, + ctx->resultMinor, BAD_CAST "MinorError", output); + + fprintf(output, "<Id>"); + xmlSecPrintXmlString(output, ctx->id); + fprintf(output, "</Id>\n"); + + fprintf(output, "<Service>"); + xmlSecPrintXmlString(output, ctx->service); + fprintf(output, "</Service>\n"); + + fprintf(output, "<Nonce>"); + xmlSecPrintXmlString(output, ctx->nonce); + fprintf(output, "</Nonce>\n"); + + fprintf(output, "<OriginalRequestId>"); + xmlSecPrintXmlString(output, ctx->originalRequestId); + fprintf(output, "</OriginalRequestId>\n"); + + fprintf(output, "<PendingNotificationMechanism>"); + xmlSecPrintXmlString(output, ctx->pendingNotificationMechanism); + fprintf(output, "</PendingNotificationMechanism>\n"); + + fprintf(output, "<PendingNotificationIdentifier>"); + xmlSecPrintXmlString(output, ctx->pendingNotificationIdentifier); + fprintf(output, "</PendingNotificationIdentifier>\n"); + + if(ctx->responseLimit != XMLSEC_XKMS_NO_RESPONSE_LIMIT) { + fprintf(output, "<ResponseLimit>%d</ResponseLimit>\n", ctx->responseLimit); + } + xmlSecQName2BitMaskDebugXmlDump(gXmlSecXkmsResponseMechanismInfo, + ctx->responseMechanismMask, BAD_CAST "ResponseMechanism", output); + + + fprintf(output, "<ExpectedService>"); + xmlSecPrintXmlString(output, ctx->expectedService); + fprintf(output, "</ExpectedService>\n"); + + fprintf(output, "<Flags>%08x</Flags>\n", ctx->flags); + fprintf(output, "<Flags2>%08x</Flags2>\n", ctx->flags2); + + fprintf(output, "<KeyInfoReadCtx>\n"); + xmlSecKeyInfoCtxDebugXmlDump(&(ctx->keyInfoReadCtx), output); + fprintf(output, "</KeyInfoReadCtx>\n"); + + fprintf(output, "<KeyInfoWriteCtx>\n"); + xmlSecKeyInfoCtxDebugXmlDump(&(ctx->keyInfoWriteCtx), output); + fprintf(output, "</KeyInfoWriteCtx>\n"); + + if(xmlSecPtrListGetSize(&(ctx->enabledRespondWithIds)) > 0) { + fprintf(output, "<EnabledRespondWith>\n"); + xmlSecTransformIdListDebugXmlDump(&(ctx->enabledRespondWithIds), output); + fprintf(output, "</EnabledRespondWith>\n"); + } else { + fprintf(output, "<EnabledRespondWith>all</EnabledRespondWith>\n"); + } + + if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) { + fprintf(output, "<EnabledServerRequest>\n"); + xmlSecTransformIdListDebugXmlDump(&(ctx->enabledServerRequestIds), output); + fprintf(output, "</EnabledServerRequest>\n"); + } else { + fprintf(output, "<EnabledServerRequest>all</EnabledServerRequest>\n"); + } + + + fprintf(output, "<RespondWithList>\n"); + xmlSecPtrListDebugXmlDump(&(ctx->respWithList), output); + fprintf(output, "</RespondWithList>\n"); + + fprintf(output, "<Keys>\n"); + xmlSecPtrListDebugXmlDump(&(ctx->keys), output); + fprintf(output, "</Keys>\n"); + + if(ctx->compoundRequestContexts != NULL) { + fprintf(output, "<CompoundRequest>\n"); + xmlSecPtrListDebugXmlDump(ctx->compoundRequestContexts, output); + fprintf(output, "</CompoundRequest>\n"); + } + + fprintf(output, "</XkmsServerRequestContext>\n"); +} + +/** + * <xkms:MessageAbstractType Id Service Nonce?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * + * <xkms:RequestAbstractType Id Service Nonce? OriginalRequestId? ResponseLimit?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:ResponseMechanism>* + * <xkms:RespondWith>* + * <xkms:PendingNotification Mechanism Identifier>? + * + * XML Schema: + * + * <!-- RequestAbstractType --> + * <complexType name="RequestAbstractType" abstract="true"> + * <complexContent> + * <extension base="xkms:MessageAbstractType"> + * <sequence> + * <element ref="xkms:ResponseMechanism" minOccurs="0" + * maxOccurs="unbounded"/> + * <element ref="xkms:RespondWith" minOccurs="0" + * maxOccurs="unbounded"/> + * <element ref="xkms:PendingNotification" minOccurs="0"/> + * </sequence> + * <attribute name="OriginalRequestId" type="anyURI" + * use="optional"/> + * <attribute name="ResponseLimit" type="integer" use="optional"/> + * </extension> + * </complexContent> + * </complexType> + * <!-- /RequestAbstractType --> + * + * <!-- MessageAbstractType --> + * <complexType name="MessageAbstractType" abstract="true"> + * <sequence> + * <element ref="ds:Signature" minOccurs="0"/> + * <element ref="xkms:MessageExtension" minOccurs="0" + * maxOccurs="unbounded"/> + * <element ref="xkms:OpaqueClientData" minOccurs="0"/> + * </sequence> + * <attribute name="Id" type="ID" use="required"/> + * <attribute name="Service" type="anyURI" use="required"/> + * <attribute name="Nonce" type="base64Binary" use="optional"/> + * </complexType> + * <!-- /MessageAbstractType --> + */ +static int +xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) { + xmlNodePtr cur; + xmlChar* tmp; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2((*node) != NULL, -1); + + cur = (*node); + xmlSecAssert2(cur != NULL, -1); + + /* required Id attribute */ + xmlSecAssert2(ctx->id == NULL, -1); + ctx->id = xmlGetProp(cur, xmlSecAttrId); + if(ctx->id == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s;node=%s", + xmlSecErrorsSafeString(xmlSecAttrId), + xmlSecErrorsSafeString(cur->name)); + return(-1); + } + + /* required Service attribute */ + xmlSecAssert2(ctx->service == NULL, -1); + ctx->service = xmlGetProp(cur, xmlSecAttrService); + if(ctx->service == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s;node=%s", + xmlSecErrorsSafeString(xmlSecAttrService), + xmlSecErrorsSafeString(cur->name)); + return(-1); + } + + /* check service */ + if((ctx->expectedService != NULL) && (!xmlStrEqual(ctx->expectedService, ctx->service))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "expectedService=%s;actualService=%s", + xmlSecErrorsSafeString(ctx->expectedService), + xmlSecErrorsSafeString(ctx->service)); + return(-1); + } + + /* optional Nonce attribute */ + xmlSecAssert2(ctx->nonce == NULL, -1); + ctx->nonce = xmlGetProp(cur, xmlSecAttrNonce); + + /* optional OriginalRequestId attribute */ + xmlSecAssert2(ctx->originalRequestId == NULL, -1); + ctx->originalRequestId = xmlGetProp(cur, xmlSecAttrOriginalRequestId); + + /* optional ResponseLimit attribute */ + xmlSecAssert2(ctx->responseLimit == XMLSEC_XKMS_NO_RESPONSE_LIMIT, -1); + tmp = xmlGetProp(cur, xmlSecAttrResponseLimit); + if(tmp != NULL) { + ctx->responseLimit = atoi((char*)tmp); + xmlFree(tmp); + } + + /* now read children */ + cur = xmlSecGetNextElementNode(cur->children); + + /* first node is optional <dsig:Signature/> node */ + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeSignature, xmlSecDSigNs)) { + ret = xmlSecXkmsServerCtxSignatureNodeRead(ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxSignatureNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is zero or more <xkms:MessageExtension/> nodes */ + ret = xmlSecXkmsServerCtxMessageExtensionNodesRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxMessageExtensionNodesRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* next is optional <xkms:OpaqueClientData/> node */ + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeOpaqueClientData, xmlSecXkmsNs)) { + ret = xmlSecXkmsServerCtxOpaqueClientDataNodeRead(ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxOpaqueClientDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is zero or more <xkms:ResponseMechanism/> nodes */ + ret = xmlSecQName2BitMaskNodesRead(gXmlSecXkmsResponseMechanismInfo, &cur, + xmlSecNodeResponseMechanism, xmlSecXkmsNs, + ((ctx->flags & XMLSEC_XKMS_SERVER_FLAGS_STOP_ON_UNKNOWN_RESPONSE_MECHANISM) != 0) ? 1 : 0, + &ctx->responseMechanismMask); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskNodesRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecNodeResponseMechanism)); + return(-1); + } + + /* next is zero or more <xkms:RespondWith/> nodes */ + ret = xmlSecXkmsServerCtxRespondWithNodesRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRespondWithNodesRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* next is optional <xkms:PendingNotification/> node */ + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodePendingNotification, xmlSecXkmsNs)) { + ret = xmlSecXkmsServerCtxPendingNotificationNodeRead(ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxPendingNotificationNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + (*node) = cur; + return(0); +} + +static int +xmlSecXkmsServerCtxSignatureNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* todo: verify signature and make sure that correct data was signed */ + return(0); +} + +/** + * <!-- MessageExtension --> + * <element name="MessageExtension" type="xkms:MessageExtensionAbstractType" + * abstract="true"/> + * <complexType name="MessageExtensionAbstractType" abstract="true"/> + * <!-- /MessageExtension --> + */ +static int +xmlSecXkmsServerCtxMessageExtensionNodesRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) { + xmlNodePtr cur; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->firtsMsgExtNode == NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = (*node); + while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeMessageExtension, xmlSecXkmsNs)) { + if(ctx->firtsMsgExtNode == NULL) { + ctx->firtsMsgExtNode = cur; + } + cur = xmlSecGetNextElementNode(cur->next); + } + + (*node) = cur; + return(0); +} + +static int +xmlSecXkmsServerCtxOpaqueClientDataNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->opaqueClientDataNode == NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* remember that node, will copy it in the response later */ + ctx->opaqueClientDataNode = node; + return(0); +} + +static int +xmlSecXkmsServerCtxRespondWithNodesRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = (*node); + while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeRespondWith, xmlSecXkmsNs)) { + xmlSecXkmsRespondWithId id = xmlSecXkmsRespondWithIdUnknown; + + if(xmlSecPtrListGetSize(&(ctx->enabledRespondWithIds)) > 0) { + id = xmlSecXkmsRespondWithIdListFindByNodeValue(&(ctx->enabledRespondWithIds), cur); + } else { + id = xmlSecXkmsRespondWithIdListFindByNodeValue(xmlSecXkmsRespondWithIdsGet(), cur); + } + + if(id != xmlSecXkmsRespondWithIdUnknown) { + ret = xmlSecXkmsRespondWithNodeRead(id, ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCreateTree", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else if((ctx->flags & XMLSEC_XKMS_SERVER_FLAGS_STOP_ON_UNKNOWN_RESPOND_WITH) != 0) { + xmlChar* content ; + + content = xmlNodeGetContent(cur); + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(cur->name), + xmlSecErrorsSafeString(content)); + if(content != NULL) { + xmlFree(content); + } + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + (*node) = cur; + return(0); +} + +/** + * XML Schema: + * <!-- PendingNotification --> + * <element name="PendingNotification" type="xkms:PendingNotificationType"/> + * <complexType name="PendingNotificationType"> + * <attribute name="Mechanism" type="anyURI" use="required"/> + * <attribute name="Identifier" type="anyURI" use="required"/> + * </complexType> + * <!-- /PendingNotification --> + */ +static int +xmlSecXkmsServerCtxPendingNotificationNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + xmlSecAssert2(ctx->pendingNotificationMechanism == NULL, -1); + ctx->pendingNotificationMechanism = xmlGetProp(node, xmlSecAttrMechanism); + if(ctx->pendingNotificationMechanism == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s;node=%s", + xmlSecErrorsSafeString(xmlSecAttrMechanism), + xmlSecErrorsSafeString(node->name)); + return(-1); + } + + xmlSecAssert2(ctx->pendingNotificationIdentifier == NULL, -1); + ctx->pendingNotificationIdentifier = xmlGetProp(node, xmlSecAttrIdentifier); + if(ctx->pendingNotificationIdentifier == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s;node=%s", + xmlSecErrorsSafeString(xmlSecAttrIdentifier), + xmlSecErrorsSafeString(node->name)); + return(-1); + } + + return(0); +} + +/** + * <xkms:PendingRequestType Id Service Nonce? OriginalRequestId? ResponseLimit? ResponseId?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:ResponseMechanism>* + * <xkms:RespondWith>* + * <xkms:PendingNotification Mechanism Identifier>? + * + * XML Schema: + * + * <!-- PendingRequest --> + * <element name="PendingRequest" type="xkms:PendingRequestType"/> + * <complexType name="PendingRequestType"> + * <complexContent> + * <extension base="xkms:RequestAbstractType"> + * <attribute name="ResponseId" type="anyURI" use="optional"/> + * </extension> + * </complexContent> + * </complexType> + * <!-- /PendingRequest --> * + */ +static int +xmlSecXkmsServerCtxPendingRequestNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first read "parent" type */ + ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* todo: read responseId */ + return(0); +} + +/** + * <xkms:QueryKeyBinding Id? + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:TimeInstant Time>? + * + * XML Schema: + * <!-- QueryKeyBinding --> + * <element name="QueryKeyBinding" type="xkms:QueryKeyBindingType"/> + * <complexType name="QueryKeyBindingType"> + * <complexContent> + * <extension base="xkms:KeyBindingAbstractType"> + * <sequence> + * <element ref="xkms:TimeInstant" minOccurs="0"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /QueryKeyBinding --> + */ +static int +xmlSecXkmsServerCtxQueryKeyBindingNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first read "parent" type */ + cur = node; + ret = xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* next is optional <xkms:TimeInstant/> node */ + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeTimeInstant, xmlSecXkmsNs)) { + ret = xmlSecXkmsServerCtxTimeInstantNodeRead(ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxTimeInstantNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* check that there is nothing after the last node */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * <xkms:KeyBindingAbstractType Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * + * XML Schema: + * <!-- KeyBindingAbstractType--> + * <complexType name="KeyBindingAbstractType" abstract="true"> + * <sequence> + * <element ref="ds:KeyInfo" minOccurs="0"/> + * <element ref="xkms:KeyUsage" minOccurs="0" maxOccurs="3"/> + * <element ref="xkms:UseKeyWith" minOccurs="0" + * maxOccurs="unbounded"/> + * </sequence> + * <attribute name="Id" type="ID" use="optional"/> + * </complexType> + * <!-- /KeyBindingAbstractType--> + */ +static int +xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2((*node) != NULL, -1); + + cur = (*node); + xmlSecAssert2(cur != NULL, -1); + + /* we don't care about Id attribute in this node */ + cur = xmlSecGetNextElementNode(cur->children); + + /* first node is optional <dsig:KeyInfo/> node. for now we only remember pointer */ + xmlSecAssert2(ctx->keyInfoNode == NULL, -1); + if((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs)) { + ctx->keyInfoNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is zero or more <xkms:KeyUsage/> nodes */ + ret = xmlSecQName2BitMaskNodesRead(gXmlSecXkmsKeyUsageInfo, &cur, + xmlSecNodeKeyUsage, xmlSecXkmsNs, + ((ctx->flags & XMLSEC_XKMS_SERVER_FLAGS_STOP_ON_UNKNOWN_KEY_USAGE) != 0) ? 1 : 0, + &(ctx->keyInfoReadCtx.keyReq.keyUsage)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskNodesRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyUsage)); + return(-1); + } + + /* next is zero or more <xkms:UseKeyWith/> nodes */ + ret = xmlSecXkmsServerCtxUseKeyWithNodesRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxUseKeyWithNodesRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + (*node) = cur; + return(0); +} + +static int +xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(key != NULL, -1); + + /* generate and add Id attribute */ + ret = xmlSecGenerateAndAddID(node, xmlSecAttrId, ctx->idPrefix, ctx->idLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGenerateAndAddID", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* <dsig:KeyInfo/> node */ + cur = xmlSecAddChild(node, xmlSecNodeKeyInfo, xmlSecDSigNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyInfo)); + return(-1); + } + + ret = xmlSecXkmsServerCtxKeyInfoNodeWrite(ctx, cur, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxKeyInfoNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* next is <xkms:KeyUsage/> node */ + ret = xmlSecQName2BitMaskNodesWrite(gXmlSecXkmsKeyUsageInfo, node, + xmlSecNodeKeyUsage, xmlSecXkmsNs, + key->usage); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskNodesWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecNodeKeyUsage)); + return(-1); + } + + /* and the last node is <xkms:UseKeyWith/> */ + ret = xmlSecXkmsServerCtxUseKeyWithNodesWrite(ctx, node, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxUseKeyWithNodesWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecXkmsServerCtxKeyInfoNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* add child nodes as requested in <xkms:RespondWith/> nodes */ + ret = xmlSecXkmsRespondWithIdListWrite(&(ctx->respWithList), ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdListWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecKeyInfoNodeWrite(node, key, &(ctx->keyInfoWriteCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + + +/** + * XML Schema: + * <!-- UseKeyWith --> + * <element name="UseKeyWith" type="xkms:UseKeyWithType"/> + * <complexType name="UseKeyWithType"> + * <attribute name="Application" type="anyURI" use="required"/> + * <attribute name="Identifier" type="string" use="required"/> + * </complexType> + * <!-- /UseKeyWith --> + */ +static int +xmlSecXkmsServerCtxUseKeyWithNodesRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr* node) { + xmlSecPtrListPtr list; + xmlNodePtr cur; + xmlSecKeyUseWithPtr keyUseWith; + xmlChar* application; + xmlChar* identifier; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + list = &(ctx->keyInfoReadCtx.keyReq.keyUseWithList); + xmlSecAssert2(xmlSecPtrListGetSize(list) == 0, -1); + + cur = (*node); + while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeUseKeyWith, xmlSecXkmsNs)) { + application = xmlGetProp(cur, xmlSecAttrApplication); + if(application == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s;node=%s", + xmlSecErrorsSafeString(xmlSecAttrApplication), + xmlSecErrorsSafeString(cur->name)); + return(-1); + } + + identifier = xmlGetProp(cur, xmlSecAttrIdentifier); + if(identifier == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s;node=%s", + xmlSecErrorsSafeString(xmlSecAttrIdentifier), + xmlSecErrorsSafeString(cur->name)); + xmlFree(application); + return(-1); + } + + keyUseWith = xmlSecKeyUseWithCreate(application, identifier); + if(keyUseWith == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyUseWithCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(application); + xmlFree(identifier); + return(-1); + } + xmlFree(application); + xmlFree(identifier); + + ret = xmlSecPtrListAdd(list, keyUseWith); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyUseWithDestroy(keyUseWith); + return(-1); + } + + cur = xmlSecGetNextElementNode(cur->next); + } + + (*node) = cur; + return(0); +} + +static int +xmlSecXkmsServerCtxUseKeyWithNodesWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(key != NULL, -1); + + /* todo: write UseKeyWith */ + return(0); +} + + +static int +xmlSecXkmsServerCtxTimeInstantNodeRead(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* todo: parse xml schema dataTime or use libxml? */ + return(0); +} + +/** + * <xkms:ResultType Id Service Nonce? ResultMajor ResultMinor? RequestId?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:RequestSignatureValue>* + * + * XML Schema: + * <!-- ResultType --> + * <element name="Result" type="xkms:ResultType"/> + * <complexType name="ResultType"> + * <complexContent> + * <extension base="xkms:MessageAbstractType"> + * <sequence> + * <element ref="xkms:RequestSignatureValue" minOccurs="0"/> + * </sequence> + * <attribute name="ResultMajor" type="QName" use="required"/> + * <attribute name="ResultMinor" type="QName" use="optional"/> + * <attribute name="RequestId" type="anyURI" use="optional"/> + * </extension> + * </complexContent> + * </complexType> + * <!-- /ResultType --> + */ +static int +xmlSecXkmsServerCtxResultTypeNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* generate and add Id attribute */ + ret = xmlSecGenerateAndAddID(node, xmlSecAttrId, ctx->idPrefix, ctx->idLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGenerateAndAddID", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* todo: generate nonce? */ + + /* set Service atribute (required) */ + if((ctx->service == NULL) || (xmlSetProp(node, xmlSecAttrService, ctx->service) == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrService), + xmlSecErrorsSafeString(ctx->service)); + return(-1); + } + + + /* set RequestId atribute (optional) */ + if((ctx->id != NULL) && (xmlSetProp(node, xmlSecAttrRequestId, ctx->id) == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s,value=%s", + xmlSecErrorsSafeString(xmlSecAttrRequestId), + xmlSecErrorsSafeString(ctx->id)); + return(-1); + } + + + /* set major code (required) */ + ret = xmlSecQName2IntegerAttributeWrite(gXmlSecXkmsResultMajorInfo, node, + xmlSecAttrResultMajor, ctx->resultMajor); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerAttributeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s,value=%d", + xmlSecErrorsSafeString(xmlSecAttrResultMajor), + ctx->resultMajor); + return(-1); + } + + /* set minor code (optional) */ + if(ctx->resultMinor != xmlSecXkmsResultMinorNone) { + ret = xmlSecQName2IntegerAttributeWrite(gXmlSecXkmsMinorErrorInfo, node, + xmlSecAttrResultMinor, ctx->resultMinor); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerAttributeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s,value=%d", + xmlSecErrorsSafeString(xmlSecAttrResultMinor), + ctx->resultMinor); + return(-1); + } + } + + /* todo: create signature template */ + + /* todo: create message extension nodes? */ + + /* <xkms:OpaqueClientData/>: An XKMS service SHOULD return the value of + * the <OpaqueClientData> element unmodified in a request in a response + * with status code Succes */ + if((ctx->resultMajor == xmlSecXkmsResultMajorSuccess) && (ctx->opaqueClientDataNode != NULL)) { + xmlNodePtr copyNode; + + copyNode = xmlDocCopyNode(ctx->opaqueClientDataNode, node->doc, 1); + if(copyNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "name=%s", + xmlSecErrorsSafeString(ctx->opaqueClientDataNode->name)); + return(-1); + } + + if(xmlSecAddChildNode(node, copyNode) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChildNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(copyNode->name)); + return(-1); + } + } + + ret = xmlSecXkmsServerCtxRequestSignatureValueNodeWrite(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRequestSignatureValueNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * A service SHOULD include the <RequestSignatureValue> element in a response + * if the following conditions are satisfied and MUST NOT include the value + * otherwise: + * + * + * - The <ds:Signature> element was present in the corresponding request + * - The service successfully verified the <ds:Signature> element in the + * corresponding request, and + * - The ResponseMechanism RequestSignatureValue was specified. + * + */ +static int +xmlSecXkmsServerCtxRequestSignatureValueNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* todo: check all conditions for RequestSignatureValue */ + if((ctx->responseMechanismMask & XMLSEC_XKMS_RESPONSE_MECHANISM_MASK_REQUEST_SIGNATURE_VALUE) == 0) { + /* The ResponseMechanism RequestSignatureValue was not specified. */ + return(0); + } + + /* todo: write RequestSignatureValue */ + return(0); +} + + +/** + * + * <xkms:UnverifiedKeyBindingType Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:ValidityInterval NotBefore NotOnOrAfter>? + * + * XML Schema: + * + * <!-- UnverifiedKeyBinding --> + * <element name="UnverifiedKeyBinding" type="xkms:UnverifiedKeyBindingType"/> + * <complexType name="UnverifiedKeyBindingType"> + * <complexContent> + * <extension base="xkms:KeyBindingAbstractType"> + * <sequence> + * <element ref="xkms:ValidityInterval" minOccurs="0"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /UnverifiedKeyBinding --> + */ +static int +xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first write "parent" type */ + ret = xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite(ctx, node, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* <xkms:ValidityInterval/> node */ + ret = xmlSecXkmsServerCtxValidityIntervalNodeWrite(ctx, node, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxValidityIntervalNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecXkmsServerCtxValidityIntervalNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* todo: write key validity interval */ + return(0); +} + +/** + * <xkms:KeyBinding Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:ValidityInterval NotBefore NotOnOrAfter>? + * <xkms:Status StatusValue> + * (<xkms:ValidReason>? + * <xkms:IndeterminateReason>? + * <xkms:InvalidReason>? + * )* + * + * XML Schema: + * + * <!-- KeyBinding --> + * <element name="KeyBinding" type="xkms:KeyBindingType"/> + * <complexType name="KeyBindingType"> + * <complexContent> + * <extension base="xkms:UnverifiedKeyBindingType"> + * <sequence> + * <element ref="xkms:Status"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /KeyBinding --> + */ +static int +xmlSecXkmsServerCtxKeyBindingNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first write "parent" type */ + ret = xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(ctx, node, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxKeyBindingAbstractTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* <xkms:Status/> node */ + ret = xmlSecXkmsServerCtxKeyBindingStatusNodeWrite(ctx, node, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxKeyBindingStatusNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * <xkms:Status StatusValue> + * (<xkms:ValidReason>? + * <xkms:IndeterminateReason>? + * <xkms:InvalidReason>? + * )* + * + * XML Schema: + * + * <!-- Status --> + * <element name="Status" type="xkms:StatusType"/> + * <complexType name="StatusType"> + * <sequence> + * <element ref="xkms:ValidReason" minOccurs="0" + * maxOccurs="unbounded"/> + * <element ref="xkms:IndeterminateReason" minOccurs="0" + * maxOccurs="unbounded"/> + * <element ref="xkms:InvalidReason" minOccurs="0" + * maxOccurs="unbounded"/> + * </sequence> + * <attribute name="StatusValue" type="xkms:KeyBindingStatus" + * use="required"/> + * </complexType> + * <simpleType name="KeyBindingStatus"> + * <restriction base="QName"> + * <enumeration value="xkms:Valid"/> + * <enumeration value="xkms:Invalid"/> + * <enumeration value="xkms:Indeterminate"/> + * </restriction> + * </simpleType> + * <!-- /Status --> + */ +static int +xmlSecXkmsServerCtxKeyBindingStatusNodeWrite(xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node, xmlSecKeyPtr key) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = xmlSecAddChild(node, xmlSecNodeStatus, xmlSecXkmsNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeStatus)); + return(-1); + } + + /* if we are here then the key was validated */ + ret = xmlSecQName2IntegerAttributeWrite(gXmlSecXkmsKeyBindingStatusInfo, cur, + xmlSecAttrStatusValue, xmlSecXkmsKeyBindingStatusValid); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerAttributeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecAttrStatusValue)); + return(-1); + } + + /* todo: write the reasons */ + return(0); +} + +/************************************************************************ + * + * xmlSecXkmsServerCtx list + * + ************************************************************************/ +static xmlSecPtrListKlass xmlSecXkmsServerCtxPtrListKlass = { + BAD_CAST "xkms-server-ctx-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecXkmsServerCtxDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerCtxDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerCtxDebugXmlDump, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +xmlSecPtrListId +xmlSecXkmsServerCtxPtrListGetKlass(void) { + return(&xmlSecXkmsServerCtxPtrListKlass); +} + + +/************************************************************************** + * + * Global xmlSecXkmsRespondWithIds list functions + * + *************************************************************************/ +static xmlSecPtrList xmlSecAllXkmsRespondWithIds; + + +/** + * xmlSecXkmsRespondWithIdsGet: + * + * Gets global registered RespondWith klasses list. + * + * Returns: the pointer to list of all registered RespondWith klasses. + */ +xmlSecPtrListPtr +xmlSecXkmsRespondWithIdsGet(void) { + return(&xmlSecAllXkmsRespondWithIds); +} + +/** + * xmlSecXkmsRespondWithIdsInit: + * + * Initializes the RespondWith klasses. This function is called from the + * #xmlSecInit function and the application should not call it directly. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsRespondWithIdsInit(void) { + int ret; + + ret = xmlSecPtrListInitialize(xmlSecXkmsRespondWithIdsGet(), xmlSecXkmsRespondWithIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListPtrInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecXkmsRespondWithIdListId"); + return(-1); + } + + ret = xmlSecXkmsRespondWithIdsRegisterDefault(); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegisterDefault", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsRespondWithIdsShutdown: + * + * Shuts down the keys data klasses. This function is called from the + * #xmlSecShutdown function and the application should not call it directly. + */ +void +xmlSecXkmsRespondWithIdsShutdown(void) { + xmlSecPtrListFinalize(xmlSecXkmsRespondWithIdsGet()); +} + +/** + * xmlSecXkmsRespondWithIdsRegister: + * @id: the RespondWith klass. + * + * Registers @id in the global list of RespondWith klasses. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithId id) { + int ret; + + xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1); + + ret = xmlSecPtrListAdd(xmlSecXkmsRespondWithIdsGet(), (xmlSecPtr)id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "RespondWith=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id))); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsRespondWithIdsRegisterDefault: + * + * Registers default (implemented by XML Security Library) + * RespondWith klasses: KeyName, KeyValue,... + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsRespondWithIdsRegisterDefault(void) { + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithKeyNameId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithKeyNameId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithKeyValueId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithKeyValueId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithPrivateKeyId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithPrivateKeyId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithRetrievalMethodId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithRetrievalMethodId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithX509CertId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithX509CertId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithX509ChainId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithX509ChainId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithX509CRLId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithX509CRLId))); + return(-1); + } + + /* TODO: OCSP, PGP, PGPWeb, SPKI */ + /* + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithPGPId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithPGPId))); + return(-1); + } + + if(xmlSecXkmsRespondWithIdsRegister(xmlSecXkmsRespondWithSPKIId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(xmlSecXkmsRespondWithSPKIId))); + return(-1); + } + */ + return(0); +} + + +/************************************************************************ + * + * XKMS RespondWith Klass + * + ************************************************************************/ +/** + * xmlSecXkmsRespondWithNodeRead: + * @id: the RespondWith class. + * @ctx: the XKMS request processing context. + * @node: the pointer to <xkms:RespondWith/> node. + * + * Reads the content of the <xkms:RespondWith/> @node. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsRespondWithNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + if(id->readNode != NULL) { + return((id->readNode)(id, ctx, node)); + } + return(0); +} + +/** + * xmlSecXkmsRespondWithNodeWrite: + * @id: the RespondWith class. + * @ctx: the XKMS request processing context. + * @node: the pointer to <xkms:RespondWith/> node. + * + * Writes the content of the <xkms:RespondWith/> @node. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsRespondWithNodeWrite(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + if(id->writeNode != NULL) { + return((id->writeNode)(id, ctx, node)); + } + return(0); +} + +/** + * xmlSecXkmsRespondWithDebugDump: + * @id: the RespondWith class. + * @output: the output file. + * + * Writes debug information about @id into the @output. + */ +void +xmlSecXkmsRespondWithDebugDump(xmlSecXkmsRespondWithId id, FILE* output) { + xmlSecAssert(id != xmlSecXkmsRespondWithIdUnknown); + xmlSecAssert(output != NULL); + + fprintf(output, "=== RespondWith: \"%s\" (href=\"%s\")\n", + xmlSecErrorsSafeString(id->valueName), + xmlSecErrorsSafeString(id->valueNs)); +} + +/** + * xmlSecXkmsRespondWithDebugXmlDump: + * @id: the RespondWith class. + * @output: the output file. + * + * Writes debug information about @id into the @output in XML format. + */ +void +xmlSecXkmsRespondWithDebugXmlDump(xmlSecXkmsRespondWithId id, FILE* output) { + xmlSecAssert(id != xmlSecXkmsRespondWithIdUnknown); + xmlSecAssert(output != NULL); + + fprintf(output, "<RespondWith href=\""); + xmlSecPrintXmlString(output, id->valueNs); + fprintf(output, "\">"); + xmlSecPrintXmlString(output, id->valueName); + fprintf(output, "</RespondWith>\n"); +} + +int +xmlSecXkmsRespondWithDefaultNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + int ret; + + xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + ret = xmlSecXkmsRespondWithIdListFind(&(ctx->respWithList), id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithIdListFind", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } else if(ret > 0) { + /* do nothing, we already have it in the list */ + return(0); + } + + ret = xmlSecPtrListAdd(&(ctx->respWithList), id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +int +xmlSecXkmsRespondWithDefaultNodeWrite(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + xmlNodePtr cur; + + xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1); + xmlSecAssert2(id->nodeName != NULL, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = xmlSecAddChild(node, id->nodeName, id->nodeNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(id->nodeName)); + return(-1); + } + + return(0); +} + +/************************************************************************ + * + * XKMS RespondWith Klass List + * + ************************************************************************/ +static xmlSecPtrListKlass xmlSecXkmsRespondWithIdListKlass = { + BAD_CAST "respond-with-ids-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + NULL, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsRespondWithDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsRespondWithDebugXmlDump, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +xmlSecPtrListId +xmlSecXkmsRespondWithIdListGetKlass(void) { + return(&xmlSecXkmsRespondWithIdListKlass); +} + +int +xmlSecXkmsRespondWithIdListFind(xmlSecPtrListPtr list, xmlSecXkmsRespondWithId id) { + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsRespondWithIdListId), -1); + xmlSecAssert2(id != xmlSecXkmsRespondWithIdUnknown, -1); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + if((xmlSecXkmsRespondWithId)xmlSecPtrListGetItem(list, i) == id) { + return(1); + } + } + return(0); +} + +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithIdListFindByNodeValue(xmlSecPtrListPtr list, xmlNodePtr node) { + xmlSecXkmsRespondWithId result = xmlSecXkmsRespondWithIdUnknown; + xmlSecXkmsRespondWithId id; + xmlChar* content; + xmlChar* qnameLocalPart = NULL; + xmlChar* qnamePrefix = NULL; + const xmlChar* qnameHref; + xmlNsPtr ns; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsRespondWithIdListId), xmlSecXkmsRespondWithIdUnknown); + xmlSecAssert2(node != NULL, xmlSecXkmsRespondWithIdUnknown); + + content = xmlNodeGetContent(node); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNodeGetContent", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + return(xmlSecXkmsRespondWithIdUnknown); + } + + qnameLocalPart = (xmlChar*)xmlStrchr(content, ':'); + if(qnameLocalPart != NULL) { + qnamePrefix = content; + *(qnameLocalPart++) = '\0'; + } else { + qnamePrefix = NULL; + qnameLocalPart = content; + } + + /* search namespace href */ + ns = xmlSearchNs(node->doc, node, qnamePrefix); + if((ns == NULL) && (qnamePrefix != NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSearchNs", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s,qnamePrefix=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnamePrefix)); + xmlFree(content); + return(xmlSecXkmsRespondWithIdUnknown); + } + qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL; + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + id = (xmlSecXkmsRespondWithId)xmlSecPtrListGetItem(list, i); + if((id != xmlSecXkmsRespondWithIdUnknown) && + xmlStrEqual(id->valueName, qnameLocalPart) && + xmlStrEqual(id->valueNs, qnameHref)) { + result = id; + break; + } + } + + xmlFree(content); + return(result); +} + +int +xmlSecXkmsRespondWithIdListWrite(xmlSecPtrListPtr list, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecXkmsRespondWithId id; + xmlSecSize i, size; + int ret; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsRespondWithIdListId), -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + id = (xmlSecXkmsRespondWithId)xmlSecPtrListGetItem(list, i); + if(id != xmlSecXkmsRespondWithIdUnknown) { + ret = xmlSecXkmsRespondWithNodeWrite(id, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + } + + return(0); +} + +/******************************************************************** + * + * XML Sec Library RespondWith Ids + * + *******************************************************************/ +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithKeyNameKlass = { + xmlSecRespondWithKeyName, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeKeyName, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithDefaultNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithKeyNameGetKlass: + * + * The respond with KeyName klass. + * + * Returns: respond with KeyName klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithKeyNameGetKlass(void) { + return(&xmlSecXkmsRespondWithKeyNameKlass); +} + + + +static int xmlSecXkmsRespondWithKeyValueNodeRead (xmlSecXkmsRespondWithId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithKeyValueKlass = { + xmlSecRespondWithKeyValue, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeKeyValue, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithKeyValueNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithKeyValueGetKlass: + * + * The respond with KeyValue klass. + * + * Returns: respond with KeyValue klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithKeyValueGetKlass(void) { + return(&xmlSecXkmsRespondWithKeyValueKlass); +} + +static int +xmlSecXkmsRespondWithKeyValueNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsRespondWithKeyValueId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* do usual stuff */ + ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithDefaultNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* and now set some parameters in the ctx to look for a public or private + * key and to write a public key + */ + ctx->keyInfoReadCtx.keyReq.keyType |= (xmlSecKeyDataTypePublic | xmlSecKeyDataTypePrivate); + ctx->keyInfoWriteCtx.keyReq.keyType |= xmlSecKeyDataTypePublic; + + return(0); +} + +static int xmlSecXkmsRespondWithPrivateKeyNodeRead (xmlSecXkmsRespondWithId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithPrivateKeyKlass = { + xmlSecRespondWithPrivateKey, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeKeyValue, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithPrivateKeyNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithPrivateKeyGetKlass: + * + * The respond with PrivateKey klass. + * + * Returns: respond with PrivateKey klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithPrivateKeyGetKlass(void) { + return(&xmlSecXkmsRespondWithPrivateKeyKlass); +} + +static int +xmlSecXkmsRespondWithPrivateKeyNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsRespondWithPrivateKeyId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* do usual stuff */ + ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithDefaultNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* and now set some parameters in the ctx to look for a private + * key and to write a private key + */ + ctx->keyInfoReadCtx.keyReq.keyType |= xmlSecKeyDataTypePrivate; + ctx->keyInfoWriteCtx.keyReq.keyType |= xmlSecKeyDataTypePrivate; + + return(0); +} + +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithRetrievalMethodKlass = { + xmlSecRespondWithRetrievalMethod, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeRetrievalMethod, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithDefaultNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithRetrievalMethodGetKlass: + * + * The respond with RetrievalMethod klass. + * + * Returns: respond with RetrievalMethod klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithRetrievalMethodGetKlass(void) { + return(&xmlSecXkmsRespondWithRetrievalMethodKlass); +} + + + +static int xmlSecXkmsRespondWithX509CertNodeRead (xmlSecXkmsRespondWithId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithX509CertKlass = { + xmlSecRespondWithX509Cert, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeX509Data, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithX509CertNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithX509CertGetKlass: + * + * The respond with X509Cert klass. + * + * Returns: respond with X509Cert klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithX509CertGetKlass(void) { + return(&xmlSecXkmsRespondWithX509CertKlass); +} + +static int +xmlSecXkmsRespondWithX509CertNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsRespondWithX509CertId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* do usual stuff */ + ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithDefaultNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int xmlSecXkmsRespondWithX509ChainNodeRead (xmlSecXkmsRespondWithId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithX509ChainKlass = { + xmlSecRespondWithX509Chain, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeX509Data, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithX509ChainNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithX509ChainGetKlass: + * + * The respond with X509Chain klass. + * + * Returns: respond with X509Chain klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithX509ChainGetKlass(void) { + return(&xmlSecXkmsRespondWithX509ChainKlass); +} + +static int +xmlSecXkmsRespondWithX509ChainNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsRespondWithX509ChainId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* do usual stuff */ + ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithDefaultNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int xmlSecXkmsRespondWithX509CRLNodeRead (xmlSecXkmsRespondWithId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithX509CRLKlass = { + xmlSecRespondWithX509CRL, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeX509Data, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithX509CRLNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithX509CRLGetKlass: + * + * The respond with X509CRL klass. + * + * Returns: respond with X509CRL klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithX509CRLGetKlass(void) { + return(&xmlSecXkmsRespondWithX509CRLKlass); +} + +static int +xmlSecXkmsRespondWithX509CRLNodeRead(xmlSecXkmsRespondWithId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsRespondWithX509CRLId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* do usual stuff */ + ret = xmlSecXkmsRespondWithDefaultNodeRead(id, ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecXkmsRespondWithKlassGetName(id)), + "xmlSecXkmsRespondWithDefaultNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithPGPKlass = { + xmlSecRespondWithPGP, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodePGPData, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithDefaultNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithPGPGetKlass: + * + * The respond with PGP klass. + * + * Returns: respond with PGP klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithPGPGetKlass(void) { + return(&xmlSecXkmsRespondWithPGPKlass); +} + +static xmlSecXkmsRespondWithKlass xmlSecXkmsRespondWithSPKIKlass = { + xmlSecRespondWithSPKI, /* const xmlChar* valueName; */ + xmlSecXkmsNs, /* const xmlChar* valueNs; */ + xmlSecNodeSPKIData, /* const xmlChar* nodeName; */ + xmlSecDSigNs, /* const xmlChar* nodeNs; */ + xmlSecXkmsRespondWithDefaultNodeRead, /* xmlSecXkmsRespondWithNodeReadMethod readNode; */ + xmlSecXkmsRespondWithDefaultNodeWrite, /* xmlSecXkmsRespondWithNodeWriteMethod writeNode; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsRespondWithSPKIGetKlass: + * + * The respond with SPKI klass. + * + * Returns: respond with SPKI klass. + */ +xmlSecXkmsRespondWithId +xmlSecXkmsRespondWithSPKIGetKlass(void) { + return(&xmlSecXkmsRespondWithSPKIKlass); +} + +/************************************************************************** + * + * Global xmlSecXkmsServerRequestIds list functions + * + *************************************************************************/ +static xmlSecPtrList xmlSecAllXkmsServerRequestIds; + + +/** + * xmlSecXkmsServerRequestIdsGet: + * + * Gets global registered ServerRequest klasses list. + * + * Returns: the pointer to list of all registered ServerRequest klasses. + */ +xmlSecPtrListPtr +xmlSecXkmsServerRequestIdsGet(void) { + return(&xmlSecAllXkmsServerRequestIds); +} + +/** + * xmlSecXkmsServerRequestIdsInit: + * + * Initializes the ServerRequest klasses. This function is called from the + * #xmlSecInit function and the application should not call it directly. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerRequestIdsInit(void) { + int ret; + + ret = xmlSecPtrListInitialize(xmlSecXkmsServerRequestIdsGet(), xmlSecXkmsServerRequestIdListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListPtrInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecXkmsServerRequestIdListId"); + return(-1); + } + + ret = xmlSecXkmsServerRequestIdsRegisterDefault(); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsRegisterDefault", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsServerRequestIdsShutdown: + * + * Shuts down the keys data klasses. This function is called from the + * #xmlSecShutdown function and the application should not call it directly. + */ +void +xmlSecXkmsServerRequestIdsShutdown(void) { + xmlSecPtrListFinalize(xmlSecXkmsServerRequestIdsGet()); +} + +/** + * xmlSecXkmsServerRequestIdsRegister: + * @id: the ServerRequest klass. + * + * Registers @id in the global list of ServerRequest klasses. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestId id) { + int ret; + + xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1); + + ret = xmlSecPtrListAdd(xmlSecXkmsServerRequestIdsGet(), (xmlSecPtr)id); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ServerRequest=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(id))); + return(-1); + } + + return(0); +} + +/** + * xmlSecXkmsServerRequestIdsRegisterDefault: + * + * Registers default (implemented by XML Security Library) + * ServerRequest klasses: KeyName, KeyValue,... + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerRequestIdsRegisterDefault(void) { + if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestResultId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestResultId))); + return(-1); + } + + if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestStatusId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestStatusId))); + return(-1); + } + + if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestCompoundId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestCompoundId))); + return(-1); + } + + if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestLocateId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestLocateId))); + return(-1); + } + + if(xmlSecXkmsServerRequestIdsRegister(xmlSecXkmsServerRequestValidateId) < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsRegister", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(xmlSecXkmsServerRequestValidateId))); + return(-1); + } + + return(0); +} + + +/************************************************************************ + * + * XKMS ServerRequest Klass + * + ************************************************************************/ +/** + * xmlSecXkmsServerRequestNodeRead: + * @id: the ServerRequest class. + * @ctx: the XKMS request processing context. + * @node: the pointer to <xkms:ServerRequest/> node. + * + * Reads the content of the <xkms:ServerRequest/> @node. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerRequestNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node) { + xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + if(id->readNode != NULL) { + return((id->readNode)(id, ctx, node)); + } + return(0); +} + +/** + * xmlSecXkmsServerExecute: + * @id: the ServerRequest class. + * @ctx: the XKMS request processing context. + * + * Executes XKMS server request. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecXkmsServerRequestExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) { + xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1); + xmlSecAssert2(ctx != NULL, -1); + + if(id->execute != NULL) { + return((id->execute)(id, ctx)); + } + return(0); +} + + +/** + * xmlSecXkmsServerResponseNodeWrite: + * @id: the ServerRequest class. + * @ctx: the XKMS request processing context. + * @doc: the pointer to response parent XML document (might be NULL). + * @node: the pointer to response parent XML node (might be NULL). + * + * Writes XKMS response from context to a newly created node. Caller is + * responsible for adding the returned node to the XML document. + * + * Returns: pointer to newly created XKMS response node or NULL + * if an error occurs. + */ +xmlNodePtr +xmlSecXkmsServerRequestNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, + xmlDocPtr doc, xmlNodePtr node) { + xmlNodePtr respNode; + int ret; + + xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, NULL); + xmlSecAssert2(ctx != NULL, NULL); + + /* create the response root node */ + if(node == NULL) { + xmlNsPtr ns; + + respNode = xmlNewDocNode(doc, NULL, id->resultNodeName, NULL); + if(respNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDocNode", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(id->resultNodeName)); + return(NULL); + } + ns = xmlNewNs(respNode, id->resultNodeNs, NULL); + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(id->resultNodeNs)); + xmlFreeNode(respNode); + return(NULL); + } + xmlSetNs(respNode, ns); + } else { + respNode = xmlSecAddChild(node, id->resultNodeName, id->resultNodeNs); + if(respNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(id->resultNodeName)); + return(NULL); + } + } + + if(id->writeNode != NULL) { + ret = (id->writeNode)(id, ctx, respNode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "writeNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(id->resultNodeName)); + xmlFreeNode(respNode); + return(NULL); + } + } + + return(respNode); +} + +/** + * xmlSecXkmsServerRequestDebugDump: + * @id: the ServerRequest class. + * @output: the output file. + * + * Writes debug information about @id into the @output. + */ +void +xmlSecXkmsServerRequestDebugDump(xmlSecXkmsServerRequestId id, FILE* output) { + xmlSecAssert(id != xmlSecXkmsServerRequestIdUnknown); + xmlSecAssert(output != NULL); + + fprintf(output, "=== ServerRequest: %s\n", xmlSecErrorsSafeString(id->name)); +} + +/** + * xmlSecXkmsServerRequestDebugXmlDump: + * @id: the ServerRequest class. + * @output: the output file. + * + * Writes debug information about @id into the @output in XML format. + */ +void +xmlSecXkmsServerRequestDebugXmlDump(xmlSecXkmsServerRequestId id, FILE* output) { + xmlSecAssert(id != xmlSecXkmsServerRequestIdUnknown); + xmlSecAssert(output != NULL); + + fprintf(output, "<ServerRequest>"); + xmlSecPrintXmlString(output, id->name); + fprintf(output, "</ServerRequest>\n"); +} + +/************************************************************************ + * + * XKMS ServerRequest Klass List + * + ************************************************************************/ +static xmlSecPtrListKlass xmlSecXkmsServerRequestIdListKlass = { + BAD_CAST "xkms-server-request-ids-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + NULL, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerRequestDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecXkmsServerRequestDebugXmlDump, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +xmlSecPtrListId +xmlSecXkmsServerRequestIdListGetKlass(void) { + return(&xmlSecXkmsServerRequestIdListKlass); +} + +int +xmlSecXkmsServerRequestIdListFind(xmlSecPtrListPtr list, xmlSecXkmsServerRequestId id) { + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsServerRequestIdListId), -1); + xmlSecAssert2(id != xmlSecXkmsServerRequestIdUnknown, -1); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + if((xmlSecXkmsServerRequestId)xmlSecPtrListGetItem(list, i) == id) { + return(1); + } + } + return(0); +} + +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestIdListFindByName(xmlSecPtrListPtr list, const xmlChar* name) { + xmlSecXkmsServerRequestId id; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsServerRequestIdListId), xmlSecXkmsServerRequestIdUnknown); + xmlSecAssert2(name != NULL, xmlSecXkmsServerRequestIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + id = (xmlSecXkmsServerRequestId)xmlSecPtrListGetItem(list, i); + if((id != xmlSecXkmsServerRequestIdUnknown) && xmlStrEqual(id->name, name)) { + return(id); + } + } + return(xmlSecXkmsServerRequestIdUnknown); +} + +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestIdListFindByNode(xmlSecPtrListPtr list, xmlNodePtr node) { + xmlSecXkmsServerRequestId id; + xmlSecSize i, size; + + xmlSecAssert2(xmlSecPtrListCheckId(list, xmlSecXkmsServerRequestIdListId), xmlSecXkmsServerRequestIdUnknown); + xmlSecAssert2(node != NULL, xmlSecXkmsServerRequestIdUnknown); + + size = xmlSecPtrListGetSize(list); + for(i = 0; i < size; ++i) { + id = (xmlSecXkmsServerRequestId)xmlSecPtrListGetItem(list, i); + if((id != xmlSecXkmsServerRequestIdUnknown) && + xmlSecCheckNodeName(node, id->requestNodeName, id->requestNodeNs)) { + + return(id); + } + } + return(xmlSecXkmsServerRequestIdUnknown); +} + +/******************************************************************** + * + * XML Sec Library ServerRequest Ids + * + *******************************************************************/ + + +/******************************************************************** + * + * Result response + * + *******************************************************************/ +static int xmlSecXkmsServerRequestResultNodeWrite (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); + +static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestResultKlass = { + xmlSecXkmsServerRequestResultName, /* const xmlChar* name; */ + NULL, /* const xmlChar* requestNodeName; */ + NULL, /* const xmlChar* requestNodeNs; */ + xmlSecNodeResult, /* const xmlChar* responseNodeName; */ + xmlSecXkmsNs, /* const xmlChar* responseNodeNs; */ + 0, /* xmlSecBitMask flags; */ + NULL, /* xmlSecXkmsServerRequestNodeReadMethod readNode; */ + xmlSecXkmsServerRequestResultNodeWrite, /* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */ + NULL, /* xmlSecXkmsServerRequestExecuteMethod execute; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsServerRequestResultGetKlass: + * + * The Result response klass. + * + * Returns: Result response klass. + */ +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestResultGetKlass(void) { + return(&xmlSecXkmsServerRequestResultKlass); +} + +static int +xmlSecXkmsServerRequestResultNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestResultId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* set missing parameters (if any) */ + if(ctx->service == NULL) { + ctx->service = xmlStrdup((ctx->expectedService != NULL) ? ctx->expectedService : BAD_CAST ""); + if(ctx->service == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + /* first write the "parent" type */ + ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResultTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/******************************************************************** + * + * StatusRequest/StatusResponse + * + *******************************************************************/ +static int xmlSecXkmsServerRequestStatusNodeRead (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestStatusNodeWrite (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); + +static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestStatusKlass = { + xmlSecXkmsServerRequestStatusName, /* const xmlChar* name; */ + xmlSecNodeStatusRequest, /* const xmlChar* requestNodeName; */ + xmlSecXkmsNs, /* const xmlChar* requestNodeNs; */ + xmlSecNodeStatusResult, /* const xmlChar* responseNodeName; */ + xmlSecXkmsNs, /* const xmlChar* responseNodeNs; */ + 0, /* xmlSecBitMask flags; */ + xmlSecXkmsServerRequestStatusNodeRead, /* xmlSecXkmsServerRequestNodeReadMethod readNode; */ + xmlSecXkmsServerRequestStatusNodeWrite, /* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */ + NULL, /* xmlSecXkmsServerRequestExecuteMethod execute; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsServerRequestStatusGetKlass: + * + * The StatusRequest klass. + * + * Returns: StatusRequest klass. + */ +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestStatusGetKlass(void) { + return(&xmlSecXkmsServerRequestStatusKlass); +} + +/** + * + * <xkms:StatusRequest Id Service Nonce? OriginalRequestId? ResponseLimit? ResponseId?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:ResponseMechanism>* + * <xkms:RespondWith>* + * <xkms:PendingNotification Mechanism Identifier>? + * + * XML Schema: + * <!-- StatusRequest --> + * <element name="StatusRequest" type="xkms:StatusRequestType"/> + * <complexType name="StatusRequestType"> + * <complexContent> + * <extension base="xkms:PendingRequestType"/> + * </complexContent> + * </complexType> + * <!-- /StatusRequest --> + */ +static int +xmlSecXkmsServerRequestStatusNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestStatusId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = node; + + /* first read "parent" type */ + ret = xmlSecXkmsServerCtxPendingRequestNodeRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxPendingRequestNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* check that there is nothing after the last node */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * + * <xkms:StatusResult Id Service Nonce? ResultMajor ResultMinor? RequestId? Success? Failure? Pending?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:RequestSignatureValue>* + * + * XML Schema: + * + * <!-- StatusResult --> + * <element name="StatusResult" type="xkms:StatusResultType"/> + * <complexType name="StatusResultType"> + * <complexContent> + * <extension base="xkms:ResultType"> + * <attribute name="Success" type="integer" use="optional"/> + * <attribute name="Failure" type="integer" use="optional"/> + * <attribute name="Pending" type="integer" use="optional"/> + * </extension> + * </complexContent> + * </complexType> + * <!-- /StatusResult --> * + */ +static int +xmlSecXkmsServerRequestStatusNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestStatusId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first write the "parent" type */ + ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResultTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* todo: add optional StatusResult attributes */ + return(0); +} + +/******************************************************************** + * + * CompoundRequest/CompoundResponse + * + *******************************************************************/ +static int xmlSecXkmsServerRequestCompoundNodeRead (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestCompoundNodeWrite(xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestCompoundExecute (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx); + +static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestCompoundKlass = { + xmlSecXkmsServerRequestCompoundName, /* const xmlChar* name; */ + xmlSecNodeCompoundRequest, /* const xmlChar* requestNodeName; */ + xmlSecXkmsNs, /* const xmlChar* requestNodeNs; */ + xmlSecNodeCompoundResult, /* const xmlChar* responseNodeName; */ + xmlSecXkmsNs, /* const xmlChar* responseNodeNs; */ + 0, /* xmlSecBitMask flags; */ + xmlSecXkmsServerRequestCompoundNodeRead, /* xmlSecXkmsServerRequestNodeReadMethod readNode; */ + xmlSecXkmsServerRequestCompoundNodeWrite, /* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */ + xmlSecXkmsServerRequestCompoundExecute, /* xmlSecXkmsServerRequestExecuteMethod execute; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsServerRequestCompoundGetKlass: + * + * The CompoundRequest klass. + * + * Returns: CompoundRequest klass. + */ +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestCompoundGetKlass(void) { + return(&xmlSecXkmsServerRequestCompoundKlass); +} + +/** + * <xkms:CompoundRequest Id Service Nonce? OriginalRequestId? ResponseLimit?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:ResponseMechanism>* + * <xkms:RespondWith>* + * <xkms:PendingNotification Mechanism Identifier>? + * ( + * <xkms:LocateRequest>? + * <xkms:ValidateRequest>? + * <xkms:RegisterRequest>? + * <xkms:ReissueRequest>? + * <xkms:RecoverRequest>? + * <xkms:RevokeRequest>? + * )* + * + * XML Schema: + * + * <!-- CompoundRequest --> + * <element name="CompoundRequest" type="xkms:CompoundRequestType"/> + * <complexType name="CompoundRequestType"> + * <complexContent> + * <extension base="xkms:RequestAbstractType"> + * <choice maxOccurs="unbounded"> + * <element ref="xkms:LocateRequest"/> + * <element ref="xkms:ValidateRequest"/> + * <element ref="xkms:RegisterRequest"/> + * <element ref="xkms:ReissueRequest"/> + * <element ref="xkms:RecoverRequest"/> + * <element ref="xkms:RevokeRequest"/> + * </choice> + * </extension> + * </complexContent> + * </complexType> + * <!-- /CompoundRequest --> + */ +static int +xmlSecXkmsServerRequestCompoundNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecPtrListPtr serverRequestIdsList; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestCompoundId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = node; + + /* first read "parent" type */ + ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* create list for compound requests */ + xmlSecAssert2(ctx->compoundRequestContexts == NULL, -1); + ctx->compoundRequestContexts = xmlSecPtrListCreate(xmlSecXkmsServerCtxPtrListId); + if(ctx->compoundRequestContexts == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* get the list of enabled or all request klasses */ + if(xmlSecPtrListGetSize(&(ctx->enabledServerRequestIds)) > 0) { + serverRequestIdsList = &(ctx->enabledServerRequestIds); + } else { + serverRequestIdsList = xmlSecXkmsServerRequestIdsGet(); + } + xmlSecAssert2(serverRequestIdsList != NULL, -1); + + while(cur != NULL) { + xmlSecXkmsServerCtxPtr ctxChild; + + /* create a new context */ + ctxChild = xmlSecXkmsServerCtxCreate(ctx->keyInfoReadCtx.keysMngr); + if(ctxChild == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* copy all settings from us */ + ret = xmlSecXkmsServerCtxCopyUserPref(ctxChild, ctx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxDestroy(ctxChild); + return(-1); + } + + /* add it to the list */ + ret = xmlSecPtrListAdd(ctx->compoundRequestContexts, ctxChild); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxDestroy(ctxChild); + return(-1); + } + + /* and now process request from current node */ + ctxChild->requestId = xmlSecXkmsServerRequestIdListFindByNode(serverRequestIdsList, cur); + if((ctxChild->requestId == xmlSecXkmsServerRequestIdUnknown) || + ((ctxChild->requestId->flags & XMLSEC_XKMS_SERVER_REQUEST_KLASS_ALLOWED_IN_COUMPOUND) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdListFindByNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorMessageNotSupported); + return(-1); + } + + ret = xmlSecXkmsServerRequestNodeRead(ctxChild->requestId, ctxChild, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "request=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctxChild->requestId))); + xmlSecXkmsServerCtxSetResult(ctxChild, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* check that there is nothing after the last node */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * <xkms:CompoundResult Id Service Nonce? ResultMajor ResultMinor? RequestId?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:RequestSignatureValue>* + * ( + * <xkms:LocateResult>? + * <xkms:ValidateResult>? + * <xkms:RegisterResult>? + * <xkms:ReissueResult>? + * <xkms:RecoverResult>? + * <xkms:RevokeResult>? + * )* + * + * + * XML Schema: + * + * <!-- CompoundResponse --> + * <element name="CompoundResult" type="xkms:CompoundResultType"/> + * <complexType name="CompoundResultType"> + * <complexContent> + * <extension base="xkms:ResultType"> + * <choice maxOccurs="unbounded"> + * <element ref="xkms:LocateResult"/> + * <element ref="xkms:ValidateResult"/> + * <element ref="xkms:RegisterResult"/> + * <element ref="xkms:ReissueResult"/> + * <element ref="xkms:RecoverResult"/> + * <element ref="xkms:RevokeResult"/> + * </choice> + * </extension> + * </complexContent> + * </complexType> + * <!-- /CompoundResponse --> + */ +static int +xmlSecXkmsServerRequestCompoundNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestCompoundId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* walk thru the list of chilren and pickup first error */ + if(ctx->compoundRequestContexts != NULL) { + xmlSecSize pos; + + for(pos = 0; pos < xmlSecPtrListGetSize(ctx->compoundRequestContexts); pos++) { + xmlSecXkmsServerCtxPtr ctxChild; + + ctxChild = (xmlSecXkmsServerCtxPtr)xmlSecPtrListGetItem(ctx->compoundRequestContexts, pos); + if(ctxChild == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListGetItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(ctxChild->resultMajor != xmlSecXkmsResultMajorSuccess) { + xmlSecXkmsServerCtxSetResult(ctx, ctxChild->resultMajor, ctxChild->resultMinor); + break; + } + } + } + + /* first write the "parent" type */ + ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResultTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* write compound result */ + if(ctx->compoundRequestContexts != NULL) { + xmlSecSize pos; + + for(pos = 0; pos < xmlSecPtrListGetSize(ctx->compoundRequestContexts); pos++) { + xmlSecXkmsServerCtxPtr ctxChild; + xmlNodePtr cur; + + ctxChild = (xmlSecXkmsServerCtxPtr)xmlSecPtrListGetItem(ctx->compoundRequestContexts, pos); + if(ctxChild == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListGetItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + cur = xmlSecXkmsServerRequestNodeWrite(ctxChild->requestId, ctxChild, node->doc, node); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "request=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctxChild->requestId))); + return(-1); + } + + if(xmlSecAddChildNode(node, cur) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChildNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeNode(cur); + return(-1); + } + } + } + + return(0); +} + +static int +xmlSecXkmsServerRequestCompoundExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) { + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestCompoundId, -1); + xmlSecAssert2(ctx != NULL, -1); + + if(ctx->compoundRequestContexts != NULL) { + xmlSecSize pos; + + for(pos = 0; pos < xmlSecPtrListGetSize(ctx->compoundRequestContexts); pos++) { + xmlSecXkmsServerCtxPtr ctxChild; + + ctxChild = (xmlSecXkmsServerCtxPtr)xmlSecPtrListGetItem(ctx->compoundRequestContexts, pos); + if(ctxChild == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListGetItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorReceiver, xmlSecXkmsResultMinorFailure); + continue; + } + + ret = xmlSecXkmsServerRequestExecute(ctxChild->requestId, ctxChild); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "request=%s", + xmlSecErrorsSafeString(xmlSecXkmsServerRequestKlassGetName(ctxChild->requestId))); + xmlSecXkmsServerCtxSetResult(ctxChild, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorFailure); + continue; + } + } + } + + return(0); +} + + +/******************************************************************** + * + * LocateRequest/LocateResponse + * + *******************************************************************/ +static int xmlSecXkmsServerRequestLocateNodeRead (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestLocateNodeWrite (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestLocateExecute (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx); + +static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestLocateKlass = { + xmlSecXkmsServerRequestLocateName, /* const xmlChar* name; */ + xmlSecNodeLocateRequest, /* const xmlChar* requestNodeName; */ + xmlSecXkmsNs, /* const xmlChar* requestNodeNs; */ + xmlSecNodeLocateResult, /* const xmlChar* responseNodeName; */ + xmlSecXkmsNs, /* const xmlChar* responseNodeNs; */ + XMLSEC_XKMS_SERVER_REQUEST_KLASS_ALLOWED_IN_COUMPOUND, /* xmlSecBitMask flags; */ + xmlSecXkmsServerRequestLocateNodeRead, /* xmlSecXkmsServerRequestNodeReadMethod readNode; */ + xmlSecXkmsServerRequestLocateNodeWrite, /* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */ + xmlSecXkmsServerRequestLocateExecute, /* xmlSecXkmsServerRequestExecuteMethod execute; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsServerRequestLocateGetKlass: + * + * The LocateRequest klass. + * + * Returns: LocateRequest klass. + */ +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestLocateGetKlass(void) { + return(&xmlSecXkmsServerRequestLocateKlass); +} + +/** + * <xkms:LocateRequest Id Service Nonce? OriginalRequestId? ResponseLimit?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:ResponseMechanism>* + * <xkms:RespondWith>* + * <xkms:PendingNotification Mechanism Identifier>? + * <xkms:QueryKeyBinding Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:TimeInstant Time>? + * + * XML Schema: + * + * <!-- LocateRequest --> + * <element name="LocateRequest" type="xkms:LocateRequestType"/> + * <complexType name="LocateRequestType"> + * <complexContent> + * <extension base="xkms:RequestAbstractType"> + * <sequence> + * <element ref="xkms:QueryKeyBinding"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /LocateRequest --> + */ +static int +xmlSecXkmsServerRequestLocateNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestLocateId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = node; + + /* first read "parent" type */ + ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* now read required <xkms:QueryKeyBinding/> node */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeQueryKeyBinding, xmlSecXkmsNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeQueryKeyBinding)); + return(-1); + } + + /* read <xkms:QueryKeyBinding/> node */ + ret = xmlSecXkmsServerCtxQueryKeyBindingNodeRead(ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxQueryKeyBindingNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + /* check that there is nothing after the last node */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * <xkms:LocateResult Id Service Nonce? ResultMajor ResultMinor? RequestId?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:RequestSignatureValue>* + * (<xkms:UnverifiedKeyBinding Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:ValidityInterval NotBefore NotOnOrAfter>? + * )* + * + * XML Schema: + * <!-- LocateResult --> + * <element name="LocateResult" type="xkms:LocateResultType"/> + * <complexType name="LocateResultType"> + * <complexContent> + * <extension base="xkms:ResultType"> + * <sequence> + * <element ref="xkms:UnverifiedKeyBinding" minOccurs="0" + * maxOccurs="unbounded"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /LocateResult --> + */ +static int +xmlSecXkmsServerRequestLocateNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecSize pos, size; + xmlSecKeyPtr key; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestLocateId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first write the "parent" type */ + ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResultTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* write keys in <xkms:UnverifiedKeyBinding> nodes */ + size = xmlSecPtrListGetSize(&(ctx->keys)); + for(pos = 0; pos < size; ++pos) { + key = (xmlSecKeyPtr)xmlSecPtrListGetItem(&(ctx->keys), pos); + if(key == NULL) { + continue; + } + + cur = xmlSecAddChild(node, xmlSecNodeUnverifiedKeyBinding, xmlSecXkmsNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeUnverifiedKeyBinding)); + return(-1); + } + + ret = xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite(ctx, cur, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxUnverifiedKeyBindingNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +static int +xmlSecXkmsServerRequestLocateExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) { + xmlSecKeyPtr key = NULL; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestLocateId, -1); + xmlSecAssert2(ctx != NULL, -1); + + /* now we are ready to search for key */ + if((ctx->keyInfoReadCtx.keysMngr != NULL) && (ctx->keyInfoReadCtx.keysMngr->getKey != NULL)) { + /* todo: set parameters to locate but not validate the key */ + key = (ctx->keyInfoReadCtx.keysMngr->getKey)(ctx->keyInfoNode, &(ctx->keyInfoReadCtx)); + } + + /* check that we got what we needed */ + if((key == NULL) || (!xmlSecKeyMatch(key, NULL, &(ctx->keyInfoReadCtx.keyReq)))) { + if(key != NULL) { + xmlSecKeyDestroy(key); + } + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorNoMatch); + return(-1); + } + + xmlSecAssert2(key != NULL, -1); + ret = xmlSecPtrListAdd(&(ctx->keys), key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + return(-1); + } + + return(0); +} + + +/******************************************************************** + * + * ValidateRequest/ValidateResponse + * + *******************************************************************/ +static int xmlSecXkmsServerRequestValidateNodeRead (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestValidateNodeWrite(xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx, + xmlNodePtr node); +static int xmlSecXkmsServerRequestValidateExecute (xmlSecXkmsServerRequestId id, + xmlSecXkmsServerCtxPtr ctx); + +static xmlSecXkmsServerRequestKlass xmlSecXkmsServerRequestValidateKlass = { + xmlSecXkmsServerRequestValidateName, /* const xmlChar* name; */ + xmlSecNodeValidateRequest, /* const xmlChar* requestNodeName; */ + xmlSecXkmsNs, /* const xmlChar* requestNodeNs; */ + xmlSecNodeValidateResult, /* const xmlChar* responseNodeName; */ + xmlSecXkmsNs, /* const xmlChar* responseNodeNs; */ + XMLSEC_XKMS_SERVER_REQUEST_KLASS_ALLOWED_IN_COUMPOUND, /* xmlSecBitMask flags; */ + xmlSecXkmsServerRequestValidateNodeRead, /* xmlSecXkmsServerRequestNodeReadMethod readNode; */ + xmlSecXkmsServerRequestValidateNodeWrite, /* xmlSecXkmsServerRequestNodeWriteMethod writeNode; */ + xmlSecXkmsServerRequestValidateExecute, /* xmlSecXkmsServerRequestExecuteMethod execute; */ + NULL, /* void* reserved1; */ + NULL /* void* reserved2; */ +}; + +/** + * xmlSecXkmsServerRequestValidateGetKlass: + * + * The ValidateRequest klass. + * + * Returns: ValidateRequest klass. + */ +xmlSecXkmsServerRequestId +xmlSecXkmsServerRequestValidateGetKlass(void) { + return(&xmlSecXkmsServerRequestValidateKlass); +} + +/** + * <xkms:ValidateRequest Id Service Nonce? OriginalRequestId? ResponseLimit?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:ResponseMechanism>* + * <xkms:RespondWith>* + * <xkms:PendingNotification Mechanism Identifier>? + * <xkms:QueryKeyBinding Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:TimeInstant Time>? + * + * XML Schema: + * + * <!-- ValidateRequest --> + * <element name="ValidateRequest" type="xkms:ValidateRequestType"/> + * <complexType name="ValidateRequestType"> + * <complexContent> + * <extension base="xkms:RequestAbstractType"> + * <sequence> + * <element ref="xkms:QueryKeyBinding"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /ValidateRequest --> + */ +static int +xmlSecXkmsServerRequestValidateNodeRead(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestValidateId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = node; + + /* first read "parent" type */ + ret = xmlSecXkmsServerCtxRequestAbstractTypeNodeRead(ctx, &cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxRequestAbstractTypeNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* now read required <xkms:QueryKeyBinding/> node */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeQueryKeyBinding, xmlSecXkmsNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeQueryKeyBinding)); + return(-1); + } + + /* read <xkms:QueryKeyBinding/> node */ + ret = xmlSecXkmsServerCtxQueryKeyBindingNodeRead(ctx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxQueryKeyBindingNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + /* check that there is nothing after the last node */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * <xkms:ValidateResult Id Service Nonce? ResultMajor ResultMinor? RequestId?> + * <ds:Signature>? + * <xkms:MessageExtension>* + * (<xkms:OpaqueClientData> + * <xkms:OpaqueData>? + * )? + * <xkms:RequestSignatureValue>* + * (<xkms:KeyBinding Id?> + * <ds:KeyInfo>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:KeyUsage>? + * <xkms:UseKeyWith Application Identifier>* + * <xkms:ValidityInterval NotBefore NotOnOrAfter>? + * <xkms:Status StatusValue> + * (<xkms:ValidReason>? + * <xkms:IndeterminateReason>? + * <xkms:InvalidReason>? + * )* + * )* + * + * XML Schema: + * + * <!-- ValidateResult --> + * <element name="ValidateResult" type="xkms:ValidateResultType"/> + * <complexType name="ValidateResultType"> + * <complexContent> + * <extension base="xkms:ResultType"> + * <sequence> + * <element ref="xkms:KeyBinding" minOccurs="0" + * maxOccurs="unbounded"/> + * </sequence> + * </extension> + * </complexContent> + * </complexType> + * <!-- /ValidateResult --> + */ +static int +xmlSecXkmsServerRequestValidateNodeWrite(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx, xmlNodePtr node) { + xmlSecSize pos, size; + xmlSecKeyPtr key; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestValidateId, -1); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first write the "parent" type */ + ret = xmlSecXkmsServerCtxResultTypeNodeWrite(ctx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxResultTypeNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* write keys in <xkms:UnverifiedKeyBinding> nodes */ + size = xmlSecPtrListGetSize(&(ctx->keys)); + for(pos = 0; pos < size; ++pos) { + key = (xmlSecKeyPtr)xmlSecPtrListGetItem(&(ctx->keys), pos); + if(key == NULL) { + continue; + } + + cur = xmlSecAddChild(node, xmlSecNodeUnverifiedKeyBinding, xmlSecXkmsNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeUnverifiedKeyBinding)); + return(-1); + } + + ret = xmlSecXkmsServerCtxKeyBindingNodeWrite(ctx, cur, key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerCtxKeyBindingNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +static int +xmlSecXkmsServerRequestValidateExecute(xmlSecXkmsServerRequestId id, xmlSecXkmsServerCtxPtr ctx) { + xmlSecKeyPtr key = NULL; + int ret; + + xmlSecAssert2(id == xmlSecXkmsServerRequestValidateId, -1); + xmlSecAssert2(ctx != NULL, -1); + + /* now we are ready to search for key */ + if((ctx->keyInfoReadCtx.keysMngr != NULL) && (ctx->keyInfoReadCtx.keysMngr->getKey != NULL)) { + key = (ctx->keyInfoReadCtx.keysMngr->getKey)(ctx->keyInfoNode, &(ctx->keyInfoReadCtx)); + } + + /* check that we got what we needed */ + if((key == NULL) || (!xmlSecKeyMatch(key, NULL, &(ctx->keyInfoReadCtx.keyReq)))) { + if(key != NULL) { + xmlSecKeyDestroy(key); + } + xmlSecXkmsServerCtxSetResult(ctx, xmlSecXkmsResultMajorSender, xmlSecXkmsResultMinorNoMatch); + return(-1); + } + + xmlSecAssert2(key != NULL, -1); + ret = xmlSecPtrListAdd(&(ctx->keys), key); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecKeyDestroy(key); + return(-1); + } + + return(0); +} + +#endif /* XMLSEC_NO_XKMS */ + diff --git a/src/xmldsig.c b/src/xmldsig.c new file mode 100644 index 00000000..cbd825e5 --- /dev/null +++ b/src/xmldsig.c @@ -0,0 +1,1795 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * "XML Digital Signature" implementation + * http://www.w3.org/TR/xmldsig-core/ + * http://www.w3.org/Signature/Overview.html + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_XMLDSIG + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/membuf.h> +#include <xmlsec/xmldsig.h> +#include <xmlsec/errors.h> + +/************************************************************************** + * + * xmlSecDSigCtx + * + *************************************************************************/ +static int xmlSecDSigCtxProcessSignatureNode (xmlSecDSigCtxPtr dsigCtx, + xmlNodePtr node); +static int xmlSecDSigCtxProcessSignedInfoNode (xmlSecDSigCtxPtr dsigCtx, + xmlNodePtr node); +static int xmlSecDSigCtxProcessKeyInfoNode (xmlSecDSigCtxPtr dsigCtx, + xmlNodePtr node); +static int xmlSecDSigCtxProcessObjectNode (xmlSecDSigCtxPtr dsigCtx, + xmlNodePtr node); +static int xmlSecDSigCtxProcessManifestNode (xmlSecDSigCtxPtr dsigCtx, + xmlNodePtr node); + +/* The ID attribute in XMLDSig is 'Id' */ +static const xmlChar* xmlSecDSigIds[] = { xmlSecAttrId, NULL }; + +/** + * xmlSecDSigCtxCreate: + * @keysMngr: the pointer to keys manager. + * + * Creates <dsig:Signature/> element processing context. + * The caller is responsible for destroying returend object by calling + * #xmlSecDSigCtxDestroy function. + * + * Returns: pointer to newly allocated context object or NULL if an error + * occurs. + */ +xmlSecDSigCtxPtr +xmlSecDSigCtxCreate(xmlSecKeysMngrPtr keysMngr) { + xmlSecDSigCtxPtr dsigCtx; + int ret; + + dsigCtx = (xmlSecDSigCtxPtr) xmlMalloc(sizeof(xmlSecDSigCtx)); + if(dsigCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecDSigCtx)=%d", + sizeof(xmlSecDSigCtx)); + return(NULL); + } + + ret = xmlSecDSigCtxInitialize(dsigCtx, keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecDSigCtxDestroy(dsigCtx); + return(NULL); + } + return(dsigCtx); +} + +/** + * xmlSecDSigCtxDestroy: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * + * Destroy context object created with #xmlSecDSigCtxCreate function. + */ +void +xmlSecDSigCtxDestroy(xmlSecDSigCtxPtr dsigCtx) { + xmlSecAssert(dsigCtx != NULL); + + xmlSecDSigCtxFinalize(dsigCtx); + xmlFree(dsigCtx); +} + +/** + * xmlSecDSigCtxInitialize: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @keysMngr: the pointer to keys manager. + * + * Initializes <dsig:Signature/> element processing context. + * The caller is responsible for cleaing up returend object by calling + * #xmlSecDSigCtxFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecDSigCtxInitialize(xmlSecDSigCtxPtr dsigCtx, xmlSecKeysMngrPtr keysMngr) { + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + + memset(dsigCtx, 0, sizeof(xmlSecDSigCtx)); + + /* initialize key info */ + ret = xmlSecKeyInfoCtxInitialize(&(dsigCtx->keyInfoReadCtx), keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + dsigCtx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead; + + ret = xmlSecKeyInfoCtxInitialize(&(dsigCtx->keyInfoWriteCtx), keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + dsigCtx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite; + /* it's not wise to write private key :) */ + dsigCtx->keyInfoWriteCtx.keyReq.keyType = xmlSecKeyDataTypePublic; + + /* initializes transforms dsigCtx */ + ret = xmlSecTransformCtxInitialize(&(dsigCtx->transformCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* references lists from SignedInfo and Manifest elements */ + xmlSecPtrListInitialize(&(dsigCtx->signedInfoReferences), + xmlSecDSigReferenceCtxListId); + xmlSecPtrListInitialize(&(dsigCtx->manifestReferences), + xmlSecDSigReferenceCtxListId); + + dsigCtx->enabledReferenceUris = xmlSecTransformUriTypeAny; + return(0); +} + +/** + * xmlSecDSigCtxFinalize: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * + * Cleans up @dsigCtx object initialized with #xmlSecDSigCtxInitialize function. + */ +void +xmlSecDSigCtxFinalize(xmlSecDSigCtxPtr dsigCtx) { + xmlSecAssert(dsigCtx != NULL); + + xmlSecTransformCtxFinalize(&(dsigCtx->transformCtx)); + xmlSecKeyInfoCtxFinalize(&(dsigCtx->keyInfoReadCtx)); + xmlSecKeyInfoCtxFinalize(&(dsigCtx->keyInfoWriteCtx)); + xmlSecPtrListFinalize(&(dsigCtx->signedInfoReferences)); + xmlSecPtrListFinalize(&(dsigCtx->manifestReferences)); + + if(dsigCtx->enabledReferenceTransforms != NULL) { + xmlSecPtrListDestroy(dsigCtx->enabledReferenceTransforms); + } + if(dsigCtx->signKey != NULL) { + xmlSecKeyDestroy(dsigCtx->signKey); + } + if(dsigCtx->id != NULL) { + xmlFree(dsigCtx->id); + } + memset(dsigCtx, 0, sizeof(xmlSecDSigCtx)); +} + +/** + * xmlSecDSigCtxEnableReferenceTransform: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @transformId: the transform klass. + * + * Enables @transformId for <dsig:Reference/> elements processing. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecDSigCtxEnableReferenceTransform(xmlSecDSigCtxPtr dsigCtx, xmlSecTransformId transformId) { + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->result == NULL, -1); + xmlSecAssert2(transformId != xmlSecTransformIdUnknown, -1); + + if(dsigCtx->enabledReferenceTransforms == NULL) { + dsigCtx->enabledReferenceTransforms = xmlSecPtrListCreate(xmlSecTransformIdListId); + if(dsigCtx->enabledReferenceTransforms == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + ret = xmlSecPtrListAdd(dsigCtx->enabledReferenceTransforms, (void*)transformId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecDSigCtxEnableSignatureTransform: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @transformId: the transform klass. + * + * Enables @transformId for <dsig:SignedInfo/> element processing. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecDSigCtxEnableSignatureTransform(xmlSecDSigCtxPtr dsigCtx, xmlSecTransformId transformId) { + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->result == NULL, -1); + xmlSecAssert2(transformId != xmlSecTransformIdUnknown, -1); + + return(xmlSecPtrListAdd(&(dsigCtx->transformCtx.enabledTransforms), (void*)transformId)); +} + +/** + * xmlSecDSigCtxGetPreSignBuffer: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * + * Gets pointer to the buffer with serialized <dsig:SignedInfo/> element + * just before signature claculation (valid if and only if + * #XMLSEC_DSIG_FLAGS_STORE_SIGNATURE context flag is set. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +xmlSecBufferPtr +xmlSecDSigCtxGetPreSignBuffer(xmlSecDSigCtxPtr dsigCtx) { + xmlSecAssert2(dsigCtx != NULL, NULL); + + return((dsigCtx->preSignMemBufMethod != NULL) ? + xmlSecTransformMemBufGetBuffer(dsigCtx->preSignMemBufMethod) : NULL); +} + +/** + * xmlSecDSigCtxSign: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @tmpl: the pointer to <dsig:Signature/> node with signature template. + * + * Signs the data as described in @tmpl node. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecDSigCtxSign(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr tmpl) { + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->result == NULL, -1); + xmlSecAssert2(tmpl != NULL, -1); + xmlSecAssert2(tmpl->doc != NULL, -1); + + /* add ids for Signature nodes */ + dsigCtx->operation = xmlSecTransformOperationSign; + dsigCtx->status = xmlSecDSigStatusUnknown; + xmlSecAddIDs(tmpl->doc, tmpl, xmlSecDSigIds); + + /* read signature template */ + ret = xmlSecDSigCtxProcessSignatureNode(dsigCtx, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxSigantureProcessNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(dsigCtx->signMethod != NULL, -1); + xmlSecAssert2(dsigCtx->signValueNode != NULL, -1); + + /* references processing might change the status */ + if(dsigCtx->status != xmlSecDSigStatusUnknown) { + return(0); + } + + /* check what we've got */ + dsigCtx->result = dsigCtx->transformCtx.result; + if((dsigCtx->result == NULL) || (xmlSecBufferGetData(dsigCtx->result) == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_RESULT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* write signed data to xml */ + xmlNodeSetContentLen(dsigCtx->signValueNode, + xmlSecBufferGetData(dsigCtx->result), + xmlSecBufferGetSize(dsigCtx->result)); + + /* set success status and we are done */ + dsigCtx->status = xmlSecDSigStatusSucceeded; + return(0); +} + +/** + * xmlSecDSigCtxVerify: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @node: the pointer with <dsig:Signature/> node. + * + * Vaidates signature in the @node. The verification result is returned + * in #status member of the @dsigCtx object. + * + * Returns: 0 on success (check #status member of @dsigCtx to get + * signature verification result) or a negative value if an error occurs. + */ +int +xmlSecDSigCtxVerify(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->doc != NULL, -1); + + /* add ids for Signature nodes */ + dsigCtx->operation = xmlSecTransformOperationVerify; + dsigCtx->status = xmlSecDSigStatusUnknown; + xmlSecAddIDs(node->doc, node, xmlSecDSigIds); + + /* read siganture info */ + ret = xmlSecDSigCtxProcessSignatureNode(dsigCtx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxSigantureProcessNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + xmlSecAssert2(dsigCtx->signMethod != NULL, -1); + xmlSecAssert2(dsigCtx->signValueNode != NULL, -1); + + /* references processing might change the status */ + if(dsigCtx->status != xmlSecDSigStatusUnknown) { + return(0); + } + + /* verify SignatureValue node content */ + ret = xmlSecTransformVerifyNodeContent(dsigCtx->signMethod, dsigCtx->signValueNode, + &(dsigCtx->transformCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformVerifyNodeContent", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* set status and we are done */ + if(dsigCtx->signMethod->status == xmlSecTransformStatusOk) { + dsigCtx->status = xmlSecDSigStatusSucceeded; + } else { + dsigCtx->status = xmlSecDSigStatusInvalid; + } + return(0); +} + +/** + * xmlSecDSigCtxProcessSignatureNode: + * + * The Signature element (http://www.w3.org/TR/xmldsig-core/#sec-Signature) + * + * The Signature element is the root element of an XML Signature. + * Implementation MUST generate laxly schema valid [XML-schema] Signature + * elements as specified by the following schema: + * The way in which the SignedInfo element is presented to the + * canonicalization method is dependent on that method. The following + * applies to algorithms which process XML as nodes or characters: + * + * - XML based canonicalization implementations MUST be provided with + * a [XPath] node-set originally formed from the document containing + * the SignedInfo and currently indicating the SignedInfo, its descendants, + * and the attribute and namespace nodes of SignedInfo and its descendant + * elements. + * + * - Text based canonicalization algorithms (such as CRLF and charset + * normalization) should be provided with the UTF-8 octets that represent + * the well-formed SignedInfo element, from the first character to the + * last character of the XML representation, inclusive. This includes + * the entire text of the start and end tags of the SignedInfo element + * as well as all descendant markup and character data (i.e., the text) + * between those tags. Use of text based canonicalization of SignedInfo + * is NOT RECOMMENDED. + * + * ================================= + * we do not support any non XML based C14N + * + * Schema Definition: + * + * <element name="Signature" type="ds:SignatureType"/> + * <complexType name="SignatureType"> + * <sequence> + * <element ref="ds:SignedInfo"/> + * <element ref="ds:SignatureValue"/> + * <element ref="ds:KeyInfo" minOccurs="0"/> + * <element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/> + * </sequence> <attribute name="Id" type="ID" use="optional"/> + * </complexType> + * + * DTD: + * + * <!ELEMENT Signature (SignedInfo, SignatureValue, KeyInfo?, Object*) > + * <!ATTLIST Signature + * xmlns CDATA #FIXED 'http://www.w3.org/2000/09/xmldsig#' + * Id ID #IMPLIED > + * + */ +static int +xmlSecDSigCtxProcessSignatureNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) { + xmlSecTransformDataType firstType; + xmlNodePtr signedInfoNode = NULL; + xmlNodePtr keyInfoNode = NULL; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2((dsigCtx->operation == xmlSecTransformOperationSign) || (dsigCtx->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1); + xmlSecAssert2(dsigCtx->signValueNode == NULL, -1); + xmlSecAssert2(dsigCtx->signMethod == NULL, -1); + xmlSecAssert2(dsigCtx->c14nMethod == NULL, -1); + xmlSecAssert2(node != NULL, -1); + + if(!xmlSecCheckNodeName(node, xmlSecNodeSignature, xmlSecDSigNs)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeSignature)); + return(-1); + } + + /* read node data */ + xmlSecAssert2(dsigCtx->id == NULL, -1); + dsigCtx->id = xmlGetProp(node, xmlSecAttrId); + + /* first node is required SignedInfo */ + cur = xmlSecGetNextElementNode(node->children); + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeSignedInfo, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeSignedInfo)); + return(-1); + } + signedInfoNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + + /* next node is required SignatureValue */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeSignatureValue, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeSignatureValue)); + return(-1); + } + dsigCtx->signValueNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + + /* next node is optional KeyInfo */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) { + keyInfoNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + } else { + keyInfoNode = NULL; + } + + /* next nodes are optional Object nodes */ + while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeObject, xmlSecDSigNs))) { + /* read manifests from objects */ + if((dsigCtx->flags & XMLSEC_DSIG_FLAGS_IGNORE_MANIFESTS) == 0) { + ret = xmlSecDSigCtxProcessObjectNode(dsigCtx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxProcessObjectNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* if there is something left than it's an error */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* now validated all the references and prepare transform */ + ret = xmlSecDSigCtxProcessSignedInfoNode(dsigCtx, signedInfoNode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxProcessSignedInfoNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + /* references processing might change the status */ + if(dsigCtx->status != xmlSecDSigStatusUnknown) { + return(0); + } + + /* as the result, we should have sign and c14n methods set */ + xmlSecAssert2(dsigCtx->signMethod != NULL, -1); + xmlSecAssert2(dsigCtx->c14nMethod != NULL, -1); + + ret = xmlSecDSigCtxProcessKeyInfoNode(dsigCtx, keyInfoNode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxProcessKeyInfoNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + /* as the result, we should have a key */ + xmlSecAssert2(dsigCtx->signKey != NULL, -1); + + /* if we need to write result to xml node then we need base64 encode result */ + if(dsigCtx->operation == xmlSecTransformOperationSign) { + xmlSecTransformPtr base64Encode; + + /* we need to add base64 encode transform */ + base64Encode = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), + xmlSecTransformBase64Id); + if(base64Encode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + base64Encode->operation = xmlSecTransformOperationEncode; + } + + firstType = xmlSecTransformGetDataType(dsigCtx->transformCtx.first, + xmlSecTransformModePush, + &(dsigCtx->transformCtx)); + if((firstType & xmlSecTransformDataTypeXml) != 0) { + xmlSecNodeSetPtr nodeset = NULL; + + xmlSecAssert2(signedInfoNode != NULL, -1); + nodeset = xmlSecNodeSetGetChildren(signedInfoNode->doc, signedInfoNode, 1, 0); + if(nodeset == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetGetChildren", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(signedInfoNode))); + return(-1); + } + + /* calculate the signature */ + ret = xmlSecTransformCtxXmlExecute(&(dsigCtx->transformCtx), nodeset); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxXmlExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecNodeSetDestroy(nodeset); + return(-1); + } + xmlSecNodeSetDestroy(nodeset); + } else { + /* TODO */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "the binary c14n transforms are not supported yet", + XMLSEC_ERRORS_R_NOT_IMPLEMENTED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecDSigCtxProcessSignedInfoNode: + * + * The SignedInfo Element (http://www.w3.org/TR/xmldsig-core/#sec-SignedInfo) + * + * The structure of SignedInfo includes the canonicalization algorithm, + * a result algorithm, and one or more references. The SignedInfo element + * may contain an optional ID attribute that will allow it to be referenced by + * other signatures and objects. + * + * SignedInfo does not include explicit result or digest properties (such as + * calculation time, cryptographic device serial number, etc.). If an + * application needs to associate properties with the result or digest, + * it may include such information in a SignatureProperties element within + * an Object element. + * + * Schema Definition: + * + * <element name="SignedInfo" type="ds:SignedInfoType"/> + * <complexType name="SignedInfoType"> + * <sequence> + * <element ref="ds:CanonicalizationMethod"/> + * <element ref="ds:SignatureMethod"/> + * <element ref="ds:Reference" maxOccurs="unbounded"/> + * </sequence> + * <attribute name="Id" type="ID" use="optional"/> + * </complexType> + * + * DTD: + * + * <!ELEMENT SignedInfo (CanonicalizationMethod, SignatureMethod, Reference+) > + * <!ATTLIST SignedInfo Id ID #IMPLIED> + * + */ +static int +xmlSecDSigCtxProcessSignedInfoNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) { + xmlSecDSigReferenceCtxPtr dsigRefCtx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1); + xmlSecAssert2(dsigCtx->signMethod == NULL, -1); + xmlSecAssert2(dsigCtx->c14nMethod == NULL, -1); + xmlSecAssert2((dsigCtx->operation == xmlSecTransformOperationSign) || (dsigCtx->operation == xmlSecTransformOperationVerify), -1); + xmlSecAssert2(xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) == 0, -1); + xmlSecAssert2(node != NULL, -1); + + /* first node is required CanonicalizationMethod. */ + cur = xmlSecGetNextElementNode(node->children); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCanonicalizationMethod, xmlSecDSigNs))) { + dsigCtx->c14nMethod = xmlSecTransformCtxNodeRead(&(dsigCtx->transformCtx), + cur, xmlSecTransformUsageC14NMethod); + if(dsigCtx->c14nMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + } else if(dsigCtx->defC14NMethodId != xmlSecTransformIdUnknown) { + /* the dsig spec does require CanonicalizationMethod node + * to be present but in some case it application might decide to + * minimize traffic */ + dsigCtx->c14nMethod = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), + dsigCtx->defC14NMethodId); + if(dsigCtx->c14nMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CanonicalizationMethod", + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeCanonicalizationMethod)); + return(-1); + } + + /* insert membuf if requested */ + if((dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNATURE) != 0) { + xmlSecAssert2(dsigCtx->preSignMemBufMethod == NULL, -1); + dsigCtx->preSignMemBufMethod = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), + xmlSecTransformMemBufId); + if(dsigCtx->preSignMemBufMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId))); + } + } + + /* next node is required SignatureMethod. */ + cur = xmlSecGetNextElementNode( ((cur != NULL) ? cur->next : node->children) ); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeSignatureMethod, xmlSecDSigNs))) { + dsigCtx->signMethod = xmlSecTransformCtxNodeRead(&(dsigCtx->transformCtx), + cur, xmlSecTransformUsageSignatureMethod); + if(dsigCtx->signMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + } else if(dsigCtx->defSignMethodId != xmlSecTransformIdUnknown) { + /* the dsig spec does require SignatureMethod node + * to be present but in some case it application might decide to + * minimize traffic */ + dsigCtx->signMethod = xmlSecTransformCtxCreateAndAppend(&(dsigCtx->transformCtx), + dsigCtx->defSignMethodId); + if(dsigCtx->signMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeSignatureMethod)); + return(-1); + } + dsigCtx->signMethod->operation = dsigCtx->operation; + + /* calculate references */ + cur = xmlSecGetNextElementNode(cur->next); + while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs))) { + /* create reference */ + dsigRefCtx = xmlSecDSigReferenceCtxCreate(dsigCtx, xmlSecDSigReferenceOriginSignedInfo); + if(dsigRefCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigReferenceCtxCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* add to the list */ + ret = xmlSecPtrListAdd(&(dsigCtx->signedInfoReferences), dsigRefCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecDSigReferenceCtxDestroy(dsigRefCtx); + return(-1); + } + + /* process */ + ret = xmlSecDSigReferenceCtxProcessNode(dsigRefCtx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigReferenceCtxProcessNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + /* bail out if next Reference processing failed */ + if(dsigRefCtx->status != xmlSecDSigStatusSucceeded) { + dsigCtx->status = xmlSecDSigStatusInvalid; + return(0); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* check that we have at least one Reference */ + if(xmlSecPtrListGetSize(&(dsigCtx->signedInfoReferences)) == 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_DSIG_NO_REFERENCES, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* if there is something left than it's an error */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static int +xmlSecDSigCtxProcessKeyInfoNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->signMethod != NULL, -1); + + /* set key requirements */ + ret = xmlSecTransformSetKeyReq(dsigCtx->signMethod, &(dsigCtx->keyInfoReadCtx.keyReq)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformSetKeyReq", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(dsigCtx->signMethod))); + return(-1); + } + + /* ignore <dsig:KeyInfo /> if there is the key is already set */ + /* todo: throw an error if key is set and node != NULL? */ + if((dsigCtx->signKey == NULL) && (dsigCtx->keyInfoReadCtx.keysMngr != NULL) + && (dsigCtx->keyInfoReadCtx.keysMngr->getKey != NULL)) { + dsigCtx->signKey = (dsigCtx->keyInfoReadCtx.keysMngr->getKey)(node, &(dsigCtx->keyInfoReadCtx)); + } + + /* check that we have exactly what we want */ + if((dsigCtx->signKey == NULL) || (!xmlSecKeyMatch(dsigCtx->signKey, NULL, &(dsigCtx->keyInfoReadCtx.keyReq)))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_KEY_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* set the key to the transform */ + ret = xmlSecTransformSetKey(dsigCtx->signMethod, dsigCtx->signKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformSetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(dsigCtx->signMethod))); + return(-1); + } + + /* if we are signing document, update <dsig:KeyInfo/> node */ + if((node != NULL) && (dsigCtx->operation == xmlSecTransformOperationSign)) { + ret = xmlSecKeyInfoNodeWrite(node, dsigCtx->signKey, &(dsigCtx->keyInfoWriteCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +/** + * xmlSecDSigCtxProcessObjectNode: + * + * The Object Element (http://www.w3.org/TR/xmldsig-core/#sec-Object) + * + * Object is an optional element that may occur one or more times. When + * present, this element may contain any data. The Object element may include + * optional MIME type, ID, and encoding attributes. + * + * Schema Definition: + * + * <element name="Object" type="ds:ObjectType"/> + * <complexType name="ObjectType" mixed="true"> + * <sequence minOccurs="0" maxOccurs="unbounded"> + * <any namespace="##any" processContents="lax"/> + * </sequence> + * <attribute name="Id" type="ID" use="optional"/> + * <attribute name="MimeType" type="string" use="optional"/> + * <attribute name="Encoding" type="anyURI" use="optional"/> + * </complexType> + * + * DTD: + * + * <!ELEMENT Object (#PCDATA|Signature|SignatureProperties|Manifest %Object.ANY;)* > + * <!ATTLIST Object Id ID #IMPLIED + * MimeType CDATA #IMPLIED + * Encoding CDATA #IMPLIED > + */ +static int +xmlSecDSigCtxProcessObjectNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1); + xmlSecAssert2(node != NULL, -1); + + /* we care about Manifest nodes only; ignore everything else */ + cur = xmlSecGetNextElementNode(node->children); + while(cur != NULL) { + if(xmlSecCheckNodeName(cur, xmlSecNodeManifest, xmlSecDSigNs)) { + ret = xmlSecDSigCtxProcessManifestNode(dsigCtx, cur); + if(ret < 0){ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigCtxProcessManifestNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + cur = xmlSecGetNextElementNode(cur->next); + } + return(0); +} + +/** + * xmlSecDSigCtxProcessManifestNode: + * + * The Manifest Element (http://www.w3.org/TR/xmldsig-core/#sec-Manifest) + * + * The Manifest element provides a list of References. The difference from + * the list in SignedInfo is that it is application defined which, if any, of + * the digests are actually checked against the objects referenced and what to + * do if the object is inaccessible or the digest compare fails. If a Manifest + * is pointed to from SignedInfo, the digest over the Manifest itself will be + * checked by the core result validation behavior. The digests within such + * a Manifest are checked at the application's discretion. If a Manifest is + * referenced from another Manifest, even the overall digest of this two level + * deep Manifest might not be checked. + * + * Schema Definition: + * + * <element name="Manifest" type="ds:ManifestType"/> + * <complexType name="ManifestType"> + * <sequence> + * <element ref="ds:Reference" maxOccurs="unbounded"/> + * </sequence> + * <attribute name="Id" type="ID" use="optional"/> + * </complexType> + * + * DTD: + * + * <!ELEMENT Manifest (Reference+) > + * <!ATTLIST Manifest Id ID #IMPLIED > + */ +static int +xmlSecDSigCtxProcessManifestNode(xmlSecDSigCtxPtr dsigCtx, xmlNodePtr node) { + xmlSecDSigReferenceCtxPtr dsigRefCtx; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigCtx->status == xmlSecDSigStatusUnknown, -1); + xmlSecAssert2(node != NULL, -1); + + /* calculate references */ + cur = xmlSecGetNextElementNode(node->children); + while((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReference, xmlSecDSigNs))) { + /* create reference */ + dsigRefCtx = xmlSecDSigReferenceCtxCreate(dsigCtx, xmlSecDSigReferenceOriginManifest); + if(dsigRefCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigReferenceCtxCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* add to the list */ + ret = xmlSecPtrListAdd(&(dsigCtx->manifestReferences), dsigRefCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecDSigReferenceCtxDestroy(dsigRefCtx); + return(-1); + } + + /* process */ + ret = xmlSecDSigReferenceCtxProcessNode(dsigRefCtx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigReferenceCtxProcessNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + /* we don;t care if Reference processing failed because + * it's Manifest node */ + cur = xmlSecGetNextElementNode(cur->next); + } + + /* we should have nothing else here */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecDSigCtxDebugDump: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @output: the pointer to output FILE. + * + * Prints the debug information about @dsigCtx to @output. + */ +void +xmlSecDSigCtxDebugDump(xmlSecDSigCtxPtr dsigCtx, FILE* output) { + xmlSecAssert(dsigCtx != NULL); + xmlSecAssert(output != NULL); + + if(dsigCtx->operation == xmlSecTransformOperationSign) { + fprintf(output, "= SIGNATURE CONTEXT\n"); + } else { + fprintf(output, "= VERIFICATION CONTEXT\n"); + } + switch(dsigCtx->status) { + case xmlSecDSigStatusUnknown: + fprintf(output, "== Status: unknown\n"); + break; + case xmlSecDSigStatusSucceeded: + fprintf(output, "== Status: succeeded\n"); + break; + case xmlSecDSigStatusInvalid: + fprintf(output, "== Status: invalid\n"); + break; + } + fprintf(output, "== flags: 0x%08x\n", dsigCtx->flags); + fprintf(output, "== flags2: 0x%08x\n", dsigCtx->flags2); + + if(dsigCtx->id != NULL) { + fprintf(output, "== Id: \"%s\"\n", dsigCtx->id); + } + + fprintf(output, "== Key Info Read Ctx:\n"); + xmlSecKeyInfoCtxDebugDump(&(dsigCtx->keyInfoReadCtx), output); + fprintf(output, "== Key Info Write Ctx:\n"); + xmlSecKeyInfoCtxDebugDump(&(dsigCtx->keyInfoWriteCtx), output); + + fprintf(output, "== Signature Transform Ctx:\n"); + xmlSecTransformCtxDebugDump(&(dsigCtx->transformCtx), output); + + if(dsigCtx->signMethod != NULL) { + fprintf(output, "== Signature Method:\n"); + xmlSecTransformDebugDump(dsigCtx->signMethod, output); + } + + if(dsigCtx->signKey != NULL) { + fprintf(output, "== Signature Key:\n"); + xmlSecKeyDebugDump(dsigCtx->signKey, output); + } + + fprintf(output, "== SignedInfo References List:\n"); + xmlSecPtrListDebugDump(&(dsigCtx->signedInfoReferences), output); + + fprintf(output, "== Manifest References List:\n"); + xmlSecPtrListDebugDump(&(dsigCtx->manifestReferences), output); + + if((dsigCtx->result != NULL) && + (xmlSecBufferGetData(dsigCtx->result) != NULL)) { + + fprintf(output, "== Result - start buffer:\n"); + fwrite(xmlSecBufferGetData(dsigCtx->result), + xmlSecBufferGetSize(dsigCtx->result), + 1, output); + fprintf(output, "\n== Result - end buffer\n"); + } + if(((dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNATURE) != 0) && + (xmlSecDSigCtxGetPreSignBuffer(dsigCtx) != NULL) && + (xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)) != NULL)) { + + fprintf(output, "== PreSigned data - start buffer:\n"); + fwrite(xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), + xmlSecBufferGetSize(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), + 1, output); + fprintf(output, "\n== PreSigned data - end buffer\n"); + } +} + +/** + * xmlSecDSigCtxDebugXmlDump: + * @dsigCtx: the pointer to <dsig:Signature/> processing context. + * @output: the pointer to output FILE. + * + * Prints the debug information about @dsigCtx to @output in XML format. + */ +void +xmlSecDSigCtxDebugXmlDump(xmlSecDSigCtxPtr dsigCtx, FILE* output) { + xmlSecAssert(dsigCtx != NULL); + xmlSecAssert(output != NULL); + + if(dsigCtx->operation == xmlSecTransformOperationSign) { + fprintf(output, "<SignatureContext \n"); + } else { + fprintf(output, "<VerificationContext \n"); + } + switch(dsigCtx->status) { + case xmlSecDSigStatusUnknown: + fprintf(output, "status=\"unknown\" >\n"); + break; + case xmlSecDSigStatusSucceeded: + fprintf(output, "status=\"succeeded\" >\n"); + break; + case xmlSecDSigStatusInvalid: + fprintf(output, "status=\"invalid\" >\n"); + break; + } + + fprintf(output, "<Flags>%08x</Flags>\n", dsigCtx->flags); + fprintf(output, "<Flags2>%08x</Flags2>\n", dsigCtx->flags2); + + fprintf(output, "<Id>"); + xmlSecPrintXmlString(output, dsigCtx->id); + fprintf(output, "</Id>\n"); + + fprintf(output, "<KeyInfoReadCtx>\n"); + xmlSecKeyInfoCtxDebugXmlDump(&(dsigCtx->keyInfoReadCtx), output); + fprintf(output, "</KeyInfoReadCtx>\n"); + + fprintf(output, "<KeyInfoWriteCtx>\n"); + xmlSecKeyInfoCtxDebugXmlDump(&(dsigCtx->keyInfoWriteCtx), output); + fprintf(output, "</KeyInfoWriteCtx>\n"); + + fprintf(output, "<SignatureTransformCtx>\n"); + xmlSecTransformCtxDebugXmlDump(&(dsigCtx->transformCtx), output); + fprintf(output, "</SignatureTransformCtx>\n"); + + if(dsigCtx->signMethod != NULL) { + fprintf(output, "<SignatureMethod>\n"); + xmlSecTransformDebugXmlDump(dsigCtx->signMethod, output); + fprintf(output, "</SignatureMethod>\n"); + } + + if(dsigCtx->signKey != NULL) { + fprintf(output, "<SignatureKey>\n"); + xmlSecKeyDebugXmlDump(dsigCtx->signKey, output); + fprintf(output, "</SignatureKey>\n"); + } + + fprintf(output, "<SignedInfoReferences>\n"); + xmlSecPtrListDebugXmlDump(&(dsigCtx->signedInfoReferences), output); + fprintf(output, "</SignedInfoReferences>\n"); + + fprintf(output, "<ManifestReferences>\n"); + xmlSecPtrListDebugXmlDump(&(dsigCtx->manifestReferences), output); + fprintf(output, "</ManifestReferences>\n"); + + if((dsigCtx->result != NULL) && + (xmlSecBufferGetData(dsigCtx->result) != NULL)) { + + fprintf(output, "<Result>"); + fwrite(xmlSecBufferGetData(dsigCtx->result), + xmlSecBufferGetSize(dsigCtx->result), + 1, output); + fprintf(output, "</Result>\n"); + } + if(((dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNATURE) != 0) && + (xmlSecDSigCtxGetPreSignBuffer(dsigCtx) != NULL) && + (xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)) != NULL)) { + + fprintf(output, "<PreSignedData>"); + fwrite(xmlSecBufferGetData(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), + xmlSecBufferGetSize(xmlSecDSigCtxGetPreSignBuffer(dsigCtx)), + 1, output); + fprintf(output, "</PreSignedData>\n"); + } + + if(dsigCtx->operation == xmlSecTransformOperationSign) { + fprintf(output, "</SignatureContext>\n"); + } else { + fprintf(output, "</VerificationContext>\n"); + } +} + +/************************************************************************** + * + * xmlSecDSigReferenceCtx + * + *************************************************************************/ +/** + * xmlSecDSigReferenceCtxCreate: + * @dsigCtx: the pointer to parent <dsig:Signature/> node processing context. + * @origin: the reference origin (<dsig:SignedInfo/> or <dsig:Manifest/> node). + * + * Creates new <dsig:Reference/> element processing context. Caller is responsible + * for destroying the returned context by calling #xmlSecDSigReferenceCtxDestroy + * function. + * + * Returns: pointer to newly created context or NULL if an error occurs. + */ +xmlSecDSigReferenceCtxPtr +xmlSecDSigReferenceCtxCreate(xmlSecDSigCtxPtr dsigCtx, xmlSecDSigReferenceOrigin origin) { + xmlSecDSigReferenceCtxPtr dsigRefCtx; + int ret; + + xmlSecAssert2(dsigCtx != NULL, NULL); + + dsigRefCtx = (xmlSecDSigReferenceCtxPtr) xmlMalloc(sizeof(xmlSecDSigReferenceCtx)); + if(dsigRefCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecDSigReferenceCtx)=%d", + sizeof(xmlSecDSigReferenceCtx)); + return(NULL); + } + + ret = xmlSecDSigReferenceCtxInitialize(dsigRefCtx, dsigCtx, origin); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecDSigReferenceCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecDSigReferenceCtxDestroy(dsigRefCtx); + return(NULL); + } + return(dsigRefCtx); +} + +/** + * xmlSecDSigReferenceCtxDestroy: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * + * Destroy context object created with #xmlSecDSigReferenceCtxCreate function. + */ +void +xmlSecDSigReferenceCtxDestroy(xmlSecDSigReferenceCtxPtr dsigRefCtx) { + xmlSecAssert(dsigRefCtx != NULL); + + xmlSecDSigReferenceCtxFinalize(dsigRefCtx); + xmlFree(dsigRefCtx); +} + +/** + * xmlSecDSigReferenceCtxInitialize: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * @dsigCtx: the pointer to parent <dsig:Signature/> node processing context. + * @origin: the reference origin (<dsig:SignedInfo/> or <dsig:Manifest/> node). + * + * Initializes new <dsig:Reference/> element processing context. Caller is responsible + * for cleaning up the returned context by calling #xmlSecDSigReferenceCtxFinalize + * function. + * + * Returns: 0 on succes or aa negative value otherwise. + */ +int +xmlSecDSigReferenceCtxInitialize(xmlSecDSigReferenceCtxPtr dsigRefCtx, xmlSecDSigCtxPtr dsigCtx, + xmlSecDSigReferenceOrigin origin) { + int ret; + + xmlSecAssert2(dsigCtx != NULL, -1); + xmlSecAssert2(dsigRefCtx != NULL, -1); + + memset(dsigRefCtx, 0, sizeof(xmlSecDSigReferenceCtx)); + + dsigRefCtx->dsigCtx = dsigCtx; + dsigRefCtx->origin = origin; + + /* initializes transforms dsigRefCtx */ + ret = xmlSecTransformCtxInitialize(&(dsigRefCtx->transformCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* copy enabled transforms */ + if(dsigCtx->enabledReferenceTransforms != NULL) { + ret = xmlSecPtrListCopy(&(dsigRefCtx->transformCtx.enabledTransforms), + dsigCtx->enabledReferenceTransforms); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListCopy", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + dsigRefCtx->transformCtx.preExecCallback = dsigCtx->referencePreExecuteCallback; + dsigRefCtx->transformCtx.enabledUris = dsigCtx->enabledReferenceUris; + + if((dsigCtx->flags & XMLSEC_DSIG_FLAGS_USE_VISA3D_HACK) != 0) { + dsigRefCtx->transformCtx.flags |= XMLSEC_TRANSFORMCTX_FLAGS_USE_VISA3D_HACK; + } + return(0); +} + +/** + * xmlSecDSigReferenceCtxFinalize: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * + * Cleans up context object created with #xmlSecDSigReferenceCtxInitialize function. + */ +void +xmlSecDSigReferenceCtxFinalize(xmlSecDSigReferenceCtxPtr dsigRefCtx) { + xmlSecAssert(dsigRefCtx != NULL); + + xmlSecTransformCtxFinalize(&(dsigRefCtx->transformCtx)); + if(dsigRefCtx->id != NULL) { + xmlFree(dsigRefCtx->id); + } + if(dsigRefCtx->uri != NULL) { + xmlFree(dsigRefCtx->uri); + } + if(dsigRefCtx->type != NULL) { + xmlFree(dsigRefCtx->type); + } + memset(dsigRefCtx, 0, sizeof(xmlSecDSigReferenceCtx)); +} + +/** + * xmlSecDSigReferenceCtxGetPreDigestBuffer: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * + * Gets the results of <dsig:Reference/> node processing just before digesting + * (valid only if #XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES or + * #XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES flas of signature context + * is set). + * + * Returns: pointer to the buffer or NULL if an error occurs. + */ +xmlSecBufferPtr +xmlSecDSigReferenceCtxGetPreDigestBuffer(xmlSecDSigReferenceCtxPtr dsigRefCtx) { + xmlSecAssert2(dsigRefCtx != NULL, NULL); + + return((dsigRefCtx->preDigestMemBufMethod != NULL) ? + xmlSecTransformMemBufGetBuffer(dsigRefCtx->preDigestMemBufMethod) : NULL); +} + +/** + * xmlSecDSigReferenceCtxProcessNode: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * @node: the pointer to <dsig:Reference/> node. + + * The Reference Element (http://www.w3.org/TR/xmldsig-core/#sec-Reference) + * + * Reference is an element that may occur one or more times. It specifies + * a digest algorithm and digest value, and optionally an identifier of the + * object being signed, the type of the object, and/or a list of transforms + * to be applied prior to digesting. The identification (URI) and transforms + * describe how the digested content (i.e., the input to the digest method) + * was created. The Type attribute facilitates the processing of referenced + * data. For example, while this specification makes no requirements over + * external data, an application may wish to signal that the referent is a + * Manifest. An optional ID attribute permits a Reference to be referenced + * from elsewhere. + * + * Returns: 0 on succes or aa negative value otherwise. + */ +int +xmlSecDSigReferenceCtxProcessNode(xmlSecDSigReferenceCtxPtr dsigRefCtx, xmlNodePtr node) { + xmlSecTransformCtxPtr transformCtx; + xmlNodePtr digestValueNode; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(dsigRefCtx != NULL, -1); + xmlSecAssert2(dsigRefCtx->dsigCtx != NULL, -1); + xmlSecAssert2(dsigRefCtx->digestMethod == NULL, -1); + xmlSecAssert2(dsigRefCtx->digestMethod == NULL, -1); + xmlSecAssert2(dsigRefCtx->preDigestMemBufMethod == NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->doc != NULL, -1); + + transformCtx = &(dsigRefCtx->transformCtx); + + /* read attributes first */ + dsigRefCtx->uri = xmlGetProp(node, xmlSecAttrURI); + dsigRefCtx->id = xmlGetProp(node, xmlSecAttrId); + dsigRefCtx->type= xmlGetProp(node, xmlSecAttrType); + + /* set start URI (and check that it is enabled!) */ + ret = xmlSecTransformCtxSetUri(transformCtx, dsigRefCtx->uri, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxSetUri", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", + xmlSecErrorsSafeString(dsigRefCtx->uri)); + return(-1); + } + + /* first is optional Transforms node */ + cur = xmlSecGetNextElementNode(node->children); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecDSigNs))) { + ret = xmlSecTransformCtxNodesListRead(transformCtx, + cur, xmlSecTransformUsageDSigTransform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxNodesListRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + cur = xmlSecGetNextElementNode(cur->next); + } + + /* insert membuf if requested */ + if(((dsigRefCtx->origin == xmlSecDSigReferenceOriginSignedInfo) && + ((dsigRefCtx->dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_SIGNEDINFO_REFERENCES) != 0)) || + ((dsigRefCtx->origin == xmlSecDSigReferenceOriginManifest) && + ((dsigRefCtx->dsigCtx->flags & XMLSEC_DSIG_FLAGS_STORE_MANIFEST_REFERENCES) != 0))) { + + xmlSecAssert2(dsigRefCtx->preDigestMemBufMethod == NULL, -1); + dsigRefCtx->preDigestMemBufMethod = xmlSecTransformCtxCreateAndAppend( + transformCtx, + xmlSecTransformMemBufId); + if(dsigRefCtx->preDigestMemBufMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformKlassGetName(xmlSecTransformMemBufId))); + return(-1); + } + } + + /* next node is required DigestMethod. */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDigestMethod, xmlSecDSigNs))) { + dsigRefCtx->digestMethod = xmlSecTransformCtxNodeRead(&(dsigRefCtx->transformCtx), + cur, xmlSecTransformUsageDigestMethod); + if(dsigRefCtx->digestMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + + cur = xmlSecGetNextElementNode(cur->next); + } else if(dsigRefCtx->dsigCtx->defSignMethodId != xmlSecTransformIdUnknown) { + /* the dsig spec does require DigestMethod node + * to be present but in some case it application might decide to + * minimize traffic */ + dsigRefCtx->digestMethod = xmlSecTransformCtxCreateAndAppend(&(dsigRefCtx->transformCtx), + dsigRefCtx->dsigCtx->defSignMethodId); + if(dsigRefCtx->digestMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeDigestMethod)); + return(-1); + } + dsigRefCtx->digestMethod->operation = dsigRefCtx->dsigCtx->operation; + + /* last node is required DigestValue */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeDigestValue, xmlSecDSigNs))) { + digestValueNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeDigestValue)); + return(-1); + } + + /* if we have something else then it's an error */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* if we need to write result to xml node then we need base64 encode result */ + if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) { + xmlSecTransformPtr base64Encode; + + /* we need to add base64 encode transform */ + base64Encode = xmlSecTransformCtxCreateAndAppend(transformCtx, xmlSecTransformBase64Id); + if(base64Encode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + base64Encode->operation = xmlSecTransformOperationEncode; + } + + /* finally get transforms results */ + ret = xmlSecTransformCtxExecute(transformCtx, node->doc); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + dsigRefCtx->result = transformCtx->result; + + if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) { + if((dsigRefCtx->result == NULL) || (xmlSecBufferGetData(dsigRefCtx->result) == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* write signed data to xml */ + xmlNodeSetContentLen(digestValueNode, + xmlSecBufferGetData(dsigRefCtx->result), + xmlSecBufferGetSize(dsigRefCtx->result)); + + /* set success status and we are done */ + dsigRefCtx->status = xmlSecDSigStatusSucceeded; + } else { + /* verify SignatureValue node content */ + ret = xmlSecTransformVerifyNodeContent(dsigRefCtx->digestMethod, + digestValueNode, transformCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformVerifyNodeContent", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* set status and we are done */ + if(dsigRefCtx->digestMethod->status == xmlSecTransformStatusOk) { + dsigRefCtx->status = xmlSecDSigStatusSucceeded; + } else { + dsigRefCtx->status = xmlSecDSigStatusInvalid; + } + } + + return(0); +} + +/** + * xmlSecDSigReferenceCtxDebugDump: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * @output: the pointer to output FILE. + * + * Prints debug information about @dsigRefCtx to @output. + */ +void +xmlSecDSigReferenceCtxDebugDump(xmlSecDSigReferenceCtxPtr dsigRefCtx, FILE* output) { + xmlSecAssert(dsigRefCtx != NULL); + xmlSecAssert(dsigRefCtx->dsigCtx != NULL); + xmlSecAssert(output != NULL); + + if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) { + fprintf(output, "= REFERENCE CALCULATION CONTEXT\n"); + } else { + fprintf(output, "= REFERENCE VERIFICATION CONTEXT\n"); + } + switch(dsigRefCtx->status) { + case xmlSecDSigStatusUnknown: + fprintf(output, "== Status: unknown\n"); + break; + case xmlSecDSigStatusSucceeded: + fprintf(output, "== Status: succeeded\n"); + break; + case xmlSecDSigStatusInvalid: + fprintf(output, "== Status: invalid\n"); + break; + } + if(dsigRefCtx->id != NULL) { + fprintf(output, "== Id: \"%s\"\n", dsigRefCtx->id); + } + if(dsigRefCtx->uri != NULL) { + fprintf(output, "== URI: \"%s\"\n", dsigRefCtx->uri); + } + if(dsigRefCtx->type != NULL) { + fprintf(output, "== Type: \"%s\"\n", dsigRefCtx->type); + } + + fprintf(output, "== Reference Transform Ctx:\n"); + xmlSecTransformCtxDebugDump(&(dsigRefCtx->transformCtx), output); + + if(dsigRefCtx->digestMethod != NULL) { + fprintf(output, "== Digest Method:\n"); + xmlSecTransformDebugDump(dsigRefCtx->digestMethod, output); + } + + if((xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx) != NULL) && + (xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)) != NULL)) { + + fprintf(output, "== PreDigest data - start buffer:\n"); + fwrite(xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), + xmlSecBufferGetSize(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), + 1, output); + fprintf(output, "\n== PreDigest data - end buffer\n"); + } + + if((dsigRefCtx->result != NULL) && + (xmlSecBufferGetData(dsigRefCtx->result) != NULL)) { + + fprintf(output, "== Result - start buffer:\n"); + fwrite(xmlSecBufferGetData(dsigRefCtx->result), + xmlSecBufferGetSize(dsigRefCtx->result), 1, + output); + fprintf(output, "\n== Result - end buffer\n"); + } +} + +/** + * xmlSecDSigReferenceCtxDebugXmlDump: + * @dsigRefCtx: the pointer to <dsig:Reference/> element processing context. + * @output: the pointer to output FILE. + * + * Prints debug information about @dsigRefCtx to @output in output format. + */ +void +xmlSecDSigReferenceCtxDebugXmlDump(xmlSecDSigReferenceCtxPtr dsigRefCtx, FILE* output) { + xmlSecAssert(dsigRefCtx != NULL); + xmlSecAssert(dsigRefCtx->dsigCtx != NULL); + xmlSecAssert(output != NULL); + + if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) { + fprintf(output, "<ReferenceCalculationContext "); + } else { + fprintf(output, "<ReferenceVerificationContext "); + } + switch(dsigRefCtx->status) { + case xmlSecDSigStatusUnknown: + fprintf(output, "status=\"unknown\" >\n"); + break; + case xmlSecDSigStatusSucceeded: + fprintf(output, "status=\"succeeded\" >\n"); + break; + case xmlSecDSigStatusInvalid: + fprintf(output, "status=\"invalid\" >\n"); + break; + } + + fprintf(output, "<Id>"); + xmlSecPrintXmlString(output, dsigRefCtx->id); + fprintf(output, "</Id>\n"); + + fprintf(output, "<URI>"); + xmlSecPrintXmlString(output, dsigRefCtx->uri); + fprintf(output, "</URI>\n"); + + fprintf(output, "<Type>"); + xmlSecPrintXmlString(output, dsigRefCtx->type); + fprintf(output, "</Type>\n"); + + fprintf(output, "<ReferenceTransformCtx>\n"); + xmlSecTransformCtxDebugXmlDump(&(dsigRefCtx->transformCtx), output); + fprintf(output, "</ReferenceTransformCtx>\n"); + + if(dsigRefCtx->digestMethod != NULL) { + fprintf(output, "<DigestMethod>\n"); + xmlSecTransformDebugXmlDump(dsigRefCtx->digestMethod, output); + fprintf(output, "</DigestMethod>\n"); + } + + if((dsigRefCtx->result != NULL) && + (xmlSecBufferGetData(dsigRefCtx->result) != NULL)) { + + fprintf(output, "<Result>"); + fwrite(xmlSecBufferGetData(dsigRefCtx->result), + xmlSecBufferGetSize(dsigRefCtx->result), 1, + output); + fprintf(output, "</Result>\n"); + } + + if((xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx) != NULL) && + (xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)) != NULL)) { + + fprintf(output, "<PreDigestData>"); + fwrite(xmlSecBufferGetData(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), + xmlSecBufferGetSize(xmlSecDSigReferenceCtxGetPreDigestBuffer(dsigRefCtx)), + 1, output); + fprintf(output, "</PreDigestData>\n"); + } + if(dsigRefCtx->dsigCtx->operation == xmlSecTransformOperationSign) { + fprintf(output, "</ReferenceCalculationContext>\n"); + } else { + fprintf(output, "</ReferenceVerificationContext>\n"); + } +} + + +/************************************************************************** + * + * xmlSecDSigReferenceCtxListKlass + * + *************************************************************************/ +static xmlSecPtrListKlass xmlSecDSigReferenceCtxListKlass = { + BAD_CAST "dsig-reference-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecDSigReferenceCtxDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecDSigReferenceCtxDebugDump, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + (xmlSecPtrDebugDumpItemMethod)xmlSecDSigReferenceCtxDebugXmlDump, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +/** + * xmlSecDSigReferenceCtxListGetKlass: + * + * The <dsig:Reference/> element processing contexts list klass. + * + * Returns: <dsig:Reference/> element processing context list klass. + */ +xmlSecPtrListId +xmlSecDSigReferenceCtxListGetKlass(void) { + return(&xmlSecDSigReferenceCtxListKlass); +} + +#endif /* XMLSEC_NO_XMLDSIG */ + + diff --git a/src/xmlenc.c b/src/xmlenc.c new file mode 100644 index 00000000..cd226a5a --- /dev/null +++ b/src/xmlenc.c @@ -0,0 +1,1339 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * "XML Encryption" implementation + * http://www.w3.org/TR/xmlenc-core + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_XMLENC + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/parser.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/buffer.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/keysmngr.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keyinfo.h> +#include <xmlsec/xmlenc.h> +#include <xmlsec/errors.h> + +static int xmlSecEncCtxEncDataNodeRead (xmlSecEncCtxPtr encCtx, + xmlNodePtr node); +static int xmlSecEncCtxEncDataNodeWrite (xmlSecEncCtxPtr encCtx); +static int xmlSecEncCtxCipherDataNodeRead (xmlSecEncCtxPtr encCtx, + xmlNodePtr node); +static int xmlSecEncCtxCipherReferenceNodeRead (xmlSecEncCtxPtr encCtx, + xmlNodePtr node); + +/* The ID attribute in XMLEnc is 'Id' */ +static const xmlChar* xmlSecEncIds[] = { BAD_CAST "Id", NULL }; + + +/** + * xmlSecEncCtxCreate: + * @keysMngr: the pointer to keys manager. + * + * Creates <enc:EncryptedData/> element processing context. + * The caller is responsible for destroying returend object by calling + * #xmlSecEncCtxDestroy function. + * + * Returns: pointer to newly allocated context object or NULL if an error + * occurs. + */ +xmlSecEncCtxPtr +xmlSecEncCtxCreate(xmlSecKeysMngrPtr keysMngr) { + xmlSecEncCtxPtr encCtx; + int ret; + + encCtx = (xmlSecEncCtxPtr) xmlMalloc(sizeof(xmlSecEncCtx)); + if(encCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecEncCtx)=%d", + sizeof(xmlSecEncCtx)); + return(NULL); + } + + ret = xmlSecEncCtxInitialize(encCtx, keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecEncCtxDestroy(encCtx); + return(NULL); + } + return(encCtx); +} + +/** + * xmlSecEncCtxDestroy: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * + * Destroy context object created with #xmlSecEncCtxCreate function. + */ +void +xmlSecEncCtxDestroy(xmlSecEncCtxPtr encCtx) { + xmlSecAssert(encCtx != NULL); + + xmlSecEncCtxFinalize(encCtx); + xmlFree(encCtx); +} + +/** + * xmlSecEncCtxInitialize: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @keysMngr: the pointer to keys manager. + * + * Initializes <enc:EncryptedData/> element processing context. + * The caller is responsible for cleaing up returend object by calling + * #xmlSecEncCtxFinalize function. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecEncCtxInitialize(xmlSecEncCtxPtr encCtx, xmlSecKeysMngrPtr keysMngr) { + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + + memset(encCtx, 0, sizeof(xmlSecEncCtx)); + + /* initialize key info */ + ret = xmlSecKeyInfoCtxInitialize(&(encCtx->keyInfoReadCtx), keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + encCtx->keyInfoReadCtx.mode = xmlSecKeyInfoModeRead; + + ret = xmlSecKeyInfoCtxInitialize(&(encCtx->keyInfoWriteCtx), keysMngr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + encCtx->keyInfoWriteCtx.mode = xmlSecKeyInfoModeWrite; + /* it's not wise to write private key :) */ + encCtx->keyInfoWriteCtx.keyReq.keyType = xmlSecKeyDataTypePublic; + + /* initializes transforms encCtx */ + ret = xmlSecTransformCtxInitialize(&(encCtx->transformCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecEncCtxFinalize: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * + * Cleans up @encCtx object. + */ +void +xmlSecEncCtxFinalize(xmlSecEncCtxPtr encCtx) { + xmlSecAssert(encCtx != NULL); + + xmlSecEncCtxReset(encCtx); + + xmlSecTransformCtxFinalize(&(encCtx->transformCtx)); + xmlSecKeyInfoCtxFinalize(&(encCtx->keyInfoReadCtx)); + xmlSecKeyInfoCtxFinalize(&(encCtx->keyInfoWriteCtx)); + + memset(encCtx, 0, sizeof(xmlSecEncCtx)); +} + +/** + * xmlSecEncCtxReset: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * + * Resets @encCtx object, user settings are not touched. + */ +void +xmlSecEncCtxReset(xmlSecEncCtxPtr encCtx) { + xmlSecAssert(encCtx != NULL); + + xmlSecTransformCtxReset(&(encCtx->transformCtx)); + xmlSecKeyInfoCtxReset(&(encCtx->keyInfoReadCtx)); + xmlSecKeyInfoCtxReset(&(encCtx->keyInfoWriteCtx)); + + encCtx->operation = xmlSecTransformOperationNone; + encCtx->result = NULL; + encCtx->resultBase64Encoded = 0; + encCtx->resultReplaced = 0; + encCtx->encMethod = NULL; + + if (encCtx->replacedNodeList != NULL) { + xmlFreeNodeList(encCtx->replacedNodeList); + encCtx->replacedNodeList = NULL; + } + + if(encCtx->encKey != NULL) { + xmlSecKeyDestroy(encCtx->encKey); + encCtx->encKey = NULL; + } + + if(encCtx->id != NULL) { + xmlFree(encCtx->id); + encCtx->id = NULL; + } + + if(encCtx->type != NULL) { + xmlFree(encCtx->type); + encCtx->type = NULL; + } + + if(encCtx->mimeType != NULL) { + xmlFree(encCtx->mimeType); + encCtx->mimeType = NULL; + } + + if(encCtx->encoding != NULL) { + xmlFree(encCtx->encoding); + encCtx->encoding = NULL; + } + + if(encCtx->recipient != NULL) { + xmlFree(encCtx->recipient); + encCtx->recipient = NULL; + } + + if(encCtx->carriedKeyName != NULL) { + xmlFree(encCtx->carriedKeyName); + encCtx->carriedKeyName = NULL; + } + + encCtx->encDataNode = encCtx->encMethodNode = + encCtx->keyInfoNode = encCtx->cipherValueNode = NULL; +} + +/** + * xmlSecEncCtxCopyUserPref: + * @dst: the pointer to destination context. + * @src: the pointer to source context. + * + * Copies user preference from @src context to @dst. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecEncCtxCopyUserPref(xmlSecEncCtxPtr dst, xmlSecEncCtxPtr src) { + int ret; + + xmlSecAssert2(dst != NULL, -1); + xmlSecAssert2(src != NULL, -1); + + dst->userData = src->userData; + dst->flags = src->flags; + dst->flags2 = src->flags2; + dst->defEncMethodId = src->defEncMethodId; + dst->mode = src->mode; + + ret = xmlSecTransformCtxCopyUserPref(&(dst->transformCtx), &(src->transformCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoReadCtx), &(src->keyInfoReadCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecKeyInfoCtxCopyUserPref(&(dst->keyInfoWriteCtx), &(src->keyInfoWriteCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoCtxCopyUserPref", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecEncCtxBinaryEncrypt: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @tmpl: the pointer to <enc:EncryptedData/> template node. + * @data: the pointer for binary buffer. + * @dataSize: the @data buffer size. + * + * Encrypts @data according to template @tmpl. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecEncCtxBinaryEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, + const xmlSecByte* data, xmlSecSize dataSize) { + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(encCtx->result == NULL, -1); + xmlSecAssert2(tmpl != NULL, -1); + xmlSecAssert2(data != NULL, -1); + + /* initialize context and add ID atributes to the list of known ids */ + encCtx->operation = xmlSecTransformOperationEncrypt; + xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds); + + /* read the template and set encryption method, key, etc. */ + ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecTransformCtxBinaryExecute(&(encCtx->transformCtx), data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxBinaryExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "dataSize=%d", + dataSize); + return(-1); + } + + encCtx->result = encCtx->transformCtx.result; + xmlSecAssert2(encCtx->result != NULL, -1); + + ret = xmlSecEncCtxEncDataNodeWrite(encCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecEncCtxXmlEncrypt: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @tmpl: the pointer to <enc:EncryptedData/> template node. + * @node: the pointer to node for encryption. + * + * Encrypts @node according to template @tmpl. If requested, @node is replaced + * with result <enc:EncryptedData/> node. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecEncCtxXmlEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, xmlNodePtr node) { + xmlOutputBufferPtr output; + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(encCtx->result == NULL, -1); + xmlSecAssert2(tmpl != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->doc != NULL, -1); + + /* initialize context and add ID atributes to the list of known ids */ + encCtx->operation = xmlSecTransformOperationEncrypt; + xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds); + + /* read the template and set encryption method, key, etc. */ + ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecTransformCtxPrepare(&(encCtx->transformCtx), xmlSecTransformDataTypeBin); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxPrepare", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "type=bin"); + return(-1); + } + + xmlSecAssert2(encCtx->transformCtx.first != NULL, -1); + output = xmlSecTransformCreateOutputBuffer(encCtx->transformCtx.first, + &(encCtx->transformCtx)); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->transformCtx.first)), + "xmlSecTransformCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* push data thru */ + if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) { + /* get the content of the node */ + xmlNodeDumpOutput(output, node->doc, node, 0, 0, NULL); + } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) { + xmlNodePtr cur; + + /* get the content of the nodes childs */ + for(cur = node->children; cur != NULL; cur = cur->next) { + xmlNodeDumpOutput(output, node->doc, cur, 0, 0, NULL); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "type=%s", + xmlSecErrorsSafeString(encCtx->type)); + xmlOutputBufferClose(output); + return(-1); + } + + /* close the buffer and flush everything */ + ret = xmlOutputBufferClose(output); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + encCtx->result = encCtx->transformCtx.result; + xmlSecAssert2(encCtx->result != NULL, -1); + + ret = xmlSecEncCtxEncDataNodeWrite(encCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* now we need to update our original document */ + if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) { + /* check if we need to return the replaced node */ + if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { + ret = xmlSecReplaceNodeAndReturn(node, tmpl, &(encCtx->replacedNodeList)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } else { + ret = xmlSecReplaceNode(node, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } + + encCtx->resultReplaced = 1; + } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) { + /* check if we need to return the replaced node */ + if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { + ret = xmlSecReplaceContentAndReturn(node, tmpl, &(encCtx->replacedNodeList)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceContentAndReturn", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } else { + ret = xmlSecReplaceContent(node, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceContent", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } + + encCtx->resultReplaced = 1; + } else { + /* we should've catached this error before */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_TYPE, + "type=%s", + xmlSecErrorsSafeString(encCtx->type)); + return(-1); + } + return(0); +} + +/** + * xmlSecEncCtxUriEncrypt: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @tmpl: the pointer to <enc:EncryptedData/> template node. + * @uri: the URI. + * + * Encrypts data from @uri according to template @tmpl. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecEncCtxUriEncrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr tmpl, const xmlChar *uri) { + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(encCtx->result == NULL, -1); + xmlSecAssert2(tmpl != NULL, -1); + xmlSecAssert2(uri != NULL, -1); + + /* initialize context and add ID atributes to the list of known ids */ + encCtx->operation = xmlSecTransformOperationEncrypt; + xmlSecAddIDs(tmpl->doc, tmpl, xmlSecEncIds); + + /* we need to add input uri transform first */ + ret = xmlSecTransformCtxSetUri(&(encCtx->transformCtx), uri, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxSetUri", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", + xmlSecErrorsSafeString(uri)); + return(-1); + } + + /* read the template and set encryption method, key, etc. */ + ret = xmlSecEncCtxEncDataNodeRead(encCtx, tmpl); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* encrypt the data */ + ret = xmlSecTransformCtxExecute(&(encCtx->transformCtx), tmpl->doc); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + encCtx->result = encCtx->transformCtx.result; + xmlSecAssert2(encCtx->result != NULL, -1); + + ret = xmlSecEncCtxEncDataNodeWrite(encCtx); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +/** + * xmlSecEncCtxDecrypt: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @node: the pointer to <enc:EncryptedData/> node. + * + * Decrypts @node and if necessary replaces @node with decrypted data. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecEncCtxDecrypt(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { + xmlSecBufferPtr buffer; + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* decrypt */ + buffer = xmlSecEncCtxDecryptToBuffer(encCtx, node); + if(buffer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxDecryptToBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* replace original node if requested */ + if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncElement)) { + /* check if we need to return the replaced node */ + if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { + ret = xmlSecReplaceNodeBufferAndReturn(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), &(encCtx->replacedNodeList)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceNodeBufferAndReturn", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } else { + ret = xmlSecReplaceNodeBuffer(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceNodeBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } + + encCtx->resultReplaced = 1; + } else if((encCtx->type != NULL) && xmlStrEqual(encCtx->type, xmlSecTypeEncContent)) { + /* replace the node with the buffer */ + + /* check if we need to return the replaced node */ + if((encCtx->flags & XMLSEC_ENC_RETURN_REPLACED_NODE) != 0) { + ret = xmlSecReplaceNodeBufferAndReturn(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer), &(encCtx->replacedNodeList)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceNodeBufferAndReturn", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } else { + ret = xmlSecReplaceNodeBuffer(node, xmlSecBufferGetData(buffer), xmlSecBufferGetSize(buffer)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecReplaceNodeBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(node))); + return(-1); + } + } + encCtx->resultReplaced = 1; + } + + return(0); +} + +/** + * xmlSecEncCtxDecryptToBuffer: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @node: the pointer to <enc:EncryptedData/> node. + * + * Decrypts @node data to the @encCtx buffer. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +xmlSecBufferPtr +xmlSecEncCtxDecryptToBuffer(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { + int ret; + + xmlSecAssert2(encCtx != NULL, NULL); + xmlSecAssert2(encCtx->result == NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + /* initialize context and add ID atributes to the list of known ids */ + encCtx->operation = xmlSecTransformOperationDecrypt; + xmlSecAddIDs(node->doc, node, xmlSecEncIds); + + ret = xmlSecEncCtxEncDataNodeRead(encCtx, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxEncDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* decrypt the data */ + if(encCtx->cipherValueNode != NULL) { + xmlChar* data = NULL; + xmlSecSize dataSize = 0; + + data = xmlNodeGetContent(encCtx->cipherValueNode); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->cipherValueNode)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + dataSize = xmlStrlen(data); + + ret = xmlSecTransformCtxBinaryExecute(&(encCtx->transformCtx), data, dataSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxBinaryExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + if(data != NULL) { + xmlFree(data); + } + return(NULL); + } + if(data != NULL) { + xmlFree(data); + } + } else { + ret = xmlSecTransformCtxExecute(&(encCtx->transformCtx), node->doc); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxBinaryExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + } + + encCtx->result = encCtx->transformCtx.result; + xmlSecAssert2(encCtx->result != NULL, NULL); + + return(encCtx->result); +} + +static int +xmlSecEncCtxEncDataNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2((encCtx->operation == xmlSecTransformOperationEncrypt) || (encCtx->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(node != NULL, -1); + + switch(encCtx->mode) { + case xmlEncCtxModeEncryptedData: + if(!xmlSecCheckNodeName(node, xmlSecNodeEncryptedData, xmlSecEncNs)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptedData)); + return(-1); + } + break; + case xmlEncCtxModeEncryptedKey: + if(!xmlSecCheckNodeName(node, xmlSecNodeEncryptedKey, xmlSecEncNs)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeEncryptedKey)); + return(-1); + } + break; + } + + /* first read node data */ + xmlSecAssert2(encCtx->id == NULL, -1); + xmlSecAssert2(encCtx->type == NULL, -1); + xmlSecAssert2(encCtx->mimeType == NULL, -1); + xmlSecAssert2(encCtx->encoding == NULL, -1); + xmlSecAssert2(encCtx->recipient == NULL, -1); + xmlSecAssert2(encCtx->carriedKeyName == NULL, -1); + + encCtx->id = xmlGetProp(node, xmlSecAttrId); + encCtx->type = xmlGetProp(node, xmlSecAttrType); + encCtx->mimeType = xmlGetProp(node, xmlSecAttrMimeType); + encCtx->encoding = xmlGetProp(node, xmlSecAttrEncoding); + if(encCtx->mode == xmlEncCtxModeEncryptedKey) { + encCtx->recipient = xmlGetProp(node, xmlSecAttrRecipient); + /* todo: check recipient? */ + } + cur = xmlSecGetNextElementNode(node->children); + + /* first node is optional EncryptionMethod, we'll read it later */ + xmlSecAssert2(encCtx->encMethodNode == NULL, -1); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeEncryptionMethod, xmlSecEncNs))) { + encCtx->encMethodNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next node is optional KeyInfo, we'll process it later */ + xmlSecAssert2(encCtx->keyInfoNode == NULL, -1); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeKeyInfo, xmlSecDSigNs))) { + encCtx->keyInfoNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is required CipherData node */ + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeCipherData, xmlSecEncNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCipherData)); + return(-1); + } + + ret = xmlSecEncCtxCipherDataNodeRead(encCtx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxCipherDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + + /* next is optional EncryptionProperties node (we simply ignore it) */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeEncryptionProperties, xmlSecEncNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* there are more possible nodes for the <EncryptedKey> node */ + if(encCtx->mode == xmlEncCtxModeEncryptedKey) { + /* next is optional ReferenceList node (we simply ignore it) */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeReferenceList, xmlSecEncNs))) { + cur = xmlSecGetNextElementNode(cur->next); + } + + /* next is optional CarriedKeyName node (we simply ignore it) */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCarriedKeyName, xmlSecEncNs))) { + encCtx->carriedKeyName = xmlNodeGetContent(cur); + if(encCtx->carriedKeyName == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeCipherData)); + return(-1); + } + /* TODO: decode the name? */ + cur = xmlSecGetNextElementNode(cur->next); + } + } + + /* if there is something left than it's an error */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* now read the encryption method node */ + xmlSecAssert2(encCtx->encMethod == NULL, -1); + if(encCtx->encMethodNode != NULL) { + encCtx->encMethod = xmlSecTransformCtxNodeRead(&(encCtx->transformCtx), encCtx->encMethodNode, + xmlSecTransformUsageEncryptionMethod); + if(encCtx->encMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->encMethodNode))); + return(-1); + } + } else if(encCtx->defEncMethodId != xmlSecTransformIdUnknown) { + encCtx->encMethod = xmlSecTransformCtxCreateAndAppend(&(encCtx->transformCtx), + encCtx->defEncMethodId); + if(encCtx->encMethod == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "encryption method not specified"); + return(-1); + } + encCtx->encMethod->operation = encCtx->operation; + + /* we have encryption method, find key */ + ret = xmlSecTransformSetKeyReq(encCtx->encMethod, &(encCtx->keyInfoReadCtx.keyReq)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformSetKeyReq", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->encMethod))); + return(-1); + } + + /* TODO: KeyInfo node != NULL and encKey != NULL */ + if((encCtx->encKey == NULL) && (encCtx->keyInfoReadCtx.keysMngr != NULL) + && (encCtx->keyInfoReadCtx.keysMngr->getKey != NULL)) { + encCtx->encKey = (encCtx->keyInfoReadCtx.keysMngr->getKey)(encCtx->keyInfoNode, + &(encCtx->keyInfoReadCtx)); + } + + /* check that we have exactly what we want */ + if((encCtx->encKey == NULL) || + (!xmlSecKeyMatch(encCtx->encKey, NULL, &(encCtx->keyInfoReadCtx.keyReq)))) { + + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_KEY_NOT_FOUND, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* set the key to the transform */ + ret = xmlSecTransformSetKey(encCtx->encMethod, encCtx->encKey); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformSetKey", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "transform=%s", + xmlSecErrorsSafeString(xmlSecTransformGetName(encCtx->encMethod))); + return(-1); + } + + /* if we need to write result to xml node then we need base64 encode it */ + if((encCtx->operation == xmlSecTransformOperationEncrypt) && (encCtx->cipherValueNode != NULL)) { + xmlSecTransformPtr base64Encode; + + /* we need to add base64 encode transform */ + base64Encode = xmlSecTransformCtxCreateAndAppend(&(encCtx->transformCtx), xmlSecTransformBase64Id); + if(base64Encode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndAppend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + base64Encode->operation = xmlSecTransformOperationEncode; + encCtx->resultBase64Encoded = 1; + } + + return(0); +} + +static int +xmlSecEncCtxEncDataNodeWrite(xmlSecEncCtxPtr encCtx) { + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(encCtx->result != NULL, -1); + xmlSecAssert2(encCtx->encKey != NULL, -1); + + /* write encrypted data to xml (if requested) */ + if(encCtx->cipherValueNode != NULL) { + xmlSecAssert2(xmlSecBufferGetData(encCtx->result) != NULL, -1); + + xmlNodeSetContentLen(encCtx->cipherValueNode, + xmlSecBufferGetData(encCtx->result), + xmlSecBufferGetSize(encCtx->result)); + encCtx->resultReplaced = 1; + } + + /* update <enc:KeyInfo/> node */ + if(encCtx->keyInfoNode != NULL) { + ret = xmlSecKeyInfoNodeWrite(encCtx->keyInfoNode, encCtx->encKey, &(encCtx->keyInfoWriteCtx)); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyInfoNodeWrite", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + + return(0); +} + +static int +xmlSecEncCtxCipherDataNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { + xmlNodePtr cur; + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + cur = xmlSecGetNextElementNode(node->children); + + /* we either have CipherValue or CipherReference node */ + xmlSecAssert2(encCtx->cipherValueNode == NULL, -1); + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCipherValue, xmlSecEncNs))) { + /* don't need data from CipherData node when we are encrypting */ + if(encCtx->operation == xmlSecTransformOperationDecrypt) { + xmlSecTransformPtr base64Decode; + + /* we need to add base64 decode transform */ + base64Decode = xmlSecTransformCtxCreateAndPrepend(&(encCtx->transformCtx), xmlSecTransformBase64Id); + if(base64Decode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxCreateAndPrepend", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + } + encCtx->cipherValueNode = cur; + cur = xmlSecGetNextElementNode(cur->next); + } else if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeCipherReference, xmlSecEncNs))) { + /* don't need data from CipherReference node when we are encrypting */ + if(encCtx->operation == xmlSecTransformOperationDecrypt) { + ret = xmlSecEncCtxCipherReferenceNodeRead(encCtx, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecEncCtxCipherReferenceNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + } + cur = xmlSecGetNextElementNode(cur->next); + } + + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static int +xmlSecEncCtxCipherReferenceNodeRead(xmlSecEncCtxPtr encCtx, xmlNodePtr node) { + xmlNodePtr cur; + xmlChar* uri; + int ret; + + xmlSecAssert2(encCtx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* first read the optional uri attr and check that we can process it */ + uri = xmlGetProp(node, xmlSecAttrURI); + ret = xmlSecTransformCtxSetUri(&(encCtx->transformCtx), uri, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxSetUri", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "uri=%s", + xmlSecErrorsSafeString(uri)); + xmlFree(uri); + return(-1); + } + xmlFree(uri); + + cur = xmlSecGetNextElementNode(node->children); + + /* the only one node is optional Transforms node */ + if((cur != NULL) && (xmlSecCheckNodeName(cur, xmlSecNodeTransforms, xmlSecEncNs))) { + ret = xmlSecTransformCtxNodesListRead(&(encCtx->transformCtx), cur, + xmlSecTransformUsageDSigTransform); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformCtxNodesListRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(encCtx->encMethodNode))); + return(-1); + } + cur = xmlSecGetNextElementNode(cur->next); + } + + /* if there is something left than it's an error */ + if(cur != NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_UNEXPECTED_NODE, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/** + * xmlSecEncCtxDebugDump: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @output: the pointer to output FILE. + * + * Prints the debug information about @encCtx to @output. + */ +void +xmlSecEncCtxDebugDump(xmlSecEncCtxPtr encCtx, FILE* output) { + xmlSecAssert(encCtx != NULL); + xmlSecAssert(output != NULL); + + switch(encCtx->mode) { + case xmlEncCtxModeEncryptedData: + if(encCtx->operation == xmlSecTransformOperationEncrypt) { + fprintf(output, "= DATA ENCRYPTION CONTEXT\n"); + } else { + fprintf(output, "= DATA DECRYPTION CONTEXT\n"); + } + break; + case xmlEncCtxModeEncryptedKey: + if(encCtx->operation == xmlSecTransformOperationEncrypt) { + fprintf(output, "= KEY ENCRYPTION CONTEXT\n"); + } else { + fprintf(output, "= KEY DECRYPTION CONTEXT\n"); + } + break; + } + fprintf(output, "== Status: %s\n", + (encCtx->resultReplaced) ? "replaced" : "not-replaced" ); + + fprintf(output, "== flags: 0x%08x\n", encCtx->flags); + fprintf(output, "== flags2: 0x%08x\n", encCtx->flags2); + + if(encCtx->id != NULL) { + fprintf(output, "== Id: \"%s\"\n", encCtx->id); + } + if(encCtx->type != NULL) { + fprintf(output, "== Type: \"%s\"\n", encCtx->type); + } + if(encCtx->mimeType != NULL) { + fprintf(output, "== MimeType: \"%s\"\n", encCtx->mimeType); + } + if(encCtx->encoding != NULL) { + fprintf(output, "== Encoding: \"%s\"\n", encCtx->encoding); + } + if(encCtx->recipient != NULL) { + fprintf(output, "== Recipient: \"%s\"\n", encCtx->recipient); + } + if(encCtx->carriedKeyName != NULL) { + fprintf(output, "== CarriedKeyName: \"%s\"\n", encCtx->carriedKeyName); + } + + fprintf(output, "== Key Info Read Ctx:\n"); + xmlSecKeyInfoCtxDebugDump(&(encCtx->keyInfoReadCtx), output); + + fprintf(output, "== Key Info Write Ctx:\n"); + xmlSecKeyInfoCtxDebugDump(&(encCtx->keyInfoWriteCtx), output); + + fprintf(output, "== Encryption Transform Ctx:\n"); + xmlSecTransformCtxDebugDump(&(encCtx->transformCtx), output); + + if(encCtx->encMethod != NULL) { + fprintf(output, "== Encryption Method:\n"); + xmlSecTransformDebugDump(encCtx->encMethod, output); + } + + if(encCtx->encKey != NULL) { + fprintf(output, "== Encryption Key:\n"); + xmlSecKeyDebugDump(encCtx->encKey, output); + } + + if((encCtx->result != NULL) && + (xmlSecBufferGetData(encCtx->result) != NULL) && + (encCtx->resultBase64Encoded != 0)) { + + fprintf(output, "== Result - start buffer:\n"); + fwrite(xmlSecBufferGetData(encCtx->result), + xmlSecBufferGetSize(encCtx->result), 1, + output); + fprintf(output, "\n== Result - end buffer\n"); + } +} + +/** + * xmlSecEncCtxDebugXmlDump: + * @encCtx: the pointer to <enc:EncryptedData/> processing context. + * @output: the pointer to output FILE. + * + * Prints the debug information about @encCtx to @output in XML format. + */ +void +xmlSecEncCtxDebugXmlDump(xmlSecEncCtxPtr encCtx, FILE* output) { + xmlSecAssert(encCtx != NULL); + xmlSecAssert(output != NULL); + + switch(encCtx->mode) { + case xmlEncCtxModeEncryptedData: + if(encCtx->operation == xmlSecTransformOperationEncrypt) { + fprintf(output, "<DataEncryptionContext "); + } else { + fprintf(output, "<DataDecryptionContext "); + } + break; + case xmlEncCtxModeEncryptedKey: + if(encCtx->operation == xmlSecTransformOperationEncrypt) { + fprintf(output, "<KeyEncryptionContext "); + } else { + fprintf(output, "<KeyDecryptionContext "); + } + break; + } + fprintf(output, "status=\"%s\" >\n", (encCtx->resultReplaced) ? "replaced" : "not-replaced" ); + + fprintf(output, "<Flags>%08x</Flags>\n", encCtx->flags); + fprintf(output, "<Flags2>%08x</Flags2>\n", encCtx->flags2); + + fprintf(output, "<Id>"); + xmlSecPrintXmlString(output, encCtx->id); + fprintf(output, "</Id>"); + + fprintf(output, "<Type>"); + xmlSecPrintXmlString(output, encCtx->type); + fprintf(output, "</Type>"); + + fprintf(output, "<MimeType>"); + xmlSecPrintXmlString(output, encCtx->mimeType); + fprintf(output, "</MimeType>"); + + fprintf(output, "<Encoding>"); + xmlSecPrintXmlString(output, encCtx->encoding); + fprintf(output, "</Encoding>"); + + fprintf(output, "<Recipient>"); + xmlSecPrintXmlString(output, encCtx->recipient); + fprintf(output, "</Recipient>"); + + fprintf(output, "<CarriedKeyName>"); + xmlSecPrintXmlString(output, encCtx->carriedKeyName); + fprintf(output, "</CarriedKeyName>"); + + fprintf(output, "<KeyInfoReadCtx>\n"); + xmlSecKeyInfoCtxDebugXmlDump(&(encCtx->keyInfoReadCtx), output); + fprintf(output, "</KeyInfoReadCtx>\n"); + + fprintf(output, "<KeyInfoWriteCtx>\n"); + xmlSecKeyInfoCtxDebugXmlDump(&(encCtx->keyInfoWriteCtx), output); + fprintf(output, "</KeyInfoWriteCtx>\n"); + + fprintf(output, "<EncryptionTransformCtx>\n"); + xmlSecTransformCtxDebugXmlDump(&(encCtx->transformCtx), output); + fprintf(output, "</EncryptionTransformCtx>\n"); + + if(encCtx->encMethod != NULL) { + fprintf(output, "<EncryptionMethod>\n"); + xmlSecTransformDebugXmlDump(encCtx->encMethod, output); + fprintf(output, "</EncryptionMethod>\n"); + } + + if(encCtx->encKey != NULL) { + fprintf(output, "<EncryptionKey>\n"); + xmlSecKeyDebugXmlDump(encCtx->encKey, output); + fprintf(output, "</EncryptionKey>\n"); + } + + if((encCtx->result != NULL) && + (xmlSecBufferGetData(encCtx->result) != NULL) && + (encCtx->resultBase64Encoded != 0)) { + + fprintf(output, "<Result>"); + fwrite(xmlSecBufferGetData(encCtx->result), + xmlSecBufferGetSize(encCtx->result), 1, + output); + fprintf(output, "</Result>\n"); + } + + switch(encCtx->mode) { + case xmlEncCtxModeEncryptedData: + if(encCtx->operation == xmlSecTransformOperationEncrypt) { + fprintf(output, "</DataEncryptionContext>\n"); + } else { + fprintf(output, "</DataDecryptionContext>\n"); + } + break; + case xmlEncCtxModeEncryptedKey: + if(encCtx->operation == xmlSecTransformOperationEncrypt) { + fprintf(output, "</KeyEncryptionContext>\n"); + } else { + fprintf(output, "</KeyDecryptionContext>\n"); + } + break; + } +} + +#endif /* XMLSEC_NO_XMLENC */ + diff --git a/src/xmlsec.c b/src/xmlsec.c new file mode 100644 index 00000000..3baa81a0 --- /dev/null +++ b/src/xmlsec.c @@ -0,0 +1,185 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * General functions. + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <stdio.h> + +#include <libxml/tree.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/app.h> +#include <xmlsec/io.h> +#include <xmlsec/xkms.h> +#include <xmlsec/errors.h> + +/** + * xmlSecInit: + * + * Initializes XML Security Library. The depended libraries + * (LibXML and LibXSLT) must be initialized before. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecInit(void) { + xmlSecErrorsInit(); + xmlSecIOInit(); + +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLInit() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#endif /* XMLSEC_NO_CRYPTO_DYNAMIC_LOADING */ + + if(xmlSecKeyDataIdsInit() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecKeyDataIdsInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(xmlSecTransformIdsInit() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecTransformIdsInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + +#ifndef XMLSEC_NO_XKMS + if(xmlSecXkmsRespondWithIdsInit() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsRespondWithIdsInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + if(xmlSecXkmsServerRequestIdsInit() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXkmsServerRequestIdsInit", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } +#endif /* XMLSEC_NO_XKMS */ + + /* we use rand() function to generate id attributes */ + srand(time(NULL)); + return(0); +} + +/** + * xmlSecShutdown: + * + * Clean ups the XML Security Library. + * + * Returns: 0 on success or a negative value otherwise. + */ +int +xmlSecShutdown(void) { + int res = 0; + +#ifndef XMLSEC_NO_XKMS + xmlSecXkmsServerRequestIdsShutdown(); + xmlSecXkmsRespondWithIdsShutdown(); +#endif /* XMLSEC_NO_XKMS */ + + xmlSecTransformIdsShutdown(); + xmlSecKeyDataIdsShutdown(); + +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING + if(xmlSecCryptoDLShutdown() < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecCryptoDLShutdown", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + res = -1; + } +#endif /* XMLSEC_NO_CRYPTO_DYNAMIC_LOADING */ + + xmlSecIOShutdown(); + xmlSecErrorsShutdown(); + return(res); +} + +/** + * xmlSecCheckVersionExt: + * @major: the major version number. + * @minor: the minor version number. + * @subminor: the subminor version number. + * @mode: the version check mode. + * + * Checks if the loaded version of xmlsec library could be used. + * + * Returns: 1 if the loaded xmlsec library version is OK to use + * 0 if it is not or a negative value if an error occurs. + */ +int +xmlSecCheckVersionExt(int major, int minor, int subminor, xmlSecCheckVersionMode mode) { + /* we always want to have a match for major version number */ + if(major != XMLSEC_VERSION_MAJOR) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "expected major version=%d;real major version=%d", + XMLSEC_VERSION_MAJOR, major); + return(0); + } + + switch(mode) { + case xmlSecCheckVersionExactMatch: + if((minor != XMLSEC_VERSION_MINOR) || (subminor != XMLSEC_VERSION_SUBMINOR)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "mode=exact;expected minor version=%d;real minor version=%d;expected subminor version=%d;real subminor version=%d", + XMLSEC_VERSION_MINOR, minor, + XMLSEC_VERSION_SUBMINOR, subminor); + return(0); + } + break; + case xmlSecCheckVersionABICompatible: + if((minor < XMLSEC_VERSION_MINOR) || + ((minor == XMLSEC_VERSION_MINOR) && + (subminor < XMLSEC_VERSION_SUBMINOR))) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "mode=abi compatible;expected minor version=%d;real minor version=%d;expected subminor version=%d;real subminor version=%d", + XMLSEC_VERSION_MINOR, minor, + XMLSEC_VERSION_SUBMINOR, subminor); + return(0); + } + break; + } + + return(1); +} + + diff --git a/src/xmltree.c b/src/xmltree.c new file mode 100644 index 00000000..96ea53c1 --- /dev/null +++ b/src/xmltree.c @@ -0,0 +1,1908 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * Common XML Doc utility functions + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include <libxml/tree.h> +#include <libxml/valid.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/parser.h> +#include <xmlsec/private.h> +#include <xmlsec/base64.h> +#include <xmlsec/errors.h> + +/** + * xmlSecFindChild: + * @parent: the pointer to XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches a direct child of the @parent node having given name and + * namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindChild(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + cur = parent->children; + while(cur != NULL) { + if(cur->type == XML_ELEMENT_NODE) { + if(xmlSecCheckNodeName(cur, name, ns)) { + return(cur); + } + } + cur = cur->next; + } + return(NULL); +} + +/** + * xmlSecFindParent: + * @cur: the pointer to an XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches the ancestors axis of the @cur node for a node having given name + * and namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindParent(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) { + xmlSecAssert2(cur != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + if(xmlSecCheckNodeName(cur, name, ns)) { + return(cur); + } else if(cur->parent != NULL) { + return(xmlSecFindParent(cur->parent, name, ns)); + } + return(NULL); +} + +/** + * xmlSecFindNode: + * @parent: the pointer to XML node. + * @name: the name. + * @ns: the namespace href (may be NULL). + * + * Searches all children of the @parent node having given name and + * namespace href. + * + * Returns: the pointer to the found node or NULL if an error occurs or + * node is not found. + */ +xmlNodePtr +xmlSecFindNode(const xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr ret; + + xmlSecAssert2(name != NULL, NULL); + + cur = parent; + while(cur != NULL) { + if((cur->type == XML_ELEMENT_NODE) && xmlSecCheckNodeName(cur, name, ns)) { + return(cur); + } + if(cur->children != NULL) { + ret = xmlSecFindNode(cur->children, name, ns); + if(ret != NULL) { + return(ret); + } + } + cur = cur->next; + } + return(NULL); +} + +/** + * xmlSecGetNodeNsHref: + * @cur: the pointer to node. + * + * Get's node's namespace href. + * + * Returns: node's namespace href. + */ +const xmlChar* +xmlSecGetNodeNsHref(const xmlNodePtr cur) { + xmlNsPtr ns; + + xmlSecAssert2(cur != NULL, NULL); + + /* do we have a namespace in the node? */ + if(cur->ns != NULL) { + return(cur->ns->href); + } + + /* search for default namespace */ + ns = xmlSearchNs(cur->doc, cur, NULL); + if(ns != NULL) { + return(ns->href); + } + + return(NULL); +} + +/** + * xmlSecCheckNodeName: + * @cur: the pointer to an XML node. + * @name: the name, + * @ns: the namespace href. + * + * Checks that the node has a given name and a given namespace href. + * + * Returns: 1 if the node matches or 0 otherwise. + */ +int +xmlSecCheckNodeName(const xmlNodePtr cur, const xmlChar *name, const xmlChar *ns) { + xmlSecAssert2(cur != NULL, 0); + + return(xmlStrEqual(cur->name, name) && + xmlStrEqual(xmlSecGetNodeNsHref(cur), ns)); +} + +/** + * xmlSecAddChild: + * @parent: the pointer to an XML node. + * @name: the new node name. + * @ns: the new node namespace. + * + * Adds a child to the node @parent with given @name and namespace @ns. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddChild(xmlNodePtr parent, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr text; + + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + if(parent->children == NULL) { + /* TODO: add indents */ + text = xmlNewText(xmlSecStringCR); + if(text == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewText", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddChild(parent, text); + } + + cur = xmlNewChild(parent, NULL, name, NULL); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewChild", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* namespaces support */ + if(ns != NULL) { + xmlNsPtr nsPtr; + + /* find namespace by href and check that its prefix is not overwritten */ + nsPtr = xmlSearchNsByHref(cur->doc, cur, ns); + if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) { + nsPtr = xmlNewNs(cur, ns, NULL); + } + xmlSetNs(cur, nsPtr); + } + + /* TODO: add indents */ + text = xmlNewText(xmlSecStringCR); + if(text == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewText", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddChild(parent, text); + + return(cur); +} + +/** + * xmlSecAddChildNode: + * @parent: the pointer to an XML node. + * @child: the new node. + * + * Adds @child node to the @parent node. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddChildNode(xmlNodePtr parent, xmlNodePtr child) { + xmlNodePtr text; + + xmlSecAssert2(parent != NULL, NULL); + xmlSecAssert2(child != NULL, NULL); + + if(parent->children == NULL) { + /* TODO: add indents */ + text = xmlNewText(xmlSecStringCR); + if(text == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewText", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddChild(parent, text); + } + + xmlAddChild(parent, child); + + /* TODO: add indents */ + text = xmlNewText(xmlSecStringCR); + if(text == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewText", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddChild(parent, text); + + return(child); +} + +/** + * xmlSecAddNextSibling + * @node: the pointer to an XML node. + * @name: the new node name. + * @ns: the new node namespace. + * + * Adds next sibling to the node @node with given @name and namespace @ns. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddNextSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr text; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + cur = xmlNewNode(NULL, name); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNode", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddNextSibling(node, cur); + + /* namespaces support */ + if(ns != NULL) { + xmlNsPtr nsPtr; + + /* find namespace by href and check that its prefix is not overwritten */ + nsPtr = xmlSearchNsByHref(cur->doc, cur, ns); + if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) { + nsPtr = xmlNewNs(cur, ns, NULL); + } + xmlSetNs(cur, nsPtr); + } + + /* TODO: add indents */ + text = xmlNewText(xmlSecStringCR); + if(text == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewText", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddNextSibling(node, text); + + return(cur); +} + +/** + * xmlSecAddPrevSibling + * @node: the pointer to an XML node. + * @name: the new node name. + * @ns: the new node namespace. + * + * Adds prev sibling to the node @node with given @name and namespace @ns. + * + * Returns: pointer to the new node or NULL if an error occurs. + */ +xmlNodePtr +xmlSecAddPrevSibling(xmlNodePtr node, const xmlChar *name, const xmlChar *ns) { + xmlNodePtr cur; + xmlNodePtr text; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(name != NULL, NULL); + + cur = xmlNewNode(NULL, name); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNode", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddPrevSibling(node, cur); + + /* namespaces support */ + if(ns != NULL) { + xmlNsPtr nsPtr; + + /* find namespace by href and check that its prefix is not overwritten */ + nsPtr = xmlSearchNsByHref(cur->doc, cur, ns); + if((nsPtr == NULL) || (xmlSearchNs(cur->doc, cur, nsPtr->prefix) != nsPtr)) { + nsPtr = xmlNewNs(cur, ns, NULL); + } + xmlSetNs(cur, nsPtr); + } + + /* TODO: add indents */ + text = xmlNewText(xmlSecStringCR); + if(text == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewText", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlAddPrevSibling(node, text); + + return(cur); +} + +/** + * xmlSecGetNextElementNode: + * @cur: the pointer to an XML node. + * + * Seraches for the next element node. + * + * Returns: the pointer to next element node or NULL if it is not found. + */ +xmlNodePtr +xmlSecGetNextElementNode(xmlNodePtr cur) { + + while((cur != NULL) && (cur->type != XML_ELEMENT_NODE)) { + cur = cur->next; + } + return(cur); +} + +/** + * xmlSecReplaceNode: + * @node: the current node. + * @newNode: the new node. + * + * Swaps the @node and @newNode in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNode(xmlNodePtr node, xmlNodePtr newNode) { + return xmlSecReplaceNodeAndReturn(node, newNode, NULL); +} + +/** + * xmlSecReplaceNodeAndReturn: + * @node: the current node. + * @newNode: the new node. + * @replaced: the replaced node, or release it if NULL is given + * + * Swaps the @node and @newNode in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNodeAndReturn(xmlNodePtr node, xmlNodePtr newNode, xmlNodePtr* replaced) { + xmlNodePtr oldNode; + int restoreRoot = 0; + + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(newNode != NULL, -1); + + /* fix documents children if necessary first */ + if((node->doc != NULL) && (node->doc->children == node)) { + node->doc->children = node->next; + restoreRoot = 1; + } + if((newNode->doc != NULL) && (newNode->doc->children == newNode)) { + newNode->doc->children = newNode->next; + } + + oldNode = xmlReplaceNode(node, newNode); + if(oldNode == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlReplaceNode", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if(restoreRoot != 0) { + xmlDocSetRootElement(oldNode->doc, newNode); + } + + /* return the old node if requested */ + if(replaced != NULL) { + (*replaced) = oldNode; + } else { + xmlFreeNode(oldNode); + } + + return(0); +} + +/** + * xmlSecReplaceContent + * @node: the current node. + * @newNode: the new node. + * + * Swaps the content of @node and @newNode. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceContent(xmlNodePtr node, xmlNodePtr newNode) { + return xmlSecReplaceContentAndReturn(node, newNode, NULL); +} + +/** + * xmlSecReplaceContentAndReturn + * @node: the current node. + * @newNode: the new node. + * @replaced: the replaced nodes, or release them if NULL is given + * + * Swaps the content of @node and @newNode. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceContentAndReturn(xmlNodePtr node, xmlNodePtr newNode, xmlNodePtr *replaced) { + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(newNode != NULL, -1); + + xmlUnlinkNode(newNode); + xmlSetTreeDoc(newNode, node->doc); + + /* return the old nodes if requested */ + if(replaced != NULL) { + xmlNodePtr cur, next, tail; + + (*replaced) = tail = NULL; + for(cur = node->children; (cur != NULL); cur = next) { + next = cur->next; + if((*replaced) != NULL) { + /* n is unlinked in this function */ + xmlAddNextSibling(tail, cur); + tail = cur; + } else { + /* this is the first node, (*replaced) is the head */ + xmlUnlinkNode(cur); + (*replaced) = tail = cur; + } + } + } else { + /* just delete the content */ + xmlNodeSetContent(node, NULL); + } + + xmlAddChild(node, newNode); + xmlSetTreeDoc(newNode, node->doc); + + return(0); +} + +/** + * xmlSecReplaceNodeBuffer: + * @node: the current node. + * @buffer: the XML data. + * @size: the XML data size. + * + * Swaps the @node and the parsed XML data from the @buffer in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNodeBuffer(xmlNodePtr node, const xmlSecByte *buffer, xmlSecSize size) { + return xmlSecReplaceNodeBufferAndReturn(node, buffer, size, NULL); +} + +/** + * xmlSecReplaceNodeBufferAndReturn: + * @node: the current node. + * @buffer: the XML data. + * @size: the XML data size. + * @replaced: the replaced nodes, or release them if NULL is given + * + * Swaps the @node and the parsed XML data from the @buffer in the XML tree. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecReplaceNodeBufferAndReturn(xmlNodePtr node, const xmlSecByte *buffer, xmlSecSize size, xmlNodePtr *replaced) { + xmlNodePtr results = NULL; + xmlNodePtr next = NULL; + + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->parent != NULL, -1); + + /* parse buffer in the context of node's parent */ + if(xmlParseInNodeContext(node->parent, (const char*)buffer, size, XML_PARSE_NODICT, &results) != XML_ERR_OK) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlParseInNodeContext", + XMLSEC_ERRORS_R_XML_FAILED, + "Failed to parse content"); + return(-1); + } + + /* add new nodes */ + while (results != NULL) { + next = results->next; + xmlAddPrevSibling(node, results); + results = next; + } + + /* remove old node */ + xmlUnlinkNode(node); + + /* return the old node if requested */ + if(replaced != NULL) { + (*replaced) = node; + } else { + xmlFreeNode(node); + } + + return(0); +} + +/** + * xmlSecNodeEncodeAndSetContent: + * @node: the pointer to an XML node. + * @buffer: the pointer to the node content. + * + * Encodes "special" characters in the @buffer and sets the result + * as the node content. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecNodeEncodeAndSetContent(xmlNodePtr node, const xmlChar * buffer) { + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(node->doc != NULL, -1); + + if(buffer != NULL) { + xmlChar * tmp; + + tmp = xmlEncodeSpecialChars(node->doc, buffer); + if (tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlEncodeSpecialChars", + XMLSEC_ERRORS_R_XML_FAILED, + "Failed to encode special characters"); + return(-1); + } + + xmlNodeSetContent(node, tmp); + xmlFree(tmp); + } else { + xmlNodeSetContent(node, NULL); + } + + return(0); +} + +/** + * xmlSecAddIDs: + * @doc: the pointer to an XML document. + * @cur: the pointer to an XML node. + * @ids: the pointer to a NULL terminated list of ID attributes. + * + * Walks thru all children of the @cur node and adds all attributes + * from the @ids list to the @doc document IDs attributes hash. + */ +void +xmlSecAddIDs(xmlDocPtr doc, xmlNodePtr cur, const xmlChar** ids) { + xmlNodePtr children = NULL; + + xmlSecAssert(doc != NULL); + xmlSecAssert(ids != NULL); + + if((cur != NULL) && (cur->type == XML_ELEMENT_NODE)) { + xmlAttrPtr attr; + xmlAttrPtr tmp; + int i; + xmlChar* name; + + for(attr = cur->properties; attr != NULL; attr = attr->next) { + for(i = 0; ids[i] != NULL; ++i) { + if(xmlStrEqual(attr->name, ids[i])) { + name = xmlNodeListGetString(doc, attr->children, 1); + if(name != NULL) { + tmp = xmlGetID(doc, name); + if(tmp == NULL) { + xmlAddID(NULL, doc, name, attr); + } else if(tmp != attr) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_INVALID_DATA, + "id=%s already defined", + xmlSecErrorsSafeString(name)); + } + xmlFree(name); + } + } + } + } + + children = cur->children; + } else if(cur == NULL) { + children = doc->children; + } + + while(children != NULL) { + if(children->type == XML_ELEMENT_NODE) { + xmlSecAddIDs(doc, children, ids); + } + children = children->next; + } +} + +/** + * xmlSecGenerateAndAddID: + * @node: the node to ID attr to. + * @attrName: the ID attr name. + * @prefix: the prefix to add to the generated ID (can be NULL). + * @len: the length of ID. + * + * Generates a unique ID in the format <@prefix>base64-encoded(@len random bytes) + * and puts it in the attribute @attrName. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecGenerateAndAddID(xmlNodePtr node, const xmlChar* attrName, const xmlChar* prefix, xmlSecSize len) { + xmlChar* id; + int count; + + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(attrName != NULL, -1); + + /* we will try 5 times before giving up */ + for(count = 0; count < 5; count++) { + id = xmlSecGenerateID(prefix, len); + if(id == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGenerateID", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + if((node->doc == NULL) || (xmlGetID(node->doc, id) == NULL)) { + /* this is a unique ID in the document and we can use it */ + if(xmlSetProp(node, attrName, id) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSetProp", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(id); + return(-1); + } + + xmlFree(id); + return(0); + } + xmlFree(id); + } + + return(-1); +} + +/** + * xmlSecGenerateID: + * @prefix: the prefix to add to the generated ID (can be NULL). + * @len: the length of ID. + * + * Generates a unique ID in the format <@prefix>base64-encoded(@len random bytes). + * The caller is responsible for freeing returned string using @xmlFree function. + * + * Returns: pointer to generated ID string or NULL if an error occurs. + */ +xmlChar* +xmlSecGenerateID(const xmlChar* prefix, xmlSecSize len) { + xmlSecBuffer buffer; + xmlSecSize i, binLen; + xmlChar* res; + xmlChar* p; + int ret; + + xmlSecAssert2(len > 0, NULL); + + /* we will do base64 decoding later */ + binLen = (3 * len + 1) / 4; + + ret = xmlSecBufferInitialize(&buffer, binLen + 1); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + xmlSecAssert2(xmlSecBufferGetData(&buffer) != NULL, NULL); + xmlSecAssert2(xmlSecBufferGetMaxSize(&buffer) >= binLen, NULL); + + ret = xmlSecBufferSetSize(&buffer, binLen); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + xmlSecAssert2(xmlSecBufferGetSize(&buffer) == binLen, NULL); + + /* create random bytes */ + for(i = 0; i < binLen; i++) { + (xmlSecBufferGetData(&buffer)) [i] = (xmlSecByte) (256.0 * rand() / (RAND_MAX + 1.0)); + } + + /* base64 encode random bytes */ + res = xmlSecBase64Encode(xmlSecBufferGetData(&buffer), xmlSecBufferGetSize(&buffer), 0); + if((res == NULL) || (xmlStrlen(res) == 0)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBase64Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecBufferFinalize(&buffer); + return(NULL); + } + xmlSecBufferFinalize(&buffer); + + /* truncate the generated id attribute if needed */ + if(xmlStrlen(res) > (int)len) { + res[len] = '\0'; + } + + /* we need to cleanup base64 encoded id because ID attr can't have '+' or '/' characters */ + for(p = res; (*p) != '\0'; p++) { + if(((*p) == '+') || ((*p) == '/')) { + (*p) = '_'; + } + } + + /* add prefix if exist */ + if(prefix) { + xmlChar* tmp; + xmlSecSize tmpLen; + + tmpLen = xmlStrlen(prefix) + xmlStrlen(res) + 1; + tmp = xmlMalloc(tmpLen + 1); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFree(res); + return(NULL); + } + + xmlSecStrPrintf(tmp, tmpLen, BAD_CAST "%s%s", prefix, res); + xmlFree(res); + res = tmp; + } else { + /* no prefix: check that ID attribute starts from a letter */ + if(!(((res[0] >= 'A') && (res[0] <= 'Z')) || + ((res[0] >= 'a') && (res[0] <= 'z')))) { + res[0] = 'A'; + } + } + + return(res); +} + + +/** + * xmlSecCreateTree: + * @rootNodeName: the root node name. + * @rootNodeNs: the root node namespace (otpional). + * + * Creates a new XML tree with one root node @rootNodeName. + * + * Returns: pointer to the newly created tree or NULL if an error occurs. + */ +xmlDocPtr +xmlSecCreateTree(const xmlChar* rootNodeName, const xmlChar* rootNodeNs) { + xmlDocPtr doc; + xmlNodePtr root; + xmlNsPtr ns; + + xmlSecAssert2(rootNodeName != NULL, NULL); + + /* create doc */ + doc = xmlNewDoc(BAD_CAST "1.0"); + if(doc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDoc", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(NULL); + } + + /* create root node */ + root = xmlNewDocNode(doc, NULL, rootNodeName, NULL); + if(root == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewDocNode", + XMLSEC_ERRORS_R_XML_FAILED, + "node=Keys"); + xmlFreeDoc(doc); + return(NULL); + } + xmlDocSetRootElement(doc, root); + + /* and set root node namespace */ + ns = xmlNewNs(root, rootNodeNs, NULL); + if(ns == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNewNs", + XMLSEC_ERRORS_R_XML_FAILED, + "ns=%s", + xmlSecErrorsSafeString(rootNodeNs)); + xmlFreeDoc(doc); + return(NULL); + } + xmlSetNs(root, ns); + + return(doc); +} + +/** + * xmlSecIsEmptyNode: + * @node: the node to check + * + * Checks whethere the @node is empty (i.e. has only whitespaces children). + * + * Returns: 1 if @node is empty, 0 otherwise or a negative value if an error occurs. + */ +int +xmlSecIsEmptyNode(xmlNodePtr node) { + xmlChar* content; + int res; + + xmlSecAssert2(node != NULL, -1); + + if(xmlSecGetNextElementNode(node->children) != NULL) { + return(0); + } + + content = xmlNodeGetContent(node); + if(content == NULL) { + return(1); + } + + res = xmlSecIsEmptyString(content); + xmlFree(content); + return(res); +} + +/** + * xmlSecIsEmptyString: + * @str: the string to check + * + * Checks whethere the @str is empty (i.e. has only whitespaces children). + * + * Returns: 1 if @str is empty, 0 otherwise or a negative value if an error occurs. + */ +int +xmlSecIsEmptyString(const xmlChar* str) { + xmlSecAssert2(str != NULL, -1); + + for( ;*str != '\0'; ++str) { + if(!isspace((int)(*str))) { + return(0); + } + } + return(1); +} + +/** + * xmlSecPrintXmlString: + * @fd: the file descriptor to write the XML string to + * @str: the string + * + * Encodes the @str (e.g. replaces '&' with '&') and writes it to @fd. + * + * Returns: he number of bytes transmitted or a negative value if an error occurs. + */ +int +xmlSecPrintXmlString(FILE * fd, const xmlChar * str) { + int res; + + if(str != NULL) { + xmlChar * encoded_str = NULL; + encoded_str = xmlEncodeSpecialChars(NULL, str); + if(encoded_str == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlEncodeSpecialChars", + XMLSEC_ERRORS_R_XML_FAILED, + "string=%s", + xmlSecErrorsSafeString(str)); + return(-1); + } + + res = fprintf(fd, "%s", (const char*)encoded_str); + xmlFree(encoded_str); + } else { + res = fprintf(fd, "NULL"); + } + + if(res < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "fprintf", + XMLSEC_ERRORS_R_IO_FAILED, + "res=%d,errno=%d", + res, errno); + return(-1); + } + return(res); +} + + +/** + * xmlSecGetQName: + * @node: the context node. + * @href: the QName href (can be NULL). + * @local: the QName local part. + * + * Creates QName (prefix:local) from @href and @local in the context of the @node. + * Caller is responsible for freeing returned string with xmlFree. + * + * Returns: qname or NULL if an error occurs. + */ +xmlChar* +xmlSecGetQName(xmlNodePtr node, const xmlChar* href, const xmlChar* local) { + xmlChar* qname; + xmlNsPtr ns; + + xmlSecAssert2(node != NULL, NULL); + xmlSecAssert2(local != NULL, NULL); + + /* we don't want to create namespace node ourselves because + * it might cause collisions */ + ns = xmlSearchNsByHref(node->doc, node, href); + if((ns == NULL) && (href != NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSearchNsByHref", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s,href=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(href)); + return(NULL); + } + + if((ns != NULL) && (ns->prefix != NULL)) { + xmlSecSize len; + + len = xmlStrlen(local) + xmlStrlen(ns->prefix) + 4; + qname = xmlMalloc(len); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlMalloc", + XMLSEC_ERRORS_R_MALLOC_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + return(NULL); + } + xmlSecStrPrintf(qname, len, BAD_CAST "%s:%s", ns->prefix, local); + } else { + qname = xmlStrdup(local); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + return(NULL); + } + } + + + return(qname); +} + + +/************************************************************************* + * + * QName <-> Integer mapping + * + ************************************************************************/ +/** + * xmlSecQName2IntegerGetInfo: + * @info: the qname<->integer mapping information. + * @intValue: the integer value. + * + * Maps integer @intValue to a QName prefix. + * + * Returns: the QName info that is mapped to @intValue or NULL if such value + * is not found. + */ +xmlSecQName2IntegerInfoConstPtr +xmlSecQName2IntegerGetInfo(xmlSecQName2IntegerInfoConstPtr info, int intValue) { + unsigned int ii; + + xmlSecAssert2(info != NULL, NULL); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + if(info[ii].intValue == intValue) { + return(&info[ii]); + } + } + + return(NULL); +} + +/** + * xmlSecQName2IntegerGetInteger: + * @info: the qname<->integer mapping information. + * @qnameHref: the qname href value. + * @qnameLocalPart: the qname local part value. + * @intValue: the pointer to result integer value. + * + * Maps qname qname to an integer and returns it in @intValue. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerGetInteger(xmlSecQName2IntegerInfoConstPtr info, + const xmlChar* qnameHref, const xmlChar* qnameLocalPart, + int* intValue) { + unsigned int ii; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(qnameLocalPart != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) && + xmlStrEqual(info[ii].qnameHref, qnameHref)) { + (*intValue) = info[ii].intValue; + return(0); + } + } + + return(-1); +} + +/** + * xmlSecQName2IntegerGetIntegerFromString: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @qname: the qname string. + * @intValue: the pointer to result integer value. + * + * Converts @qname into integer in context of @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerGetIntegerFromString(xmlSecQName2IntegerInfoConstPtr info, + xmlNodePtr node, const xmlChar* qname, + int* intValue) { + const xmlChar* qnameLocalPart = NULL; + xmlChar* qnamePrefix = NULL; + const xmlChar* qnameHref; + xmlNsPtr ns; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(qname != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + qnameLocalPart = xmlStrchr(qname, ':'); + if(qnameLocalPart != NULL) { + qnamePrefix = xmlStrndup(qname, qnameLocalPart - qname); + if(qnamePrefix == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrndup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + "node=%s,value=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qname)); + return(-1); + } + qnameLocalPart++; + } else { + qnamePrefix = NULL; + qnameLocalPart = qname; + } + + /* search namespace href */ + ns = xmlSearchNs(node->doc, node, qnamePrefix); + if((ns == NULL) && (qnamePrefix != NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSearchNs", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s,qnamePrefix=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnamePrefix)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL; + + /* and finally search for integer */ + ret = xmlSecQName2IntegerGetInteger(info, qnameHref, qnameLocalPart, intValue); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetInteger", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,qnameLocalPart=%s,qnameHref=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnameLocalPart), + xmlSecErrorsSafeString(qnameHref)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(0); +} + + +/** + * xmlSecQName2IntegerGetStringFromInteger: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @intValue: the integer value. + * + * Creates qname string for @intValue in context of given @node. Caller + * is responsible for freeing returned string with @xmlFree. + * + * Returns: pointer to newly allocated string on success or NULL if an error occurs, + */ +xmlChar* +xmlSecQName2IntegerGetStringFromInteger(xmlSecQName2IntegerInfoConstPtr info, + xmlNodePtr node, int intValue) { + xmlSecQName2IntegerInfoConstPtr qnameInfo; + + xmlSecAssert2(info != NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue); + if(qnameInfo == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetInfo", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + intValue); + return(NULL); + } + + return (xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart)); +} + +/** + * xmlSecQName2IntegerNodeRead: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @intValue: the pointer to result integer value. + * + * Reads the content of @node and converts it to an integer using mapping + * from @info. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerNodeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, int* intValue) { + xmlChar* content = NULL; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + content = xmlNodeGetContent(node); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNodeGetContent", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(node->name)); + return(-1); + } + /* todo: trim content? */ + + ret = xmlSecQName2IntegerGetIntegerFromString(info, node, content, intValue); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetIntegerFromString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,value=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(content)); + xmlFree(content); + return(-1); + } + + xmlFree(content); + return(0); +} + +/** + * xmlSecQName2IntegerNodeWrite: + * @info: the qname<->integer mapping information. + * @node: the parent node. + * @nodeName: the child node name. + * @nodeNs: the child node namespace. + * @intValue: the integer value. + * + * Creates new child node in @node and sets its value to @intValue. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerNodeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, + const xmlChar* nodeName, const xmlChar* nodeNs, int intValue) { + xmlNodePtr cur; + xmlChar* qname = NULL; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(nodeName != NULL, -1); + + /* find and build qname */ + qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetStringFromInteger", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + intValue); + return(-1); + } + + cur = xmlSecAddChild(node, nodeName, nodeNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,intValue=%d", + xmlSecErrorsSafeString(nodeName), + intValue); + xmlFree(qname); + return(-1); + } + + xmlNodeSetContent(cur, qname); + xmlFree(qname); + return(0); +} + +/** + * xmlSecQName2IntegerAttributeRead: + * @info: the qname<->integer mapping information. + * @node: the element node. + * @attrName: the attribute name. + * @intValue: the pointer to result integer value. + * + * Gets the value of @attrName atrtibute from @node and converts it to integer + * according to @info. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerAttributeRead(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, + const xmlChar* attrName, int* intValue) { + xmlChar* attrValue; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(attrName != NULL, -1); + xmlSecAssert2(intValue != NULL, -1); + + attrValue = xmlGetProp(node, attrName); + if(attrValue == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlGetProp", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s,attrValue=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName)); + return(-1); + } + /* todo: trim value? */ + + ret = xmlSecQName2IntegerGetIntegerFromString(info, node, attrValue, intValue); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetIntegerFromString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,attrName=%s,attrValue=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName), + xmlSecErrorsSafeString(attrValue)); + xmlFree(attrValue); + return(-1); + } + + xmlFree(attrValue); + return(0); +} + +/** + * xmlSecQName2IntegerAttributeWrite: + * @info: the qname<->integer mapping information. + * @node: the parent node. + * @attrName: the name of attribute. + * @intValue: the integer value. + * + * Converts @intValue to a qname and sets it to the value of + * attribute @attrName in @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2IntegerAttributeWrite(xmlSecQName2IntegerInfoConstPtr info, xmlNodePtr node, + const xmlChar* attrName, int intValue) { + xmlChar* qname; + xmlAttrPtr attr; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(attrName != NULL, -1); + + /* find and build qname */ + qname = xmlSecQName2IntegerGetStringFromInteger(info, node, intValue); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2IntegerGetStringFromInteger", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,attrName=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName), + intValue); + return(-1); + } + + attr = xmlSetProp(node, attrName, qname); + if(attr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChildNode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,attrName=%s,intValue=%d", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(attrName), + intValue); + xmlFree(qname); + return(-1); + } + + xmlFree(qname); + return(0); +} + +/** + * xmlSecQName2IntegerDebugDump: + * @info: the qname<->integer mapping information. + * @intValue: the integer value. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints @intValue into @output. + */ +void +xmlSecQName2IntegerDebugDump(xmlSecQName2IntegerInfoConstPtr info, int intValue, + const xmlChar* name, FILE* output) { + xmlSecQName2IntegerInfoConstPtr qnameInfo; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue); + if(qnameInfo != NULL) { + fprintf(output, "== %s: %d (name=\"%s\", href=\"%s\")\n", name, intValue, + (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL, + (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL); + } +} + +/** + * xmlSecQName2IntegerDebugXmlDump: + * @info: the qname<->integer mapping information. + * @intValue: the integer value. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints @intValue into @output in XML format. + */ +void +xmlSecQName2IntegerDebugXmlDump(xmlSecQName2IntegerInfoConstPtr info, int intValue, + const xmlChar* name, FILE* output) { + xmlSecQName2IntegerInfoConstPtr qnameInfo; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + qnameInfo = xmlSecQName2IntegerGetInfo(info, intValue); + if(qnameInfo != NULL) { + fprintf(output, "<%s value=\"%d\" href=\"%s\">%s<%s>\n", name, intValue, + (qnameInfo->qnameHref) ? qnameInfo->qnameHref : BAD_CAST NULL, + (qnameInfo->qnameLocalPart) ? qnameInfo->qnameLocalPart : BAD_CAST NULL, + name); + } +} + + +/************************************************************************* + * + * QName <-> Bits mask mapping + * + ************************************************************************/ +/** + * xmlSecQName2BitMaskGetInfo: + * @info: the qname<->bit mask mapping information. + * @mask: the bit mask. + * + * Converts @mask to qname. + * + * Returns: pointer to the qname info for @mask or NULL if mask is unknown. + */ +xmlSecQName2BitMaskInfoConstPtr +xmlSecQName2BitMaskGetInfo(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask) { + unsigned int ii; + + xmlSecAssert2(info != NULL, NULL); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + xmlSecAssert2(info[ii].mask != 0, NULL); + if(info[ii].mask == mask) { + return(&info[ii]); + } + } + + return(NULL); +} + +/** + * xmlSecQName2BitMaskGetBitMask: + * @info: the qname<->bit mask mapping information. + * @qnameHref: the qname Href value. + * @qnameLocalPart: the qname LocalPart value. + * @mask: the pointer to result mask. + * + * Converts @qnameLocalPart to @mask. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskGetBitMask(xmlSecQName2BitMaskInfoConstPtr info, + const xmlChar* qnameHref, const xmlChar* qnameLocalPart, + xmlSecBitMask* mask) { + unsigned int ii; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(qnameLocalPart != NULL, -1); + xmlSecAssert2(mask != NULL, -1); + + for(ii = 0; info[ii].qnameLocalPart != NULL; ii++) { + xmlSecAssert2(info[ii].mask != 0, -1); + if(xmlStrEqual(info[ii].qnameLocalPart, qnameLocalPart) && + xmlStrEqual(info[ii].qnameHref, qnameHref)) { + + (*mask) = info[ii].mask; + return(0); + } + } + + return(-1); +} + +/** + * xmlSecQName2BitMaskGetBitMaskFromString: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @qname: the qname string. + * @mask: the pointer to result msk value. + * + * Converts @qname into integer in context of @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskGetBitMaskFromString(xmlSecQName2BitMaskInfoConstPtr info, + xmlNodePtr node, const xmlChar* qname, + xmlSecBitMask* mask) { + const xmlChar* qnameLocalPart = NULL; + xmlChar* qnamePrefix = NULL; + const xmlChar* qnameHref; + xmlNsPtr ns; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(qname != NULL, -1); + xmlSecAssert2(mask != NULL, -1); + + qnameLocalPart = xmlStrchr(qname, ':'); + if(qnameLocalPart != NULL) { + qnamePrefix = xmlStrndup(qname, qnameLocalPart - qname); + if(qnamePrefix == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrndup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + "node=%s,value=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qname)); + return(-1); + } + qnameLocalPart++; + } else { + qnamePrefix = NULL; + qnameLocalPart = qname; + } + + /* search namespace href */ + ns = xmlSearchNs(node->doc, node, qnamePrefix); + if((ns == NULL) && (qnamePrefix != NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSearchNs", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s,qnamePrefix=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnamePrefix)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + qnameHref = (ns != NULL) ? ns->href : BAD_CAST NULL; + + /* and finally search for integer */ + ret = xmlSecQName2BitMaskGetBitMask(info, qnameHref, qnameLocalPart, mask); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskGetBitMask", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,qnameLocalPart=%s,qnameHref=%s", + xmlSecErrorsSafeString(node->name), + xmlSecErrorsSafeString(qnameLocalPart), + xmlSecErrorsSafeString(qnameHref)); + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(-1); + } + + if(qnamePrefix != NULL) { + xmlFree(qnamePrefix); + } + return(0); +} + + +/** + * xmlSecQName2BitMaskGetStringFromBitMask: + * @info: the qname<->integer mapping information. + * @node: the pointer to node. + * @mask: the mask. + * + * Creates qname string for @mask in context of given @node. Caller + * is responsible for freeing returned string with @xmlFree. + * + * Returns: pointer to newly allocated string on success or NULL if an error occurs, + */ +xmlChar* +xmlSecQName2BitMaskGetStringFromBitMask(xmlSecQName2BitMaskInfoConstPtr info, + xmlNodePtr node, xmlSecBitMask mask) { + xmlSecQName2BitMaskInfoConstPtr qnameInfo; + + xmlSecAssert2(info != NULL, NULL); + xmlSecAssert2(node != NULL, NULL); + + qnameInfo = xmlSecQName2BitMaskGetInfo(info, mask); + if(qnameInfo == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskGetInfo", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "node=%s,mask=%d", + xmlSecErrorsSafeString(node->name), + mask); + return(NULL); + } + + return(xmlSecGetQName(node, qnameInfo->qnameHref, qnameInfo->qnameLocalPart)); +} + +/** + * xmlSecQName2BitMaskNodesRead: + * @info: the qname<->bit mask mapping information. + * @node: the start. + * @nodeName: the mask nodes name. + * @nodeNs: the mask nodes namespace. + * @stopOnUnknown: if this flag is set then function exits if unknown + * value was found. + * @mask: the pointer to result mask. + * + * Reads <@nodeNs:@nodeName> elements and puts the result bit mask + * into @mask. When function exits, @node points to the first element node + * after all the <@nodeNs:@nodeName> elements. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskNodesRead(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr* node, + const xmlChar* nodeName, const xmlChar* nodeNs, + int stopOnUnknown, xmlSecBitMask* mask) { + xmlNodePtr cur; + xmlChar* content; + xmlSecBitMask tmp; + int ret; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(mask != NULL, -1); + + (*mask) = 0; + cur = (*node); + while((cur != NULL) && (xmlSecCheckNodeName(cur, nodeName, nodeNs))) { + content = xmlNodeGetContent(cur); + if(content == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlNodeGetContent", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(cur->name)); + return(-1); + } + + ret = xmlSecQName2BitMaskGetBitMaskFromString(info, cur, content, &tmp); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskGetBitMaskFromString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "value=%s", + xmlSecErrorsSafeString(content)); + xmlFree(content); + return(-1); + } + xmlFree(content); + + if((stopOnUnknown != 0) && (tmp == 0)) { + /* todo: better error */ + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecQName2BitMaskGetBitMaskFromString", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "value=%s", + xmlSecErrorsSafeString(content)); + return(-1); + } + + (*mask) |= tmp; + cur = xmlSecGetNextElementNode(cur->next); + } + + (*node) = cur; + return(0); +} + +/** + * xmlSecQName2BitMaskNodesWrite: + * @info: the qname<->bit mask mapping information. + * @node: the parent element for mask nodes. + * @nodeName: the mask nodes name. + * @nodeNs: the mask nodes namespace. + * @mask: the bit mask. + * + * Writes <@nodeNs:@nodeName> elemnts with values from @mask to @node. + * + * Returns: 0 on success or a negative value if an error occurs, + */ +int +xmlSecQName2BitMaskNodesWrite(xmlSecQName2BitMaskInfoConstPtr info, xmlNodePtr node, + const xmlChar* nodeName, const xmlChar* nodeNs, + xmlSecBitMask mask) { + unsigned int ii; + + xmlSecAssert2(info != NULL, -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(nodeName != NULL, -1); + + for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) { + xmlSecAssert2(info[ii].mask != 0, -1); + + if((mask & info[ii].mask) != 0) { + xmlNodePtr cur; + xmlChar* qname; + + qname = xmlSecGetQName(node, info[ii].qnameHref, info[ii].qnameLocalPart); + if(qname == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecGetQName", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(nodeName)); + return(-1); + } + + cur = xmlSecAddChild(node, nodeName, nodeNs); + if(cur == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecAddChild", + XMLSEC_ERRORS_R_XML_FAILED, + "node=%s", + xmlSecErrorsSafeString(nodeName)); + xmlFree(qname); + return(-1); + } + + xmlNodeSetContent(cur, qname); + xmlFree(qname); + } + } + return(0); +} + +/** + * xmlSecQName2BitMaskDebugDump: + * @info: the qname<->bit mask mapping information. + * @mask: the bit mask. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints debug information about @mask to @output. + */ +void +xmlSecQName2BitMaskDebugDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask, + const xmlChar* name, FILE* output) { + unsigned int ii; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + if(mask == 0) { + return; + } + + fprintf(output, "== %s (0x%08x): ", name, mask); + for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) { + xmlSecAssert(info[ii].mask != 0); + + if((mask & info[ii].mask) != 0) { + fprintf(output, "name=\"%s\" (href=\"%s\"),", info[ii].qnameLocalPart, info[ii].qnameHref); + } + } + fprintf(output, "\n"); +} + +/** + * xmlSecQName2BitMaskDebugXmlDump: + * @info: the qname<->bit mask mapping information. + * @mask: the bit mask. + * @name: the value name to print. + * @output: the pointer to output FILE. + * + * Prints debug information about @mask to @output in XML format. + */ +void +xmlSecQName2BitMaskDebugXmlDump(xmlSecQName2BitMaskInfoConstPtr info, xmlSecBitMask mask, + const xmlChar* name, FILE* output) { + unsigned int ii; + + xmlSecAssert(info != NULL); + xmlSecAssert(name != NULL); + xmlSecAssert(output != NULL); + + if(mask == 0) { + return; + } + + fprintf(output, "<%sList>\n", name); + for(ii = 0; (mask != 0) && (info[ii].qnameLocalPart != NULL); ii++) { + xmlSecAssert(info[ii].mask != 0); + + if((mask & info[ii].mask) != 0) { + fprintf(output, "<%s href=\"%s\">%s</%s>\n", name, + info[ii].qnameHref, info[ii].qnameLocalPart, name); + } + } + fprintf(output, "</%sList>\n", name); +} + + + + diff --git a/src/xpath.c b/src/xpath.c new file mode 100644 index 00000000..8b0b4f8e --- /dev/null +++ b/src/xpath.c @@ -0,0 +1,1148 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * XPath transform + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxml/xpath.h> +#include <libxml/xpathInternals.h> +#include <libxml/xpointer.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/list.h> +#include <xmlsec/transforms.h> +#include <xmlsec/errors.h> + + +/************************************************************************** + * + * xmlSecXPathHereFunction: + * @ctxt: the ponter to XPath context. + * @nargs: the arguments nubmer. + * + * The implementation of XPath "here()" function. + * See xmlXPtrHereFunction() in xpointer.c. the only change is that + * we return NodeSet instead of NodeInterval. + * + *****************************************************************************/ +static void +xmlSecXPathHereFunction(xmlXPathParserContextPtr ctxt, int nargs) { + CHECK_ARITY(0); + + if((ctxt == NULL) || (ctxt->context == NULL) || (ctxt->context->here == NULL)) { + XP_ERROR(XPTR_SYNTAX_ERROR); + } + valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->here)); +} + +/************************************************************************** + * + * XPath/XPointer data + * + *****************************************************************************/ +typedef struct _xmlSecXPathData xmlSecXPathData, + *xmlSecXPathDataPtr; +typedef enum { + xmlSecXPathDataTypeXPath, + xmlSecXPathDataTypeXPath2, + xmlSecXPathDataTypeXPointer +} xmlSecXPathDataType; + +struct _xmlSecXPathData { + xmlSecXPathDataType type; + xmlXPathContextPtr ctx; + xmlChar* expr; + xmlSecNodeSetOp nodeSetOp; + xmlSecNodeSetType nodeSetType; +}; + +static xmlSecXPathDataPtr xmlSecXPathDataCreate (xmlSecXPathDataType type); +static void xmlSecXPathDataDestroy (xmlSecXPathDataPtr data); +static int xmlSecXPathDataSetExpr (xmlSecXPathDataPtr data, + const xmlChar* expr); +static int xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, + xmlNodePtr node); +static int xmlSecXPathDataNodeRead (xmlSecXPathDataPtr data, + xmlNodePtr node); +static xmlSecNodeSetPtr xmlSecXPathDataExecute (xmlSecXPathDataPtr data, + xmlDocPtr doc, + xmlNodePtr hereNode); + +static xmlSecXPathDataPtr +xmlSecXPathDataCreate(xmlSecXPathDataType type) { + xmlSecXPathDataPtr data; + + data = (xmlSecXPathDataPtr) xmlMalloc(sizeof(xmlSecXPathData)); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "sizeof(xmlSecXPathData)=%d", + sizeof(xmlSecXPathData)); + return(NULL); + } + memset(data, 0, sizeof(xmlSecXPathData)); + + data->type = type; + data->nodeSetType = xmlSecNodeSetTree; + + /* create xpath or xpointer context */ + switch(data->type) { + case xmlSecXPathDataTypeXPath: + case xmlSecXPathDataTypeXPath2: + data->ctx = xmlXPathNewContext(NULL); /* we'll set doc in the context later */ + if(data->ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlXPathNewContext", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(NULL); + } + break; + case xmlSecXPathDataTypeXPointer: + data->ctx = xmlXPtrNewContext(NULL, NULL, NULL); /* we'll set doc in the context later */ + if(data->ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlXPtrNewContext", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(NULL); + } + break; + } + + return(data); +} + +static void +xmlSecXPathDataDestroy(xmlSecXPathDataPtr data) { + xmlSecAssert(data != NULL); + + if(data->expr != NULL) { + xmlFree(data->expr); + } + if(data->ctx != NULL) { + xmlXPathFreeContext(data->ctx); + } + memset(data, 0, sizeof(xmlSecXPathData)); + xmlFree(data); +} + +static int +xmlSecXPathDataSetExpr(xmlSecXPathDataPtr data, const xmlChar* expr) { + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(data->expr == NULL, -1); + xmlSecAssert2(data->ctx != NULL, -1); + xmlSecAssert2(expr != NULL, -1); + + data->expr = xmlStrdup(expr); + if(data->expr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_STRDUP_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + + +static int +xmlSecXPathDataRegisterNamespaces(xmlSecXPathDataPtr data, xmlNodePtr node) { + xmlNodePtr cur; + xmlNsPtr ns; + int ret; + + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(data->ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + /* register namespaces */ + for(cur = node; cur != NULL; cur = cur->parent) { + for(ns = cur->nsDef; ns != NULL; ns = ns->next) { + /* check that we have no other namespace with same prefix already */ + if((ns->prefix != NULL) && (xmlXPathNsLookup(data->ctx, ns->prefix) == NULL)){ + ret = xmlXPathRegisterNs(data->ctx, ns->prefix, ns->href); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlXPathRegisterNs", + XMLSEC_ERRORS_R_XML_FAILED, + "href=%s;prefix=%s", + xmlSecErrorsSafeString(ns->href), + xmlSecErrorsSafeString(ns->prefix)); + return(-1); + } + } + } + } + + return(0); +} + +static int +xmlSecXPathDataNodeRead(xmlSecXPathDataPtr data, xmlNodePtr node) { + int ret; + + xmlSecAssert2(data != NULL, -1); + xmlSecAssert2(data->expr == NULL, -1); + xmlSecAssert2(data->ctx != NULL, -1); + xmlSecAssert2(node != NULL, -1); + + ret = xmlSecXPathDataRegisterNamespaces (data, node); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXPathDataRegisterNamespaces", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* read node content and set expr */ + data->expr = xmlNodeGetContent(node); + if(data->expr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + xmlSecErrorsSafeString(xmlSecNodeGetName(node)), + XMLSEC_ERRORS_R_INVALID_NODE_CONTENT, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static xmlSecNodeSetPtr +xmlSecXPathDataExecute(xmlSecXPathDataPtr data, xmlDocPtr doc, xmlNodePtr hereNode) { + xmlXPathObjectPtr xpathObj = NULL; + xmlSecNodeSetPtr nodes; + + xmlSecAssert2(data != NULL, NULL); + xmlSecAssert2(data->expr != NULL, NULL); + xmlSecAssert2(data->ctx != NULL, NULL); + xmlSecAssert2(doc != NULL, NULL); + xmlSecAssert2(hereNode != NULL, NULL); + + /* do not forget to set the doc */ + data->ctx->doc = doc; + + /* here function works only on the same document */ + if(hereNode->doc == doc) { + xmlXPathRegisterFunc(data->ctx, (xmlChar *)"here", xmlSecXPathHereFunction); + data->ctx->here = hereNode; + data->ctx->xptr = 1; + } + + /* execute xpath or xpointer expression */ + switch(data->type) { + case xmlSecXPathDataTypeXPath: + case xmlSecXPathDataTypeXPath2: + xpathObj = xmlXPathEvalExpression(data->expr, data->ctx); + if(xpathObj == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlXPathEvalExpression", + XMLSEC_ERRORS_R_XML_FAILED, + "expr=%s", + xmlSecErrorsSafeString(data->expr)); + return(NULL); + } + break; + case xmlSecXPathDataTypeXPointer: + xpathObj = xmlXPtrEval(data->expr, data->ctx); + if(xpathObj == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlXPtrEval", + XMLSEC_ERRORS_R_XML_FAILED, + "expr=%s", + xmlSecErrorsSafeString(data->expr)); + return(NULL); + } + break; + } + + nodes = xmlSecNodeSetCreate(doc, xpathObj->nodesetval, data->nodeSetType); + if(nodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "type=%d", data->nodeSetType); + xmlXPathFreeObject(xpathObj); + return(NULL); + } + xpathObj->nodesetval = NULL; + xmlXPathFreeObject(xpathObj); + + return(nodes); +} + + +/************************************************************************** + * + * XPath data list + * + *****************************************************************************/ +#define xmlSecXPathDataListId \ + xmlSecXPathDataListGetKlass() +static xmlSecPtrListId xmlSecXPathDataListGetKlass (void); +static xmlSecNodeSetPtr xmlSecXPathDataListExecute (xmlSecPtrListPtr dataList, + xmlDocPtr doc, + xmlNodePtr hereNode, + xmlSecNodeSetPtr nodes); + +static xmlSecPtrListKlass xmlSecXPathDataListKlass = { + BAD_CAST "xpath-data-list", + NULL, /* xmlSecPtrDuplicateItemMethod duplicateItem; */ + (xmlSecPtrDestroyItemMethod)xmlSecXPathDataDestroy, /* xmlSecPtrDestroyItemMethod destroyItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugDumpItem; */ + NULL, /* xmlSecPtrDebugDumpItemMethod debugXmlDumpItem; */ +}; + +static xmlSecPtrListId +xmlSecXPathDataListGetKlass(void) { + return(&xmlSecXPathDataListKlass); +} + +static xmlSecNodeSetPtr +xmlSecXPathDataListExecute(xmlSecPtrListPtr dataList, xmlDocPtr doc, + xmlNodePtr hereNode, xmlSecNodeSetPtr nodes) { + xmlSecXPathDataPtr data; + xmlSecNodeSetPtr res, tmp, tmp2; + xmlSecSize pos; + + xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), NULL); + xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, NULL); + xmlSecAssert2(doc != NULL, NULL); + xmlSecAssert2(hereNode != NULL, NULL); + + res = nodes; + for(pos = 0; pos < xmlSecPtrListGetSize(dataList); ++pos) { + data = (xmlSecXPathDataPtr)xmlSecPtrListGetItem(dataList, pos); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecPtrListGetItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "pos=%d", pos); + if((res != NULL) && (res != nodes)) { + xmlSecNodeSetDestroy(res); + } + return(NULL); + } + + tmp = xmlSecXPathDataExecute(data, doc, hereNode); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecXPathDataExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + if((res != NULL) && (res != nodes)) { + xmlSecNodeSetDestroy(res); + } + return(NULL); + } + + tmp2 = xmlSecNodeSetAdd(res, tmp, data->nodeSetOp); + if(tmp2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNodeSetAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "xmlSecNodeSetIntersection"); + if((res != NULL) && (res != nodes)) { + xmlSecNodeSetDestroy(res); + } + xmlSecNodeSetDestroy(tmp); + return(NULL); + } + res = tmp2; + } + + return(res); +} + +/****************************************************************************** + * + * XPath/XPointer transforms + * + * xmlSecXPathDataList is located after xmlSecTransform structure + * + *****************************************************************************/ +#define xmlSecXPathTransformSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecPtrList)) +#define xmlSecXPathTransformGetDataList(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecXPathTransformSize)) ? \ + (xmlSecPtrListPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \ + (xmlSecPtrListPtr)NULL) +#define xmlSecTransformXPathCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecTransformXPathId) || \ + xmlSecTransformCheckId((transform), xmlSecTransformXPath2Id) || \ + xmlSecTransformCheckId((transform), xmlSecTransformXPointerId)) + +static int xmlSecTransformXPathInitialize (xmlSecTransformPtr transform); +static void xmlSecTransformXPathFinalize (xmlSecTransformPtr transform); +static int xmlSecTransformXPathExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static int +xmlSecTransformXPathInitialize(xmlSecTransformPtr transform) { + xmlSecPtrListPtr dataList; + int ret; + + xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1); + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert2(dataList != NULL, -1); + + ret = xmlSecPtrListInitialize(dataList, xmlSecXPathDataListId); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +xmlSecTransformXPathFinalize(xmlSecTransformPtr transform) { + xmlSecPtrListPtr dataList; + + xmlSecAssert(xmlSecTransformXPathCheckId(transform)); + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId)); + + xmlSecPtrListFinalize(dataList); +} + +static int +xmlSecTransformXPathExecute(xmlSecTransformPtr transform, int last, + xmlSecTransformCtxPtr transformCtx) { + xmlSecPtrListPtr dataList; + xmlDocPtr doc; + + xmlSecAssert2(xmlSecTransformXPathCheckId(transform), -1); + xmlSecAssert2(transform->hereNode != NULL, -1); + xmlSecAssert2(transform->outNodes == NULL, -1); + xmlSecAssert2(last != 0, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); + xmlSecAssert2(xmlSecPtrListGetSize(dataList) > 0, -1); + + doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc; + xmlSecAssert2(doc != NULL, -1); + + transform->outNodes = xmlSecXPathDataListExecute(dataList, doc, + transform->hereNode, transform->inNodes); + if(transform->outNodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataExecute", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +/****************************************************************************** + * + * XPath transform + * + *****************************************************************************/ +static int xmlSecTransformXPathNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecTransformXPathKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecXPathTransformSize, /* xmlSecSize objSize */ + + xmlSecNameXPath, /* const xmlChar* name; */ + xmlSecXPathNs, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecTransformXPathNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + NULL, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformXPathGetKlass: + * + * The XPath transform evaluates given XPath expression and + * intersects the result with the previous nodes set. See + * http://www.w3.org/TR/xmldsig-core/#sec-XPath for more details. + * + * Returns: XPath transform id. + */ +xmlSecTransformId +xmlSecTransformXPathGetKlass(void) { + return(&xmlSecTransformXPathKlass); +} + +static const char xpathPattern[] = "(//. | //@* | //namespace::*)[boolean(%s)]"; +static int +xmlSecTransformXPathNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecPtrListPtr dataList; + xmlSecXPathDataPtr data; + xmlNodePtr cur; + xmlChar* tmp; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPathId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); + xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); + + /* there is only one required node */ + cur = xmlSecGetNextElementNode(node->children); + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPath, xmlSecDSigNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeXPath)); + return(-1); + } + + /* read information from the node */ + data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecXPathDataNodeRead(data, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* append it to the list */ + ret = xmlSecPtrListAdd(dataList, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* create full XPath expression */ + xmlSecAssert2(data->expr != NULL, -1); + tmp = (xmlChar*) xmlMalloc(sizeof(xmlChar) * (xmlStrlen(data->expr) + + strlen(xpathPattern) + 1)); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "size=%d", + xmlStrlen(data->expr) + strlen(xpathPattern) + 1); + return(-1); + } + sprintf((char*)tmp, xpathPattern, (char*)data->expr); + xmlFree(data->expr); + data->expr = tmp; + + /* set correct node set type and operation */ + data->nodeSetOp = xmlSecNodeSetIntersection; + data->nodeSetType = xmlSecNodeSetNormal; + + /* check that we have nothing else */ + 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); +} + +/****************************************************************************** + * + * XPath2 transform + * + *****************************************************************************/ +static int xmlSecTransformXPath2NodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static xmlSecTransformKlass xmlSecTransformXPath2Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecXPathTransformSize, /* xmlSecSize objSize */ + + xmlSecNameXPath2, /* const xmlChar* name; */ + xmlSecXPath2Ns, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecTransformXPath2NodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + NULL, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformXPath2GetKlass: + * + * The XPath2 transform (http://www.w3.org/TR/xmldsig-filter2/). + * + * Returns: XPath2 transform klass. + */ +xmlSecTransformId +xmlSecTransformXPath2GetKlass(void) { + return(&xmlSecTransformXPath2Klass); +} + +static int +xmlSecTransformXPath2NodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecPtrListPtr dataList; + xmlSecXPathDataPtr data; + xmlNodePtr cur; + xmlChar* op; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPath2Id), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); + xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); + + /* There are only xpath nodes */ + cur = xmlSecGetNextElementNode(node->children); + while((cur != NULL) && xmlSecCheckNodeName(cur, xmlSecNodeXPath2, xmlSecXPath2Ns)) { + /* read information from the node */ + data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPath2); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecXPathDataNodeRead(data, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* append it to the list */ + ret = xmlSecPtrListAdd(dataList, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* set correct node set type and operation */ + data->nodeSetType = xmlSecNodeSetTree; + op = xmlGetProp(cur, xmlSecAttrFilter); + if(op == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecAttrFilter), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "node=%s", + xmlSecErrorsSafeString(xmlSecNodeGetName(cur))); + return(-1); + } + if(xmlStrEqual(op, xmlSecXPath2FilterIntersect)) { + data->nodeSetOp = xmlSecNodeSetIntersection; + } else if(xmlStrEqual(op, xmlSecXPath2FilterSubtract)) { + data->nodeSetOp = xmlSecNodeSetSubtraction; + } else if(xmlStrEqual(op, xmlSecXPath2FilterUnion)) { + data->nodeSetOp = xmlSecNodeSetUnion; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecAttrFilter), + XMLSEC_ERRORS_R_INVALID_NODE_ATTRIBUTE, + "filter=%s", + xmlSecErrorsSafeString(op)); + xmlFree(op); + return(-1); + } + xmlFree(op); + + cur = xmlSecGetNextElementNode(cur->next); + } + + /* check that we have nothing else */ + 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); +} + +/****************************************************************************** + * + * XPointer transform + * + *****************************************************************************/ +static int xmlSecTransformXPointerNodeRead (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static xmlSecTransformKlass xmlSecTransformXPointerKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecXPathTransformSize, /* xmlSecSize objSize */ + + xmlSecNameXPointer, /* const xmlChar* name; */ + xmlSecXPointerNs, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + xmlSecTransformXPathInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformXPathFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecTransformXPointerNodeRead, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + NULL, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecTransformXPathExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformXPointerGetKlass: + * + * The XPointer transform klass + * (http://www.ietf.org/internet-drafts/draft-eastlake-xmldsig-uri-02.txt). + * + * Returns: XPointer transform klass. + */ +xmlSecTransformId +xmlSecTransformXPointerGetKlass(void) { + return(&xmlSecTransformXPointerKlass); +} + +/** + * xmlSecTransformXPointerSetExpr: + * @transform: the pointer to XPointer transform. + * @expr: the XPointer expression. + * @nodeSetType: the type of evaluated XPointer expression. + * @hereNode: the pointer to "here" node. + * + * Sets the XPointer expression for an XPointer @transform. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformXPointerSetExpr(xmlSecTransformPtr transform, const xmlChar* expr, + xmlSecNodeSetType nodeSetType, xmlNodePtr hereNode) { + xmlSecPtrListPtr dataList; + xmlSecXPathDataPtr data; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1); + xmlSecAssert2(transform->hereNode == NULL, -1); + xmlSecAssert2(expr != NULL, -1); + xmlSecAssert2(hereNode != NULL, -1); + + transform->hereNode = hereNode; + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); + xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); + + data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecXPathDataRegisterNamespaces(data, hereNode); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataRegisterNamespaces", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + ret = xmlSecXPathDataSetExpr(data, expr); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataSetExpr", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* append it to the list */ + ret = xmlSecPtrListAdd(dataList, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* set correct node set type and operation */ + data->nodeSetOp = xmlSecNodeSetIntersection; + data->nodeSetType = nodeSetType; + + return(0); +} + +static int +xmlSecTransformXPointerNodeRead(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecPtrListPtr dataList; + xmlSecXPathDataPtr data; + xmlNodePtr cur; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXPointerId), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + dataList = xmlSecXPathTransformGetDataList(transform); + xmlSecAssert2(xmlSecPtrListCheckId(dataList, xmlSecXPathDataListId), -1); + xmlSecAssert2(xmlSecPtrListGetSize(dataList) == 0, -1); + + /* there is only one required node */ + cur = xmlSecGetNextElementNode(node->children); + if((cur == NULL) || (!xmlSecCheckNodeName(cur, xmlSecNodeXPointer, xmlSecXPointerNs))) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + xmlSecErrorsSafeString(xmlSecNodeGetName(cur)), + XMLSEC_ERRORS_R_INVALID_NODE, + "expected=%s", + xmlSecErrorsSafeString(xmlSecNodeXPath)); + return(-1); + } + + /* read information from the node */ + data = xmlSecXPathDataCreate(xmlSecXPathDataTypeXPointer); + if(data == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecXPathDataNodeRead(data, cur); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXPathDataNodeRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* append it to the list */ + ret = xmlSecPtrListAdd(dataList, data); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecPtrListAdd", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlSecXPathDataDestroy(data); + return(-1); + } + + /* set correct node set type and operation */ + data->nodeSetOp = xmlSecNodeSetIntersection; + data->nodeSetType = xmlSecNodeSetTree; + + /* check that we have nothing else */ + 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); +} + + +/****************************************************************************** + * + * Visa3DHack transform + * + *****************************************************************************/ +#define xmlSecVisa3DHackTransformSize \ + (sizeof(xmlSecTransform) + sizeof(xmlChar*)) +#define xmlSecVisa3DHackTransformGetIDPtr(transform) \ + ((xmlSecTransformCheckSize((transform), xmlSecVisa3DHackTransformSize)) ? \ + (xmlChar**)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform)) : \ + (xmlChar**)NULL) +#define xmlSecTransformVisa3DHackCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecTransformVisa3DHackId)) + +static int xmlSecTransformVisa3DHackInitialize (xmlSecTransformPtr transform); +static void xmlSecTransformVisa3DHackFinalize (xmlSecTransformPtr transform); +static int xmlSecTransformVisa3DHackExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); + +static xmlSecTransformKlass xmlSecTransformVisa3DHackKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecVisa3DHackTransformSize, /* xmlSecSize objSize */ + + BAD_CAST "Visa3DHackTransform", /* const xmlChar* name; */ + NULL, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecTransformUsage usage; */ + + xmlSecTransformVisa3DHackInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecTransformVisa3DHackFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + NULL, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + NULL, /* xmlSecTransformPushBinMethod pushBin; */ + NULL, /* xmlSecTransformPopBinMethod popBin; */ + xmlSecTransformDefaultPushXml, /* xmlSecTransformPushXmlMethod pushXml; */ + xmlSecTransformDefaultPopXml, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecTransformVisa3DHackExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformVisa3DHackGetKlass: + * + * The Visa3DHack transform klass. The only reason why we need this + * is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows + * invalid XPointer expressions in the URI attribute. Since we couldn't evaluate + * such expressions thru XPath/XPointer engine, we need to have this hack here. + * + * Returns: Visa3DHack transform klass. + */ +xmlSecTransformId +xmlSecTransformVisa3DHackGetKlass(void) { + return(&xmlSecTransformVisa3DHackKlass); +} + +/** + * xmlSecTransformVisa3DHackSetID: + * @transform: the pointer to Visa3DHack transform. + * @id: the ID value. + * + * Sets the ID value for an Visa3DHack @transform. + * + * Returns: 0 on success or a negative value if an error occurs. + */ +int +xmlSecTransformVisa3DHackSetID(xmlSecTransformPtr transform, const xmlChar* id) { + xmlChar** idPtr; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformVisa3DHackId), -1); + xmlSecAssert2(id != NULL, -1); + + idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform); + xmlSecAssert2(idPtr != NULL, -1); + xmlSecAssert2((*idPtr) == NULL, -1); + + (*idPtr) = xmlStrdup(id); + if((*idPtr) == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static int +xmlSecTransformVisa3DHackInitialize(xmlSecTransformPtr transform) { + xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1); + + return(0); +} + +static void +xmlSecTransformVisa3DHackFinalize(xmlSecTransformPtr transform) { + xmlChar** idPtr; + + xmlSecAssert(xmlSecTransformVisa3DHackCheckId(transform)); + + idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform); + xmlSecAssert(idPtr != NULL); + + if((*idPtr) != NULL) { + xmlFree((*idPtr)); + } + (*idPtr) = NULL; +} + +static int +xmlSecTransformVisa3DHackExecute(xmlSecTransformPtr transform, int last, + xmlSecTransformCtxPtr transformCtx) { + xmlChar** idPtr; + xmlDocPtr doc; + xmlAttrPtr attr; + xmlNodeSetPtr nodeSet; + + xmlSecAssert2(xmlSecTransformVisa3DHackCheckId(transform), -1); + xmlSecAssert2(transform->outNodes == NULL, -1); + xmlSecAssert2(last != 0, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + idPtr = xmlSecVisa3DHackTransformGetIDPtr(transform); + xmlSecAssert2(idPtr != NULL, -1); + xmlSecAssert2((*idPtr) != NULL, -1); + + doc = (transform->inNodes != NULL) ? transform->inNodes->doc : transform->hereNode->doc; + xmlSecAssert2(doc != NULL, -1); + + attr = xmlGetID(doc, (*idPtr)); + if((attr == NULL) || (attr->parent == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlGetID", + XMLSEC_ERRORS_R_XML_FAILED, + "id=\"%s\"", + xmlSecErrorsSafeString((*idPtr))); + return(-1); + } + + nodeSet = xmlXPathNodeSetCreate(attr->parent); + if(nodeSet == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlXPathNodeSetCreate", + XMLSEC_ERRORS_R_XML_FAILED, + "id=\"%s\"", + xmlSecErrorsSafeString((*idPtr))); + return(-1); + } + + transform->outNodes = xmlSecNodeSetCreate(doc, nodeSet, xmlSecNodeSetTreeWithoutComments); + if(transform->outNodes == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecNodeSetCreate", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlXPathFreeNodeSet(nodeSet); + return(-1); + } + return(0); +} + + + diff --git a/src/xslt.c b/src/xslt.c new file mode 100644 index 00000000..e5e52685 --- /dev/null +++ b/src/xslt.c @@ -0,0 +1,518 @@ +/** + * XML Security Library (http://www.aleksey.com/xmlsec). + * + * XSLT Transform (http://www.w3.org/TR/xmldsig-core/#sec-XSLT) + * + * This is free software; see Copyright file in the source + * distribution for preciese wording. + * + * Copyright (C) 2002-2003 Aleksey Sanin <aleksey@aleksey.com> + */ +#include "globals.h" + +#ifndef XMLSEC_NO_XSLT + +#include <stdlib.h> +#include <string.h> + +#include <libxml/tree.h> +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> + +#include <xmlsec/xmlsec.h> +#include <xmlsec/xmltree.h> +#include <xmlsec/keys.h> +#include <xmlsec/transforms.h> +#include <xmlsec/keys.h> +#include <xmlsec/parser.h> +#include <xmlsec/errors.h> + +/************************************************************************** + * + * Internal xslt ctx + * + *****************************************************************************/ +typedef struct _xmlSecXsltCtx xmlSecXsltCtx, *xmlSecXsltCtxPtr; +struct _xmlSecXsltCtx { + xsltStylesheetPtr xslt; + xmlParserCtxtPtr parserCtx; +}; + +/**************************************************************************** + * + * XSLT transform + * + * xmlSecXsltCtx is located after xmlSecTransform + * + ***************************************************************************/ +#define xmlSecXsltSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecXsltCtx)) +#define xmlSecXsltGetCtx(transform) \ + ((xmlSecXsltCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +static int xmlSecXsltInitialize (xmlSecTransformPtr transform); +static void xmlSecXsltFinalize (xmlSecTransformPtr transform); +static int xmlSecXsltReadNode (xmlSecTransformPtr transform, + xmlNodePtr node, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecXsltPushBin (xmlSecTransformPtr transform, + const xmlSecByte* data, + xmlSecSize dataSize, + int final, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecXsltExecute (xmlSecTransformPtr transform, + int last, + xmlSecTransformCtxPtr transformCtx); +static int xmlSecXslProcess (xmlSecBufferPtr in, + xmlSecBufferPtr out, + xsltStylesheetPtr stylesheet); +static xmlSecTransformKlass xmlSecXsltKlass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecXsltSize, /* xmlSecSize objSize */ + + xmlSecNameXslt, /* const xmlChar* name; */ + xmlSecHrefXslt, /* const xmlChar* href; */ + xmlSecTransformUsageDSigTransform, /* xmlSecAlgorithmUsage usage; */ + + xmlSecXsltInitialize, /* xmlSecTransformInitializeMethod initialize; */ + xmlSecXsltFinalize, /* xmlSecTransformFinalizeMethod finalize; */ + xmlSecXsltReadNode, /* xmlSecTransformNodeReadMethod readNode; */ + NULL, /* xmlSecTransformNodeWriteMethod writeNode; */ + NULL, /* xmlSecTransformSetKeyReqMethod setKeyReq; */ + NULL, /* xmlSecTransformSetKeyMethod setKey; */ + NULL, /* xmlSecTransformValidateMethod validate; */ + xmlSecTransformDefaultGetDataType, /* xmlSecTransformGetDataTypeMethod getDataType; */ + xmlSecXsltPushBin, /* xmlSecTransformPushBinMethod pushBin; */ + xmlSecTransformDefaultPopBin, /* xmlSecTransformPopBinMethod popBin; */ + NULL, /* xmlSecTransformPushXmlMethod pushXml; */ + NULL, /* xmlSecTransformPopXmlMethod popXml; */ + xmlSecXsltExecute, /* xmlSecTransformExecuteMethod execute; */ + + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +/** + * xmlSecTransformXsltGetKlass: + * + * XSLT transform klass (http://www.w3.org/TR/xmldsig-core/#sec-XSLT): + * + * The normative specification for XSL Transformations is [XSLT]. + * Specification of a namespace-qualified stylesheet element, which MUST be + * the sole child of the Transform element, indicates that the specified style + * sheet should be used. Whether this instantiates in-line processing of local + * XSLT declarations within the resource is determined by the XSLT processing + * model; the ordered application of multiple stylesheet may require multiple + * Transforms. No special provision is made for the identification of a remote + * stylesheet at a given URI because it can be communicated via an xsl:include + * or xsl:import within the stylesheet child of the Transform. + * + * This transform requires an octet stream as input. If the actual input is an + * XPath node-set, then the signature application should attempt to convert it + * to octets (apply Canonical XML]) as described in the Reference Processing + * Model (section 4.3.3.2).] + * + * The output of this transform is an octet stream. The processing rules for + * the XSL style sheet or transform element are stated in the XSLT specification + * [XSLT]. We RECOMMEND that XSLT transform authors use an output method of xml + * for XML and HTML. As XSLT implementations do not produce consistent + * serializations of their output, we further RECOMMEND inserting a transform + * after the XSLT transform to canonicalize the output. These steps will help + * to ensure interoperability of the resulting signatures among applications + * that support the XSLT transform. Note that if the output is actually HTML, + * then the result of these steps is logically equivalent [XHTML]. + * + * Returns: pointer to XSLT transform klass. + */ +xmlSecTransformId +xmlSecTransformXsltGetKlass(void) { + return(&xmlSecXsltKlass); +} + +static int +xmlSecXsltInitialize(xmlSecTransformPtr transform) { + xmlSecXsltCtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + /* initialize context */ + memset(ctx, 0, sizeof(xmlSecXsltCtx)); + return(0); +} + +static void +xmlSecXsltFinalize(xmlSecTransformPtr transform) { + xmlSecXsltCtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecTransformXsltId)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecXsltSize)); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert(ctx != NULL); + + if(ctx->xslt != NULL) { + xsltFreeStylesheet(ctx->xslt); + } + if(ctx->parserCtx != NULL) { + xmlFreeParserCtxt(ctx->parserCtx); + } + memset(ctx, 0, sizeof(xmlSecXsltCtx)); +} + +static int +xmlSecXsltReadNode(xmlSecTransformPtr transform, xmlNodePtr node, xmlSecTransformCtxPtr transformCtx) { + xmlSecXsltCtxPtr ctx; + xmlBufferPtr buffer; + xmlDocPtr doc; + xmlNodePtr cur; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + xmlSecAssert2(node != NULL, -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xslt == NULL, -1); + + /* read content in the buffer */ + buffer = xmlBufferCreate(); + if(buffer == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlBufferCreate", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + cur = node->children; + while(cur != NULL) { + xmlNodeDump(buffer, cur->doc, cur, 0, 0); + cur = cur->next; + } + + /* parse the buffer */ + doc = xmlSecParseMemory(xmlBufferContent(buffer), + xmlBufferLength(buffer), 1); + if(doc == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecParseMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlBufferFree(buffer); + return(-1); + } + + /* pre-process stylesheet */ + ctx->xslt = xsltParseStylesheetDoc(doc); + if(ctx->xslt == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xsltParseStylesheetDoc", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + /* after parsing stylesheet doc is assigned + * to it and will be freed by xsltFreeStylesheet() */ + xmlFreeDoc(doc); + xmlBufferFree(buffer); + return(-1); + } + + xmlBufferFree(buffer); + return(0); +} + +static int +xmlSecXsltPushBin(xmlSecTransformPtr transform, const xmlSecByte* data, + xmlSecSize dataSize, int final, xmlSecTransformCtxPtr transformCtx) { + xmlSecXsltCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xslt != NULL, -1); + + /* check/update current transform status */ + if(transform->status == xmlSecTransformStatusNone) { + xmlSecAssert2(ctx->parserCtx == NULL, -1); + + ctx->parserCtx = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL); + if(ctx->parserCtx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlCreatePushParserCtxt", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* required for c14n! */ + ctx->parserCtx->loadsubset = XML_DETECT_IDS | XML_COMPLETE_ATTRS; + ctx->parserCtx->replaceEntities = 1; + + transform->status = xmlSecTransformStatusWorking; + } else if(transform->status == xmlSecTransformStatusFinished) { + return(0); + } else if(transform->status != xmlSecTransformStatusWorking) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + xmlSecAssert2(transform->status == xmlSecTransformStatusWorking, -1); + xmlSecAssert2(ctx->parserCtx != NULL, -1); + + /* push data to the input buffer */ + if((data != NULL) && (dataSize > 0)) { + ret = xmlParseChunk(ctx->parserCtx, (const char*)data, dataSize, 0); + if(ret != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + "size=%d", dataSize); + return(-1); + } + } + + /* finish parsing, apply xslt transforms and push to next in the chain */ + if(final != 0) { + xmlDocPtr docIn; + xmlDocPtr docOut; + xmlOutputBufferPtr output; + + /* finalize */ + ret = xmlParseChunk(ctx->parserCtx, NULL, 0, 1); + if((ret != 0) || (ctx->parserCtx->myDoc == NULL)) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlParseChunk", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* todo: check that document is well formed? */ + docIn = ctx->parserCtx->myDoc; + ctx->parserCtx->myDoc = NULL; + + docOut = xsltApplyStylesheet(ctx->xslt, docIn, NULL); + if(docOut == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xsltApplyStylesheet", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docIn); + return(-1); + } + xmlFreeDoc(docIn); + + if(transform->next != NULL) { + output = xmlSecTransformCreateOutputBuffer(transform->next, transformCtx); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecTransformCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docOut); + return(-1); + } + } else { + output = xmlSecBufferCreateOutputBuffer(&(transform->outBuf)); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docOut); + return(-1); + } + } + + ret = xsltSaveResultTo(output, docOut, ctx->xslt); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xsltSaveResultTo", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlOutputBufferClose(output); + xmlFreeDoc(docOut); + return(-1); + } + ret = xmlOutputBufferClose(output); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + xmlFreeDoc(docOut); + return(-1); + } + xmlFreeDoc(docOut); + + transform->status = xmlSecTransformStatusFinished; + } + + return(0); +} + +static int +xmlSecXsltExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecXsltCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecTransformXsltId), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecXsltSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecXsltGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(ctx->xslt != NULL, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + xmlSecAssert2(outSize == 0, -1); + + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + xmlSecAssert2(outSize == 0, -1); + + ret = xmlSecXslProcess(in, out, ctx->xslt); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecXslProcess", + XMLSEC_ERRORS_R_XMLSEC_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, + "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(inSize == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + +/* TODO: create PopBin method instead */ +static int +xmlSecXslProcess(xmlSecBufferPtr in, xmlSecBufferPtr out, xsltStylesheetPtr stylesheet) { + xmlDocPtr docIn = NULL; + xmlDocPtr docOut = NULL; + xmlOutputBufferPtr output = NULL; + int res = -1; + int ret; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(stylesheet != NULL, -1); + + docIn = xmlSecParseMemory(xmlSecBufferGetData(in), xmlSecBufferGetSize(in), 1); + if(docIn == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecParseMemory", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + docOut = xsltApplyStylesheet(stylesheet, docIn, NULL); + if(docOut == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xsltApplyStylesheet", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + output = xmlSecBufferCreateOutputBuffer(out); + if(output == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecBufferCreateOutputBuffer", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xsltSaveResultTo(output, docOut, stylesheet); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xsltSaveResultTo", + XMLSEC_ERRORS_R_XSLT_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + ret = xmlOutputBufferClose(output); + output = NULL; + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlOutputBufferClose", + XMLSEC_ERRORS_R_XML_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + res = 0; + +done: + if(output != NULL) xmlOutputBufferClose(output); + if(docIn != NULL) xmlFreeDoc(docIn); + if(docOut != NULL) xmlFreeDoc(docOut); + return(res); +} + +#endif /* XMLSEC_NO_XSLT */ + |