diff options
Diffstat (limited to 'src/nss')
-rw-r--r-- | src/nss/Makefile.am | 57 | ||||
-rw-r--r-- | src/nss/Makefile.in | 798 | ||||
-rw-r--r-- | src/nss/README | 128 | ||||
-rw-r--r-- | src/nss/app.c | 1598 | ||||
-rw-r--r-- | src/nss/bignum.c | 163 | ||||
-rw-r--r-- | src/nss/ciphers.c | 838 | ||||
-rw-r--r-- | src/nss/crypto.c | 444 | ||||
-rw-r--r-- | src/nss/digests.c | 576 | ||||
-rw-r--r-- | src/nss/globals.h | 24 | ||||
-rw-r--r-- | src/nss/hmac.c | 855 | ||||
-rw-r--r-- | src/nss/keysstore.c | 485 | ||||
-rw-r--r-- | src/nss/keytrans.c | 753 | ||||
-rw-r--r-- | src/nss/kw_aes.c | 681 | ||||
-rw-r--r-- | src/nss/kw_des.c | 663 | ||||
-rw-r--r-- | src/nss/pkikeys.c | 1554 | ||||
-rw-r--r-- | src/nss/signatures.c | 841 | ||||
-rw-r--r-- | src/nss/symkeys.c | 440 | ||||
-rw-r--r-- | src/nss/x509.c | 2223 | ||||
-rw-r--r-- | src/nss/x509vfy.c | 808 |
19 files changed, 13929 insertions, 0 deletions
diff --git a/src/nss/Makefile.am b/src/nss/Makefile.am new file mode 100644 index 00000000..8cd85863 --- /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 = \ + $(NSS_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + ../libxmlsec1.la \ + $(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..46c8c927 --- /dev/null +++ b/src/nss/Makefile.in @@ -0,0 +1,798 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@SHAREDLIB_HACK_TRUE@am__append_1 = ../strings.c +subdir = src/nss +DIST_COMMON = README $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +am__libxmlsec1_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@ +GCRYPT_CFLAGS = @GCRYPT_CFLAGS@ +GCRYPT_CRYPTO_LIB = @GCRYPT_CRYPTO_LIB@ +GCRYPT_LIBS = @GCRYPT_LIBS@ +GCRYPT_MIN_VERSION = @GCRYPT_MIN_VERSION@ +GNUTLS_CFLAGS = @GNUTLS_CFLAGS@ +GNUTLS_CRYPTO_LIB = @GNUTLS_CRYPTO_LIB@ +GNUTLS_LIBS = @GNUTLS_LIBS@ +GNUTLS_MIN_VERSION = @GNUTLS_MIN_VERSION@ +GREP = @GREP@ +HELP2MAN = @HELP2MAN@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBXML_CFLAGS = @LIBXML_CFLAGS@ +LIBXML_CONFIG = @LIBXML_CONFIG@ +LIBXML_LIBS = @LIBXML_LIBS@ +LIBXML_MIN_VERSION = @LIBXML_MIN_VERSION@ +LIBXSLT_CFLAGS = @LIBXSLT_CFLAGS@ +LIBXSLT_CONFIG = @LIBXSLT_CONFIG@ +LIBXSLT_LIBS = @LIBXSLT_LIBS@ +LIBXSLT_MIN_VERSION = @LIBXSLT_MIN_VERSION@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MAN2HTML = @MAN2HTML@ +MKDIR_P = @MKDIR_P@ +MOZILLA_MIN_VERSION = @MOZILLA_MIN_VERSION@ +MSCRYPTO_CFLAGS = @MSCRYPTO_CFLAGS@ +MSCRYPTO_CRYPTO_LIB = @MSCRYPTO_CRYPTO_LIB@ +MSCRYPTO_LIBS = @MSCRYPTO_LIBS@ +MV = @MV@ +NM = @NM@ +NMEDIT = @NMEDIT@ +NSPR_MIN_VERSION = @NSPR_MIN_VERSION@ +NSPR_PACKAGE = @NSPR_PACKAGE@ +NSS_CFLAGS = @NSS_CFLAGS@ +NSS_CRYPTO_LIB = @NSS_CRYPTO_LIB@ +NSS_LIBS = @NSS_LIBS@ +NSS_MIN_VERSION = @NSS_MIN_VERSION@ +NSS_PACKAGE = @NSS_PACKAGE@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OPENSSL_CFLAGS = @OPENSSL_CFLAGS@ +OPENSSL_CRYPTO_LIB = @OPENSSL_CRYPTO_LIB@ +OPENSSL_LIBS = @OPENSSL_LIBS@ +OPENSSL_MIN_VERSION = @OPENSSL_MIN_VERSION@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKGCONFIG_PRESENT = @PKGCONFIG_PRESENT@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RM = @RM@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TAR = @TAR@ +U = @U@ +VERSION = @VERSION@ +XMLSEC_APP_DEFINES = @XMLSEC_APP_DEFINES@ +XMLSEC_CFLAGS = @XMLSEC_CFLAGS@ +XMLSEC_CORE_CFLAGS = @XMLSEC_CORE_CFLAGS@ +XMLSEC_CORE_LIBS = @XMLSEC_CORE_LIBS@ +XMLSEC_CRYPTO = @XMLSEC_CRYPTO@ +XMLSEC_CRYPTO_CFLAGS = @XMLSEC_CRYPTO_CFLAGS@ +XMLSEC_CRYPTO_DISABLED_LIST = @XMLSEC_CRYPTO_DISABLED_LIST@ +XMLSEC_CRYPTO_EXTRA_LDFLAGS = @XMLSEC_CRYPTO_EXTRA_LDFLAGS@ +XMLSEC_CRYPTO_LIB = @XMLSEC_CRYPTO_LIB@ +XMLSEC_CRYPTO_LIBS = @XMLSEC_CRYPTO_LIBS@ +XMLSEC_CRYPTO_LIST = @XMLSEC_CRYPTO_LIST@ +XMLSEC_CRYPTO_PC_FILES_LIST = @XMLSEC_CRYPTO_PC_FILES_LIST@ +XMLSEC_DEFINES = @XMLSEC_DEFINES@ +XMLSEC_DL_INCLUDES = @XMLSEC_DL_INCLUDES@ +XMLSEC_DL_LIBS = @XMLSEC_DL_LIBS@ +XMLSEC_DOCDIR = @XMLSEC_DOCDIR@ +XMLSEC_EXTRA_LDFLAGS = @XMLSEC_EXTRA_LDFLAGS@ +XMLSEC_GCRYPT_CFLAGS = @XMLSEC_GCRYPT_CFLAGS@ +XMLSEC_GCRYPT_LIBS = @XMLSEC_GCRYPT_LIBS@ +XMLSEC_GNUTLS_CFLAGS = @XMLSEC_GNUTLS_CFLAGS@ +XMLSEC_GNUTLS_LIBS = @XMLSEC_GNUTLS_LIBS@ +XMLSEC_LIBDIR = @XMLSEC_LIBDIR@ +XMLSEC_LIBS = @XMLSEC_LIBS@ +XMLSEC_NO_AES = @XMLSEC_NO_AES@ +XMLSEC_NO_APPS_CRYPTO_DYNAMIC_LOADING = @XMLSEC_NO_APPS_CRYPTO_DYNAMIC_LOADING@ +XMLSEC_NO_CRYPTO_DYNAMIC_LOADING = @XMLSEC_NO_CRYPTO_DYNAMIC_LOADING@ +XMLSEC_NO_DES = @XMLSEC_NO_DES@ +XMLSEC_NO_DSA = @XMLSEC_NO_DSA@ +XMLSEC_NO_GCRYPT = @XMLSEC_NO_GCRYPT@ +XMLSEC_NO_GNUTLS = @XMLSEC_NO_GNUTLS@ +XMLSEC_NO_GOST = @XMLSEC_NO_GOST@ +XMLSEC_NO_HMAC = @XMLSEC_NO_HMAC@ +XMLSEC_NO_LIBXSLT = @XMLSEC_NO_LIBXSLT@ +XMLSEC_NO_MD5 = @XMLSEC_NO_MD5@ +XMLSEC_NO_MSCRYPTO = @XMLSEC_NO_MSCRYPTO@ +XMLSEC_NO_NSS = @XMLSEC_NO_NSS@ +XMLSEC_NO_OPENSSL = @XMLSEC_NO_OPENSSL@ +XMLSEC_NO_RIPEMD160 = @XMLSEC_NO_RIPEMD160@ +XMLSEC_NO_RSA = @XMLSEC_NO_RSA@ +XMLSEC_NO_SHA1 = @XMLSEC_NO_SHA1@ +XMLSEC_NO_SHA224 = @XMLSEC_NO_SHA224@ +XMLSEC_NO_SHA256 = @XMLSEC_NO_SHA256@ +XMLSEC_NO_SHA384 = @XMLSEC_NO_SHA384@ +XMLSEC_NO_SHA512 = @XMLSEC_NO_SHA512@ +XMLSEC_NO_X509 = @XMLSEC_NO_X509@ +XMLSEC_NO_XKMS = @XMLSEC_NO_XKMS@ +XMLSEC_NO_XMLDSIG = @XMLSEC_NO_XMLDSIG@ +XMLSEC_NO_XMLENC = @XMLSEC_NO_XMLENC@ +XMLSEC_NSS_CFLAGS = @XMLSEC_NSS_CFLAGS@ +XMLSEC_NSS_LIBS = @XMLSEC_NSS_LIBS@ +XMLSEC_OPENSSL_CFLAGS = @XMLSEC_OPENSSL_CFLAGS@ +XMLSEC_OPENSSL_LIBS = @XMLSEC_OPENSSL_LIBS@ +XMLSEC_PACKAGE = @XMLSEC_PACKAGE@ +XMLSEC_STATIC_BINARIES = @XMLSEC_STATIC_BINARIES@ +XMLSEC_VERSION = @XMLSEC_VERSION@ +XMLSEC_VERSION_INFO = @XMLSEC_VERSION_INFO@ +XMLSEC_VERSION_MAJOR = @XMLSEC_VERSION_MAJOR@ +XMLSEC_VERSION_MINOR = @XMLSEC_VERSION_MINOR@ +XMLSEC_VERSION_SAFE = @XMLSEC_VERSION_SAFE@ +XMLSEC_VERSION_SUBMINOR = @XMLSEC_VERSION_SUBMINOR@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +NULL = +EXTRA_DIST = \ + 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 = \ + $(NSS_LIBS) \ + $(LIBXSLT_LIBS) \ + $(LIBXML_LIBS) \ + ../libxmlsec1.la \ + $(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..65a0f45e --- /dev/null +++ b/src/nss/README @@ -0,0 +1,128 @@ +WHAT VERSION OF NSS? +------------------------------------------------------------------------ +NSS 3.9 or greater and NSPR 4.4.1 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) 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 + +5) 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 + +6) 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 + +7) RIPEMD160 Digest and RIPEMD160 HMAC is not supported by NSS + + xmlsec bug: http://bugzilla.gnome.org/show_bug.cgi?id=118634 + +8) 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 + +9) 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 + +10) "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. + +11) NSS doesn't support emailAddress in the cert subject. There is a hack +that needs to be removed in xmlSecNssX509FindCert function (x509vfy.c): + +https://bugzilla.mozilla.org/show_bug.cgi?id=561689 + +12) CRLs from xml document support is not working at all. diff --git a/src/nss/app.c b/src/nss/app.c new file mode 100644 index 00000000..dabe36d1 --- /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..261155e6 --- /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..54bd2af2 --- /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..7137f1c4 --- /dev/null +++ b/src/nss/crypto.c @@ -0,0 +1,444 @@ +/** + * 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 + * + ********************************************************************/ + + /******************************* AES ********************************/ +#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 */ + + /******************************* DES ********************************/ +#ifndef XMLSEC_NO_DES + gXmlSecNssFunctions->transformDes3CbcGetKlass = xmlSecNssTransformDes3CbcGetKlass; + gXmlSecNssFunctions->transformKWDes3GetKlass = xmlSecNssTransformKWDes3GetKlass; +#endif /* XMLSEC_NO_DES */ + + /******************************* DSA ********************************/ +#ifndef XMLSEC_NO_DSA + gXmlSecNssFunctions->transformDsaSha1GetKlass = xmlSecNssTransformDsaSha1GetKlass; +#endif /* XMLSEC_NO_DSA */ + + /******************************* HMAC ********************************/ +#ifndef XMLSEC_NO_HMAC + +#ifndef XMLSEC_NO_MD5 + gXmlSecNssFunctions->transformHmacMd5GetKlass = xmlSecNssTransformHmacMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + gXmlSecNssFunctions->transformHmacRipemd160GetKlass = xmlSecNssTransformHmacRipemd160GetKlass; +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecNssFunctions->transformHmacSha1GetKlass = xmlSecNssTransformHmacSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + gXmlSecNssFunctions->transformHmacSha256GetKlass = xmlSecNssTransformHmacSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + gXmlSecNssFunctions->transformHmacSha384GetKlass = xmlSecNssTransformHmacSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + gXmlSecNssFunctions->transformHmacSha512GetKlass = xmlSecNssTransformHmacSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_HMAC */ + + /******************************* RSA ********************************/ +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + gXmlSecNssFunctions->transformRsaMd5GetKlass = xmlSecNssTransformRsaMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + gXmlSecNssFunctions->transformRsaSha1GetKlass = xmlSecNssTransformRsaSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + gXmlSecNssFunctions->transformRsaSha256GetKlass = xmlSecNssTransformRsaSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + gXmlSecNssFunctions->transformRsaSha384GetKlass = xmlSecNssTransformRsaSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + gXmlSecNssFunctions->transformRsaSha512GetKlass = xmlSecNssTransformRsaSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + gXmlSecNssFunctions->transformRsaPkcs1GetKlass = xmlSecNssTransformRsaPkcs1GetKlass; + +/* aleksey, April 2010: NSS 3.12.6 has CKM_RSA_PKCS_OAEP algorithm but + it doesn't implement the SHA1 OAEP PKCS we need + + https://bugzilla.mozilla.org/show_bug.cgi?id=158747 +*/ +#ifdef XMLSEC_NSS_RSA_OAEP_TODO + gXmlSecNssFunctions->transformRsaOaepGetKlass = xmlSecNssTransformRsaOaepGetKlass; +#endif /* XMLSEC_NSS_RSA_OAEP_TODO */ + +#endif /* XMLSEC_NO_RSA */ + + /******************************* SHA ********************************/ +#ifndef XMLSEC_NO_SHA1 + gXmlSecNssFunctions->transformSha1GetKlass = xmlSecNssTransformSha1GetKlass; +#endif /* XMLSEC_NO_SHA1 */ +#ifndef XMLSEC_NO_SHA256 + gXmlSecNssFunctions->transformSha256GetKlass = xmlSecNssTransformSha256GetKlass; +#endif /* XMLSEC_NO_SHA256 */ +#ifndef XMLSEC_NO_SHA384 + gXmlSecNssFunctions->transformSha384GetKlass = xmlSecNssTransformSha384GetKlass; +#endif /* XMLSEC_NO_SHA384 */ +#ifndef XMLSEC_NO_SHA512 + gXmlSecNssFunctions->transformSha512GetKlass = xmlSecNssTransformSha512GetKlass; +#endif /* XMLSEC_NO_SHA512 */ + + /******************************* MD5 ********************************/ +#ifndef XMLSEC_NO_MD5 + gXmlSecNssFunctions->transformMd5GetKlass = xmlSecNssTransformMd5GetKlass; +#endif /* XMLSEC_NO_MD5 */ + + + /******************************************************************** + * + * 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..8063b443 --- /dev/null +++ b/src/nss/digests.c @@ -0,0 +1,576 @@ +/** + * 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 64 + +/************************************************************************** + * + * 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 xmlSecNssDigestCheckId (xmlSecTransformPtr transform); +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) { + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformMd5Id)) { + return(1); + } +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha256Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha384Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha512Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA512 */ + + 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_MD5 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformMd5Id)) { + ctx->digest = SECOID_FindOIDByTag(SEC_OID_MD5); + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha1Id)) { + ctx->digest = SECOID_FindOIDByTag(SEC_OID_SHA1); + } else +#endif /* XMLSEC_NO_SHA1 */ + + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha256Id)) { + ctx->digest = SECOID_FindOIDByTag(SEC_OID_SHA256); + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha384Id)) { + ctx->digest = SECOID_FindOIDByTag(SEC_OID_SHA384); + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformSha512Id)) { + ctx->digest = SECOID_FindOIDByTag(SEC_OID_SHA512); + } else +#endif /* XMLSEC_NO_SHA512 */ + + 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) { + unsigned int 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); + ctx->dgstSize = XMLSEC_SIZE_BAD_CAST(dgstSize); + + 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_MD5 +/****************************************************************************** + * + * Md5 Digest transforms + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecNssMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssDigestSize, /* xmlSecSize objSize */ + + /* data */ + xmlSecNameMd5, /* const xmlChar* name; */ + xmlSecHrefMd5, /* 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; */ +}; + +/** + * xmlSecNssTransformMd5GetKlass: + * + * MD5 digest transform klass. + * + * Returns: pointer to MD5 digest transform klass. + */ +xmlSecTransformId +xmlSecNssTransformMd5GetKlass(void) { + return(&xmlSecNssMd5Klass); +} +#endif /* XMLSEC_NO_MD5 */ + + +#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 */ + + +#ifndef XMLSEC_NO_SHA256 +/****************************************************************************** + * + * SHA256 Digest transforms + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecNssSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssDigestSize, /* xmlSecSize objSize */ + + /* data */ + xmlSecNameSha256, /* const xmlChar* name; */ + xmlSecHrefSha256, /* 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; */ +}; + +/** + * xmlSecNssTransformSha256GetKlass: + * + * SHA256 digest transform klass. + * + * Returns: pointer to SHA256 digest transform klass. + */ +xmlSecTransformId +xmlSecNssTransformSha256GetKlass(void) { + return(&xmlSecNssSha256Klass); +} +#endif /* XMLSEC_NO_SHA256 */ + + +#ifndef XMLSEC_NO_SHA384 +/****************************************************************************** + * + * SHA384 Digest transforms + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecNssSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssDigestSize, /* xmlSecSize objSize */ + + /* data */ + xmlSecNameSha384, /* const xmlChar* name; */ + xmlSecHrefSha384, /* 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; */ +}; + +/** + * xmlSecNssTransformSha384GetKlass: + * + * SHA384 digest transform klass. + * + * Returns: pointer to SHA384 digest transform klass. + */ +xmlSecTransformId +xmlSecNssTransformSha384GetKlass(void) { + return(&xmlSecNssSha384Klass); +} +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/****************************************************************************** + * + * SHA512 Digest transforms + * + *****************************************************************************/ +static xmlSecTransformKlass xmlSecNssSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssDigestSize, /* xmlSecSize objSize */ + + /* data */ + xmlSecNameSha512, /* const xmlChar* name; */ + xmlSecHrefSha512, /* 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; */ +}; + +/** + * xmlSecNssTransformSha512GetKlass: + * + * SHA512 digest transform klass. + * + * Returns: pointer to SHA512 digest transform klass. + */ +xmlSecTransformId +xmlSecNssTransformSha512GetKlass(void) { + return(&xmlSecNssSha512Klass); +} +#endif /* XMLSEC_NO_SHA512 */ + diff --git a/src/nss/globals.h b/src/nss/globals.h new file mode 100644 index 00000000..770b6dba --- /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..ae7e67ef --- /dev/null +++ b/src/nss/hmac.c @@ -0,0 +1,855 @@ +/** + * 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)) + +static int xmlSecNssHmacCheckId (xmlSecTransformPtr transform); +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 +xmlSecNssHmacCheckId(xmlSecTransformPtr transform) { + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacMd5Id)) { + return(1); + } +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacRipemd160Id)) { + return(1); + } +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha256Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha384Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha512Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA512 */ + + /* not found */ + return(0); +} + +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)); + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacMd5Id)) { + ctx->digestType = CKM_MD5_HMAC; + } else +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_RIPEMD160 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacRipemd160Id)) { + ctx->digestType = CKM_RIPEMD160_HMAC; + } else +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha1Id)) { + ctx->digestType = CKM_SHA_1_HMAC; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha256Id)) { + ctx->digestType = CKM_SHA256_HMAC; + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha384Id)) { + ctx->digestType = CKM_SHA384_HMAC; + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformHmacSha512Id)) { + ctx->digestType = CKM_SHA512_HMAC; + } else +#endif /* XMLSEC_NO_SHA512 */ + + /* not found */ + { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(0); +} + +static void +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 length 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) { + unsigned int 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 = XMLSEC_SIZE_BAD_CAST(dgstSize * 8); /* no dgst size specified, use all we have */ + } else if(ctx->dgstSize <= XMLSEC_SIZE_BAD_CAST(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); +} + + +#ifndef XMLSEC_NO_RIPEMD160 +/****************************************************************************** + * + * 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); +} +#endif /* XMLSEC_NO_RIPEMD160 */ + +#ifndef XMLSEC_NO_MD5 +/****************************************************************************** + * + * 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_MD5 */ + +#ifndef XMLSEC_NO_SHA1 +/****************************************************************************** + * + * 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); +} +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 +/****************************************************************************** + * + * HMAC SHA256 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecNssHmacSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha256, /* const xmlChar* name; */ + xmlSecHrefHmacSha256, /* 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; */ +}; + +/** + * xmlSecNssTransformHmacSha256GetKlass: + * + * The HMAC-SHA256 transform klass. + * + * Returns: the HMAC-SHA256 transform klass. + */ +xmlSecTransformId +xmlSecNssTransformHmacSha256GetKlass(void) { + return(&xmlSecNssHmacSha256Klass); +} +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/****************************************************************************** + * + * HMAC SHA384 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecNssHmacSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha384, /* const xmlChar* name; */ + xmlSecHrefHmacSha384, /* 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; */ +}; + +/** + * xmlSecNssTransformHmacSha384GetKlass: + * + * The HMAC-SHA384 transform klass. + * + * Returns: the HMAC-SHA384 transform klass. + */ +xmlSecTransformId +xmlSecNssTransformHmacSha384GetKlass(void) { + return(&xmlSecNssHmacSha384Klass); +} +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/****************************************************************************** + * + * HMAC SHA512 + * + ******************************************************************************/ +static xmlSecTransformKlass xmlSecNssHmacSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssHmacSize, /* xmlSecSize objSize */ + + xmlSecNameHmacSha512, /* const xmlChar* name; */ + xmlSecHrefHmacSha512, /* 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; */ +}; + +/** + * xmlSecNssTransformHmacSha512GetKlass: + * + * The HMAC-SHA512 transform klass. + * + * Returns: the HMAC-SHA512 transform klass. + */ +xmlSecTransformId +xmlSecNssTransformHmacSha512GetKlass(void) { + return(&xmlSecNssHmacSha512Klass); +} +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_HMAC */ + + diff --git a/src/nss/keysstore.c b/src/nss/keysstore.c new file mode 100644 index 00000000..f07e44be --- /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..d84593b9 --- /dev/null +++ b/src/nss/keytrans.c @@ -0,0 +1,753 @@ +/** + * + * 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 transport 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)) { + return(1); + } +#endif /* XMLSEC_NO_RSA */ + +/* aleksey, April 2010: NSS 3.12.6 has CKM_RSA_PKCS_OAEP algorithm but + it doesn't implement the SHA1 OAEP PKCS we need + + https://bugzilla.mozilla.org/show_bug.cgi?id=158747 +*/ +#ifdef XMLSEC_NSS_RSA_OAEP_TODO +#ifndef XMLSEC_NO_RSA + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaOaepId)) { + return (1); + } +#endif /* XMLSEC_NO_RSA */ +#endif /* XMLSEC_NSS_RSA_OAEP_TODO */ + + /* not found */ + 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 ) ; + + /* initialize context */ + memset(context, 0, sizeof(xmlSecNssKeyTransportCtx)); + +#ifndef XMLSEC_NO_RSA + if(transform->id == xmlSecNssTransformRsaPkcs1Id) { + context->cipher = CKM_RSA_PKCS; + context->keyId = xmlSecNssKeyDataRsaId; + } else +#endif /* XMLSEC_NO_RSA */ + +/* aleksey, April 2010: NSS 3.12.6 has CKM_RSA_PKCS_OAEP algorithm but + it doesn't implement the SHA1 OAEP PKCS we need + + https://bugzilla.mozilla.org/show_bug.cgi?id=158747 +*/ +#ifdef XMLSEC_NSS_RSA_OAEP_TODO +#ifndef XMLSEC_NO_RSA + if(transform->id == xmlSecNssTransformRsaOaepId) { + context->cipher = CKM_RSA_PKCS_OAEP; + context->keyId = xmlSecNssKeyDataRsaId; + } else +#endif /* XMLSEC_NO_RSA */ +#endif /* XMLSEC_NSS_RSA_OAEP_TODO */ + + /* not found */ + { + xmlSecError(XMLSEC_ERRORS_HERE , + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL , + XMLSEC_ERRORS_R_CRYPTO_FAILED , + XMLSEC_ERRORS_NO_MESSAGE ) ; + return(-1); + } + + 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) ; +} + +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); +} + +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); +} + +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); +} +#endif /* XMLSEC_NO_RSA */ + +/* aleksey, April 2010: NSS 3.12.6 has CKM_RSA_PKCS_OAEP algorithm but + it doesn't implement the SHA1 OAEP PKCS we need + + https://bugzilla.mozilla.org/show_bug.cgi?id=158747 +*/ +#ifdef XMLSEC_NSS_RSA_OAEP_TODO +#ifndef XMLSEC_NO_RSA +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 /* XMLSEC_NO_RSA */ +#endif /* XMLSEC_NSS_RSA_OAEP_TODO */ + diff --git a/src/nss/kw_aes.c b/src/nss/kw_aes.c new file mode 100644 index 00000000..0438e306 --- /dev/null +++ b/src/nss/kw_aes.c @@ -0,0 +1,681 @@ +/** + * + * 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. + * Copyright (C) 2010 Aleksey Sanin, 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> + +#include "../kw_aes_des.h" + +/* + * NSS needs to implement AES KW internally and then the code + * needs to change to use the direct implementation instead. + * + * Follow the NSS bug system for more details on the fix + * http://bugzilla.mozilla.org/show_bug.cgi?id=213795 + */ +/********************************************************************* + * + * AES KW implementation + * + *********************************************************************/ +static int xmlSecNSSKWAesBlockEncrypt (const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize, + void * context); +static int xmlSecNSSKWAesBlockDecrypt (const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize, + void * context); +static xmlSecKWAesKlass xmlSecNssKWAesKlass = { + /* callbacks */ + xmlSecNSSKWAesBlockEncrypt, /* xmlSecKWAesBlockEncryptMethod encrypt; */ + xmlSecNSSKWAesBlockDecrypt, /* xmlSecKWAesBlockDecryptMethod decrypt; */ + + /* for the future */ + NULL, /* void* reserved0; */ + NULL /* void* reserved1; */ +}; + + + + +static PK11SymKey* xmlSecNssMakeAesKey (const xmlSecByte *key, + xmlSecSize keySize, + int enc); +static int xmlSecNssAesOp (PK11SymKey *aeskey, + const xmlSecByte *in, + xmlSecByte *out, + int enc); + + +/********************************************************************* + * + * AES KW transforms + * + ********************************************************************/ +typedef struct _xmlSecNssKWAesCtx xmlSecNssKWAesCtx, + *xmlSecNssKWAesCtxPtr; +struct _xmlSecNssKWAesCtx { + xmlSecBuffer keyBuffer; + xmlSecSize keyExpectedSize; +}; +#define xmlSecNssKWAesSize \ + (sizeof(xmlSecTransform) + sizeof(xmlSecNssKWAesCtx)) +#define xmlSecNssKWAesGetCtx(transform) \ + ((xmlSecNssKWAesCtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +#define xmlSecNssKWAesCheckId(transform) \ + (xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes128Id) || \ + xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes192Id) || \ + xmlSecTransformCheckId((transform), xmlSecNssTransformKWAes256Id)) + + +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 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; */ +}; + +/** + * xmlSecNssTransformKWAes128GetKlass: + * + * The AES-128 key wrapper transform klass. + * + * Returns: AES-128 key wrapper transform klass. + */ +xmlSecTransformId +xmlSecNssTransformKWAes128GetKlass(void) { + return(&xmlSecNssKWAes128Klass); +} + +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; */ +}; + +/** + * xmlSecNssTransformKWAes192GetKlass: + * + * The AES-192 key wrapper transform klass. + * + * Returns: AES-192 key wrapper transform klass. + */ +xmlSecTransformId +xmlSecNssTransformKWAes192GetKlass(void) { + return(&xmlSecNssKWAes192Klass); +} + +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; */ +}; + +/** + * 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) { + xmlSecNssKWAesCtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + + ctx = xmlSecNssKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes128Id)) { + ctx->keyExpectedSize = XMLSEC_KW_AES128_KEY_SIZE; + } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes192Id)) { + ctx->keyExpectedSize = XMLSEC_KW_AES192_KEY_SIZE; + } else if(xmlSecTransformCheckId(transform, xmlSecNssTransformKWAes256Id)) { + ctx->keyExpectedSize = XMLSEC_KW_AES256_KEY_SIZE; + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_TRANSFORM, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + ret = xmlSecBufferInitialize(&(ctx->keyBuffer), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecNssKWAesFinalize(xmlSecTransformPtr transform) { + xmlSecNssKWAesCtxPtr ctx; + + xmlSecAssert(xmlSecNssKWAesCheckId(transform)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize)); + + ctx = xmlSecNssKWAesGetCtx(transform); + xmlSecAssert(ctx != NULL); + + xmlSecBufferFinalize(&(ctx->keyBuffer)); +} + +static int +xmlSecNssKWAesSetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecNssKWAesCtxPtr ctx; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecNssKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecNssKeyDataAesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage = xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage = xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * ctx->keyExpectedSize; + + return(0); +} + +static int +xmlSecNssKWAesSetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecNssKWAesCtxPtr ctx; + xmlSecBufferPtr buffer; + xmlSecSize keySize; + int ret; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataAesId), -1); + + ctx = xmlSecNssKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + if(keySize < ctx->keyExpectedSize) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "key=%d;expected=%d", + keySize, ctx->keyExpectedSize); + return(-1); + } + + ret = xmlSecBufferSetData(&(ctx->keyBuffer), + xmlSecBufferGetData(buffer), + ctx->keyExpectedSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "expected-size=%d", + ctx->keyExpectedSize); + return(-1); + } + + return(0); +} + +static int +xmlSecNssKWAesExecute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssKWAesCtxPtr ctx; + xmlSecBufferPtr in, out; + xmlSecSize inSize, outSize, keySize; + int ret; + + xmlSecAssert2(xmlSecNssKWAesCheckId(transform), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWAesSize), -1); + xmlSecAssert2(transformCtx != NULL, -1); + + ctx = xmlSecNssKWAesGetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keySize = xmlSecBufferGetSize(&(ctx->keyBuffer)); + xmlSecAssert2(keySize == ctx->keyExpectedSize, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + xmlSecAssert2(outSize == 0, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + if((inSize % 8) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "size=%d(not 8 bytes aligned)", inSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + /* the encoded key might be 8 bytes longer plus 8 bytes just in case */ + outSize = inSize + XMLSEC_KW_AES_MAGIC_BLOCK_SIZE + + XMLSEC_KW_AES_BLOCK_SIZE; + } else { + outSize = inSize + XMLSEC_KW_AES_BLOCK_SIZE; + } + + ret = xmlSecBufferSetMaxSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "outSize=%d", outSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + PK11SymKey *aeskey = NULL; + + /* create key */ + aeskey = xmlSecNssMakeAesKey(xmlSecBufferGetData(&(ctx->keyBuffer)), keySize, 1); /* encrypt */ + if(aeskey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssMakeAesKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + + /* encrypt */ + ret = xmlSecKWAesEncode(&xmlSecNssKWAesKlass, aeskey, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWAesEncode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_FreeSymKey(aeskey); + return(-1); + } + + outSize = ret; + PK11_FreeSymKey(aeskey); + } else { + PK11SymKey *aeskey = NULL; + + /* create key */ + aeskey = xmlSecNssMakeAesKey(xmlSecBufferGetData(&(ctx->keyBuffer)), keySize, 0); /* decrypt */ + if(aeskey == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssMakeAesKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + /* decrypt */ + ret = xmlSecKWAesDecode(&xmlSecNssKWAesKlass, aeskey, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWAesDecode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_FreeSymKey(aeskey); + return(-1); + } + + outSize = ret; + PK11_FreeSymKey(aeskey); + } + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "outSize=%d", outSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "inSize%d", inSize); + return(-1); + } + + transform->status = xmlSecTransformStatusFinished; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + +/********************************************************************* + * + * AES KW implementation + * + *********************************************************************/ +static int +xmlSecNSSKWAesBlockEncrypt(const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize, + void * context) { + PK11SymKey *aeskey = (PK11SymKey *)context; + int ret; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize >= XMLSEC_KW_AES_BLOCK_SIZE, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= XMLSEC_KW_AES_BLOCK_SIZE, -1); + xmlSecAssert2(aeskey != NULL, -1); + + /* one block */ + ret = xmlSecNssAesOp(aeskey, in, out, 1); /* encrypt */ + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAesOp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(XMLSEC_KW_AES_BLOCK_SIZE); +} + +static int +xmlSecNSSKWAesBlockDecrypt(const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize, + void * context) { + PK11SymKey *aeskey = (PK11SymKey *)context; + int ret; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize >= XMLSEC_KW_AES_BLOCK_SIZE, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= XMLSEC_KW_AES_BLOCK_SIZE, -1); + xmlSecAssert2(aeskey != NULL, -1); + + /* one block */ + ret = xmlSecNssAesOp(aeskey, in, out, 0); /* decrypt */ + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssAesOp", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + return(XMLSEC_KW_AES_BLOCK_SIZE); +} + +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_KW_AES_BLOCK_SIZE), in and out can overlap */ +static int +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; + int ret = -1; + + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(out != NULL, -1); + + 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_KW_AES_BLOCK_SIZE, (unsigned char *)in, + XMLSEC_KW_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_KW_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 - success! */ + ret = 0; + +done: + if (SecParam) { + SECITEM_FreeItem(SecParam, PR_TRUE); + } + if (EncContext) { + PK11_DestroyContext(EncContext, PR_TRUE); + } + + return (ret); +} + + +#endif /* XMLSEC_NO_AES */ diff --git a/src/nss/kw_des.c b/src/nss/kw_des.c new file mode 100644 index 00000000..e75f69c9 --- /dev/null +++ b/src/nss/kw_des.c @@ -0,0 +1,663 @@ +/** + * + * XMLSec library + * + * DES KW 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. + * 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 <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> + +#include "../kw_aes_des.h" + +/********************************************************************* + * + * DES KW implementation + * + *********************************************************************/ +static int xmlSecNssKWDes3GenerateRandom (void * context, + xmlSecByte * out, + xmlSecSize outSize); +static int xmlSecNssKWDes3Sha1 (void * context, + const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize); +static int xmlSecNssKWDes3BlockEncrypt (void * context, + const xmlSecByte * iv, + xmlSecSize ivSize, + const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize); +static int xmlSecNssKWDes3BlockDecrypt (void * context, + const xmlSecByte * iv, + xmlSecSize ivSize, + const xmlSecByte * in, + xmlSecSize inSize, + xmlSecByte * out, + xmlSecSize outSize); + +static xmlSecKWDes3Klass xmlSecNssKWDes3ImplKlass = { + /* callbacks */ + xmlSecNssKWDes3GenerateRandom, /* xmlSecKWDes3GenerateRandomMethod generateRandom; */ + xmlSecNssKWDes3Sha1, /* xmlSecKWDes3Sha1Method sha1; */ + xmlSecNssKWDes3BlockEncrypt, /* xmlSecKWDes3BlockEncryptMethod encrypt; */ + xmlSecNssKWDes3BlockDecrypt, /* xmlSecKWDes3BlockDecryptMethod decrypt; */ + + /* for the future */ + NULL, /* void* reserved0; */ + NULL, /* void* reserved1; */ +}; + +static int xmlSecNssKWDes3Encrypt (const xmlSecByte *key, + xmlSecSize keySize, + const xmlSecByte *iv, + xmlSecSize ivSize, + const xmlSecByte *in, + xmlSecSize inSize, + xmlSecByte *out, + xmlSecSize outSize, + int enc); + + +/********************************************************************* + * + * Triple DES Key Wrap transform + * + * key (xmlSecBuffer) is located after xmlSecTransform structure + * + ********************************************************************/ +typedef struct _xmlSecNssKWDes3Ctx xmlSecNssKWDes3Ctx, + *xmlSecNssKWDes3CtxPtr; +struct _xmlSecNssKWDes3Ctx { + xmlSecBuffer keyBuffer; +}; +#define xmlSecNssKWDes3Size \ + (sizeof(xmlSecTransform) + sizeof(xmlSecNssKWDes3Ctx)) +#define xmlSecNssKWDes3GetCtx(transform) \ + ((xmlSecNssKWDes3CtxPtr)(((xmlSecByte*)(transform)) + sizeof(xmlSecTransform))) + +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 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) { + xmlSecNssKWDes3CtxPtr ctx; + int ret; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size), -1); + + ctx = xmlSecNssKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + ret = xmlSecBufferInitialize(&(ctx->keyBuffer), 0); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferInitialize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(0); +} + +static void +xmlSecNssKWDes3Finalize(xmlSecTransformPtr transform) { + xmlSecNssKWDes3CtxPtr ctx; + + xmlSecAssert(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id)); + xmlSecAssert(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size)); + + ctx = xmlSecNssKWDes3GetCtx(transform); + xmlSecAssert(ctx != NULL); + + xmlSecBufferFinalize(&(ctx->keyBuffer)); +} + +static int +xmlSecNssKWDes3SetKeyReq(xmlSecTransformPtr transform, xmlSecKeyReqPtr keyReq) { + xmlSecNssKWDes3CtxPtr ctx; + + xmlSecAssert2(xmlSecTransformCheckId(transform, xmlSecNssTransformKWDes3Id), -1); + xmlSecAssert2((transform->operation == xmlSecTransformOperationEncrypt) || (transform->operation == xmlSecTransformOperationDecrypt), -1); + xmlSecAssert2(xmlSecTransformCheckSize(transform, xmlSecNssKWDes3Size), -1); + xmlSecAssert2(keyReq != NULL, -1); + + ctx = xmlSecNssKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keyReq->keyId = xmlSecNssKeyDataDesId; + keyReq->keyType = xmlSecKeyDataTypeSymmetric; + if(transform->operation == xmlSecTransformOperationEncrypt) { + keyReq->keyUsage= xmlSecKeyUsageEncrypt; + } else { + keyReq->keyUsage= xmlSecKeyUsageDecrypt; + } + keyReq->keyBitsSize = 8 * XMLSEC_KW_DES3_KEY_LENGTH; + return(0); +} + +static int +xmlSecNssKWDes3SetKey(xmlSecTransformPtr transform, xmlSecKeyPtr key) { + xmlSecNssKWDes3CtxPtr ctx; + 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(key != NULL, -1); + xmlSecAssert2(xmlSecKeyDataCheckId(xmlSecKeyGetValue(key), xmlSecNssKeyDataDesId), -1); + + ctx = xmlSecNssKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + buffer = xmlSecKeyDataBinaryValueGetBuffer(xmlSecKeyGetValue(key)); + xmlSecAssert2(buffer != NULL, -1); + + keySize = xmlSecBufferGetSize(buffer); + if(keySize < XMLSEC_KW_DES3_KEY_LENGTH) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_KEY_DATA_SIZE, + "key length %d is not enough (%d expected)", + keySize, XMLSEC_KW_DES3_KEY_LENGTH); + return(-1); + } + + ret = xmlSecBufferSetData(&(ctx->keyBuffer), xmlSecBufferGetData(buffer), XMLSEC_KW_DES3_KEY_LENGTH); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", XMLSEC_KW_DES3_KEY_LENGTH); + return(-1); + } + + return(0); +} + +static int +xmlSecNssKWDes3Execute(xmlSecTransformPtr transform, int last, xmlSecTransformCtxPtr transformCtx) { + xmlSecNssKWDes3CtxPtr ctx; + xmlSecBufferPtr in, out; + 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); + + ctx = xmlSecNssKWDes3GetCtx(transform); + xmlSecAssert2(ctx != NULL, -1); + + keySize = xmlSecBufferGetSize(&(ctx->keyBuffer)); + xmlSecAssert2(keySize == XMLSEC_KW_DES3_KEY_LENGTH, -1); + + in = &(transform->inBuf); + out = &(transform->outBuf); + inSize = xmlSecBufferGetSize(in); + outSize = xmlSecBufferGetSize(out); + xmlSecAssert2(outSize == 0, -1); + + if(transform->status == xmlSecTransformStatusNone) { + transform->status = xmlSecTransformStatusWorking; + } + + if((transform->status == xmlSecTransformStatusWorking) && (last == 0)) { + /* just do nothing */ + } else if((transform->status == xmlSecTransformStatusWorking) && (last != 0)) { + if((inSize % XMLSEC_KW_DES3_BLOCK_LENGTH) != 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_SIZE, + "%d bytes - not %d bytes aligned", + inSize, XMLSEC_KW_DES3_BLOCK_LENGTH); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + /* the encoded key might be 16 bytes longer plus one block just in case */ + outSize = inSize + XMLSEC_KW_DES3_IV_LENGTH + + XMLSEC_KW_DES3_BLOCK_LENGTH + + XMLSEC_KW_DES3_BLOCK_LENGTH; + } else { + /* just in case, add a block */ + outSize = inSize + XMLSEC_KW_DES3_BLOCK_LENGTH; + } + + ret = xmlSecBufferSetMaxSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetMaxSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + + if(transform->operation == xmlSecTransformOperationEncrypt) { + ret = xmlSecKWDes3Encode(&xmlSecNssKWDes3ImplKlass, ctx, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWDes3Encode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "key=%d,in=%d,out=%d", + keySize, inSize, outSize); + return(-1); + } + outSize = ret; + } else { + ret = xmlSecKWDes3Decode(&xmlSecNssKWDes3ImplKlass, ctx, + xmlSecBufferGetData(in), inSize, + xmlSecBufferGetData(out), outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecKWDes3Decode", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "key=%d,in=%d,out=%d", + keySize, inSize, outSize); + return(-1); + } + outSize = ret; + } + + ret = xmlSecBufferSetSize(out, outSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetSize", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", outSize); + return(-1); + } + + ret = xmlSecBufferRemoveHead(in, inSize); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferRemoveHead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", inSize); + return(-1); + } + + transform->status = xmlSecTransformStatusFinished; + } else if(transform->status == xmlSecTransformStatusFinished) { + /* the only way we can get here is if there is no input */ + xmlSecAssert2(xmlSecBufferGetSize(&(transform->inBuf)) == 0, -1); + } else { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + NULL, + XMLSEC_ERRORS_R_INVALID_STATUS, + "status=%d", transform->status); + return(-1); + } + return(0); +} + +/********************************************************************* + * + * DES KW implementation + * + *********************************************************************/ +static int +xmlSecNssKWDes3Sha1(void * context, + const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecNssKWDes3CtxPtr ctx = (xmlSecNssKWDes3CtxPtr)context; + PK11Context *pk11ctx = NULL; + unsigned int outLen = 0; + SECStatus status; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= SHA1_LENGTH, -1); + + /* Create a pk11ctx for hashing (digesting) */ + pk11ctx = PK11_CreateDigestContext(SEC_OID_SHA1); + if (pk11ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CreateDigestContext", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + status = PK11_DigestBegin(pk11ctx); + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestBegin", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_DestroyContext(pk11ctx, PR_TRUE); + return(-1); + } + + status = PK11_DigestOp(pk11ctx, in, inSize); + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_DestroyContext(pk11ctx, PR_TRUE); + return(-1); + } + + status = PK11_DigestFinal(pk11ctx, out, &outLen, outSize); + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_DigestFinal", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + PK11_DestroyContext(pk11ctx, PR_TRUE); + return(-1); + } + + /* done */ + PK11_DestroyContext(pk11ctx, PR_TRUE); + xmlSecAssert2(outLen == SHA1_LENGTH, -1); + return(outLen); +} + +static int +xmlSecNssKWDes3GenerateRandom(void * context, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecNssKWDes3CtxPtr ctx = (xmlSecNssKWDes3CtxPtr)context; + SECStatus status; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize > 0, -1); + + status = PK11_GenerateRandom(out, outSize); + if(status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_GenerateRandom", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return((int)outSize); +} + +static int +xmlSecNssKWDes3BlockEncrypt(void * context, + const xmlSecByte * iv, xmlSecSize ivSize, + const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecNssKWDes3CtxPtr ctx = (xmlSecNssKWDes3CtxPtr)context; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecBufferGetData(&(ctx->keyBuffer)) != NULL, -1); + xmlSecAssert2(xmlSecBufferGetSize(&(ctx->keyBuffer)) >= XMLSEC_KW_DES3_KEY_LENGTH, -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize >= XMLSEC_KW_DES3_IV_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + ret = xmlSecNssKWDes3Encrypt(xmlSecBufferGetData(&(ctx->keyBuffer)), XMLSEC_KW_DES3_KEY_LENGTH, + iv, XMLSEC_KW_DES3_IV_LENGTH, + in, inSize, + out, outSize, + 1); /* encrypt */ + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(ret); +} + +static int +xmlSecNssKWDes3BlockDecrypt(void * context, + const xmlSecByte * iv, xmlSecSize ivSize, + const xmlSecByte * in, xmlSecSize inSize, + xmlSecByte * out, xmlSecSize outSize) { + xmlSecNssKWDes3CtxPtr ctx = (xmlSecNssKWDes3CtxPtr)context; + int ret; + + xmlSecAssert2(ctx != NULL, -1); + xmlSecAssert2(xmlSecBufferGetData(&(ctx->keyBuffer)) != NULL, -1); + xmlSecAssert2(xmlSecBufferGetSize(&(ctx->keyBuffer)) >= XMLSEC_KW_DES3_KEY_LENGTH, -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize >= XMLSEC_KW_DES3_IV_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + ret = xmlSecNssKWDes3Encrypt(xmlSecBufferGetData(&(ctx->keyBuffer)), XMLSEC_KW_DES3_KEY_LENGTH, + iv, XMLSEC_KW_DES3_IV_LENGTH, + in, inSize, + out, outSize, + 0); /* decrypt */ + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssKWDes3Encrypt", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return(-1); + } + + return(ret); +} + + + +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* param = NULL; + PK11Context* pk11ctx = NULL; + SECItem keyItem, ivItem; + SECStatus status; + int result_len = -1; + int tmp1_outlen; + unsigned int tmp2_outlen; + + xmlSecAssert2(key != NULL, -1); + xmlSecAssert2(keySize == XMLSEC_KW_DES3_KEY_LENGTH, -1); + xmlSecAssert2(iv != NULL, -1); + xmlSecAssert2(ivSize == XMLSEC_KW_DES3_IV_LENGTH, -1); + xmlSecAssert2(in != NULL, -1); + xmlSecAssert2(inSize > 0, -1); + xmlSecAssert2(out != NULL, -1); + xmlSecAssert2(outSize >= inSize, -1); + + 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; + + param = PK11_ParamFromIV(cipherMech, &ivItem); + if (param == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_ParamFromIV", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + pk11ctx = PK11_CreateContextBySymKey(cipherMech, + enc ? CKA_ENCRYPT : CKA_DECRYPT, + symKey, param); + if (pk11ctx == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CreateContextBySymKey", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + tmp1_outlen = tmp2_outlen = 0; + status = PK11_CipherOp(pk11ctx, out, &tmp1_outlen, outSize, + (unsigned char *)in, inSize); + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PK11_CipherOp", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + goto done; + } + + status = PK11_DigestFinal(pk11ctx, out+tmp1_outlen, + &tmp2_outlen, outSize-tmp1_outlen); + if (status != 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 (param) { + SECITEM_FreeItem(param, PR_TRUE); + } + if (pk11ctx) { + PK11_DestroyContext(pk11ctx, PR_TRUE); + } + + return(result_len); +} + + +#endif /* XMLSEC_NO_DES */ + diff --git a/src/nss/pkikeys.c b/src/nss/pkikeys.c new file mode 100644 index 00000000..ae9e29b4 --- /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..4f54170e --- /dev/null +++ b/src/nss/signatures.c @@ -0,0 +1,841 @@ +/** + * 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 + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaMd5Id)) { + return(1); + } +#endif /* XMLSEC_NO_MD5 */ + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha1Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha256Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha384Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha512Id)) { + return(1); + } +#endif /* XMLSEC_NO_SHA512 */ + +#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; + } else +#endif /* XMLSEC_NO_DSA */ + +#ifndef XMLSEC_NO_RSA + +#ifndef XMLSEC_NO_MD5 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaMd5Id)) { + ctx->keyId = xmlSecNssKeyDataRsaId; + ctx->alg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + } else +#endif /* XMLSEC_NO_MD5 */ + + +#ifndef XMLSEC_NO_SHA1 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha1Id)) { + ctx->keyId = xmlSecNssKeyDataRsaId; + ctx->alg = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; + } else +#endif /* XMLSEC_NO_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha256Id)) { + ctx->keyId = xmlSecNssKeyDataRsaId; + ctx->alg = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; + } else +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha384Id)) { + ctx->keyId = xmlSecNssKeyDataRsaId; + ctx->alg = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; + } else +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 + if(xmlSecTransformCheckId(transform, xmlSecNssTransformRsaSha512Id)) { + ctx->keyId = xmlSecNssKeyDataRsaId; + ctx->alg = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; + } 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); + } + + 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; + + if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) { + /* This creates a signature which is ASN1 encoded */ + SECItem signatureDer; + SECStatus statusDer; + + statusDer = DSAU_EncodeDerSig(&signatureDer, &signature); + if(statusDer != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "DSAU_EncodeDerSig", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", + PORT_GetError()); + return(-1); + } + status = VFY_EndWithSignature(ctx->u.vfy.vfyctx, &signatureDer); + SECITEM_FreeItem(&signatureDer, PR_FALSE); + } else { + status = VFY_EndWithSignature(ctx->u.vfy.vfyctx, &signature); + } + + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "VFY_EndWithSignature", + 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_EndWithSignature", + 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); + } + + if(ctx->alg == SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) { + /* This creates a signature which is ASN1 encoded */ + SECItem * signatureClr; + + signatureClr = DSAU_DecodeDerSig(&signature); + if(signatureClr == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "DSAU_EncodeDerSig", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", + PORT_GetError()); + SECITEM_FreeItem(&signature, PR_FALSE); + return(-1); + } + + ret = xmlSecBufferSetData(out, signatureClr->data, signatureClr->len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", + signatureClr->len); + SECITEM_FreeItem(&signature, PR_FALSE); + return(-1); + } + + SECITEM_FreeItem(signatureClr, PR_TRUE); + } else { + /* This signature is used as-is */ + ret = xmlSecBufferSetData(out, signature.data, signature.len); + if(ret < 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + xmlSecErrorsSafeString(xmlSecTransformGetName(transform)), + "xmlSecBufferSetData", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "size=%d", + signature.len); + SECITEM_FreeItem(&signature, PR_FALSE); + return(-1); + } + } + + /* cleanup */ + SECITEM_FreeItem(&signature, PR_FALSE); + } + 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 + +#ifndef XMLSEC_NO_MD5 +/**************************************************************************** + * + * RSA-MD5 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecNssRsaMd5Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaMd5, /* const xmlChar* name; */ + xmlSecHrefRsaMd5, /* 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; */ +}; + +/** + * xmlSecNssTransformRsaMd5GetKlass: + * + * The RSA-MD5 signature transform klass. + * + * Returns: RSA-MD5 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaMd5GetKlass(void) { + return(&xmlSecNssRsaMd5Klass); +} + +#endif /* XMLSEC_NO_MD5 */ + + +#ifndef XMLSEC_NO_SHA1 +/**************************************************************************** + * + * 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_SHA1 */ + +#ifndef XMLSEC_NO_SHA256 +/**************************************************************************** + * + * RSA-SHA256 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecNssRsaSha256Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha256, /* const xmlChar* name; */ + xmlSecHrefRsaSha256, /* 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; */ +}; + +/** + * xmlSecNssTransformRsaSha256GetKlass: + * + * The RSA-SHA256 signature transform klass. + * + * Returns: RSA-SHA256 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaSha256GetKlass(void) { + return(&xmlSecNssRsaSha256Klass); +} + +#endif /* XMLSEC_NO_SHA256 */ + +#ifndef XMLSEC_NO_SHA384 +/**************************************************************************** + * + * RSA-SHA384 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecNssRsaSha384Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha384, /* const xmlChar* name; */ + xmlSecHrefRsaSha384, /* 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; */ +}; + +/** + * xmlSecNssTransformRsaSha384GetKlass: + * + * The RSA-SHA384 signature transform klass. + * + * Returns: RSA-SHA384 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaSha384GetKlass(void) { + return(&xmlSecNssRsaSha384Klass); +} + +#endif /* XMLSEC_NO_SHA384 */ + +#ifndef XMLSEC_NO_SHA512 +/**************************************************************************** + * + * RSA-SHA512 signature transform + * + ***************************************************************************/ +static xmlSecTransformKlass xmlSecNssRsaSha512Klass = { + /* klass/object sizes */ + sizeof(xmlSecTransformKlass), /* xmlSecSize klassSize */ + xmlSecNssSignatureSize, /* xmlSecSize objSize */ + + xmlSecNameRsaSha512, /* const xmlChar* name; */ + xmlSecHrefRsaSha512, /* 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; */ +}; + +/** + * xmlSecNssTransformRsaSha512GetKlass: + * + * The RSA-SHA512 signature transform klass. + * + * Returns: RSA-SHA512 signature transform klass. + */ +xmlSecTransformId +xmlSecNssTransformRsaSha512GetKlass(void) { + return(&xmlSecNssRsaSha512Klass); +} + +#endif /* XMLSEC_NO_SHA512 */ + +#endif /* XMLSEC_NO_RSA */ + + diff --git a/src/nss/symkeys.c b/src/nss/symkeys.c new file mode 100644 index 00000000..3da7a694 --- /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..887c77cf --- /dev/null +++ b/src/nss/x509.c @@ -0,0 +1,2223 @@ +/** + * 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); + } + + crlDst = SEC_DupCrl(crlSrc); + 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; + int resLen = 64; /* not more than 64 chars */ + PRUint64 val = 0; + unsigned int ii = 0; + int shift = 0; + + xmlSecAssert2(num != NULL, NULL); + xmlSecAssert2(num->type == siBuffer, NULL); + xmlSecAssert2(num->len <= 9, NULL); + xmlSecAssert2(num->data != NULL, NULL); + + /* HACK : to be fixed after + * NSS bug http://bugzilla.mozilla.org/show_bug.cgi?id=212864 is fixed + */ + for(ii = num->len; ii > 0; --ii, shift += 8) { + val |= ((PRUint64)num->data[ii - 1]) << shift; + } + + res = (xmlChar*)xmlMalloc(resLen + 1); + if(res == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlStrdup", + XMLSEC_ERRORS_R_MALLOC_FAILED, + XMLSEC_ERRORS_NO_MESSAGE); + return (NULL); + } + + PR_snprintf((char*)res, resLen, "%llu", val); + 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..fdb866fe --- /dev/null +++ b/src/nss/x509vfy.c @@ -0,0 +1,808 @@ +/** + * 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 { + /* Two uses: + * + * 1) Just keeping a reference to destroy later. + * + * 2) NSS doesn't update it's cache correctly when new certs are added + * https://bugzilla.mozilla.org/show_bug.cgi?id=211051 + * we use this list to perform search ourselves. + */ + + 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 int xmlSecNssNumToItem (SECItem *it, + PRUint64 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(CERTCertList* certsList, + const xmlChar *subjectName, + const xmlChar *issuerName, + const 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(ctx->certsList, 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 CERTName * +xmlSecNssGetCertName(const xmlChar * name) { + xmlChar *tmp, *name2; + xmlChar *p; + CERTName *res; + + xmlSecAssert2(name != NULL, NULL); + + /* nss doesn't support emailAddress (see https://bugzilla.mozilla.org/show_bug.cgi?id=561689) + * This code is not bullet proof and may produce incorrect results if someone has + * "emailAddress=" string in one of the fields, but it is best I can suggest to fix + * this problem. + */ + name2 = xmlStrdup(name); + if(name2 == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + NULL, + XMLSEC_ERRORS_R_MALLOC_FAILED, + "xmlStrlen(name)=%d", + xmlStrlen(name)); + return(NULL); + } + while( (p = (xmlChar*)xmlStrstr(name2, BAD_CAST "emailAddress=")) != NULL) { + memcpy(p, " E=", 13); + } + + tmp = xmlSecNssX509NameRead(name2, xmlStrlen(name2)); + if(tmp == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssX509NameRead", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "name2=\"%s\"", + xmlSecErrorsSafeString(name2)); + xmlFree(name2); + return(NULL); + } + + res = CERT_AsciiToName((char*)tmp); + if (name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_AsciiToName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "ascii=\"%s\", error code=%d", + xmlSecErrorsSafeString((char*)tmp), + PORT_GetError()); + PORT_Free(tmp); + xmlFree(name2); + return(NULL); + } + + PORT_Free(tmp); + return(res); +} + +static CERTCertificate* +xmlSecNssX509FindCert(CERTCertList* certsList, const xmlChar *subjectName, + const xmlChar *issuerName, const xmlChar *issuerSerial, + xmlChar *ski) { + CERTCertificate *cert = NULL; + CERTName *name = NULL; + SECItem *nameitem = NULL; + CERTCertListNode* head; + SECItem tmpitem; + SECStatus status; + PRArenaPool *arena = NULL; + int rv; + + if ((cert == NULL) && (subjectName != NULL)) { + name = xmlSecNssGetCertName(subjectName); + if (name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssGetCertName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "subject=%s", + xmlSecErrorsSafeString(subjectName)); + goto done; + } + + if(arena == NULL) { + 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; + } + } + + 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); + } + + if((cert == NULL) && (issuerName != NULL) && (issuerSerial != NULL)) { + CERTIssuerAndSN issuerAndSN; + PRUint64 issuerSN = 0; + + name = xmlSecNssGetCertName(issuerName); + if (name == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssGetCertName", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "issuer=%s", + xmlSecErrorsSafeString(issuerName)); + goto done; + } + + if(arena == NULL) { + 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; + } + } + + 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_CRYPTO_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 */ + if(PR_sscanf((char *)issuerSerial, "%llu", &issuerSN) != 1) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "PR_sscanf", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "error code=%d", PR_GetError()); + SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE); + goto done; + } + + rv = xmlSecNssNumToItem(&issuerAndSN.serialNumber, issuerSN); + if(rv <= 0) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "xmlSecNssNumToItem", + XMLSEC_ERRORS_R_XMLSEC_FAILED, + "error code=%d", PR_GetError()); + SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE); + goto done; + } + + cert = CERT_FindCertByIssuerAndSN(CERT_GetDefaultCertDB(), &issuerAndSN); + SECITEM_FreeItem(&issuerAndSN.serialNumber, PR_FALSE); + } + + if((cert == NULL) && (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 = len; + cert = CERT_FindCertBySubjectKeyID(CERT_GetDefaultCertDB(), + &subjKeyID); + + /* try to search in our list - NSS doesn't update it's cache correctly + * when new certs are added https://bugzilla.mozilla.org/show_bug.cgi?id=211051 + */ + if((cert == NULL) && (certsList != NULL)) { + + for(head = CERT_LIST_HEAD(certsList); + (cert == NULL) && !CERT_LIST_END(head, certsList) && + (head != NULL) && (head->cert != NULL); + head = CERT_LIST_NEXT(head) + ) { + + memset(&tmpitem, 0, sizeof(tmpitem)); + status = CERT_FindSubjectKeyIDExtension(head->cert, &tmpitem); + if (status != SECSuccess) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_FindSubjectKeyIDExtension", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "ski"); + SECITEM_FreeItem(&tmpitem, PR_FALSE); + goto done; + } + + if((tmpitem.len == subjKeyID.len) && + (memcmp(tmpitem.data, subjKeyID.data, subjKeyID.len) == 0) + ) { + cert = CERT_DupCertificate(head->cert); + if(cert == NULL) { + xmlSecError(XMLSEC_ERRORS_HERE, + NULL, + "CERT_DupCertificate", + XMLSEC_ERRORS_R_CRYPTO_FAILED, + "error code=%d", PORT_GetError()); + SECITEM_FreeItem(&tmpitem, PR_FALSE); + goto done; + } + } + SECITEM_FreeItem(&tmpitem, PR_FALSE); + } + } + } + +done: + 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 int +xmlSecNssNumToItem(SECItem *it, PRUint64 ui) +{ + unsigned char bb[9]; + unsigned int zeros_len; + + xmlSecAssert2(it != NULL, -1); + + bb[0] = 0; /* important: we should have 0 at the beginning! */ + bb[1] = (unsigned char) (ui >> 56); + bb[2] = (unsigned char) (ui >> 48); + bb[3] = (unsigned char) (ui >> 40); + bb[4] = (unsigned char) (ui >> 32); + bb[5] = (unsigned char) (ui >> 24); + bb[6] = (unsigned char) (ui >> 16); + bb[7] = (unsigned char) (ui >> 8); + bb[8] = (unsigned char) (ui); + + /* + ** Small integers are encoded in a single byte. Larger integers + ** require progressively more space. Start from 1 because byte at + ** position 0 is zero + */ + for(zeros_len = 1; (zeros_len < sizeof(bb)) && (bb[zeros_len] == 0); ++zeros_len); + + it->len = sizeof(bb) - (zeros_len - 1); + it->data = (unsigned char *)PORT_Alloc(it->len); + if (it->data == NULL) { + it->len = 0; + return (-1); + } + + PORT_Memcpy(it->data, bb + (zeros_len - 1), it->len); + return(it->len); +} +#endif /* XMLSEC_NO_X509 */ + + |