diff --git a/.bind.metadata b/.bind.metadata new file mode 100644 index 0000000..1d11ff5 --- /dev/null +++ b/.bind.metadata @@ -0,0 +1,3 @@ +d7be390e6c2546f37a7280e1975e1cd134565f62 SOURCES/bind-9.9.4.tar.gz +ad9ddfde8fa124143142f1a70f88d310c0373c3d SOURCES/config-15.tar.bz2 +d3c4943f2f2aa1f7c51487af02ff3a52ca51a6d9 SOURCES/geoip-testing-data.tar.xz diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..379555a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +SOURCES/bind-9.9.4.tar.gz +SOURCES/config-15.tar.bz2 +SOURCES/geoip-testing-data.tar.xz diff --git a/README.md b/README.md deleted file mode 100644 index 0e7897f..0000000 --- a/README.md +++ /dev/null @@ -1,5 +0,0 @@ -The master branch has no content - -Look at the c7 branch if you are working with CentOS-7, or the c4/c5/c6 branch for CentOS-4, 5 or 6 - -If you find this file in a distro specific branch, it means that no content has been checked in yet diff --git a/SOURCES/README.sdb_pgsql b/SOURCES/README.sdb_pgsql new file mode 100644 index 0000000..c10c294 --- /dev/null +++ b/SOURCES/README.sdb_pgsql @@ -0,0 +1,79 @@ + PGSQL BIND SDB driver + +The postgresql BIND SDB driver is of experimental status and should not be +used for production systems. + +Usage: + +o Use the named_sdb process ( put ENABLE_SDB=yes in /etc/sysconfig/named ) + +o Edit your named.conf to contain a database zone, eg. : + +zone "pgdb.net." IN { + type master; + database "pgsql bind pgdb localhost pguser pgpasswd"; + # ^- DB name ^-Table ^-host ^-user ^-password +}; + +o Create the database zone table + The table must contain the columns "name", "rdtype", and "rdata", and + is expected to contain a properly constructed zone. The program "zonetodb" + creates such a table. + + zonetodb usage: + + zonetodb origin file dbname dbtable + + where + origin : zone origin, eg "pgdb.net." + file : master zone database file, eg. pgdb.net.db + dbname : name of postgresql database + dbtable: name of table in database + + Eg. to import this zone in the file 'pgdb.net.db' into the 'bind' database + 'pgdb' table: + +--- +#pgdb.net.db: +$TTL 1H +@ SOA localhost. root.localhost. ( 1 + 3H + 1H + 1W + 1H ) + NS localhost. +host1 A 192.168.2.1 +host2 A 192.168.2.2 +host3 A 192.168.2.3 +host4 A 192.168.2.4 +host5 A 192.168.2.5 +host6 A 192.168.2.6 +host7 A 192.168.2.7 +--- + +Issue this command as the pgsql user authorized to update the bind database: + +# zonetodb pgdb.net. pgdb.net.db bind pgdb + +will create / update the pgdb table in the 'bind' db: + +$ psql -dbind -c 'select * from pgdb;' + name | ttl | rdtype | rdata +----------------+------+--------+----------------------------------------------------- + pgdb.net | 3600 | SOA | localhost. root.localhost. 1 10800 3600 604800 3600 + pgdb.net | 3600 | NS | localhost. + host1.pgdb.net | 3600 | A | 192.168.2.1 + host2.pgdb.net | 3600 | A | 192.168.2.2 + host3.pgdb.net | 3600 | A | 192.168.2.3 + host4.pgdb.net | 3600 | A | 192.168.2.4 + host5.pgdb.net | 3600 | A | 192.168.2.5 + host6.pgdb.net | 3600 | A | 192.168.2.6 + host7.pgdb.net | 3600 | A | 192.168.2.7 +(9 rows) + +I've tested exactly the above configuration with bind-sdb-9.3.1+ and it works OK. + +NOTE: If you use pgsqldb SDB, ensure the postgresql service is started before the named + service . + +USE AT YOUR OWN RISK! diff --git a/SOURCES/bind-9.3.1rc1-sdb_tools-Makefile.in b/SOURCES/bind-9.3.1rc1-sdb_tools-Makefile.in new file mode 100644 index 0000000..7f3c5e2 --- /dev/null +++ b/SOURCES/bind-9.3.1rc1-sdb_tools-Makefile.in @@ -0,0 +1,63 @@ +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +@BIND9_VERSION@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include \ + ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} + +CDEFINES = -DBIND9 + +DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCLIBS = ../../lib/isccc/libisccc.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ +LWRESLIBS = ../../lib/lwres/liblwres.@A@ +BIND9LIBS = ../../lib/bind9/libbind9.@A@ + +DNSDEPLIBS = ../../lib/dns/libdns.@A@ +ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@ +ISCDEPLIBS = ../../lib/isc/libisc.@A@ +LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ +BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ + +DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${ISCDEPLIBS} + +LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} ${DBDRIVER_LIBS} @LIBS@ + +TARGETS = zone2ldap@EXEEXT@ zonetodb@EXEEXT@ + +OBJS = zone2ldap.@O@ zonetodb.@O@ + +SRCS = zone2ldap.c zonetodb.c + +MANPAGES = zone2ldap.1 + +EXT_CFLAGS = + +@BIND9_MAKE_RULES@ + +zone2ldap@EXEEXT@: zone2ldap.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone2ldap.@O@ -lldap -llber ${LIBS} + +zonetodb@EXEEXT@: zonetodb.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zonetodb.@O@ -lpq ${LIBS} + +clean distclean manclean maintainer-clean:: + rm -f ${TARGETS} ${OBJS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man1 + +install:: ${TARGETS} installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zone2ldap@EXEEXT@ ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zonetodb@EXEEXT@ ${DESTDIR}${sbindir} + ${INSTALL_DATA} ${srcdir}/zone2ldap.1 ${DESTDIR}${mandir}/man1/zone2ldap.1 diff --git a/SOURCES/bind-9.3.2-redhat_doc.patch b/SOURCES/bind-9.3.2-redhat_doc.patch new file mode 100644 index 0000000..6aafac2 --- /dev/null +++ b/SOURCES/bind-9.3.2-redhat_doc.patch @@ -0,0 +1,60 @@ +--- bind-9.4.0/bin/named/named.8.redhat_doc 2007-01-30 01:23:44.000000000 +0100 ++++ bind-9.4.0/bin/named/named.8 2007-03-12 15:39:19.000000000 +0100 +@@ -205,6 +205,57 @@ + \fI/var/run/named/named.pid\fR + .RS 4 + The default process\-id file. ++.PP ++.SH "NOTES" ++.PP ++.TP ++\fBRed Hat SELinux BIND Security Profile:\fR ++.PP ++By default, Red Hat ships BIND with the most secure SELinux policy ++that will not prevent normal BIND operation and will prevent exploitation ++of all known BIND security vulnerabilities . See the selinux(8) man page ++for information about SElinux. ++.PP ++It is not necessary to run named in a chroot environment if the Red Hat ++SELinux policy for named is enabled. When enabled, this policy is far ++more secure than a chroot environment. Users are recommended to enable ++SELinux and remove the bind-chroot package. ++.PP ++With this extra security comes some restrictions: ++.PP ++By default, the SELinux policy does not allow named to write any master ++zone database files. Only the root user may create files in the $ROOTDIR/var/named ++zone database file directory (the options { "directory" } option), where ++$ROOTDIR is set in /etc/sysconfig/named. ++.PP ++The "named" group must be granted read privelege to ++these files in order for named to be enabled to read them. ++.PP ++Any file created in the zone database file directory is automatically assigned ++the SELinux file context named_zone_t . ++.PP ++By default, SELinux prevents any role from modifying named_zone_t files; this ++means that files in the zone database directory cannot be modified by dynamic ++DNS (DDNS) updates or zone transfers. ++.PP ++The Red Hat BIND distribution and SELinux policy creates three directories where ++named is allowed to create and modify files: /var/named/slaves, /var/named/dynamic ++/var/named/data. By placing files you want named to modify, such as ++slave or DDNS updateable zone files and database / statistics dump files in ++these directories, named will work normally and no further operator action is ++required. Files in these directories are automatically assigned the 'named_cache_t' ++file context, which SELinux allows named to write. ++.PP ++\fBRed Hat BIND SDB support:\fR ++.PP ++Red Hat ships named with compiled in Simplified Database Backend modules that ISC ++provides in the "contrib/sdb" directory. Install bind-sdb package if you want use them ++.PP ++The SDB modules for LDAP, PostGreSQL, DirDB and SQLite are compiled into named-sdb. ++.PP ++See the documentation for the various SDB modules in /usr/share/doc/bind-sdb-*/ . ++.br ++.PP + .RE + .SH "SEE ALSO" + .PP diff --git a/SOURCES/bind-9.3.2b1-fix_sdb_ldap.patch b/SOURCES/bind-9.3.2b1-fix_sdb_ldap.patch new file mode 100644 index 0000000..42e6aa7 --- /dev/null +++ b/SOURCES/bind-9.3.2b1-fix_sdb_ldap.patch @@ -0,0 +1,524 @@ +diff -up bind-9.5.1b1/bin/sdb_tools/Makefile.in.fix_sdb_ldap bind-9.5.1b1/bin/sdb_tools/Makefile.in +--- bind-9.5.1b1/bin/sdb_tools/Makefile.in.fix_sdb_ldap 2008-07-21 12:14:00.000000000 +0200 ++++ bind-9.5.1b1/bin/sdb_tools/Makefile.in 2008-07-21 12:17:51.000000000 +0200 +@@ -30,11 +30,11 @@ DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} + LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} ${DBDRIVER_LIBS} @LIBS@ + +-TARGETS = zone2ldap@EXEEXT@ zonetodb@EXEEXT@ ++TARGETS = zone2ldap@EXEEXT@ ldap2zone@EXEEXT@ zonetodb@EXEEXT@ + +-OBJS = zone2ldap.@O@ zonetodb.@O@ ++OBJS = zone2ldap.@O@ ldap2zone.@O@ zonetodb.@O@ + +-SRCS = zone2ldap.c zonetodb.c ++SRCS = zone2ldap.c ldap2zone.c zonetodb.c + + MANPAGES = zone2ldap.1 + +@@ -48,6 +48,9 @@ zone2ldap@EXEEXT@: zone2ldap.@O@ ${DEPLI + zonetodb@EXEEXT@: zonetodb.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zonetodb.@O@ -lpq ${LIBS} + ++ldap2zone@EXEEXT@: ldap2zone.@O@ ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ ldap2zone.@O@ -lldap -llber ${LIBS} ++ + clean distclean manclean maintainer-clean:: + rm -f ${TARGETS} ${OBJS} + +@@ -57,5 +60,6 @@ installdirs: + + install:: ${TARGETS} installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zone2ldap@EXEEXT@ ${DESTDIR}${sbindir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} ldap2zone@EXEEXT@ ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zonetodb@EXEEXT@ ${DESTDIR}${sbindir} + ${INSTALL_DATA} ${srcdir}/zone2ldap.1 ${DESTDIR}${mandir}/man1/zone2ldap.1 +diff -up bind-9.5.1b1/bin/sdb_tools/zone2ldap.c.fix_sdb_ldap bind-9.5.1b1/bin/sdb_tools/zone2ldap.c +--- bind-9.5.1b1/bin/sdb_tools/zone2ldap.c.fix_sdb_ldap 2008-07-21 12:14:00.000000000 +0200 ++++ bind-9.5.1b1/bin/sdb_tools/zone2ldap.c 2008-07-21 12:14:00.000000000 +0200 +@@ -24,6 +24,7 @@ + #include <isc/hash.h> + #include <isc/mem.h> + #include <isc/print.h> ++#include <isc/hash.h> + #include <isc/result.h> + + #include <dns/db.h> +@@ -61,6 +62,9 @@ ldap_info; + /* usage Info */ + void usage (void); + ++/* Check for existence of (and possibly add) containing dNSZone objects */ ++int lookup_dns_zones( ldap_info *ldinfo); ++ + /* Add to the ldap dit */ + void add_ldap_values (ldap_info * ldinfo); + +@@ -77,7 +81,7 @@ char **hostname_to_dn_list (char *hostna + int get_attr_list_size (char **tmp); + + /* Get a DN */ +-char *build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag); ++char *build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag, char *zone); + + /* Add to RR list */ + void add_to_rr_list (char *dn, char *name, char *type, char *data, +@@ -99,11 +103,27 @@ void + init_ldap_conn (); + void usage(); + +-char *argzone, *ldapbase, *binddn, *bindpw = NULL; +-const char *ldapsystem = "localhost"; +-static const char *objectClasses[] = +- { "top", "dNSZone", NULL }; +-static const char *topObjectClasses[] = { "top", NULL }; ++static char *argzone, *ldapbase, *binddn, *bindpw = NULL; ++ ++/* these are needed to placate gcc4's const-ness const-ernations : */ ++static char localhost[] = "localhost"; ++static char *ldapsystem=&(localhost[0]); ++/* dnszone schema class names: */ ++static char topClass [] ="top"; ++static char dNSZoneClass[] ="dNSZone"; ++static char objectClass [] ="objectClass"; ++static char dcObjectClass[]="dcObject"; ++/* dnszone schema attribute names: */ ++static char relativeDomainName[]="relativeDomainName"; ++static char dNSTTL []="dNSTTL"; ++static char zoneName []="zoneName"; ++static char dc []="dc"; ++static char sameZone []="@"; ++/* LDAPMod mod_values: */ ++static char *objectClasses []= { &(topClass[0]), &(dNSZoneClass[0]), NULL }; ++static char *topObjectClasses []= { &(topClass[0]), &(dcObjectClass[0]), &(dNSZoneClass[0]), NULL }; ++static char *dn_buffer [64]={NULL}; ++ + LDAP *conn; + unsigned int debug = 0; + +@@ -119,12 +139,12 @@ main (int argc, char **argv) + isc_result_t result; + char *basedn; + ldap_info *tmp; +- LDAPMod *base_attrs[2]; +- LDAPMod base; ++ LDAPMod *base_attrs[5]; ++ LDAPMod base, dcBase, znBase, rdnBase; + isc_buffer_t buff; + char *zonefile=0L; + char fullbasedn[1024]; +- char *ctmp; ++ char *ctmp, *zn, *dcp[2], *znp[2], *rdn[2]; + dns_fixedname_t fixedzone, fixedname; + dns_rdataset_t rdataset; + char **dc_list; +@@ -137,7 +157,7 @@ main (int argc, char **argv) + extern char *optarg; + extern int optind, opterr, optopt; + int create_base = 0; +- int topt; ++ int topt, dcn, zdn, znlen; + + if ((int) argc < 2) + { +@@ -145,7 +165,7 @@ main (int argc, char **argv) + exit (-1); + } + +- while ((topt = getopt ((int) argc, argv, "D:w:b:z:f:h:?dcv")) != -1) ++ while ((topt = getopt ((int) argc, argv, "D:Ww:b:z:f:h:?dcv")) != -1) + { + switch (topt) + { +@@ -164,8 +184,11 @@ main (int argc, char **argv) + case 'w': + bindpw = strdup (optarg); + break; ++ case 'W': ++ bindpw = getpass("Enter LDAP Password: "); ++ break; + case 'b': +- ldapbase = strdup (optarg); ++ ldapbase = strdup (optarg); + break; + case 'z': + argzone = strdup (optarg); +@@ -277,27 +300,62 @@ main (int argc, char **argv) + { + if (debug) + printf ("Creating base zone DN %s\n", argzone); +- ++ + dc_list = hostname_to_dn_list (argzone, argzone, DNS_TOP); +- basedn = build_dn_from_dc_list (dc_list, 0, NO_SPEC); + +- for (ctmp = &basedn[strlen (basedn)]; ctmp >= &basedn[0]; ctmp--) ++ basedn = build_dn_from_dc_list (dc_list, 0, NO_SPEC, argzone); ++ if (debug) ++ printf ("base DN %s\n", basedn); ++ ++ for (ctmp = &basedn[strlen (basedn)], dcn=0; ctmp >= &basedn[0]; ctmp--) + { +- if ((*ctmp == ',') || (ctmp == &basedn[0])) ++ if ((*ctmp == ',') || (ctmp == &basedn[0])) + { ++ + base.mod_op = LDAP_MOD_ADD; +- base.mod_type = (char*)"objectClass"; +- base.mod_values = (char**)topObjectClasses; ++ base.mod_type = objectClass; ++ base.mod_values = topObjectClasses; + base_attrs[0] = (void*)&base; +- base_attrs[1] = NULL; +- ++ ++ dcBase.mod_op = LDAP_MOD_ADD; ++ dcBase.mod_type = dc; ++ dcp[0]=dc_list[dcn]; ++ dcp[1]=0L; ++ dcBase.mod_values=dcp; ++ base_attrs[1] = (void*)&dcBase; ++ ++ znBase.mod_op = LDAP_MOD_ADD; ++ znBase.mod_type = zoneName; ++ for( zdn = dcn, znlen = 0; zdn >= 0; zdn-- ) ++ znlen += strlen(dc_list[zdn])+1; ++ znp[0] = (char*)malloc(znlen+1); ++ znp[1] = 0L; ++ for( zdn = dcn, zn=znp[0]; zdn >= 0; zdn-- ) ++ zn+=sprintf(zn,"%s%s",dc_list[zdn], ++ ((zdn > 0) && (*(dc_list[zdn-1])!='.')) ? "." : "" ++ ); ++ ++ znBase.mod_values = znp; ++ base_attrs[2] = (void*)&znBase; ++ ++ rdnBase.mod_op = LDAP_MOD_ADD; ++ rdnBase.mod_type = relativeDomainName; ++ rdn[0] = strdup(sameZone); ++ rdn[1] = 0L; ++ rdnBase.mod_values = rdn; ++ base_attrs[3] = (void*)&rdnBase; ++ ++ dcn++; ++ ++ base.mod_values = topObjectClasses; ++ base_attrs[4] = NULL; ++ + if (ldapbase) + { + if (ctmp != &basedn[0]) + sprintf (fullbasedn, "%s,%s", ctmp + 1, ldapbase); + else +- sprintf (fullbasedn, "%s,%s", ctmp, ldapbase); +- ++ sprintf (fullbasedn, "%s,%s", ctmp, ldapbase); + } + else + { +@@ -306,8 +364,13 @@ main (int argc, char **argv) + else + sprintf (fullbasedn, "%s", ctmp); + } ++ ++ if( debug ) ++ printf("Full base dn: %s\n", fullbasedn); ++ + result = ldap_add_s (conn, fullbasedn, base_attrs); + ldap_result_check ("intial ldap_add_s", fullbasedn, result); ++ + } + + } +@@ -383,14 +446,14 @@ generate_ldap (dns_name_t * dnsname, dns + isc_result_check (result, "dns_rdata_totext"); + data[isc_buffer_usedlength (&buff)] = 0; + +- dc_list = hostname_to_dn_list (name, argzone, DNS_OBJECT); ++ dc_list = hostname_to_dn_list ((char*)name, argzone, DNS_OBJECT); + len = (get_attr_list_size (dc_list) - 2); +- dn = build_dn_from_dc_list (dc_list, ttl, WI_SPEC); ++ dn = build_dn_from_dc_list (dc_list, ttl, WI_SPEC, argzone); + + if (debug) + printf ("Adding %s (%s %s) to run queue list.\n", dn, type, data); + +- add_to_rr_list (dn, dc_list[len], type, data, ttl, DNS_OBJECT); ++ add_to_rr_list (dn, dc_list[len], (char*)type, (char*)data, ttl, DNS_OBJECT); + } + + +@@ -430,7 +493,8 @@ add_to_rr_list (char *dn, char *name, ch + int attrlist; + char ldap_type_buffer[128]; + char charttl[64]; +- ++ char *zn; ++ int znlen; + + if ((tmp = locate_by_dn (dn)) == NULL) + { +@@ -465,13 +529,13 @@ add_to_rr_list (char *dn, char *name, ch + } + } + tmp->attrs[0]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[0]->mod_type = (char*)"objectClass"; ++ tmp->attrs[0]->mod_type = objectClass; + + if (flags == DNS_OBJECT) +- tmp->attrs[0]->mod_values = (char**)objectClasses; ++ tmp->attrs[0]->mod_values = objectClasses; + else + { +- tmp->attrs[0]->mod_values = (char**)topObjectClasses; ++ tmp->attrs[0]->mod_values =topObjectClasses; + tmp->attrs[1] = NULL; + tmp->attrcnt = 2; + tmp->next = ldap_info_base; +@@ -480,7 +544,7 @@ add_to_rr_list (char *dn, char *name, ch + } + + tmp->attrs[1]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[1]->mod_type = (char*)"relativeDomainName"; ++ tmp->attrs[1]->mod_type = relativeDomainName; + tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2); + + if (tmp->attrs[1]->mod_values == (char **)NULL) +@@ -502,7 +566,7 @@ add_to_rr_list (char *dn, char *name, ch + tmp->attrs[2]->mod_values[1] = NULL; + + tmp->attrs[3]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[3]->mod_type = (char*)"dNSTTL"; ++ tmp->attrs[3]->mod_type = dNSTTL; + tmp->attrs[3]->mod_values = (char **) calloc (sizeof (char *), 2); + + if (tmp->attrs[3]->mod_values == (char **)NULL) +@@ -512,10 +576,21 @@ add_to_rr_list (char *dn, char *name, ch + tmp->attrs[3]->mod_values[0] = strdup (charttl); + tmp->attrs[3]->mod_values[1] = NULL; + ++ znlen=strlen(gbl_zone); ++ if ( *(gbl_zone + (znlen-1)) == '.' ) ++ { /* ldapdb MUST search by relative zone name */ ++ zn = (char*)malloc(znlen); ++ strncpy(zn,gbl_zone,znlen-1); ++ *(zn + (znlen-1))='\0'; ++ }else ++ { ++ zn = gbl_zone; ++ } ++ + tmp->attrs[4]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[4]->mod_type = (char*)"zoneName"; ++ tmp->attrs[4]->mod_type = zoneName; + tmp->attrs[4]->mod_values = (char **)calloc(sizeof(char *), 2); +- tmp->attrs[4]->mod_values[0] = gbl_zone; ++ tmp->attrs[4]->mod_values[0] = zn; + tmp->attrs[4]->mod_values[1] = NULL; + + tmp->attrs[5] = NULL; +@@ -526,7 +601,7 @@ add_to_rr_list (char *dn, char *name, ch + else + { + +- for (i = 0; tmp->attrs[i] != NULL; i++) ++ for (i = 0; tmp->attrs[i] != NULL; i++) + { + sprintf (ldap_type_buffer, "%sRecord", type); + if (!strncmp +@@ -595,69 +670,105 @@ char ** + hostname_to_dn_list (char *hostname, char *zone, unsigned int flags) + { + char *tmp; +- static char *dn_buffer[64]; + int i = 0; +- char *zname; +- char *hnamebuff; +- +- zname = strdup (hostname); +- +- if (flags == DNS_OBJECT) +- { ++ char *hname=0L, *last=0L; ++ int hlen=strlen(hostname), zlen=(strlen(zone)); + +- if (strlen (zname) != strlen (zone)) +- { +- tmp = &zname[strlen (zname) - strlen (zone)]; +- *--tmp = '\0'; +- hnamebuff = strdup (zname); +- zname = ++tmp; +- } +- else +- hnamebuff = (char*)"@"; +- } +- else +- { +- zname = zone; +- hnamebuff = NULL; +- } +- +- for (tmp = strrchr (zname, '.'); tmp != (char *) 0; +- tmp = strrchr (zname, '.')) +- { +- *tmp++ = '\0'; +- dn_buffer[i++] = tmp; +- } +- dn_buffer[i++] = zname; +- dn_buffer[i++] = hnamebuff; ++/* printf("hostname: %s zone: %s\n",hostname, zone); */ ++ hname=0L; ++ if(flags == DNS_OBJECT) ++ { ++ if( (zone[ zlen - 1 ] == '.') && (hostname[hlen - 1] != '.') ) ++ { ++ hname=(char*)malloc(hlen + 1); ++ hlen += 1; ++ sprintf(hname, "%s.", hostname); ++ hostname = hname; ++ } ++ if(strcmp(hostname, zone) == 0) ++ { ++ if( hname == 0 ) ++ hname=strdup(hostname); ++ last = strdup(sameZone); ++ }else ++ { ++ if( (hlen < zlen) ++ ||( strcmp( hostname + (hlen - zlen), zone ) != 0) ++ ) ++ { ++ if( hname != 0 ) ++ free(hname); ++ hname=(char*)malloc( hlen + zlen + 1); ++ if( *zone == '.' ) ++ sprintf(hname, "%s%s", hostname, zone); ++ else ++ sprintf(hname,"%s",zone); ++ }else ++ { ++ if( hname == 0 ) ++ hname = strdup(hostname); ++ } ++ last = hname; ++ } ++ }else ++ { /* flags == DNS_TOP */ ++ hname = strdup(zone); ++ last = hname; ++ } ++ ++ for (tmp = strrchr (hname, '.'); tmp != (char *) 0; ++ tmp = strrchr (hname, '.')) ++ { ++ if( *( tmp + 1 ) != '\0' ) ++ { ++ *tmp = '\0'; ++ dn_buffer[i++] = ++tmp; ++ }else ++ { /* trailing '.' ! */ ++ dn_buffer[i++] = strdup("."); ++ *tmp = '\0'; ++ if( tmp == hname ) ++ break; ++ } ++ } ++ if( ( last != hname ) && (tmp != hname) ) ++ dn_buffer[i++] = hname; ++ dn_buffer[i++] = last; + dn_buffer[i] = NULL; +- + return dn_buffer; + } + +- + /* build an sdb compatible LDAP DN from a "dc_list" (char **). + * will append dNSTTL information to each RR Record, with the + * exception of "@"/SOA. */ + + char * +-build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag) ++build_dn_from_dc_list (char **dc_list, unsigned int ttl, int flag, char *zone) + { + int size; +- int x; ++ int x, znlen; + static char dn[1024]; + char tmp[128]; ++ char zn[DNS_NAME_MAXTEXT+1]; + + bzero (tmp, sizeof (tmp)); + bzero (dn, sizeof (dn)); + size = get_attr_list_size (dc_list); ++ znlen = strlen(zone); ++ if ( *(zone + (znlen-1)) == '.' ) ++ { /* ldapdb MUST search by relative zone name */ ++ memcpy(&(zn[0]),zone,znlen-1); ++ *(zn + (znlen-1))='\0'; ++ zone = zn; ++ } + for (x = size - 2; x > 0; x--) + { + if (flag == WI_SPEC) + { + if (x == (size - 2) && (strncmp (dc_list[x], "@", 1) == 0) && (ttl)) +- sprintf (tmp, "relativeDomainName=%s + dNSTTL=%d,", dc_list[x], ttl); ++ sprintf (tmp, "zoneName=%s + relativeDomainName=%s,", zone, dc_list[x]); + else if (x == (size - 2)) +- sprintf(tmp, "relativeDomainName=%s,",dc_list[x]); ++ sprintf(tmp, "zoneName=%s + relativeDomainName=%s,", zone, dc_list[x]); + else + sprintf(tmp,"dc=%s,", dc_list[x]); + } +@@ -683,6 +794,7 @@ void + init_ldap_conn () + { + int result; ++ char ldb_tag[]="LDAP Bind"; + conn = ldap_open (ldapsystem, LDAP_PORT); + if (conn == NULL) + { +@@ -692,7 +804,7 @@ init_ldap_conn () + } + + result = ldap_simple_bind_s (conn, binddn, bindpw); +- ldap_result_check ("ldap_simple_bind_s", (char*)"LDAP Bind", result); ++ ldap_result_check ("ldap_simple_bind_s", ldb_tag , result); + } + + /* Like isc_result_check, only for LDAP */ +@@ -709,8 +821,6 @@ ldap_result_check (const char *msg, char + } + } + +- +- + /* For running the ldap_info run queue. */ + void + add_ldap_values (ldap_info * ldinfo) +@@ -718,14 +828,14 @@ add_ldap_values (ldap_info * ldinfo) + int result; + char dnbuffer[1024]; + +- + if (ldapbase != NULL) + sprintf (dnbuffer, "%s,%s", ldinfo->dn, ldapbase); + else + sprintf (dnbuffer, "%s", ldinfo->dn); + + result = ldap_add_s (conn, dnbuffer, ldinfo->attrs); +- ldap_result_check ("ldap_add_s", dnbuffer, result); ++ ldap_result_check ("ldap_add_s", dnbuffer, result); ++ + } + + +@@ -736,7 +846,7 @@ void + usage () + { + fprintf (stderr, +- "zone2ldap -D [BIND DN] -w [BIND PASSWORD] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]\n" ++ "zone2ldap -D [BIND DN] [-w BIND PASSWORD | -W:prompt] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]\n" + "\t[-c Create LDAP Base structure][-d Debug Output (lots !)]\n " + ); + } diff --git a/SOURCES/bind-9.3.2b2-sdbsrc.patch b/SOURCES/bind-9.3.2b2-sdbsrc.patch new file mode 100644 index 0000000..bd0ed32 --- /dev/null +++ b/SOURCES/bind-9.3.2b2-sdbsrc.patch @@ -0,0 +1,243 @@ +--- bind-9.3.2b2/contrib/sdb/ldap/zone2ldap.c.sdbsrc 2005-08-16 00:43:03.000000000 -0400 ++++ bind-9.3.2b2/contrib/sdb/ldap/zone2ldap.c 2005-11-15 12:57:44.000000000 -0500 +@@ -59,16 +59,16 @@ + ldap_info; + + /* usage Info */ +-void usage (); ++void usage (void); + + /* Add to the ldap dit */ + void add_ldap_values (ldap_info * ldinfo); + + /* Init an ldap connection */ +-void init_ldap_conn (); ++void init_ldap_conn (void); + + /* Ldap error checking */ +-void ldap_result_check (char *msg, char *dn, int err); ++void ldap_result_check (const char *msg, char *dn, int err); + + /* Put a hostname into a char ** array */ + char **hostname_to_dn_list (char *hostname, char *zone, unsigned int flags); +@@ -84,7 +84,7 @@ + unsigned int ttl, unsigned int flags); + + /* Error checking */ +-void isc_result_check (isc_result_t res, char *errorstr); ++void isc_result_check (isc_result_t res, const char *errorstr); + + /* Generate LDIF Format files */ + void generate_ldap (dns_name_t * dnsname, dns_rdata_t * rdata, +@@ -93,11 +93,17 @@ + /* head pointer to the list */ + ldap_info *ldap_info_base = NULL; + ++ldap_info * ++locate_by_dn (char *dn); ++void ++init_ldap_conn (); ++void usage(); ++ + char *argzone, *ldapbase, *binddn, *bindpw = NULL; +-char *ldapsystem = "localhost"; +-static char *objectClasses[] = ++const char *ldapsystem = "localhost"; ++static const char *objectClasses[] = + { "top", "dNSZone", NULL }; +-static char *topObjectClasses[] = { "top", NULL }; ++static const char *topObjectClasses[] = { "top", NULL }; + LDAP *conn; + unsigned int debug = 0; + +@@ -106,7 +112,7 @@ + #endif + + int +-main (int *argc, char **argv) ++main (int argc, char **argv) + { + isc_mem_t *mctx = NULL; + isc_entropy_t *ectx = NULL; +@@ -116,7 +122,7 @@ + LDAPMod *base_attrs[2]; + LDAPMod base; + isc_buffer_t buff; +- char *zonefile; ++ char *zonefile=0L; + char fullbasedn[1024]; + char *ctmp; + dns_fixedname_t fixedzone, fixedname; +@@ -280,9 +286,9 @@ + if ((*ctmp == ',') || (ctmp == &basedn[0])) + { + base.mod_op = LDAP_MOD_ADD; +- base.mod_type = "objectClass"; +- base.mod_values = topObjectClasses; +- base_attrs[0] = &base; ++ base.mod_type = (char*)"objectClass"; ++ base.mod_values = (char**)topObjectClasses; ++ base_attrs[0] = (void*)&base; + base_attrs[1] = NULL; + + if (ldapbase) +@@ -337,7 +343,7 @@ + * I should probably rename this function, as not to cause any + * confusion with the isc* routines. Will exit on error. */ + void +-isc_result_check (isc_result_t res, char *errorstr) ++isc_result_check (isc_result_t res, const char *errorstr) + { + if (res != ISC_R_SUCCESS) + { +@@ -449,7 +455,7 @@ + exit (-1); + } + +- for (i = 0; i < flags; i++) ++ for (i = 0; i < (int)flags; i++) + { + tmp->attrs[i] = (LDAPMod *) malloc (sizeof (LDAPMod)); + if (tmp->attrs[i] == (LDAPMod *) NULL) +@@ -459,13 +465,13 @@ + } + } + tmp->attrs[0]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[0]->mod_type = "objectClass"; ++ tmp->attrs[0]->mod_type = (char*)"objectClass"; + + if (flags == DNS_OBJECT) +- tmp->attrs[0]->mod_values = objectClasses; ++ tmp->attrs[0]->mod_values = (char**)objectClasses; + else + { +- tmp->attrs[0]->mod_values = topObjectClasses; ++ tmp->attrs[0]->mod_values = (char**)topObjectClasses; + tmp->attrs[1] = NULL; + tmp->attrcnt = 2; + tmp->next = ldap_info_base; +@@ -474,7 +480,7 @@ + } + + tmp->attrs[1]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[1]->mod_type = "relativeDomainName"; ++ tmp->attrs[1]->mod_type = (char*)"relativeDomainName"; + tmp->attrs[1]->mod_values = (char **) calloc (sizeof (char *), 2); + + if (tmp->attrs[1]->mod_values == (char **)NULL) +@@ -496,7 +502,7 @@ + tmp->attrs[2]->mod_values[1] = NULL; + + tmp->attrs[3]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[3]->mod_type = "dNSTTL"; ++ tmp->attrs[3]->mod_type = (char*)"dNSTTL"; + tmp->attrs[3]->mod_values = (char **) calloc (sizeof (char *), 2); + + if (tmp->attrs[3]->mod_values == (char **)NULL) +@@ -507,7 +513,7 @@ + tmp->attrs[3]->mod_values[1] = NULL; + + tmp->attrs[4]->mod_op = LDAP_MOD_ADD; +- tmp->attrs[4]->mod_type = "zoneName"; ++ tmp->attrs[4]->mod_type = (char*)"zoneName"; + tmp->attrs[4]->mod_values = (char **)calloc(sizeof(char *), 2); + tmp->attrs[4]->mod_values[0] = gbl_zone; + tmp->attrs[4]->mod_values[1] = NULL; +@@ -607,7 +613,7 @@ + zname = ++tmp; + } + else +- hnamebuff = "@"; ++ hnamebuff = (char*)"@"; + } + else + { +@@ -686,12 +692,12 @@ + } + + result = ldap_simple_bind_s (conn, binddn, bindpw); +- ldap_result_check ("ldap_simple_bind_s", "LDAP Bind", result); ++ ldap_result_check ("ldap_simple_bind_s", (char*)"LDAP Bind", result); + } + + /* Like isc_result_check, only for LDAP */ + void +-ldap_result_check (char *msg, char *dn, int err) ++ldap_result_check (const char *msg, char *dn, int err) + { + if ((err != LDAP_SUCCESS) && (err != LDAP_ALREADY_EXISTS)) + { +@@ -730,5 +736,8 @@ + usage () + { + fprintf (stderr, +- "zone2ldap -D [BIND DN] -w [BIND PASSWORD] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST] +- [-c Create LDAP Base structure][-d Debug Output (lots !)] \n ");} ++ "zone2ldap -D [BIND DN] -w [BIND PASSWORD] -b [BASE DN] -z [ZONE] -f [ZONE FILE] -h [LDAP HOST]\n" ++ "\t[-c Create LDAP Base structure][-d Debug Output (lots !)]\n " ++ ); ++} ++ +--- bind-9.3.2b2/contrib/sdb/bdb/bdb.c.sdbsrc 2002-07-02 00:45:34.000000000 -0400 ++++ bind-9.3.2b2/contrib/sdb/bdb/bdb.c 2005-11-15 12:57:44.000000000 -0500 +@@ -43,7 +43,7 @@ + #include <dns/lib.h> + #include <dns/ttl.h> + +-#include <named/bdb.h> ++#include "bdb.h" + #include <named/globals.h> + #include <named/config.h> + +--- bind-9.3.2b2/contrib/sdb/pgsql/pgsqldb.c.sdbsrc 2004-03-08 04:04:22.000000000 -0500 ++++ bind-9.3.2b2/contrib/sdb/pgsql/pgsqldb.c 2005-11-15 12:57:44.000000000 -0500 +@@ -23,7 +23,7 @@ + #include <string.h> + #include <stdlib.h> + +-#include <pgsql/libpq-fe.h> ++#include <libpq-fe.h> + + #include <isc/mem.h> + #include <isc/print.h> +--- bind-9.3.2b2/contrib/sdb/pgsql/zonetodb.c.sdbsrc 2005-09-05 22:12:40.000000000 -0400 ++++ bind-9.3.2b2/contrib/sdb/pgsql/zonetodb.c 2005-11-15 12:58:12.000000000 -0500 +@@ -37,7 +37,7 @@ + #include <dns/rdatatype.h> + #include <dns/result.h> + +-#include <pgsql/libpq-fe.h> ++#include <libpq-fe.h> + + /* + * Generate a PostgreSQL table from a zone. +@@ -54,6 +54,9 @@ + char str[10240]; + + void ++closeandexit(int status); ++ ++void + closeandexit(int status) { + if (conn != NULL) + PQfinish(conn); +@@ -61,6 +64,9 @@ + } + + void ++check_result(isc_result_t result, const char *message); ++ ++void + check_result(isc_result_t result, const char *message) { + if (result != ISC_R_SUCCESS) { + fprintf(stderr, "%s: %s\n", message, +@@ -84,7 +90,8 @@ + } + *dest++ = 0; + } +- ++void ++addrdata(dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata); + void + addrdata(dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) { + unsigned char namearray[DNS_NAME_MAXTEXT + 1]; diff --git a/SOURCES/bind-9.5-PIE.patch b/SOURCES/bind-9.5-PIE.patch new file mode 100644 index 0000000..a525b9b --- /dev/null +++ b/SOURCES/bind-9.5-PIE.patch @@ -0,0 +1,27 @@ +--- bind-9.5.0b2/bin/named/Makefile.in.pie 2008-02-11 17:21:47.000000000 +0100 ++++ bind-9.5.0b2/bin/named/Makefile.in 2008-02-11 17:22:10.000000000 +0100 +@@ -100,8 +100,12 @@ HTMLPAGES = named.html lwresd.html named + + MANOBJS = ${MANPAGES} ${HTMLPAGES} + ++EXT_CFLAGS = -fpie ++ + @BIND9_MAKE_RULES@ + ++LDFLAGS += -pie -Wl,-z,relro,-z,now,-z,nodlopen,-z,noexecstack ++ + main.@O@: main.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ +diff -up bind-9.5.0b2/bin/named/unix/Makefile.in.pie bind-9.5.0b2/bin/named/unix/Makefile.in +--- bind-9.5.0b2/bin/named/unix/Makefile.in.pie 2008-02-11 17:22:21.000000000 +0100 ++++ bind-9.5.0b2/bin/named/unix/Makefile.in 2008-02-11 17:23:00.000000000 +0100 +@@ -19,6 +19,8 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + ++EXT_CFLAGS = -fpie ++ + @BIND9_MAKE_INCLUDES@ + + CINCLUDES = -I${srcdir}/include -I${srcdir}/../include \ diff --git a/SOURCES/bind-9.5-dlz-64bit.patch b/SOURCES/bind-9.5-dlz-64bit.patch new file mode 100644 index 0000000..0e726d8 --- /dev/null +++ b/SOURCES/bind-9.5-dlz-64bit.patch @@ -0,0 +1,70 @@ +diff -up bind-9.9.0/contrib/dlz/config.dlz.in.64bit bind-9.9.0/contrib/dlz/config.dlz.in +--- bind-9.9.0/contrib/dlz/config.dlz.in.64bit 2011-11-05 06:14:28.000000000 +0100 ++++ bind-9.9.0/contrib/dlz/config.dlz.in 2012-04-24 14:52:08.398511143 +0200 +@@ -17,6 +17,13 @@ + # + dlzdir='${DLZ_DRIVER_DIR}' + ++AC_MSG_CHECKING([for target libdir]) ++AC_RUN_IFELSE([int main(void) {exit((sizeof(void *) == 8) ? 0 : 1);}], ++ [target_lib=lib64], ++ [target_lib=lib], ++) ++AC_MSG_RESULT(["$target_lib"]) ++ + # + # Private autoconf macro to simplify configuring drivers: + # +@@ -135,9 +142,9 @@ then + then + use_dlz_mysql=$d + mysql_include=$d/include/mysql +- if test -d $d/lib/mysql ++ if test -d $d/${target_lib}/mysql + then +- mysql_lib=$d/lib/mysql ++ mysql_lib=$d/${target_lib}/mysql + else + mysql_lib=$d/lib + fi +@@ -274,11 +281,11 @@ case "$use_dlz_bdb" in + bdb_libnames="db48 db-4.8 db47 db-4.7 db46 db-4.6 db45 db-4.5 db44 db-4.4 db43 db-4.3 db42 db-4.2 db41 db-4.1 db" + for d in $bdb_libnames + do +- if test -f "$dd/lib/lib${d}.so" ++ if test -f "$dd/${target_lib}/lib${d}.so" + then + if test "$dd" != "/usr" + then +- dlz_bdb_libs="-L${dd}/lib " ++ dlz_bdb_libs="-L${dd}/${target_lib} " + else + dlz_bdb_libs="" + fi +@@ -383,7 +390,7 @@ case "$use_dlz_ldap" in + *) + DLZ_ADD_DRIVER(LDAP, dlz_ldap_driver, + [-I$use_dlz_ldap/include], +- [-L$use_dlz_ldap/lib -lldap -llber]) ++ [-L$use_dlz_ldap/${target_lib} -lldap -llber]) + + AC_MSG_RESULT( + [using LDAP from $use_dlz_ldap/lib and $use_dlz_ldap/include]) +@@ -407,7 +414,7 @@ then + odbcdirs="/usr /usr/local /usr/pkg" + for d in $odbcdirs + do +- if test -f $d/include/sql.h -a -f $d/lib/libodbc.a ++ if test -f $d/include/sql.h -a -f $d/${target_lib}/libodbc.a + then + use_dlz_odbc=$d + break +@@ -427,7 +434,7 @@ case "$use_dlz_odbc" in + *) + DLZ_ADD_DRIVER(ODBC, dlz_odbc_driver, + [-I$use_dlz_odbc/include], +- [-L$use_dlz_odbc/lib -lodbc]) ++ [-L$use_dlz_odbc/${target_lib} -lodbc]) + + AC_MSG_RESULT([using ODBC from $use_dlz_odbc]) + ;; diff --git a/SOURCES/bind-9.5-libidn.patch b/SOURCES/bind-9.5-libidn.patch new file mode 100644 index 0000000..e0831e4 --- /dev/null +++ b/SOURCES/bind-9.5-libidn.patch @@ -0,0 +1,270 @@ +diff -up bind-9.7.0b1/bin/dig/dighost.c.libidn bind-9.7.0b1/bin/dig/dighost.c +--- bind-9.7.0b1/bin/dig/dighost.c.libidn 2009-09-16 01:48:09.000000000 +0200 ++++ bind-9.7.0b1/bin/dig/dighost.c 2009-10-20 10:49:26.719056220 +0200 +@@ -44,6 +44,11 @@ + #include <idn/api.h> + #endif + ++#ifdef WITH_LIBIDN ++#include <stringprep.h> ++#include <idna.h> ++#endif ++ + #include <dns/byaddr.h> + #ifdef DIG_SIGCHASE + #include <dns/callbacks.h> +@@ -153,6 +158,14 @@ static void idn_check_result(idn_result + int idnoptions = 0; + #endif + ++#ifdef WITH_LIBIDN ++static isc_result_t libidn_locale_to_utf8 (const char* from, char **to); ++static isc_result_t libidn_utf8_to_ascii (const char* from, char *to); ++static isc_result_t output_filter (isc_buffer_t *buffer, ++ unsigned int used_org, ++ isc_boolean_t absolute); ++#endif ++ + /*% + * Exit Codes: + * +@@ -1184,6 +1197,9 @@ setup_system(void) { + dig_searchlist_t *domain = NULL; + lwres_result_t lwresult; + unsigned int lwresflags; ++#ifdef WITH_LIBIDN ++ isc_result_t result; ++#endif + + debug("setup_system()"); + +@@ -1242,8 +1258,15 @@ setup_system(void) { + + #ifdef WITH_IDN + initialize_idn(); ++ ++#endif ++#ifdef WITH_LIBIDN ++ result = dns_name_settotextfilter(output_filter); ++ check_result(result, "dns_name_settotextfilter"); ++#ifdef HAVE_SETLOCALE ++ setlocale (LC_ALL, ""); ++#endif + #endif +- + if (keyfile[0] != 0) + setup_file_key(); + else if (keysecret[0] != 0) +@@ -1957,12 +1980,18 @@ setup_lookup(dig_lookup_t *lookup) { + idn_result_t mr; + char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME]; + #endif ++#ifdef WITH_LIBIDN ++ char *utf8_str = NULL, utf8_name[MXNAME], ascii_name[MXNAME]; ++#endif + + #ifdef WITH_IDN + result = dns_name_settotextfilter(output_filter); + check_result(result, "dns_name_settotextfilter"); + #endif +- ++#ifdef WITH_LIBIDN ++ result = dns_name_settotextfilter (output_filter); ++ check_result(result, "dns_name_settotextfilter"); ++#endif + REQUIRE(lookup != NULL); + INSIST(!free_now); + +@@ -1999,6 +2028,16 @@ setup_lookup(dig_lookup_t *lookup) { + mr = idn_encodename(IDN_LOCALCONV | IDN_DELIMMAP, lookup->textname, + utf8_textname, sizeof(utf8_textname)); + idn_check_result(mr, "convert textname to UTF-8"); ++#elif defined (WITH_LIBIDN) ++ result = libidn_locale_to_utf8 (lookup->textname, &utf8_str); ++ check_result (result, "converting textname to UTF-8"); ++ len = strlen (utf8_str); ++ if (len < MXNAME) { ++ (void) strcpy (utf8_name, utf8_str); ++ } else { ++ fatal ("Too long name"); ++ } ++ isc_mem_free (mctx, utf8_str); + #endif + + /* +@@ -2018,6 +2057,15 @@ setup_lookup(dig_lookup_t *lookup) { + lookup->origin = ISC_LIST_HEAD(search_list); + lookup->need_search = ISC_FALSE; + } ++#elif defined (WITH_LIBIDN) ++ if ((count_dots(utf8_name) >= ndots) || !usesearch) { ++ lookup->origin = NULL; /* Force abs lookup */ ++ lookup->done_as_is = ISC_TRUE; ++ lookup->need_search = usesearch; ++ } else if (lookup->origin == NULL && usesearch) { ++ lookup->origin = ISC_LIST_HEAD(search_list); ++ lookup->need_search = ISC_FALSE; ++ } + #else + if ((count_dots(lookup->textname) >= ndots) || !usesearch) { + lookup->origin = NULL; /* Force abs lookup */ +@@ -2044,6 +2092,20 @@ setup_lookup(dig_lookup_t *lookup) { + IDN_IDNCONV | IDN_LENCHECK, utf8_textname, + idn_textname, sizeof(idn_textname)); + idn_check_result(mr, "convert UTF-8 textname to IDN encoding"); ++#elif defined (WITH_LIBIDN) ++ if (lookup->origin != NULL) { ++ result = libidn_locale_to_utf8 (lookup->origin->origin, &utf8_str); ++ check_result (result, "convert origin to UTF-8"); ++ if (len + strlen (utf8_str) + 1 < MXNAME) { ++ utf8_name[len++] = '.'; ++ (void) strcpy (utf8_name + len, utf8_str); ++ } else { ++ fatal ("Too long name + origin"); ++ } ++ isc_mem_free (mctx, utf8_str); ++ } ++ ++ result = libidn_utf8_to_ascii (utf8_name, ascii_name); + #else + if (lookup->origin != NULL) { + debug("trying origin %s", lookup->origin->origin); +@@ -2099,6 +2161,13 @@ setup_lookup(dig_lookup_t *lookup) { + result = dns_name_fromtext(lookup->name, &b, + dns_rootname, 0, + &lookup->namebuf); ++#elif defined (WITH_LIBIDN) ++ len = strlen (ascii_name); ++ isc_buffer_init(&b, ascii_name, len); ++ isc_buffer_add(&b, len); ++ result = dns_name_fromtext(lookup->name, &b, ++ dns_rootname, 0, ++ &lookup->namebuf); + #else + len = strlen(lookup->textname); + isc_buffer_init(&b, lookup->textname, len); +@@ -3617,7 +3686,7 @@ destroy_libs(void) { + void * ptr; + dig_message_t *chase_msg; + #endif +-#ifdef WITH_IDN ++#if defined (WITH_IDN) || defined (WITH_LIBIDN) + isc_result_t result; + #endif + +@@ -3656,6 +3725,10 @@ destroy_libs(void) { + result = dns_name_settotextfilter(NULL); + check_result(result, "dns_name_settotextfilter"); + #endif ++#ifdef WITH_LIBIDN ++ result = dns_name_settotextfilter (NULL); ++ check_result(result, "clearing dns_name_settotextfilter"); ++#endif + dns_name_destroy(); + + if (commctx != NULL) { +@@ -3834,6 +3907,79 @@ idn_check_result(idn_result_t r, const c + } + } + #endif /* WITH_IDN */ ++#ifdef WITH_LIBIDN ++/* If stringprep_locale_to_utf8 fails simple copy string */ ++static isc_result_t ++libidn_locale_to_utf8 (const char *from, char **to) { ++ char *utf8_str; ++ ++ utf8_str = stringprep_locale_to_utf8 (from); ++ if (utf8_str == NULL) { ++ *to = isc_mem_allocate (mctx, strlen (from) + 1); ++ if (*to == NULL) ++ return (ISC_R_NOMEMORY); ++ (void) strcpy (*to, from); ++ } else { ++ *to = isc_mem_allocate (mctx, strlen (utf8_str) + 1); ++ if (*to == NULL) ++ return (ISC_R_NOMEMORY); ++ (void) strcpy (*to, utf8_str); ++ free (utf8_str); ++ } ++ return (ISC_R_SUCCESS); ++} ++static isc_result_t ++libidn_utf8_to_ascii (const char *from, char *to) { ++ char *ascii; ++ ++ if (idna_to_ascii_8z (from, &ascii, 0) != IDNA_SUCCESS) ++ return (ISC_R_FAILURE); ++ ++ (void) strcpy (to, ascii); ++ free (ascii); ++ return (ISC_R_SUCCESS); ++} ++/* based on idnkit's code*/ ++static isc_result_t ++output_filter (isc_buffer_t *buffer, unsigned int used_org, ++ isc_boolean_t absolute) { ++ char tmp1[MXNAME], *tmp2; ++ size_t fromlen, tolen; ++ isc_boolean_t end_with_dot; ++ ++ fromlen = isc_buffer_usedlength(buffer) - used_org; ++ if (fromlen >= MXNAME) ++ return (ISC_R_SUCCESS); ++ memcpy(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen); ++ end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE; ++ if (absolute && !end_with_dot) { ++ fromlen++; ++ if (fromlen >= MXNAME) ++ return (ISC_R_SUCCESS); ++ tmp1[fromlen - 1] = '.'; ++ } ++ tmp1[fromlen] = '\0'; ++ ++ if (idna_to_unicode_lzlz (tmp1, &tmp2, 0) != IDNA_SUCCESS) ++ return (ISC_R_SUCCESS); ++ ++ (void) strcpy (tmp1, tmp2); ++ free (tmp2); ++ ++ tolen = strlen(tmp1); ++ if (absolute && !end_with_dot && tmp1[tolen - 1] == '.') ++ tolen--; ++ ++ if (isc_buffer_length(buffer) < used_org + tolen) ++ return (ISC_R_NOSPACE); ++ ++ isc_buffer_subtract(buffer, isc_buffer_usedlength(buffer) - used_org); ++ memcpy(isc_buffer_used(buffer), tmp1, tolen); ++ isc_buffer_add(buffer, tolen); ++ ++ return (ISC_R_SUCCESS); ++} ++#endif /* WITH_LIBIDN*/ + + #ifdef DIG_SIGCHASE + void +diff -up bind-9.7.0b1/bin/dig/Makefile.in.libidn bind-9.7.0b1/bin/dig/Makefile.in +--- bind-9.7.0b1/bin/dig/Makefile.in.libidn 2009-09-22 10:47:55.000000000 +0200 ++++ bind-9.7.0b1/bin/dig/Makefile.in 2009-10-20 10:50:06.201543709 +0200 +@@ -46,10 +46,10 @@ DEPLIBS = ${DNSDEPLIBS} ${BIND9DEPLIBS} + ${LWRESDEPLIBS} + + LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ +- ${ISCLIBS} @IDNLIBS@ @LIBS@ ++ ${ISCLIBS} @IDNLIBS@ @LIBS@ -lidn + + NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ +- ${ISCNOSYMLIBS} @IDNLIBS@ @LIBS@ ++ ${ISCNOSYMLIBS} @IDNLIBS@ @LIBS@ -lidn + + SUBDIRS = + +@@ -67,6 +67,8 @@ HTMLPAGES = dig.html host.html nslookup. + + MANOBJS = ${MANPAGES} ${HTMLPAGES} + ++EXT_CFLAGS = -DWITH_LIBIDN ++ + @BIND9_MAKE_RULES@ + + dig@EXEEXT@: dig.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} diff --git a/SOURCES/bind-9.5-libidn2.patch b/SOURCES/bind-9.5-libidn2.patch new file mode 100644 index 0000000..785b6eb --- /dev/null +++ b/SOURCES/bind-9.5-libidn2.patch @@ -0,0 +1,221 @@ +diff -up bind-9.5.0b1/bin/dig/dighost.c.libidn2 bind-9.5.0b1/bin/dig/dighost.c +--- bind-9.5.0b1/bin/dig/dighost.c.libidn2 2007-12-10 13:12:26.000000000 +0100 ++++ bind-9.5.0b1/bin/dig/dighost.c 2007-12-10 14:21:09.000000000 +0100 +@@ -153,7 +153,7 @@ int idnoptions = 0; + #endif + + #ifdef WITH_LIBIDN +-static isc_result_t libidn_locale_to_utf8 (const char* from, char **to); ++static isc_result_t libidn_locale_to_utf8 (const char* from, char *to); + static isc_result_t libidn_utf8_to_ascii (const char* from, char *to); + static isc_result_t output_filter (isc_buffer_t *buffer, + unsigned int used_org, +@@ -1764,17 +1764,13 @@ setup_lookup(dig_lookup_t *lookup) { + char utf8_textname[MXNAME], utf8_origin[MXNAME], idn_textname[MXNAME]; + #endif + #ifdef WITH_LIBIDN +- char *utf8_str = NULL, utf8_name[MXNAME], ascii_name[MXNAME]; ++ char utf8_str[MXNAME], utf8_name[MXNAME], ascii_name[MXNAME]; + #endif + +-#ifdef WITH_IDN ++#if defined (WITH_IDN) || defined (WITH_LIBIDN) + result = dns_name_settotextfilter(output_filter); + check_result(result, "dns_name_settotextfilter"); + #endif +-#ifdef WITH_LIBIDN +- result = dns_name_settotextfilter (output_filter); +- check_result(result, "dns_name_settotextfilter"); +-#endif + REQUIRE(lookup != NULL); + INSIST(!free_now); + +@@ -1812,15 +1808,13 @@ setup_lookup(dig_lookup_t *lookup) { + utf8_textname, sizeof(utf8_textname)); + idn_check_result(mr, "convert textname to UTF-8"); + #elif defined (WITH_LIBIDN) +- result = libidn_locale_to_utf8 (lookup->textname, &utf8_str); +- check_result (result, "converting textname to UTF-8"); ++ result = libidn_locale_to_utf8 (lookup->textname, utf8_str); ++ check_result (result, "convert textname to UTF-8"); + len = strlen (utf8_str); +- if (len < MXNAME) { ++ if (len < MXNAME) + (void) strcpy (utf8_name, utf8_str); +- } else { ++ else + fatal ("Too long name"); +- } +- isc_mem_free (mctx, utf8_str); + #endif + + /* +@@ -1833,24 +1827,11 @@ setup_lookup(dig_lookup_t *lookup) { + if (lookup->new_search) { + #ifdef WITH_IDN + if ((count_dots(utf8_textname) >= ndots) || !usesearch) { +- lookup->origin = NULL; /* Force abs lookup */ +- lookup->done_as_is = ISC_TRUE; +- lookup->need_search = usesearch; +- } else if (lookup->origin == NULL && usesearch) { +- lookup->origin = ISC_LIST_HEAD(search_list); +- lookup->need_search = ISC_FALSE; +- } + #elif defined (WITH_LIBIDN) + if ((count_dots(utf8_name) >= ndots) || !usesearch) { +- lookup->origin = NULL; /* Force abs lookup */ +- lookup->done_as_is = ISC_TRUE; +- lookup->need_search = usesearch; +- } else if (lookup->origin == NULL && usesearch) { +- lookup->origin = ISC_LIST_HEAD(search_list); +- lookup->need_search = ISC_FALSE; +- } + #else + if ((count_dots(lookup->textname) >= ndots) || !usesearch) { ++#endif + lookup->origin = NULL; /* Force abs lookup */ + lookup->done_as_is = ISC_TRUE; + lookup->need_search = usesearch; +@@ -1858,7 +1839,6 @@ setup_lookup(dig_lookup_t *lookup) { + lookup->origin = ISC_LIST_HEAD(search_list); + lookup->need_search = ISC_FALSE; + } +-#endif + } + + #ifdef WITH_IDN +@@ -1877,15 +1857,12 @@ setup_lookup(dig_lookup_t *lookup) { + idn_check_result(mr, "convert UTF-8 textname to IDN encoding"); + #elif defined (WITH_LIBIDN) + if (lookup->origin != NULL) { +- result = libidn_locale_to_utf8 (lookup->origin->origin, &utf8_str); ++ result = libidn_locale_to_utf8 (lookup->origin->origin, utf8_str); + check_result (result, "convert origin to UTF-8"); +- if (len + strlen (utf8_str) + 1 < MXNAME) { +- utf8_name[len++] = '.'; ++ if (len + strlen (utf8_str) < MXNAME) + (void) strcpy (utf8_name + len, utf8_str); +- } else { ++ else + fatal ("Too long name + origin"); +- } +- isc_mem_free (mctx, utf8_str); + } + + result = libidn_utf8_to_ascii (utf8_name, ascii_name); +@@ -3600,76 +3577,85 @@ idn_check_result(idn_result_t r, const c + } + #endif /* WITH_IDN */ + #ifdef WITH_LIBIDN +-/* If stringprep_locale_to_utf8 fails simple copy string */ + static isc_result_t +-libidn_locale_to_utf8 (const char *from, char **to) { ++libidn_locale_to_utf8 (const char *from, char *to) { + char *utf8_str; + ++ debug ("libidn_locale_to_utf8"); + utf8_str = stringprep_locale_to_utf8 (from); +- if (utf8_str == NULL) { +- *to = isc_mem_allocate (mctx, strlen (from) + 1); +- if (*to == NULL) +- return (ISC_R_NOMEMORY); +- (void) strcpy (*to, from); +- } else { +- *to = isc_mem_allocate (mctx, strlen (utf8_str) + 1); +- if (*to == NULL) +- return (ISC_R_NOMEMORY); +- (void) strcpy (*to, utf8_str); ++ if (utf8_str != NULL) { ++ (void) strcpy (to, utf8_str); + free (utf8_str); ++ return ISC_R_SUCCESS; + } +- return (ISC_R_SUCCESS); ++ ++ debug ("libidn_locale_to_utf8: failure"); ++ return ISC_R_FAILURE; + } + static isc_result_t + libidn_utf8_to_ascii (const char *from, char *to) { + char *ascii; ++ int iresult; + +- if (idna_to_ascii_8z (from, &ascii, 0) != IDNA_SUCCESS) +- return (ISC_R_FAILURE); ++ debug ("libidn_utf8_to_ascii"); ++ iresult = idna_to_ascii_8z (from, &ascii, 0); ++ if (iresult != IDNA_SUCCESS) { ++ debug ("idna_to_ascii_8z: %s", idna_strerror (iresult)); ++ return ISC_R_FAILURE; ++ } + + (void) strcpy (to, ascii); + free (ascii); +- return (ISC_R_SUCCESS); ++ return ISC_R_SUCCESS; + } +-/* based on idnkit's code*/ ++ + static isc_result_t + output_filter (isc_buffer_t *buffer, unsigned int used_org, + isc_boolean_t absolute) { ++ + char tmp1[MXNAME], *tmp2; + size_t fromlen, tolen; + isc_boolean_t end_with_dot; ++ int iresult; ++ ++ debug ("output_filter"); + +- fromlen = isc_buffer_usedlength(buffer) - used_org; ++ fromlen = isc_buffer_usedlength (buffer) - used_org; + if (fromlen >= MXNAME) +- return (ISC_R_SUCCESS); +- memcpy(tmp1, (char *)isc_buffer_base(buffer) + used_org, fromlen); ++ return ISC_R_SUCCESS; ++ memcpy (tmp1, (char *) isc_buffer_base (buffer) + used_org, fromlen); + end_with_dot = (tmp1[fromlen - 1] == '.') ? ISC_TRUE : ISC_FALSE; + if (absolute && !end_with_dot) { + fromlen++; + if (fromlen >= MXNAME) +- return (ISC_R_SUCCESS); ++ return ISC_R_SUCCESS; + tmp1[fromlen - 1] = '.'; + } + tmp1[fromlen] = '\0'; + +- if (idna_to_unicode_lzlz (tmp1, &tmp2, 0) != IDNA_SUCCESS) +- return (ISC_R_SUCCESS); ++ iresult = idna_to_unicode_8z8z (tmp1, &tmp2, 0); ++ if (iresult != IDNA_SUCCESS) { ++ debug ("output_filter: %s", idna_strerror (iresult)); ++ return ISC_R_SUCCESS; ++ } + + (void) strcpy (tmp1, tmp2); + free (tmp2); + +- tolen = strlen(tmp1); ++ tolen = strlen (tmp1); + if (absolute && !end_with_dot && tmp1[tolen - 1] == '.') + tolen--; + +- if (isc_buffer_length(buffer) < used_org + tolen) +- return (ISC_R_NOSPACE); ++ if (isc_buffer_length (buffer) < used_org + tolen) ++ return ISC_R_NOSPACE; ++ ++ debug ("%s", tmp1); + +- isc_buffer_subtract(buffer, isc_buffer_usedlength(buffer) - used_org); +- memcpy(isc_buffer_used(buffer), tmp1, tolen); +- isc_buffer_add(buffer, tolen); ++ isc_buffer_subtract (buffer, isc_buffer_usedlength (buffer) - used_org); ++ memcpy (isc_buffer_used (buffer), tmp1, tolen); ++ isc_buffer_add (buffer, tolen); + +- return (ISC_R_SUCCESS); ++ return ISC_R_SUCCESS; + } + #endif /* WITH_LIBIDN*/ + diff --git a/SOURCES/bind-9.5-libidn3.patch b/SOURCES/bind-9.5-libidn3.patch new file mode 100644 index 0000000..3fd5573 --- /dev/null +++ b/SOURCES/bind-9.5-libidn3.patch @@ -0,0 +1,21 @@ +diff -up bind-9.5.0b1/bin/dig/dighost.c.libidn3 bind-9.5.0b1/bin/dig/dighost.c +--- bind-9.5.0b1/bin/dig/dighost.c.libidn3 2007-12-20 13:24:27.000000000 +0100 ++++ bind-9.5.0b1/bin/dig/dighost.c 2007-12-20 13:27:10.000000000 +0100 +@@ -1859,10 +1859,13 @@ setup_lookup(dig_lookup_t *lookup) { + if (lookup->origin != NULL) { + result = libidn_locale_to_utf8 (lookup->origin->origin, utf8_str); + check_result (result, "convert origin to UTF-8"); +- if (len + strlen (utf8_str) < MXNAME) +- (void) strcpy (utf8_name + len, utf8_str); +- else +- fatal ("Too long name + origin"); ++ if (len > 0 && utf8_name[len - 1] != '.') { ++ utf8_name[len++] = '.'; ++ if (len + strlen (utf8_str) < MXNAME) ++ (void) strcpy (utf8_name + len, utf8_str); ++ else ++ fatal ("Too long name + origin"); ++ } + } + + result = libidn_utf8_to_ascii (utf8_name, ascii_name); diff --git a/SOURCES/bind-9.5-parallel-build.patch b/SOURCES/bind-9.5-parallel-build.patch new file mode 100644 index 0000000..53e34ca --- /dev/null +++ b/SOURCES/bind-9.5-parallel-build.patch @@ -0,0 +1,14 @@ +diff -up bind-9.5.0b1/lib/dns/Makefile.in.parallel bind-9.5.0b1/lib/dns/Makefile.in +--- bind-9.5.0b1/lib/dns/Makefile.in.parallel 2008-01-17 18:27:38.000000000 +0100 ++++ bind-9.5.0b1/lib/dns/Makefile.in 2008-01-17 18:27:45.000000000 +0100 +@@ -19,10 +19,6 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + +-# Attempt to disable parallel processing. +-.NOTPARALLEL: +-.NO_PARALLEL: +- + @BIND9_VERSION@ + + @LIBDNS_API@ diff --git a/SOURCES/bind-9.5-sdb-sqlite-bld.patch b/SOURCES/bind-9.5-sdb-sqlite-bld.patch new file mode 100644 index 0000000..768af1c --- /dev/null +++ b/SOURCES/bind-9.5-sdb-sqlite-bld.patch @@ -0,0 +1,102 @@ +diff -up bind-9.8.1rc1/bin/named-sdb/main.c.sdb-sqlite-bld bind-9.8.1rc1/bin/named-sdb/main.c +--- bind-9.8.1rc1/bin/named-sdb/main.c.sdb-sqlite-bld 2011-08-31 14:41:15.646020840 +0200 ++++ bind-9.8.1rc1/bin/named-sdb/main.c 2011-08-31 14:41:35.132019452 +0200 +@@ -85,6 +85,7 @@ + /* #include "xxdb.h" */ + #include "ldapdb.h" + #include "pgsqldb.h" ++#include "sqlitedb.h" + #include "dirdb.h" + + #ifdef CONTRIB_DLZ +@@ -792,6 +793,7 @@ setup(void) { + + ldapdb_clear(); + pgsqldb_clear(); ++ sqlitedb_clear(); + dirdb_clear(); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, +@@ -921,6 +923,23 @@ setup(void) { + ISC_LOG_NOTICE, "SDB postgreSQL DB zone database module loaded." + ); + ++ result = sqlitedb_init(); ++ if (result != ISC_R_SUCCESS) ++ { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB sqlite3 module initialisation failed: %s.", ++ isc_result_totext(result) ++ ); ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB sqlite3 zone database will be unavailable." ++ ); ++ }else ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_NOTICE, "SDB sqlite3 DB zone database module loaded." ++ ); ++ + result = dirdb_init(); + if (result != ISC_R_SUCCESS) + { +@@ -971,6 +990,7 @@ cleanup(void) { + + ldapdb_clear(); + pgsqldb_clear(); ++ sqlitedb_clear(); + dirdb_clear(); + + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, +diff -up bind-9.8.1rc1/bin/named-sdb/Makefile.in.sdb-sqlite-bld bind-9.8.1rc1/bin/named-sdb/Makefile.in +--- bind-9.8.1rc1/bin/named-sdb/Makefile.in.sdb-sqlite-bld 2011-08-31 14:41:15.646020840 +0200 ++++ bind-9.8.1rc1/bin/named-sdb/Makefile.in 2011-08-31 14:41:15.658020839 +0200 +@@ -28,10 +28,10 @@ top_srcdir = @top_srcdir@ + # + # Add database drivers here. + # +-DBDRIVER_OBJS = ldapdb.@O@ pgsqldb.@O@ dirdb.@O@ +-DBDRIVER_SRCS = ldapdb.c pgsqldb.c dirdb.c ++DBDRIVER_OBJS = ldapdb.@O@ pgsqldb.@O@ sqlitedb.@O@ dirdb.@O@ ++DBDRIVER_SRCS = ldapdb.c pgsqldb.c sqlitedb.c dirdb.c + DBDRIVER_INCLUDES = +-DBDRIVER_LIBS = -lldap -llber -lpq ++DBDRIVER_LIBS = -lldap -llber -lpq -lsqlite3 + + DLZ_DRIVER_DIR = ${top_srcdir}/contrib/dlz/drivers + +diff -up bind-9.8.1rc1/bin/sdb_tools/Makefile.in.sdb-sqlite-bld bind-9.8.1rc1/bin/sdb_tools/Makefile.in +--- bind-9.8.1rc1/bin/sdb_tools/Makefile.in.sdb-sqlite-bld 2011-08-31 14:41:15.651020840 +0200 ++++ bind-9.8.1rc1/bin/sdb_tools/Makefile.in 2011-08-31 14:41:15.658020839 +0200 +@@ -32,11 +32,11 @@ DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} + LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} ${DBDRIVER_LIBS} @LIBS@ + +-TARGETS = zone2ldap@EXEEXT@ ldap2zone@EXEEXT@ zonetodb@EXEEXT@ ++TARGETS = zone2ldap@EXEEXT@ ldap2zone@EXEEXT@ zonetodb@EXEEXT@ zone2sqlite@EXEEXT@ + +-OBJS = zone2ldap.@O@ ldap2zone.@O@ zonetodb.@O@ ++OBJS = zone2ldap.@O@ ldap2zone.@O@ zonetodb.@O@ zone2sqlite.@O@ + +-SRCS = zone2ldap.c ldap2zone.c zonetodb.c ++SRCS = zone2ldap.c ldap2zone.c zonetodb.c zone2sqlite.c + + MANPAGES = zone2ldap.1 + +@@ -50,6 +50,9 @@ zone2ldap@EXEEXT@: zone2ldap.@O@ ${DEPLI + zonetodb@EXEEXT@: zonetodb.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zonetodb.@O@ -lpq ${LIBS} + ++zone2sqlite@EXEEXT@: zone2sqlite.@O@ ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ zone2sqlite.@O@ -lsqlite3 -lssl ${LIBS} ++ + ldap2zone@EXEEXT@: ldap2zone.@O@ ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ ldap2zone.@O@ -lldap -llber ${LIBS} + +@@ -64,4 +67,5 @@ install:: ${TARGETS} installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zone2ldap@EXEEXT@ ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} ldap2zone@EXEEXT@ ${DESTDIR}${sbindir} + ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zonetodb@EXEEXT@ ${DESTDIR}${sbindir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} zone2sqlite@EXEEXT@ ${DESTDIR}${sbindir} + ${INSTALL_DATA} ${srcdir}/zone2ldap.1 ${DESTDIR}${mandir}/man1/zone2ldap.1 diff --git a/SOURCES/bind-9.5-sdb.patch b/SOURCES/bind-9.5-sdb.patch new file mode 100644 index 0000000..6af9818 --- /dev/null +++ b/SOURCES/bind-9.5-sdb.patch @@ -0,0 +1,239 @@ +diff --git a/bin/Makefile.in b/bin/Makefile.in +index 187ec23..e6179e7 100644 +--- a/bin/Makefile.in ++++ b/bin/Makefile.in +@@ -19,8 +19,8 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + +-SUBDIRS = named named-pkcs11 rndc dig dnssec dnssec-pkcs11 tools tests nsupdate \ +- check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@ ++SUBDIRS = named named-pkcs11 named-sdb rndc dig dnssec dnssec-pkcs11 tools tests nsupdate \ ++ check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@ sdb_tools + TARGETS = + + @BIND9_MAKE_RULES@ +diff --git a/bin/named-sdb/Makefile.in b/bin/named-sdb/Makefile.in +index bc5be2a..71324d9 100644 +--- a/bin/named-sdb/Makefile.in ++++ b/bin/named-sdb/Makefile.in +@@ -34,10 +34,10 @@ top_srcdir = @top_srcdir@ + # + # Add database drivers here. + # +-DBDRIVER_OBJS = +-DBDRIVER_SRCS = ++DBDRIVER_OBJS = ldapdb.@O@ pgsqldb.@O@ dirdb.@O@ ++DBDRIVER_SRCS = ldapdb.c pgsqldb.c dirdb.c + DBDRIVER_INCLUDES = +-DBDRIVER_LIBS = ++DBDRIVER_LIBS = -lldap -llber -lpq + + DLZ_DRIVER_DIR = ${top_srcdir}/contrib/dlz/drivers + +@@ -83,7 +83,7 @@ NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + + SUBDIRS = unix + +-TARGETS = named@EXEEXT@ lwresd@EXEEXT@ ++TARGETS = named-sdb@EXEEXT@ + + GEOIPLINKOBJS = geoip.@O@ + +@@ -146,7 +146,7 @@ config.@O@: config.c bind.keys.h + -DNS_SYSCONFDIR=\"${sysconfdir}\" \ + -c ${srcdir}/config.c + +-named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} ++named-sdb@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} + export MAKE_SYMTABLE="yes"; \ + export BASEOBJS="${OBJS} ${UOBJS}"; \ + ${FINALBUILDCMD} +@@ -177,15 +177,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3.xsl.h + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} +- $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man5 +- $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 +- +-install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named@EXEEXT@ ${DESTDIR}${sbindir} +- (cd ${DESTDIR}${sbindir}; rm -f lwresd@EXEEXT@; @LN@ named@EXEEXT@ lwresd@EXEEXT@) +- ${INSTALL_DATA} ${srcdir}/named.8 ${DESTDIR}${mandir}/man8 +- ${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8 +- ${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5 ++ ++install:: named-sdb@EXEEXT@ installdirs ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-sdb@EXEEXT@ ${DESTDIR}${sbindir} + + @DLZ_DRIVER_RULES@ + +diff --git a/bin/named-sdb/main.c b/bin/named-sdb/main.c +index a00687f..4fba625 100644 +--- a/bin/named-sdb/main.c ++++ b/bin/named-sdb/main.c +@@ -86,6 +86,9 @@ + * Include header files for database drivers here. + */ + /* #include "xxdb.h" */ ++#include "ldapdb.h" ++#include "pgsqldb.h" ++#include "dirdb.h" + + #ifdef CONTRIB_DLZ + /* +@@ -817,6 +820,10 @@ setup(void) { + ns_main_earlyfatal("isc_app_start() failed: %s", + isc_result_totext(result)); + ++ ldapdb_clear(); ++ pgsqldb_clear(); ++ dirdb_clear(); ++ + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_NOTICE, "starting %s %s%s", ns_g_product, + ns_g_version, saved_command_line); +@@ -929,6 +936,57 @@ setup(void) { + isc_result_totext(result)); + #endif + ++ result = ldapdb_init(); ++ if (result != ISC_R_SUCCESS) ++ { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB ldap module initialisation failed: %s.", ++ isc_result_totext(result) ++ ); ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB ldap zone database will be unavailable." ++ ); ++ }else ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_NOTICE, "SDB ldap zone database module loaded." ++ ); ++ ++ result = pgsqldb_init(); ++ if (result != ISC_R_SUCCESS) ++ { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB pgsql module initialisation failed: %s.", ++ isc_result_totext(result) ++ ); ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB pgsql zone database will be unavailable." ++ ); ++ }else ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_NOTICE, "SDB postgreSQL DB zone database module loaded." ++ ); ++ ++ result = dirdb_init(); ++ if (result != ISC_R_SUCCESS) ++ { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB directory DB module initialisation failed: %s.", ++ isc_result_totext(result) ++ ); ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_ERROR, ++ "SDB directory DB zone database will be unavailable." ++ ); ++ }else ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, ++ ISC_LOG_NOTICE, "SDB directory DB zone database module loaded." ++ ); ++ + ns_server_create(ns_g_mctx, &ns_g_server); + } + +@@ -960,6 +1018,10 @@ cleanup(void) { + + dns_name_destroy(); + ++ ldapdb_clear(); ++ pgsqldb_clear(); ++ dirdb_clear(); ++ + isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_MAIN, + ISC_LOG_NOTICE, "exiting"); + ns_log_shutdown(); +diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in +index bc5be2a..3c69c9b 100644 +--- a/bin/named/Makefile.in ++++ b/bin/named/Makefile.in +@@ -51,7 +51,7 @@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ + ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = @CONTRIB_DLZ@ @CRYPTO@ ++CDEFINES = @CRYPTO@ + + CWARNINGS = + +@@ -75,11 +75,11 @@ DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + + LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \ +- ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@ ++ @LIBS@ + + NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \ +- ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@ ++ @LIBS@ + + SUBDIRS = unix + +@@ -94,8 +94,7 @@ OBJS = builtin.@O@ client.@O@ config.@O@ control.@O@ \ + tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \ + zoneconf.@O@ \ + lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \ +- lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \ +- ${DLZDRIVER_OBJS} ${DBDRIVER_OBJS} ++ lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ + + UOBJS = unix/os.@O@ unix/dlz_dlopen_driver.@O@ + +@@ -110,8 +109,7 @@ SRCS = builtin.c client.c config.c control.c \ + tkeyconf.c tsigconf.c update.c xfrout.c \ + zoneconf.c \ + lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \ +- lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \ +- ${DLZDRIVER_SRCS} ${DBDRIVER_SRCS} ++ lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c + + MANPAGES = named.8 lwresd.8 named.conf.5 + +@@ -187,7 +185,5 @@ install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs + ${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8 + ${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5 + +-@DLZ_DRIVER_RULES@ +- + named-symtbl.@O@: named-symtbl.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -c named-symtbl.c +diff --git a/configure.in b/configure.in +index 9bb9a2a..d72093f 100644 +--- a/configure.in ++++ b/configure.in +@@ -4018,12 +4018,15 @@ AC_CONFIG_FILES([ + bin/named-pkcs11/Makefile + bin/named-pkcs11/unix/Makefile + bin/named/unix/Makefile ++ bin/named-sdb/Makefile ++ bin/named-sdb/unix/Makefile + bin/nsupdate/Makefile + bin/pkcs11/Makefile + bin/python/Makefile + bin/python/dnssec-checkds.py + bin/python/dnssec-coverage.py + bin/rndc/Makefile ++ bin/sdb_tools/Makefile + bin/tests/Makefile + bin/tests/atomic/Makefile + bin/tests/db/Makefile diff --git a/SOURCES/bind-9.9-allow_external_dnskey.patch b/SOURCES/bind-9.9-allow_external_dnskey.patch new file mode 100644 index 0000000..37b3d9f --- /dev/null +++ b/SOURCES/bind-9.9-allow_external_dnskey.patch @@ -0,0 +1,1727 @@ +From 0c91911b4d1e872b87eaf6431ed47fe24d18dd43 Mon Sep 17 00:00:00 2001 +From: Mark Andrews <marka@isc.org> +Date: Wed, 4 Sep 2013 13:53:02 +1000 +Subject: [PATCH] 3642. [func] Allow externally generated DNSKEY to + be imported into the DNSKEY management framework. A + new tool dnssec-importkey is used to this. [RT + #34698] + +--- + CHANGES | 4 + + bin/dnssec/.gitignore | 1 + + bin/dnssec/Makefile.in | 8 +- + bin/dnssec/dnssec-importkey.8 | 112 +++++++++ + bin/dnssec/dnssec-importkey.c | 399 +++++++++++++++++++++++++++++++++ + bin/dnssec/dnssec-importkey.docbook | 185 +++++++++++++++ + bin/dnssec/dnssec-importkey.html | 112 +++++++++ + bin/dnssec/dnssec-settime.c | 4 +- + bin/tests/system/conf.sh.in | 1 + + bin/tests/system/inline/clean.sh | 3 + + bin/tests/system/inline/ns1/root.db.in | 3 + + bin/tests/system/inline/ns3/named.conf | 8 + + bin/tests/system/inline/ns3/sign.sh | 29 +++ + bin/tests/system/inline/setup.sh | 1 + + bin/tests/system/inline/tests.sh | 17 +- + lib/dns/dnssec.c | 96 ++++---- + lib/dns/dst_api.c | 10 + + lib/dns/dst_internal.h | 1 + + lib/dns/dst_parse.c | 63 ++++-- + lib/dns/dst_result.c | 2 +- + lib/dns/include/dns/master.h | 1 + + lib/dns/include/dst/dst.h | 6 + + lib/dns/master.c | 4 +- + lib/dns/openssldsa_link.c | 19 ++ + lib/dns/opensslecdsa_link.c | 53 +++-- + lib/dns/opensslgost_link.c | 27 ++- + lib/dns/opensslrsa_link.c | 18 +- + lib/dns/zone.c | 4 + + 28 files changed, 1108 insertions(+), 83 deletions(-) + create mode 100644 bin/dnssec/dnssec-importkey.8 + create mode 100644 bin/dnssec/dnssec-importkey.c + create mode 100644 bin/dnssec/dnssec-importkey.docbook + create mode 100644 bin/dnssec/dnssec-importkey.html + +diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in +index 4f8bceb..ecb0fae 100644 +--- a/bin/dnssec/Makefile.in ++++ b/bin/dnssec/Makefile.in +@@ -45,13 +45,13 @@ NOSYMLIBS = ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@ + TARGETS = dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \ + dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \ + dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ \ +- dnssec-verify@EXEEXT@ ++ dnssec-verify@EXEEXT@ dnssec-importkey@EXEEXT@ + + OBJS = dnssectool.@O@ + + SRCS = dnssec-dsfromkey.c dnssec-keyfromlabel.c dnssec-keygen.c \ + dnssec-revoke.c dnssec-settime.c dnssec-signzone.c \ +- dnssec-verify.c dnssectool.c ++ dnssec-verify.c dnssec-importkey.c dnssectool.c + + MANPAGES = dnssec-dsfromkey.8 dnssec-keyfromlabel.8 dnssec-keygen.8 \ + dnssec-revoke.8 dnssec-settime.8 dnssec-signzone.8 \ +@@ -102,6 +102,10 @@ dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-settime.@O@ ${OBJS} ${LIBS} + ++dnssec-importkey@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ ++ dnssec-importkey.@O@ ${OBJS} ${LIBS} ++ + doc man:: ${MANOBJS} + + docclean manclean maintainer-clean:: +diff --git a/bin/dnssec/dnssec-importkey.8 b/bin/dnssec/dnssec-importkey.8 +new file mode 100644 +index 0000000..33a3ef4 +--- /dev/null ++++ b/bin/dnssec/dnssec-importkey.8 +@@ -0,0 +1,112 @@ ++.\" Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++.\" ++.\" Permission to use, copy, modify, and/or distribute this software for any ++.\" purpose with or without fee is hereby granted, provided that the above ++.\" copyright notice and this permission notice appear in all copies. ++.\" ++.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++.\" PERFORMANCE OF THIS SOFTWARE. ++.\" ++.\" $Id$ ++.\" ++.hy 0 ++.ad l ++'\" t ++.\" Title: dnssec-importkey ++.\" Author: [see the "AUTHOR" section] ++.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> ++.\" Date: August 30, 2013 ++.\" Manual: BIND9 ++.\" Source: BIND9 ++.\" Language: English ++.\" ++.TH "DNSSEC\-IMPORTKEY" "8" "August 30, 2013" "BIND9" "BIND9" ++.\" ----------------------------------------------------------------- ++.\" * Define some portability stuff ++.\" ----------------------------------------------------------------- ++.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++.\" http://bugs.debian.org/507673 ++.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html ++.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ++.ie \n(.g .ds Aq \(aq ++.el .ds Aq ' ++.\" ----------------------------------------------------------------- ++.\" * set default formatting ++.\" ----------------------------------------------------------------- ++.\" disable hyphenation ++.nh ++.\" disable justification (adjust text to left margin only) ++.ad l ++.\" ----------------------------------------------------------------- ++.\" * MAIN CONTENT STARTS HERE * ++.\" ----------------------------------------------------------------- ++.SH "NAME" ++dnssec-importkey \- Import DNSKEY records from external systems so they can be managed\&. ++.SH "SYNOPSIS" ++.HP 17 ++\fBdnssec\-importkey\fR [\fB\-f\ \fR\fB\fIfilename\fR\fR] [\fB\-K\ \fR\fB\fIdirectory\fR\fR] [\fB\-P\ \fR\fB\fIdate/offset\fR\fR] [\fB\-D\ \fR\fB\fIdate/offset\fR\fR] [\fB\-h\fR] [\fB\-v\ \fR\fB\fIlevel\fR\fR] [\fBkeyname\fR] ++.SH "DESCRIPTION" ++.PP ++\fBdnssec\-importkey\fR ++read a DNSKEY record and generated a \&.key/\&.private key pair\&. Publication (\fB\-P\fR) and deletions (\fB\-D\fR) times can be set for the key\&. ++.SH "OPTIONS" ++.PP ++\-f \fIfilename\fR ++.RS 4 ++Filename to read the key from\&. ++.RE ++.PP ++\-K \fIdirectory\fR ++.RS 4 ++Sets the directory in which the key files are to reside\&. ++.RE ++.PP ++\-L \fIttl\fR ++.RS 4 ++Sets the default TTL to use for this key when it is converted into a DNSKEY RR\&. If the key is imported into a zone, this is the TTL that will be used for it, unless there was already a DNSKEY RRset in place, in which case the existing TTL would take precedence\&. importkey the default TTL to ++0 ++or ++none ++removes it\&. ++.RE ++.PP ++\-h ++.RS 4 ++Emit usage message and exit\&. ++.RE ++.PP ++\-v \fIlevel\fR ++.RS 4 ++Sets the debugging level\&. ++.RE ++.SH "TIMING OPTIONS" ++.PP ++Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS\&. If the argument begins with a \*(Aq+\*(Aq or \*(Aq\-\*(Aq, it is interpreted as an offset from the present time\&. For convenience, if such an offset is followed by one of the suffixes \*(Aqy\*(Aq, \*(Aqmo\*(Aq, \*(Aqw\*(Aq, \*(Aqd\*(Aq, \*(Aqh\*(Aq, or \*(Aqmi\*(Aq, then the offset is computed in years (defined as 365 24\-hour days, ignoring leap years), months (defined as 30 24\-hour days), weeks, days, hours, or minutes, respectively\&. Without a suffix, the offset is computed in seconds\&. To unset a date, use \*(Aqnone\*(Aq\&. ++.PP ++\-P \fIdate/offset\fR ++.RS 4 ++Sets the date on which a key is to be published to the zone\&. After that date, the key will be included in the zone but will not be used to sign it\&. ++.RE ++.PP ++\-D \fIdate/offset\fR ++.RS 4 ++Sets the date on which the key is to be deleted\&. After that date, the key will no longer be included in the zone\&. (It may remain in the key repository, however\&.) ++.RE ++.SH "SEE ALSO" ++.PP ++\fBdnssec-keygen\fR(8), ++\fBdnssec-signzone\fR(8), ++BIND 9 Administrator Reference Manual, ++RFC 5011\&. ++.SH "AUTHOR" ++.PP ++Internet Systems Consortium ++.SH "COPYRIGHT" ++.br ++Copyright \(co 2013 Internet Systems Consortium, Inc. ("ISC") ++.br +diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c +new file mode 100644 +index 0000000..3491828 +--- /dev/null ++++ b/bin/dnssec/dnssec-importkey.c +@@ -0,0 +1,399 @@ ++/* ++ * Copyright (C) 2008-2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdlib.h> ++ ++#include <isc/buffer.h> ++#include <isc/commandline.h> ++#include <isc/entropy.h> ++#include <isc/hash.h> ++#include <isc/mem.h> ++#include <isc/print.h> ++#include <isc/string.h> ++#include <isc/util.h> ++ ++#include <dns/callbacks.h> ++#include <dns/db.h> ++#include <dns/dbiterator.h> ++#include <dns/ds.h> ++#include <dns/fixedname.h> ++#include <dns/keyvalues.h> ++#include <dns/log.h> ++#include <dns/master.h> ++#include <dns/name.h> ++#include <dns/rdata.h> ++#include <dns/rdataclass.h> ++#include <dns/rdataset.h> ++#include <dns/rdatasetiter.h> ++#include <dns/rdatatype.h> ++#include <dns/result.h> ++ ++#include <dst/dst.h> ++ ++#include "dnssectool.h" ++ ++#ifndef PATH_MAX ++#define PATH_MAX 1024 /* AIX, WIN32, and others don't define this. */ ++#endif ++ ++const char *program = "dnssec-importkey"; ++int verbose; ++ ++static dns_rdataclass_t rdclass; ++static dns_fixedname_t fixed; ++static dns_name_t *name = NULL; ++static isc_mem_t *mctx = NULL; ++static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE; ++static isc_stdtime_t pub = 0, del = 0; ++ ++static isc_result_t ++initname(char *setname) { ++ isc_result_t result; ++ isc_buffer_t buf; ++ ++ dns_fixedname_init(&fixed); ++ name = dns_fixedname_name(&fixed); ++ ++ isc_buffer_init(&buf, setname, strlen(setname)); ++ isc_buffer_add(&buf, strlen(setname)); ++ result = dns_name_fromtext(name, &buf, dns_rootname, 0, NULL); ++ return (result); ++} ++ ++static void ++db_load_from_stream(dns_db_t *db, FILE *fp) { ++ isc_result_t result; ++ dns_rdatacallbacks_t callbacks; ++ ++ dns_rdatacallbacks_init(&callbacks); ++ result = dns_db_beginload(db, &callbacks.add, &callbacks.add_private); ++ if (result != ISC_R_SUCCESS) ++ fatal("dns_db_beginload failed: %s", isc_result_totext(result)); ++ ++ result = dns_master_loadstream(fp, name, name, rdclass, 0, ++ &callbacks, mctx); ++ if (result != ISC_R_SUCCESS) ++ fatal("can't load from input: %s", isc_result_totext(result)); ++ ++ result = dns_db_endload(db, &callbacks.add_private); ++ if (result != ISC_R_SUCCESS) ++ fatal("dns_db_endload failed: %s", isc_result_totext(result)); ++} ++ ++static isc_result_t ++loadset(const char *filename, dns_rdataset_t *rdataset) { ++ isc_result_t result; ++ dns_db_t *db = NULL; ++ dns_dbnode_t *node = NULL; ++ char setname[DNS_NAME_FORMATSIZE]; ++ ++ dns_name_format(name, setname, sizeof(setname)); ++ ++ result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone, ++ rdclass, 0, NULL, &db); ++ if (result != ISC_R_SUCCESS) ++ fatal("can't create database"); ++ ++ if (strcmp(filename, "-") == 0) { ++ db_load_from_stream(db, stdin); ++ filename = "input"; ++ } else { ++ result = dns_db_load3(db, filename, dns_masterformat_text, ++ DNS_MASTER_NOTTL); ++ if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE) ++ fatal("can't load %s: %s", filename, ++ isc_result_totext(result)); ++ } ++ ++ result = dns_db_findnode(db, name, ISC_FALSE, &node); ++ if (result != ISC_R_SUCCESS) ++ fatal("can't find %s node in %s", setname, filename); ++ ++ result = dns_db_findrdataset(db, node, NULL, dns_rdatatype_dnskey, ++ 0, 0, rdataset, NULL); ++ ++ if (result == ISC_R_NOTFOUND) ++ fatal("no DNSKEY RR for %s in %s", setname, filename); ++ else if (result != ISC_R_SUCCESS) ++ fatal("dns_db_findrdataset"); ++ ++ if (node != NULL) ++ dns_db_detachnode(db, &node); ++ if (db != NULL) ++ dns_db_detach(&db); ++ return (result); ++} ++ ++static void ++loadkey(char *filename, unsigned char *key_buf, unsigned int key_buf_size, ++ dns_rdata_t *rdata) ++{ ++ isc_result_t result; ++ dst_key_t *key = NULL; ++ isc_buffer_t keyb; ++ isc_region_t r; ++ ++ dns_rdata_init(rdata); ++ ++ isc_buffer_init(&keyb, key_buf, key_buf_size); ++ ++ result = dst_key_fromnamedfile(filename, NULL, DST_TYPE_PUBLIC, ++ mctx, &key); ++ if (result != ISC_R_SUCCESS) ++ fatal("invalid keyfile name %s: %s", ++ filename, isc_result_totext(result)); ++ ++ if (verbose > 2) { ++ char keystr[DST_KEY_FORMATSIZE]; ++ ++ dst_key_format(key, keystr, sizeof(keystr)); ++ fprintf(stderr, "%s: %s\n", program, keystr); ++ } ++ ++ result = dst_key_todns(key, &keyb); ++ if (result != ISC_R_SUCCESS) ++ fatal("can't decode key"); ++ ++ isc_buffer_usedregion(&keyb, &r); ++ dns_rdata_fromregion(rdata, dst_key_class(key), ++ dns_rdatatype_dnskey, &r); ++ ++ rdclass = dst_key_class(key); ++ ++ dns_fixedname_init(&fixed); ++ name = dns_fixedname_name(&fixed); ++ result = dns_name_copy(dst_key_name(key), name, NULL); ++ if (result != ISC_R_SUCCESS) ++ fatal("can't copy name"); ++ ++ dst_key_free(&key); ++} ++ ++static void ++emit(const char *dir, dns_rdata_t *rdata) { ++ isc_result_t result; ++ char keystr[DST_KEY_FORMATSIZE]; ++ char newname[1024]; ++ isc_buffer_t buf; ++ dst_key_t *key = NULL; ++ ++ isc_buffer_init(&buf, rdata->data, rdata->length); ++ isc_buffer_add(&buf, rdata->length); ++ result = dst_key_fromdns(name, rdclass, &buf, mctx, &key); ++ if (result != ISC_R_SUCCESS) { ++ fatal("dst_key_fromdns: %s", isc_result_totext(result)); ++ } ++ ++ dst_key_setexternal(key, ISC_TRUE); ++ if (setpub) ++ dst_key_settime(key, DST_TIME_PUBLISH, pub); ++ if (setdel) ++ dst_key_settime(key, DST_TIME_DELETE, del); ++ ++ isc_buffer_init(&buf, newname, sizeof(newname)); ++ result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); ++ if (result != ISC_R_SUCCESS) { ++ fatal("Failed to build public key filename: %s", ++ isc_result_totext(result)); ++ } ++ ++ result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, ++ dir); ++ if (result != ISC_R_SUCCESS) { ++ dst_key_format(key, keystr, sizeof(keystr)); ++ fatal("Failed to write key %s: %s", keystr, ++ isc_result_totext(result)); ++ } ++ ++ printf("%s\n", newname); ++ ++ isc_buffer_clear(&buf); ++ result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); ++ if (result != ISC_R_SUCCESS) { ++ fatal("Failed to build private key filename: %s", ++ isc_result_totext(result)); ++ } ++ printf("%s\n", newname); ++ dst_key_free(&key); ++} ++ ++ISC_PLATFORM_NORETURN_PRE static void ++usage(void) ISC_PLATFORM_NORETURN_POST; ++ ++static void ++usage(void) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, " %s options [-K dir] file\n\n", program); ++ fprintf(stderr, "Version: %s\n", VERSION); ++ fprintf(stderr, "Options:\n"); ++ fprintf(stderr, " -v <verbose level>\n"); ++ fprintf(stderr, " -K <directory>: directory in which to store " ++ "the keyset files\n"); ++ fprintf(stderr, " -f file: read keyset from zone file\n"); ++ ++ exit (-1); ++} ++ ++int ++main(int argc, char **argv) { ++ char *classname = NULL; ++ char *filename = NULL, *dir = NULL, *namestr; ++ char *endp; ++ int ch; ++ isc_result_t result; ++ isc_log_t *log = NULL; ++ isc_entropy_t *ectx = NULL; ++ dns_rdataset_t rdataset; ++ dns_rdata_t rdata; ++ isc_stdtime_t now; ++ ++ dns_rdata_init(&rdata); ++ isc_stdtime_get(&now); ++ ++ if (argc == 1) ++ usage(); ++ ++ result = isc_mem_create(0, 0, &mctx); ++ if (result != ISC_R_SUCCESS) ++ fatal("out of memory"); ++ ++ dns_result_register(); ++ ++ isc_commandline_errprint = ISC_FALSE; ++ ++ while ((ch = isc_commandline_parse(argc, argv, "D:f:hK:P:v:")) != -1) { ++ switch (ch) { ++ case 'D': ++ if (setdel) ++ fatal("-D specified more than once"); ++ ++ setdel = ISC_TRUE; ++ del = strtotime(isc_commandline_argument, now, now); ++ break; ++ case 'K': ++ dir = isc_commandline_argument; ++ if (strlen(dir) == 0U) ++ fatal("directory must be non-empty string"); ++ break; ++ case 'P': ++ if (setpub) ++ fatal("-P specified more than once"); ++ ++ setpub = ISC_TRUE; ++ pub = strtotime(isc_commandline_argument, now, now); ++ break; ++ case 'f': ++ filename = isc_commandline_argument; ++ break; ++ case 'v': ++ verbose = strtol(isc_commandline_argument, &endp, 0); ++ if (*endp != '\0') ++ fatal("-v must be followed by a number"); ++ break; ++ case '?': ++ if (isc_commandline_option != '?') ++ fprintf(stderr, "%s: invalid argument -%c\n", ++ program, isc_commandline_option); ++ /* FALLTHROUGH */ ++ case 'h': ++ usage(); ++ ++ default: ++ fprintf(stderr, "%s: unhandled option -%c\n", ++ program, isc_commandline_option); ++ exit(1); ++ } ++ } ++ ++ rdclass = strtoclass(classname); ++ ++ if (argc < isc_commandline_index + 1 && filename == NULL) ++ fatal("the key file name was not specified"); ++ if (argc > isc_commandline_index + 1) ++ fatal("extraneous arguments"); ++ ++ if (ectx == NULL) ++ setup_entropy(mctx, NULL, &ectx); ++ result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); ++ if (result != ISC_R_SUCCESS) ++ fatal("could not initialize hash"); ++ result = dst_lib_init(mctx, ectx, ++ ISC_ENTROPY_BLOCKING | ISC_ENTROPY_GOODONLY); ++ if (result != ISC_R_SUCCESS) ++ fatal("could not initialize dst: %s", ++ isc_result_totext(result)); ++ isc_entropy_stopcallbacksources(ectx); ++ ++ setup_logging(verbose, mctx, &log); ++ ++ dns_rdataset_init(&rdataset); ++ ++ if (filename != NULL) { ++ if (argc < isc_commandline_index + 1 && filename != NULL) { ++ /* using zone name as the zone file name */ ++ namestr = filename; ++ } else ++ namestr = argv[isc_commandline_index]; ++ ++ result = initname(namestr); ++ if (result != ISC_R_SUCCESS) ++ fatal("could not initialize name %s", namestr); ++ ++ result = loadset(filename, &rdataset); ++ ++ if (result != ISC_R_SUCCESS) ++ fatal("could not load DNSKEY set: %s\n", ++ isc_result_totext(result)); ++ ++ for (result = dns_rdataset_first(&rdataset); ++ result == ISC_R_SUCCESS; ++ result = dns_rdataset_next(&rdataset)) { ++ ++ dns_rdata_init(&rdata); ++ dns_rdataset_current(&rdataset, &rdata); ++ emit(dir, &rdata); ++ } ++ } else { ++ unsigned char key_buf[DST_KEY_MAXSIZE]; ++ ++ loadkey(argv[isc_commandline_index], key_buf, ++ DST_KEY_MAXSIZE, &rdata); ++ ++ emit(dir, &rdata); ++ } ++ ++ if (dns_rdataset_isassociated(&rdataset)) ++ dns_rdataset_disassociate(&rdataset); ++ cleanup_logging(&log); ++ dst_lib_destroy(); ++ isc_hash_destroy(); ++ cleanup_entropy(&ectx); ++ dns_name_destroy(); ++ if (verbose > 10) ++ isc_mem_stats(mctx, stdout); ++ isc_mem_destroy(&mctx); ++ ++ fflush(stdout); ++ if (ferror(stdout)) { ++ fprintf(stderr, "write error\n"); ++ return (1); ++ } else ++ return (0); ++} +diff --git a/bin/dnssec/dnssec-importkey.docbook b/bin/dnssec/dnssec-importkey.docbook +new file mode 100644 +index 0000000..b8d160c +--- /dev/null ++++ b/bin/dnssec/dnssec-importkey.docbook +@@ -0,0 +1,185 @@ ++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" ++ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" ++ [<!ENTITY mdash "—">]> ++<!-- ++ - Copyright (C) 2009-2011 Internet Systems Consortium, Inc. ("ISC") ++ - ++ - Permission to use, copy, modify, and/or distribute this software for any ++ - purpose with or without fee is hereby granted, provided that the above ++ - copyright notice and this permission notice appear in all copies. ++ - ++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ - PERFORMANCE OF THIS SOFTWARE. ++--> ++ ++<!-- $Id: dnssec-importkey.docbook,v 1.15 2011/11/03 20:21:37 each Exp $ --> ++<refentry id="man.dnssec-importkey"> ++ <refentryinfo> ++ <date>August 30, 2013</date> ++ </refentryinfo> ++ ++ <refmeta> ++ <refentrytitle><application>dnssec-importkey</application></refentrytitle> ++ <manvolnum>8</manvolnum> ++ <refmiscinfo>BIND9</refmiscinfo> ++ </refmeta> ++ ++ <refnamediv> ++ <refname><application>dnssec-importkey</application></refname> ++ <refpurpose>Import DNSKEY records from external systems so they can be managed.</refpurpose> ++ </refnamediv> ++ ++ <docinfo> ++ <copyright> ++ <year>2013</year> ++ <holder>Internet Systems Consortium, Inc. ("ISC")</holder> ++ </copyright> ++ </docinfo> ++ ++ <refsynopsisdiv> ++ <cmdsynopsis> ++ <command>dnssec-importkey</command> ++ <arg><option>-f <replaceable class="parameter">filename</replaceable></option></arg> ++ <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg> ++ <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg> ++ <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg> ++ <arg><option>-h</option></arg> ++ <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg> ++ <arg><option>keyname</option></arg> ++ </cmdsynopsis> ++ </refsynopsisdiv> ++ ++ <refsect1> ++ <title>DESCRIPTION</title> ++ <para><command>dnssec-importkey</command> ++ read a DNSKEY record and generated a .key/.private key pair. ++ Publication (<option>-P</option>) and deletions (<option>-D</option>) ++ times can be set for the key. ++ </para> ++ </refsect1> ++ ++ <refsect1> ++ <title>OPTIONS</title> ++ ++ <variablelist> ++ <varlistentry> ++ <term>-f <replaceable class="parameter">filename</replaceable></term> ++ <listitem> ++ <para> ++ Filename to read the key from. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-K <replaceable class="parameter">directory</replaceable></term> ++ <listitem> ++ <para> ++ Sets the directory in which the key files are to reside. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-L <replaceable class="parameter">ttl</replaceable></term> ++ <listitem> ++ <para> ++ Sets the default TTL to use for this key when it is converted ++ into a DNSKEY RR. If the key is imported into a zone, ++ this is the TTL that will be used for it, unless there was ++ already a DNSKEY RRset in place, in which case the existing TTL ++ would take precedence. importkey the default TTL to ++ <literal>0</literal> or <literal>none</literal> removes it. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-h</term> ++ <listitem> ++ <para> ++ Emit usage message and exit. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-v <replaceable class="parameter">level</replaceable></term> ++ <listitem> ++ <para> ++ Sets the debugging level. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ </variablelist> ++ </refsect1> ++ ++ <refsect1> ++ <title>TIMING OPTIONS</title> ++ <para> ++ Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. ++ If the argument begins with a '+' or '-', it is interpreted as ++ an offset from the present time. For convenience, if such an offset ++ is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi', ++ then the offset is computed in years (defined as 365 24-hour days, ++ ignoring leap years), months (defined as 30 24-hour days), weeks, ++ days, hours, or minutes, respectively. Without a suffix, the offset ++ is computed in seconds. To unset a date, use 'none'. ++ </para> ++ ++ <variablelist> ++ <varlistentry> ++ <term>-P <replaceable class="parameter">date/offset</replaceable></term> ++ <listitem> ++ <para> ++ Sets the date on which a key is to be published to the zone. ++ After that date, the key will be included in the zone but will ++ not be used to sign it. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-D <replaceable class="parameter">date/offset</replaceable></term> ++ <listitem> ++ <para> ++ Sets the date on which the key is to be deleted. After that ++ date, the key will no longer be included in the zone. (It ++ may remain in the key repository, however.) ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ </variablelist> ++ </refsect1> ++ ++ <refsect1> ++ <title>SEE ALSO</title> ++ <para><citerefentry> ++ <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum> ++ </citerefentry>, ++ <citerefentry> ++ <refentrytitle>dnssec-signzone</refentrytitle><manvolnum>8</manvolnum> ++ </citerefentry>, ++ <citetitle>BIND 9 Administrator Reference Manual</citetitle>, ++ <citetitle>RFC 5011</citetitle>. ++ </para> ++ </refsect1> ++ ++ <refsect1> ++ <title>AUTHOR</title> ++ <para><corpauthor>Internet Systems Consortium</corpauthor> ++ </para> ++ </refsect1> ++ ++</refentry><!-- ++ - Local variables: ++ - mode: sgml ++ - End: ++--> +diff --git a/bin/dnssec/dnssec-importkey.html b/bin/dnssec/dnssec-importkey.html +new file mode 100644 +index 0000000..f74be50 +--- /dev/null ++++ b/bin/dnssec/dnssec-importkey.html +@@ -0,0 +1,112 @@ ++<!-- ++ - Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ - ++ - Permission to use, copy, modify, and/or distribute this software for any ++ - purpose with or without fee is hereby granted, provided that the above ++ - copyright notice and this permission notice appear in all copies. ++ - ++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ - PERFORMANCE OF THIS SOFTWARE. ++--> ++<!-- $Id$ --> ++<html> ++<head> ++<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> ++<title>dnssec-importkey</title> ++<meta name="generator" content="DocBook XSL Stylesheets V1.78.1"> ++</head> ++<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry"> ++<a name="man.dnssec-importkey"></a><div class="titlepage"></div> ++<div class="refnamediv"> ++<h2>Name</h2> ++<p><span class="application">dnssec-importkey</span> — Import DNSKEY records from external systems so they can be managed.</p> ++</div> ++<div class="refsynopsisdiv"> ++<h2>Synopsis</h2> ++<div class="cmdsynopsis"><p><code class="command">dnssec-importkey</code> [<code class="option">-f <em class="replaceable"><code>filename</code></em></code>] [<code class="option">-K <em class="replaceable"><code>directory</code></em></code>] [<code class="option">-P <em class="replaceable"><code>date/offset</code></em></code>] [<code class="option">-D <em class="replaceable"><code>date/offset</code></em></code>] [<code class="option">-h</code>] [<code class="option">-v <em class="replaceable"><code>level</code></em></code>] [<code class="option">keyname</code>]</p></div> ++</div> ++<div class="refsect1"> ++<a name="idp5321760"></a><h2>DESCRIPTION</h2> ++<p><span class="command"><strong>dnssec-importkey</strong></span> ++ read a DNSKEY record and generated a .key/.private key pair. ++ Publication (<code class="option">-P</code>) and deletions (<code class="option">-D</code>) ++ times can be set for the key. ++ </p> ++</div> ++<div class="refsect1"> ++<a name="idp5324080"></a><h2>OPTIONS</h2> ++<div class="variablelist"><dl class="variablelist"> ++<dt><span class="term">-f <em class="replaceable"><code>filename</code></em></span></dt> ++<dd><p> ++ Filename to read the key from. ++ </p></dd> ++<dt><span class="term">-K <em class="replaceable"><code>directory</code></em></span></dt> ++<dd><p> ++ Sets the directory in which the key files are to reside. ++ </p></dd> ++<dt><span class="term">-L <em class="replaceable"><code>ttl</code></em></span></dt> ++<dd><p> ++ Sets the default TTL to use for this key when it is converted ++ into a DNSKEY RR. If the key is imported into a zone, ++ this is the TTL that will be used for it, unless there was ++ already a DNSKEY RRset in place, in which case the existing TTL ++ would take precedence. importkey the default TTL to ++ <code class="literal">0</code> or <code class="literal">none</code> removes it. ++ </p></dd> ++<dt><span class="term">-h</span></dt> ++<dd><p> ++ Emit usage message and exit. ++ </p></dd> ++<dt><span class="term">-v <em class="replaceable"><code>level</code></em></span></dt> ++<dd><p> ++ Sets the debugging level. ++ </p></dd> ++</dl></div> ++</div> ++<div class="refsect1"> ++<a name="idp5336224"></a><h2>TIMING OPTIONS</h2> ++<p> ++ Dates can be expressed in the format YYYYMMDD or YYYYMMDDHHMMSS. ++ If the argument begins with a '+' or '-', it is interpreted as ++ an offset from the present time. For convenience, if such an offset ++ is followed by one of the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi', ++ then the offset is computed in years (defined as 365 24-hour days, ++ ignoring leap years), months (defined as 30 24-hour days), weeks, ++ days, hours, or minutes, respectively. Without a suffix, the offset ++ is computed in seconds. To unset a date, use 'none'. ++ </p> ++<div class="variablelist"><dl class="variablelist"> ++<dt><span class="term">-P <em class="replaceable"><code>date/offset</code></em></span></dt> ++<dd><p> ++ Sets the date on which a key is to be published to the zone. ++ After that date, the key will be included in the zone but will ++ not be used to sign it. ++ </p></dd> ++<dt><span class="term">-D <em class="replaceable"><code>date/offset</code></em></span></dt> ++<dd><p> ++ Sets the date on which the key is to be deleted. After that ++ date, the key will no longer be included in the zone. (It ++ may remain in the key repository, however.) ++ </p></dd> ++</dl></div> ++</div> ++<div class="refsect1"> ++<a name="idp5342816"></a><h2>SEE ALSO</h2> ++<p><span class="citerefentry"><span class="refentrytitle">dnssec-keygen</span>(8)</span>, ++ <span class="citerefentry"><span class="refentrytitle">dnssec-signzone</span>(8)</span>, ++ <em class="citetitle">BIND 9 Administrator Reference Manual</em>, ++ <em class="citetitle">RFC 5011</em>. ++ </p> ++</div> ++<div class="refsect1"> ++<a name="idp5346704"></a><h2>AUTHOR</h2> ++<p><span class="corpauthor">Internet Systems Consortium</span> ++ </p> ++</div> ++</div></body> ++</html> +diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c +index 4c88a07..108d803 100644 +--- a/bin/dnssec/dnssec-settime.c ++++ b/bin/dnssec/dnssec-settime.c +@@ -370,7 +370,7 @@ main(int argc, char **argv) { + if (result != ISC_R_SUCCESS) + fatal("Invalid keyfile %s: %s", + filename, isc_result_totext(result)); +- if (!dst_key_isprivate(prevkey)) ++ if (!dst_key_isprivate(prevkey) && !dst_key_isexternal(prevkey)) + fatal("%s is not a private key", filename); + + name = dst_key_name(prevkey); +@@ -462,7 +462,7 @@ main(int argc, char **argv) { + fatal("Invalid keyfile %s: %s", + filename, isc_result_totext(result)); + +- if (!dst_key_isprivate(key)) ++ if (!dst_key_isprivate(key) && !dst_key_isexternal(key)) + fatal("%s is not a private key", filename); + + dst_key_format(key, keystr, sizeof(keystr)); +diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in +index 60f22f8..b15853d 100644 +--- a/bin/tests/system/conf.sh.in ++++ b/bin/tests/system/conf.sh.in +@@ -43,6 +43,7 @@ SIGNER=$TOP/bin/dnssec/dnssec-signzone + REVOKE=$TOP/bin/dnssec/dnssec-revoke + SETTIME=$TOP/bin/dnssec/dnssec-settime + DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey ++IMPORTKEY=$TOP/bin/dnssec/dnssec-importkey + CHECKDS=$TOP/bin/python/dnssec-checkds + COVERAGE=$TOP/bin/python/dnssec-coverage + CHECKZONE=$TOP/bin/check/named-checkzone +diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh +index 8ef3e2c..412031a 100644 +--- a/bin/tests/system/inline/clean.sh ++++ b/bin/tests/system/inline/clean.sh +@@ -60,6 +60,9 @@ rm -f ns3/retransfer.bk + rm -f ns3/retransfer.bk.jnl + rm -f ns3/retransfer.bk.signed + rm -f ns3/retransfer.bk.signed.jnl ++rm -f ns3/externalkey.db ++rm -f ns3/externalkey.db.signed ++rm -f ns3/externalkey.db.signed.jnl + rm -f ns4/K* + rm -f ns4/noixfr.db + rm -f ns4/noixfr.db.jnl +diff --git a/bin/tests/system/inline/ns1/root.db.in b/bin/tests/system/inline/ns1/root.db.in +index 8d3af51..a08db51 100644 +--- a/bin/tests/system/inline/ns1/root.db.in ++++ b/bin/tests/system/inline/ns1/root.db.in +@@ -50,3 +50,6 @@ ns3.retransfer. A 10.53.0.3 + + nsec3. NS ns3.nsec3. + ns3.nsec3. A 10.53.0.3 ++ ++externalkey. NS ns3.externalkey. ++ns3.externalkey. A 10.53.0.3 +diff --git a/bin/tests/system/inline/ns3/named.conf b/bin/tests/system/inline/ns3/named.conf +index a17384c..7c23edd 100644 +--- a/bin/tests/system/inline/ns3/named.conf ++++ b/bin/tests/system/inline/ns3/named.conf +@@ -103,3 +103,11 @@ zone "nsec3" { + allow-update { any; }; + file "nsec3.db"; + }; ++ ++zone "externalkey" { ++ type master; ++ inline-signing yes; ++ auto-dnssec maintain; ++ allow-update { any; }; ++ file "externalkey.db"; ++}; +diff --git a/bin/tests/system/inline/ns3/sign.sh b/bin/tests/system/inline/ns3/sign.sh +index bbd11af..f695973 100644 +--- a/bin/tests/system/inline/ns3/sign.sh ++++ b/bin/tests/system/inline/ns3/sign.sh +@@ -92,3 +92,32 @@ do + keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 768 -n zone $zone` + keyname=`$KEYGEN -q -r $RANDFILE -a RSASHA1 -b 1024 -n zone -f KSK $zone` + done ++ ++zone=externalkey ++rm -f K${zone}.+*+*.key ++rm -f K${zone}.+*+*.private ++ ++for alg in ECDSAP256SHA256 NSEC3RSASHA1 DSA ECCGOST ++do ++ ++if test $alg = ECCGOST ++then ++ sh ../../gost/prereq.sh 2> /dev/null || continue ++fi ++ ++k1=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone` ++k2=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` ++k3=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` ++k4=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` ++keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone $zone` ++keyname=`$KEYGEN -q -r $RANDFILE -a $alg -b 1024 -n zone -f KSK $zone` ++$DSFROMKEY -T 1200 $keyname >> ../ns1/root.db ++rm -f ${k3}.* ${k4}.* ++ ++# ++# Convert k1 and k2 in to External Keys. ++rm -f $k1.private ++$IMPORTKEY -P now -D now+3600 -f $k1.key $zone ++rm -f $k2.private ++$IMPORTKEY -f $k2.key $zone ++done +diff --git a/bin/tests/system/inline/setup.sh b/bin/tests/system/inline/setup.sh +index 9fa42ab..adee4ff 100644 +--- a/bin/tests/system/inline/setup.sh ++++ b/bin/tests/system/inline/setup.sh +@@ -29,6 +29,7 @@ cp ns3/master.db.in ns3/dynamic.db + cp ns3/master.db.in ns3/updated.db + cp ns3/master.db.in ns3/expired.db + cp ns3/master.db.in ns3/nsec3.db ++cp ns3/master.db.in ns3/externalkey.db + + touch ns4/trusted.conf + cp ns4/noixfr.db.in ns4/noixfr.db +diff --git a/bin/tests/system/inline/tests.sh b/bin/tests/system/inline/tests.sh +index 7e2e3d2..8acdee2 100644 +--- a/bin/tests/system/inline/tests.sh ++++ b/bin/tests/system/inline/tests.sh +@@ -809,7 +809,22 @@ $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 addzone test-$zone \ + $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 delzone test-$zone + done + +-if [ $ret != 0 ]; then echo "I:failed"; fi ++n=`expr $n + 1` ++echo "I:testing adding external keys to a inline zone ($n)" ++ret=0 ++$DIG $DIGOPTS @10.53.0.3 -p 5300 dnskey externalkey > dig.out.ns3.test$n ++for alg in 3 7 12 13 ++do ++if test $alg = 12 ++then ++ sh ../gost/prereq.sh 2>/dev/null || continue; ++fi ++ ++dnskeys=`grep "IN.DNSKEY.25[67] [0-9]* $alg " dig.out.ns3.test$n | wc -l` ++rrsigs=`grep "RRSIG.DNSKEY $alg " dig.out.ns3.test$n | wc -l` ++test ${dnskeys:-0} -eq 3 || { echo "I: failed $alg (dnskeys ${dnskeys:-0})"; ret=1; } ++test ${rrsigs:-0} -eq 2 || { echo "I: failed $alg (rrsigs ${rrsigs:-0})"; ret=1; } ++done + status=`expr $status + $ret` + + exit $status +diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c +index a1c5c69..cf97404 100644 +--- a/lib/dns/dnssec.c ++++ b/lib/dns/dnssec.c +@@ -684,6 +684,7 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver, + isc_stdtime_get(&now); + + *nkeys = 0; ++ memset(keys, 0, sizeof(*keys) * maxkeys); + dns_rdataset_init(&rdataset); + RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0, + &rdataset, NULL)); +@@ -1312,9 +1313,9 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, + isc_dir_t dir; + dns_dnsseckey_t *key = NULL; + dst_key_t *dstkey = NULL; +- char namebuf[DNS_NAME_FORMATSIZE], *p; ++ char namebuf[DNS_NAME_FORMATSIZE]; + isc_buffer_t b; +- unsigned int len; ++ unsigned int len, i; + isc_stdtime_t now; + + REQUIRE(keylist != NULL); +@@ -1334,49 +1335,62 @@ dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory, + isc_stdtime_get(&now); + + while (isc_dir_read(&dir) == ISC_R_SUCCESS) { +- if (dir.entry.name[0] == 'K' && +- dir.entry.length > len + 1 && +- dir.entry.name[len + 1] == '+' && +- strncasecmp(dir.entry.name + 1, namebuf, len) == 0) { +- p = strrchr(dir.entry.name, '.'); +- if (p != NULL && strcmp(p, ".private") != 0) +- continue; ++ if (dir.entry.name[0] != 'K' || ++ dir.entry.length < len + 1 || ++ dir.entry.name[len + 1] != '+' || ++ strncasecmp(dir.entry.name + 1, namebuf, len) != 0) ++ continue; ++ ++ for (i = len + 1 + 1; i < dir.entry.length ; i++) ++ if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9') ++ break; ++ ++ if (i == len + 1 + 1 || i >= dir.entry.length || ++ dir.entry.name[i] != '+') ++ continue; ++ ++ for (i++ ; i < dir.entry.length ; i++) ++ if (dir.entry.name[i] < '0' || dir.entry.name[i] > '9') ++ break; + +- dstkey = NULL; +- result = dst_key_fromnamedfile(dir.entry.name, +- directory, +- DST_TYPE_PUBLIC | +- DST_TYPE_PRIVATE, +- mctx, &dstkey); +- +- if (result != ISC_R_SUCCESS) { +- isc_log_write(dns_lctx, +- DNS_LOGCATEGORY_GENERAL, +- DNS_LOGMODULE_DNSSEC, +- ISC_LOG_WARNING, +- "dns_dnssec_findmatchingkeys: " +- "error reading key file %s: %s", +- dir.entry.name, +- isc_result_totext(result)); ++ if (strcmp(dir.entry.name + i, ".private") != 0) + continue; +- } + +- RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); +- key->source = dns_keysource_repository; +- get_hints(key, now); ++ dstkey = NULL; ++ result = dst_key_fromnamedfile(dir.entry.name, ++ directory, ++ DST_TYPE_PUBLIC | ++ DST_TYPE_PRIVATE, ++ mctx, &dstkey); + +- if (key->legacy) { +- dns_dnsseckey_destroy(mctx, &key); +- } else { +- ISC_LIST_APPEND(list, key, link); +- key = NULL; +- } ++ if (result != ISC_R_SUCCESS) { ++ isc_log_write(dns_lctx, ++ DNS_LOGCATEGORY_GENERAL, ++ DNS_LOGMODULE_DNSSEC, ++ ISC_LOG_WARNING, ++ "dns_dnssec_findmatchingkeys: " ++ "error reading key file %s: %s", ++ dir.entry.name, ++ isc_result_totext(result)); ++ continue; ++ } ++ ++ RETERR(dns_dnsseckey_create(mctx, &dstkey, &key)); ++ key->source = dns_keysource_repository; ++ get_hints(key, now); ++ ++ if (key->legacy) { ++ dns_dnsseckey_destroy(mctx, &key); ++ } else { ++ ISC_LIST_APPEND(list, key, link); ++ key = NULL; + } + } + +- if (!ISC_LIST_EMPTY(list)) ++ if (!ISC_LIST_EMPTY(list)) { ++ result = ISC_R_SUCCESS; + ISC_LIST_APPENDLIST(*keylist, list, link); +- else ++ } else + result = ISC_R_NOTFOUND; + + failure: +@@ -1794,7 +1808,13 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys, + for (key2 = ISC_LIST_HEAD(*keys); + key2 != NULL; + key2 = ISC_LIST_NEXT(key2, link)) { +- if (dst_key_pubcompare(key1->key, key2->key, ++ int f1 = dst_key_flags(key1->key); ++ int f2 = dst_key_flags(key2->key); ++ int nr1 = f1 & ~DNS_KEYFLAG_REVOKE; ++ int nr2 = f2 & ~DNS_KEYFLAG_REVOKE; ++ if (nr1 == nr2 && ++ dst_key_alg(key1->key) == dst_key_alg(key2->key) && ++ dst_key_pubcompare(key1->key, key2->key, + ISC_TRUE)) { + int r1, r2; + r1 = dst_key_flags(key1->key) & +diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c +index c310be5..4c174f3 100644 +--- a/lib/dns/dst_api.c ++++ b/lib/dns/dst_api.c +@@ -448,6 +448,16 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory) { + return (ISC_R_SUCCESS); + } + ++void ++dst_key_setexternal(dst_key_t *key, isc_boolean_t value) { ++ key->external = value; ++} ++ ++isc_boolean_t ++dst_key_isexternal(dst_key_t *key) { ++ return (key->external); ++} ++ + isc_result_t + dst_key_fromfile(dns_name_t *name, dns_keytag_t id, + unsigned int alg, int type, const char *directory, +diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h +index 48ce9b8..49ca424 100644 +--- a/lib/dns/dst_internal.h ++++ b/lib/dns/dst_internal.h +@@ -128,6 +128,7 @@ struct dst_key { + isc_boolean_t numset[DST_MAX_NUMERIC + 1]; /*%< data set? */ + isc_boolean_t inactive; /*%< private key not present as it is + inactive */ ++ isc_boolean_t external; /*%< external key */ + + int fmt_major; /*%< private key format, major version */ + int fmt_minor; /*%< private key format, minor version */ +diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c +index ca43cb3..6348cc1 100644 +--- a/lib/dns/dst_parse.c ++++ b/lib/dns/dst_parse.c +@@ -178,14 +178,18 @@ find_numericdata(const char *s) { + } + + static int +-check_rsa(const dst_private_t *priv) { ++check_rsa(const dst_private_t *priv, isc_boolean_t external) { + int i, j; + isc_boolean_t have[RSA_NTAGS]; + isc_boolean_t ok; + unsigned int mask; + ++ if (external) ++ return ((priv->nelements == 0) ? 0 : -1); ++ + for (i = 0; i < RSA_NTAGS; i++) + have[i] = ISC_FALSE; ++ + for (j = 0; j < priv->nelements; j++) { + for (i = 0; i < RSA_NTAGS; i++) + if (priv->elements[j].tag == TAG(DST_ALG_RSAMD5, i)) +@@ -231,10 +235,15 @@ check_dh(const dst_private_t *priv) { + } + + static int +-check_dsa(const dst_private_t *priv) { ++check_dsa(const dst_private_t *priv, isc_boolean_t external) { + int i, j; ++ ++ if (external) ++ return ((priv->nelements == 0)? 0 : -1); ++ + if (priv->nelements != DSA_NTAGS) + return (-1); ++ + for (i = 0; i < DSA_NTAGS; i++) { + for (j = 0; j < priv->nelements; j++) + if (priv->elements[j].tag == TAG(DST_ALG_DSA, i)) +@@ -246,7 +255,11 @@ check_dsa(const dst_private_t *priv) { + } + + static int +-check_gost(const dst_private_t *priv) { ++check_gost(const dst_private_t *priv, isc_boolean_t external) { ++ ++ if (external) ++ return ((priv->nelements == 0)? 0 : -1); ++ + if (priv->nelements != GOST_NTAGS) + return (-1); + if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) +@@ -255,7 +268,11 @@ check_gost(const dst_private_t *priv) { + } + + static int +-check_ecdsa(const dst_private_t *priv) { ++check_ecdsa(const dst_private_t *priv, isc_boolean_t external) { ++ ++ if (external) ++ return ((priv->nelements == 0) ? 0 : -1); ++ + if (priv->nelements != ECDSA_NTAGS) + return (-1); + if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0)) +@@ -309,7 +326,7 @@ check_hmac_sha(const dst_private_t *priv, unsigned int ntags, + + static int + check_data(const dst_private_t *priv, const unsigned int alg, +- isc_boolean_t old) ++ isc_boolean_t old, isc_boolean_t external) + { + /* XXXVIX this switch statement is too sparse to gen a jump table. */ + switch (alg) { +@@ -318,17 +335,17 @@ check_data(const dst_private_t *priv, const unsigned int alg, + case DST_ALG_NSEC3RSASHA1: + case DST_ALG_RSASHA256: + case DST_ALG_RSASHA512: +- return (check_rsa(priv)); ++ return (check_rsa(priv, external)); + case DST_ALG_DH: + return (check_dh(priv)); + case DST_ALG_DSA: + case DST_ALG_NSEC3DSA: +- return (check_dsa(priv)); ++ return (check_dsa(priv, external)); + case DST_ALG_ECCGOST: +- return (check_gost(priv)); ++ return (check_gost(priv, external)); + case DST_ALG_ECDSA256: + case DST_ALG_ECDSA384: +- return (check_ecdsa(priv)); ++ return (check_ecdsa(priv, external)); + case DST_ALG_HMACMD5: + return (check_hmac_md5(priv, old)); + case DST_ALG_HMACSHA1: +@@ -372,6 +389,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, + unsigned int opt = ISC_LEXOPT_EOL; + isc_stdtime_t when; + isc_result_t ret; ++ isc_boolean_t external = ISC_FALSE; + + REQUIRE(priv != NULL); + +@@ -467,9 +485,15 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, + + if (token.type != isc_tokentype_string) { + ret = DST_R_INVALIDPRIVATEKEY; ++ NEXTTOKEN(lex, opt, &token); + goto fail; + } + ++ if (strcmp(DST_AS_STR(token), "External:") == 0) { ++ external = ISC_TRUE; ++ goto next; ++ } ++ + /* Numeric metadata */ + tag = find_numericdata(DST_AS_STR(token)); + if (tag >= 0) { +@@ -534,8 +558,14 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, + READLINE(lex, opt, &token); + data = NULL; + } ++ + done: +- check = check_data(priv, alg, ISC_TRUE); ++ if (external && priv->nelements != 0) { ++ ret = DST_R_INVALIDPRIVATEKEY; ++ goto fail; ++ } ++ ++ check = check_data(priv, alg, ISC_TRUE, external); + if (check < 0) { + ret = DST_R_INVALIDPRIVATEKEY; + goto fail; +@@ -544,6 +574,8 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, + goto fail; + } + ++ key->external = external; ++ + return (ISC_R_SUCCESS); + + fail: +@@ -573,7 +605,7 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, + + REQUIRE(priv != NULL); + +- ret = check_data(priv, dst_key_alg(key), ISC_FALSE); ++ ret = check_data(priv, dst_key_alg(key), ISC_FALSE, key->external); + if (ret < 0) + return (DST_R_INVALIDPRIVATEKEY); + else if (ret != ISC_R_SUCCESS) +@@ -691,6 +723,9 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, + fprintf(fp, "%s %.*s\n", s, (int)r.length, r.base); + } + ++ if (key->external) ++ fprintf(fp, "External:\n"); ++ + /* Add the metadata tags */ + if (major > 1 || (major == 1 && minor >= 3)) { + for (i = 0; i < NUMERIC_NTAGS; i++) { +@@ -706,14 +741,14 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, + + isc_buffer_init(&b, buffer, sizeof(buffer)); + result = dns_time32_totext(when, &b); +- if (result != ISC_R_SUCCESS) { ++ if (result != ISC_R_SUCCESS) { + fclose(fp); + return (DST_R_INVALIDPRIVATEKEY); +- } ++ } + + isc_buffer_usedregion(&b, &r); + +- fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length, ++ fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length, + r.base); + } + } +diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c +index 297e809..30aa1fa 100644 +--- a/lib/dns/dst_result.c ++++ b/lib/dns/dst_result.c +@@ -35,7 +35,7 @@ static const char *text[DST_R_NRESULTS] = { + "illegal operation for a null key", /*%< 3 */ + "public key is invalid", /*%< 4 */ + "private key is invalid", /*%< 5 */ +- "UNUSED6", /*%< 6 */ ++ "external key", /*%< 6 */ + "error occurred writing key to disk", /*%< 7 */ + "invalid algorithm specific parameter", /*%< 8 */ + "UNUSED9", /*%< 9 */ +diff --git a/lib/dns/include/dns/master.h b/lib/dns/include/dns/master.h +index 6abcb7e..931e930 100644 +--- a/lib/dns/include/dns/master.h ++++ b/lib/dns/include/dns/master.h +@@ -57,6 +57,7 @@ + + #define DNS_MASTER_RESIGN 0x00002000 + #define DNS_MASTER_KEY 0x00004000 /*%< Loading a key zone master file. */ ++#define DNS_MASTER_NOTTL 0x00008000 /*%< Don't require ttl. */ + + ISC_LANG_BEGINDECLS + +diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h +index 6ce3a0c..8676d1a 100644 +--- a/lib/dns/include/dst/dst.h ++++ b/lib/dns/include/dst/dst.h +@@ -953,6 +953,12 @@ dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive); + * 'key' to be valid. + */ + ++void ++dst_key_setexternal(dst_key_t *key, isc_boolean_t value); ++ ++isc_boolean_t ++dst_key_isexternal(dst_key_t *key); ++ + ISC_LANG_ENDDECLS + + #endif /* DST_DST_H */ +diff --git a/lib/dns/master.c b/lib/dns/master.c +index aa8f1ac..1a2c84a 100644 +--- a/lib/dns/master.c ++++ b/lib/dns/master.c +@@ -592,9 +592,9 @@ loadctx_create(dns_masterformat_t format, isc_mem_t *mctx, + isc_lex_setcomments(lctx->lex, ISC_LEXCOMMENT_DNSMASTERFILE); + } + +- lctx->ttl_known = ISC_FALSE; ++ lctx->ttl_known = ISC_TF((options & DNS_MASTER_NOTTL) != 0); + lctx->ttl = 0; +- lctx->default_ttl_known = ISC_FALSE; ++ lctx->default_ttl_known = lctx->ttl_known; + lctx->default_ttl = 0; + lctx->warn_1035 = ISC_TRUE; /* XXX Argument? */ + lctx->warn_tcr = ISC_TRUE; /* XXX Argument? */ +diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c +index 8bea1c0..a24baae 100644 +--- a/lib/dns/openssldsa_link.c ++++ b/lib/dns/openssldsa_link.c +@@ -522,6 +522,11 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) { + + if (key->keydata.dsa == NULL) + return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } + + dsa = key->keydata.dsa; + +@@ -569,6 +574,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + #define DST_RET(a) {ret = a; goto err;} + + UNUSED(pub); ++ + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) +@@ -607,6 +613,19 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + } + dst__privstruct_free(&priv, mctx); + ++ if (key->external) { ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ dsa->q = pub->keydata.dsa->q; ++ pub->keydata.dsa->q = NULL; ++ dsa->p = pub->keydata.dsa->p; ++ pub->keydata.dsa->p = NULL; ++ dsa->g = pub->keydata.dsa->g; ++ pub->keydata.dsa->g = NULL; ++ dsa->pub_key = pub->keydata.dsa->pub_key; ++ pub->keydata.dsa->pub_key = NULL; ++ } ++ + key->key_size = BN_num_bits(dsa->p); + + return (ISC_R_SUCCESS); +diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c +index c3f5061..7eff9a0 100644 +--- a/lib/dns/opensslecdsa_link.c ++++ b/lib/dns/opensslecdsa_link.c +@@ -453,6 +453,11 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.pkey == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ + pkey = key->keydata.pkey; + eckey = EVP_PKEY_get1_EC_KEY(pkey); + if (eckey == NULL) +@@ -514,8 +519,9 @@ static isc_result_t + opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; + isc_result_t ret; +- EVP_PKEY *pkey; +- EC_KEY *eckey = NULL; ++ EVP_PKEY *pkey, *pubpkey; ++ EC_KEY *eckey = NULL, *pubeckey = NULL; ++ const EC_POINT *pubkey; + BIGNUM *privkey; + int group_nid; + isc_mem_t *mctx = key->mctx; +@@ -537,17 +543,36 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (ret != ISC_R_SUCCESS) + goto err; + +- privkey = BN_bin2bn(priv.elements[0].data, +- priv.elements[0].length, NULL); +- if (privkey == NULL) +- DST_RET(ISC_R_NOMEMORY); +- if (!EC_KEY_set_private_key(eckey, privkey)) +- DST_RET(ISC_R_NOMEMORY); +- if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- dst__privstruct_free(&priv, mctx); +- memset(&priv, 0, sizeof(priv)); +- ++ if (key->external) { ++ /* ++ * Copy the public key to this new key. ++ */ ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ pubpkey = pub->keydata.pkey; ++ pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey); ++ if (pubeckey == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ pubkey = EC_KEY_get0_public_key(pubeckey); ++ if (pubkey == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ if (EC_KEY_set_public_key(eckey, pubkey) != 1) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ if (EC_KEY_check_key(eckey) != 1) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ } else { ++ privkey = BN_bin2bn(priv.elements[0].data, ++ priv.elements[0].length, NULL); ++ if (privkey == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ if (!EC_KEY_set_private_key(eckey, privkey)) ++ DST_RET(ISC_R_NOMEMORY); ++ if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ } ++ + pkey = EVP_PKEY_new(); + if (pkey == NULL) + DST_RET (ISC_R_NOMEMORY); +@@ -561,6 +586,8 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + err: + if (eckey != NULL) + EC_KEY_free(eckey); ++ if (pubeckey != NULL) ++ EC_KEY_free(pubeckey); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c +index 1ce4405..325a7c0 100644 +--- a/lib/dns/opensslgost_link.c ++++ b/lib/dns/opensslgost_link.c +@@ -296,6 +296,11 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.pkey == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ + pkey = key->keydata.pkey; + + len = i2d_PrivateKey(pkey, NULL); +@@ -337,13 +342,21 @@ opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (ret != ISC_R_SUCCESS) + return (ret); + +- INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); +- p = priv.elements[0].data; +- if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, +- (long) priv.elements[0].length) == NULL) +- DST_RET(dst__openssl_toresult2("d2i_PrivateKey", +- DST_R_INVALIDPRIVATEKEY)); +- key->keydata.pkey = pkey; ++ if (key->external) { ++ INSIST(priv.nelements == 0); ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ } else { ++ INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); ++ p = priv.elements[0].data; ++ if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, ++ (long) priv.elements[0].length) == NULL) ++ DST_RET(dst__openssl_toresult2("d2i_PrivateKey", ++ DST_R_INVALIDPRIVATEKEY)); ++ key->keydata.pkey = pkey; ++ } + key->key_size = EVP_PKEY_bits(pkey); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); +diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c +index fa7412c..894c7ae 100644 +--- a/lib/dns/opensslrsa_link.c ++++ b/lib/dns/opensslrsa_link.c +@@ -1048,8 +1048,14 @@ opensslrsa_tofile(const dst_key_t *key, const char *directory) { + return (DST_R_NULLKEY); + rsa = key->keydata.rsa; + #endif +- + memset(bufs, 0, sizeof(bufs)); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ result = dst__privstruct_writefile(key, &priv, directory); ++ goto fail; ++ } ++ + for (i = 0; i < 8; i++) { + bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(rsa->n)); + if (bufs[i] == NULL) { +@@ -1205,6 +1211,9 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (ret != ISC_R_SUCCESS) + goto err; + ++ if (key->external && priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_RSA_ENGINE: +@@ -1217,6 +1226,7 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + break; + } + } ++ + /* + * Is this key is stored in a HSM? + * See if we can fetch it. +@@ -1328,8 +1338,10 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); +- if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) +- DST_RET(ISC_R_RANGE); ++ if (!key->external) { ++ if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) ++ DST_RET(ISC_R_RANGE); ++ } + key->key_size = BN_num_bits(rsa->n); + if (pubrsa != NULL) + RSA_free(pubrsa); +diff --git a/lib/dns/zone.c b/lib/dns/zone.c +index daf495b..b82ad58 100644 +--- a/lib/dns/zone.c ++++ b/lib/dns/zone.c +@@ -5545,6 +5545,7 @@ find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, + const char *directory = dns_zone_getkeydirectory(zone); + + CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node)); ++ memset(keys, 0, sizeof(*keys) * maxkeys); + result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db), + directory, mctx, maxkeys, keys, + nkeys); +@@ -13132,6 +13133,7 @@ sync_secure_db(dns_zone_t *seczone, dns_db_t *secdb, + + static void + receive_secure_serial(isc_task_t *task, isc_event_t *event) { ++ static char me[] = "receive_secure_serial"; + isc_result_t result; + dns_journal_t *rjournal = NULL; + isc_uint32_t start, end; +@@ -13147,6 +13149,8 @@ receive_secure_serial(isc_task_t *task, isc_event_t *event) { + end = ((struct secure_event *)event)->serial; + isc_event_free(&event); + ++ ENTER; ++ + LOCK_ZONE(zone); + + dns_diff_init(zone->mctx, &diff); +-- +1.9.3 + diff --git a/SOURCES/bind-9.9-dist-native-pkcs11.patch b/SOURCES/bind-9.9-dist-native-pkcs11.patch new file mode 100644 index 0000000..36c0ea4 --- /dev/null +++ b/SOURCES/bind-9.9-dist-native-pkcs11.patch @@ -0,0 +1,740 @@ +diff --git a/bin/Makefile.in b/bin/Makefile.in +index 87ca5b2..187ec23 100644 +--- a/bin/Makefile.in ++++ b/bin/Makefile.in +@@ -19,7 +19,7 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + +-SUBDIRS = named rndc dig dnssec tools tests nsupdate \ ++SUBDIRS = named named-pkcs11 rndc dig dnssec dnssec-pkcs11 tools tests nsupdate \ + check confgen @PYTHON_TOOLS@ @PKCS11_TOOLS@ + TARGETS = + +diff --git a/bin/dnssec-pkcs11/Makefile.in b/bin/dnssec-pkcs11/Makefile.in +index 64e1846..7846662 100644 +--- a/bin/dnssec-pkcs11/Makefile.in ++++ b/bin/dnssec-pkcs11/Makefile.in +@@ -23,18 +23,18 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ++CINCLUDES = ${DNS_PKCS11_INCLUDES} ${ISC_PKCS11_INCLUDES} + + CDEFINES = -DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \ +- @CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\" ++ @CRYPTO_PK11@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\" + CWARNINGS = + +-DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +-ISCLIBS = ../../lib/isc/libisc.@A@ +-ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ ++DNSLIBS = ../../lib/dns-pkcs11/libdns-pkcs11.@A@ @DNS_CRYPTO_PK11_LIBS@ ++ISCLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ ++ISCNOSYMLIBS = ../../lib/isc-pkcs11/libisc-pkcs11-nosymtbl.@A@ + +-DNSDEPLIBS = ../../lib/dns/libdns.@A@ +-ISCDEPLIBS = ../../lib/isc/libisc.@A@ ++DNSDEPLIBS = ../../lib/dns-pkcs11/libdns-pkcs11.@A@ ++ISCDEPLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + + DEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS} + +@@ -43,10 +43,10 @@ LIBS = ${DNSLIBS} ${ISCLIBS} @LIBS@ + NOSYMLIBS = ${DNSLIBS} ${ISCNOSYMLIBS} @LIBS@ + + # Alphabetically +-TARGETS = dnssec-keygen@EXEEXT@ dnssec-signzone@EXEEXT@ \ +- dnssec-keyfromlabel@EXEEXT@ dnssec-dsfromkey@EXEEXT@ \ +- dnssec-revoke@EXEEXT@ dnssec-settime@EXEEXT@ \ +- dnssec-verify@EXEEXT@ dnssec-importkey@EXEEXT@ ++TARGETS = dnssec-keygen-pkcs11@EXEEXT@ dnssec-signzone-pkcs11@EXEEXT@ \ ++ dnssec-keyfromlabel-pkcs11@EXEEXT@ dnssec-dsfromkey-pkcs11@EXEEXT@ \ ++ dnssec-revoke-pkcs11@EXEEXT@ dnssec-settime-pkcs11@EXEEXT@ \ ++ dnssec-verify-pkcs11@EXEEXT@ dnssec-importkey-pkcs11@EXEEXT@ + + OBJS = dnssectool.@O@ + +@@ -67,15 +67,15 @@ MANOBJS = ${MANPAGES} ${HTMLPAGES} + + @BIND9_MAKE_RULES@ + +-dnssec-dsfromkey@EXEEXT@: dnssec-dsfromkey.@O@ ${OBJS} ${DEPLIBS} ++dnssec-dsfromkey-pkcs11@EXEEXT@: dnssec-dsfromkey.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-dsfromkey.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +-dnssec-keyfromlabel@EXEEXT@: dnssec-keyfromlabel.@O@ ${OBJS} ${DEPLIBS} ++dnssec-keyfromlabel-pkcs11@EXEEXT@: dnssec-keyfromlabel.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-keyfromlabel.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +-dnssec-keygen@EXEEXT@: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS} ++dnssec-keygen-pkcs11@EXEEXT@: dnssec-keygen.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-keygen.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +@@ -83,7 +83,7 @@ dnssec-signzone.@O@: dnssec-signzone.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \ + -c ${srcdir}/dnssec-signzone.c + +-dnssec-signzone@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS} ++dnssec-signzone-pkcs11@EXEEXT@: dnssec-signzone.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-signzone.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +@@ -91,19 +91,19 @@ dnssec-verify.@O@: dnssec-verify.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} -DVERSION=\"${VERSION}\" \ + -c ${srcdir}/dnssec-verify.c + +-dnssec-verify@EXEEXT@: dnssec-verify.@O@ ${OBJS} ${DEPLIBS} ++dnssec-verify-pkcs11@EXEEXT@: dnssec-verify.@O@ ${OBJS} ${DEPLIBS} + export BASEOBJS="dnssec-verify.@O@ ${OBJS}"; \ + ${FINALBUILDCMD} + +-dnssec-revoke@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS} ++dnssec-revoke-pkcs11@EXEEXT@: dnssec-revoke.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-revoke.@O@ ${OBJS} ${LIBS} + +-dnssec-settime@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS} ++dnssec-settime-pkcs11@EXEEXT@: dnssec-settime.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-settime.@O@ ${OBJS} ${LIBS} + +-dnssec-importkey@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS} ++dnssec-importkey-pkcs11@EXEEXT@: dnssec-importkey.@O@ ${OBJS} ${DEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + dnssec-importkey.@O@ ${OBJS} ${LIBS} + +@@ -114,11 +114,9 @@ docclean manclean maintainer-clean:: + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} +- $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 + + install:: ${TARGETS} installdirs + for t in ${TARGETS}; do ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} $$t ${DESTDIR}${sbindir}; done +- for m in ${MANPAGES}; do ${INSTALL_DATA} ${srcdir}/$$m ${DESTDIR}${mandir}/man8; done + + clean distclean:: + rm -f ${TARGETS} +diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in +index 64e1846..cfb5628 100644 +--- a/bin/dnssec/Makefile.in ++++ b/bin/dnssec/Makefile.in +@@ -25,7 +25,7 @@ top_srcdir = @top_srcdir@ + + CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} + +-CDEFINES = -DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \ ++CDEFINES = -DVERSION=\"${VERSION}\" \ + @CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\" + CWARNINGS = + +diff --git a/bin/named-pkcs11/Makefile.in b/bin/named-pkcs11/Makefile.in +index 8b9e87a..5b7d939 100644 +--- a/bin/named-pkcs11/Makefile.in ++++ b/bin/named-pkcs11/Makefile.in +@@ -45,26 +45,26 @@ DLZDRIVER_INCLUDES = @DLZ_DRIVER_INCLUDES@ + DLZDRIVER_LIBS = @DLZ_DRIVER_LIBS@ + + CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ +- ${LWRES_INCLUDES} ${DNS_INCLUDES} ${BIND9_INCLUDES} \ +- ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ ++ ${LWRES_INCLUDES} ${DNS_PKCS11_INCLUDES} ${BIND9_INCLUDES} \ ++ ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_PKCS11_INCLUDES} \ + ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@ ++CDEFINES = @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO_PK11@ + + CWARNINGS = + +-DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ ++DNSLIBS = ../../lib/dns-pkcs11/libdns-pkcs11.@A@ @DNS_CRYPTO_LIBS@ + ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ + ISCCCLIBS = ../../lib/isccc/libisccc.@A@ +-ISCLIBS = ../../lib/isc/libisc.@A@ ++ISCLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + ISCNOSYMLIBS = ../../lib/isc/libisc-nosymtbl.@A@ + LWRESLIBS = ../../lib/lwres/liblwres.@A@ + BIND9LIBS = ../../lib/bind9/libbind9.@A@ + +-DNSDEPLIBS = ../../lib/dns/libdns.@A@ ++DNSDEPLIBS = ../../lib/dns-pkcs11/libdns-pkcs11.@A@ + ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ + ISCCCDEPLIBS = ../../lib/isccc/libisccc.@A@ +-ISCDEPLIBS = ../../lib/isc/libisc.@A@ ++ISCDEPLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ + BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ + +@@ -73,15 +73,15 @@ DEPLIBS = ${LWRESDEPLIBS} ${DNSDEPLIBS} ${BIND9DEPLIBS} \ + + LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCLIBS} \ +- ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@ ++ @LIBS@ + + NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} \ + ${ISCCFGLIBS} ${ISCCCLIBS} ${ISCNOSYMLIBS} \ +- ${DLZDRIVER_LIBS} ${DBDRIVER_LIBS} @LIBS@ ++ @LIBS@ + + SUBDIRS = unix + +-TARGETS = named@EXEEXT@ lwresd@EXEEXT@ ++TARGETS = named-pkcs11@EXEEXT@ + + GEOIPLINKOBJS = geoip.@O@ + +@@ -92,8 +92,7 @@ OBJS = builtin.@O@ client.@O@ config.@O@ control.@O@ \ + tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \ + zoneconf.@O@ \ + lwaddr.@O@ lwresd.@O@ lwdclient.@O@ lwderror.@O@ lwdgabn.@O@ \ +- lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ \ +- ${DLZDRIVER_OBJS} ${DBDRIVER_OBJS} ++ lwdgnba.@O@ lwdgrbn.@O@ lwdnoop.@O@ lwsearch.@O@ + + UOBJS = unix/os.@O@ unix/dlz_dlopen_driver.@O@ + +@@ -108,8 +107,7 @@ SRCS = builtin.c client.c config.c control.c \ + tkeyconf.c tsigconf.c update.c xfrout.c \ + zoneconf.c \ + lwaddr.c lwresd.c lwdclient.c lwderror.c lwdgabn.c \ +- lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c \ +- ${DLZDRIVER_SRCS} ${DBDRIVER_SRCS} ++ lwdgnba.c lwdgrbn.c lwdnoop.c lwsearch.c + + MANPAGES = named.8 lwresd.8 named.conf.5 + +@@ -145,7 +143,7 @@ config.@O@: config.c bind.keys.h + -DNS_SYSCONFDIR=\"${sysconfdir}\" \ + -c ${srcdir}/config.c + +-named@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} ++named-pkcs11@EXEEXT@: ${OBJS} ${UOBJS} ${DEPLIBS} + export MAKE_SYMTABLE="yes"; \ + export BASEOBJS="${OBJS} ${UOBJS}"; \ + ${FINALBUILDCMD} +@@ -176,15 +174,9 @@ statschannel.@O@: bind9.xsl.h bind9.ver3.xsl.h + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${sbindir} +- $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man5 +- $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 +- +-install:: named@EXEEXT@ lwresd@EXEEXT@ installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named@EXEEXT@ ${DESTDIR}${sbindir} +- (cd ${DESTDIR}${sbindir}; rm -f lwresd@EXEEXT@; @LN@ named@EXEEXT@ lwresd@EXEEXT@) +- ${INSTALL_DATA} ${srcdir}/named.8 ${DESTDIR}${mandir}/man8 +- ${INSTALL_DATA} ${srcdir}/lwresd.8 ${DESTDIR}${mandir}/man8 +- ${INSTALL_DATA} ${srcdir}/named.conf.5 ${DESTDIR}${mandir}/man5 ++ ++install:: named-pkcs11@EXEEXT@ installdirs ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} named-pkcs11@EXEEXT@ ${DESTDIR}${sbindir} + + @DLZ_DRIVER_RULES@ + +diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in +index 8b9e87a..5ba3f56 100644 +--- a/bin/named/Makefile.in ++++ b/bin/named/Makefile.in +@@ -49,7 +49,7 @@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ + ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@ ++CDEFINES = @CONTRIB_DLZ@ @CRYPTO@ + + CWARNINGS = + +diff --git a/bin/pkcs11/Makefile.in b/bin/pkcs11/Makefile.in +index 15d3fb5..32cc753 100644 +--- a/bin/pkcs11/Makefile.in ++++ b/bin/pkcs11/Makefile.in +@@ -20,13 +20,13 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-CINCLUDES = ${ISC_INCLUDES} ++CINCLUDES = ${ISC_PKCS11_INCLUDES} + + CDEFINES = + +-ISCLIBS = ../../lib/isc/libisc.@A@ ++ISCLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + +-ISCDEPLIBS = ../../lib/isc/libisc.@A@ ++ISCDEPLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + + DEPLIBS = ${ISCDEPLIBS} + +diff --git a/configure.in b/configure.in +index 5c79d6d..6c08de9 100644 +--- a/configure.in ++++ b/configure.in +@@ -659,10 +659,10 @@ AC_ARG_WITH(pkcs11, + openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw" + if test "$use_openssl" = "auto" + then +- if test "$want_native_pkcs11" = "yes" +- then +- use_openssl="native_pkcs11" +- else ++# if test "$want_native_pkcs11" = "yes" ++# then ++# use_openssl="native_pkcs11" ++# else + for d in $openssldirs + do + if test -f $d/include/openssl/opensslv.h +@@ -671,7 +671,7 @@ then + break + fi + done +- fi ++# fi + fi + OPENSSL_ECDSA="" + OPENSSL_GOST="" +@@ -730,11 +730,11 @@ case "$use_openssl" in + If you don't want OpenSSL, use --without-openssl]) + ;; + *) +- if test "$want_native_pkcs11" = "yes" +- then +- AC_MSG_RESULT() +- AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.]) +- fi ++# if test "$want_native_pkcs11" = "yes" ++# then ++# AC_MSG_RESULT() ++# AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.]) ++# fi + if test "$use_openssl" = "yes" + then + # User did not specify a path - guess it +@@ -1014,6 +1014,7 @@ AC_SUBST(OPENSSL_ECDSA) + AC_SUBST(OPENSSL_GOST) + + DNS_CRYPTO_LIBS="$DNS_CRYPTO_LIBS $DNS_OPENSSL_LIBS" ++DNS_CRYPTO_PK11_LIBS="$DNS_CRYPTO_LIBS" + + # + # Use OpenSSL for hash functions +@@ -1195,7 +1196,7 @@ case "$use_pkcs11" in + esac + AC_SUBST(PKCS11_PROVIDER) + +- ++CRYPTO_PK11="" + PKCS11_ECDSA="" + PKCS11_GOST="" + AC_MSG_CHECKING(for native PKCS11) +@@ -1203,7 +1204,7 @@ AC_MSG_CHECKING(for native PKCS11) + case "$want_native_pkcs11" in + yes) + AC_MSG_RESULT(using native PKCS11 crypto) +- CRYPTO="-DPKCS11CRYPTO" ++ CRYPTO_PK11="-DPKCS11CRYPTO" + PKCS11LINKOBJS='${PKCS11LINKOBJS}' + PKCS11LINKSRCS='${PKCS11LINKSRCS}' + PKCS11_TEST=pkcs11 +@@ -1240,6 +1241,7 @@ esac + AC_SUBST(PKCS11LINKOBJS) + AC_SUBST(PKCS11LINKSRCS) + AC_SUBST(CRYPTO) ++AC_SUBST(CRYPTO_PK11) + AC_SUBST(PKCS11_ECDSA) + AC_SUBST(PKCS11_GOST) + AC_SUBST(PKCS11_TEST) +@@ -1531,12 +1533,13 @@ AC_SUBST(USE_GSSAPI) + AC_SUBST(DST_GSSAPI_INC) + AC_SUBST(DNS_GSSAPI_LIBS) + DNS_CRYPTO_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_LIBS" +- ++DNS_CRYPTO_PK11_LIBS="$DNS_GSSAPI_LIBS $DNS_CRYPTO_PK11_LIBS" + # + # Applications linking with libdns also need to link with these libraries. + # + + AC_SUBST(DNS_CRYPTO_LIBS) ++AC_SUBST(DNS_CRYPTO_PK11_LIBS) + + # + # was --with-randomdev specified? +@@ -4014,7 +4017,10 @@ AC_CONFIG_FILES([ + bin/confgen/unix/Makefile + bin/dig/Makefile + bin/dnssec/Makefile ++ bin/dnssec-pkcs11/Makefile + bin/named/Makefile ++ bin/named-pkcs11/Makefile ++ bin/named-pkcs11/unix/Makefile + bin/named/unix/Makefile + bin/nsupdate/Makefile + bin/pkcs11/Makefile +@@ -4097,11 +4103,19 @@ AC_CONFIG_FILES([ + lib/dns/include/dns/Makefile + lib/dns/include/dst/Makefile + lib/dns/tests/Makefile ++ lib/dns-pkcs11/Makefile ++ lib/dns-pkcs11/include/Makefile ++ lib/dns-pkcs11/include/dns/Makefile ++ lib/dns-pkcs11/include/dst/Makefile + lib/export/Makefile + lib/export/dns/Makefile + lib/export/dns/include/Makefile + lib/export/dns/include/dns/Makefile + lib/export/dns/include/dst/Makefile ++ lib/export/dns-pkcs11/Makefile ++ lib/export/dns-pkcs11/include/Makefile ++ lib/export/dns-pkcs11/include/dns/Makefile ++ lib/export/dns-pkcs11/include/dst/Makefile + lib/export/irs/Makefile + lib/export/irs/include/Makefile + lib/export/irs/include/irs/Makefile +@@ -4115,6 +4129,16 @@ AC_CONFIG_FILES([ + lib/export/isc/unix/Makefile + lib/export/isc/unix/include/Makefile + lib/export/isc/unix/include/isc/Makefile ++ lib/export/isc-pkcs11/$thread_dir/Makefile ++ lib/export/isc-pkcs11/$thread_dir/include/Makefile ++ lib/export/isc-pkcs11/$thread_dir/include/isc/Makefile ++ lib/export/isc-pkcs11/Makefile ++ lib/export/isc-pkcs11/include/Makefile ++ lib/export/isc-pkcs11/include/isc/Makefile ++ lib/export/isc-pkcs11/nls/Makefile ++ lib/export/isc-pkcs11/unix/Makefile ++ lib/export/isc-pkcs11/unix/include/Makefile ++ lib/export/isc-pkcs11/unix/include/isc/Makefile + lib/export/isccfg/Makefile + lib/export/isccfg/include/Makefile + lib/export/isccfg/include/isccfg/Makefile +@@ -4143,6 +4167,24 @@ AC_CONFIG_FILES([ + lib/isc/unix/include/Makefile + lib/isc/unix/include/isc/Makefile + lib/isc/unix/include/pkcs11/Makefile ++ lib/isc-pkcs11/$arch/Makefile ++ lib/isc-pkcs11/$arch/include/Makefile ++ lib/isc-pkcs11/$arch/include/isc/Makefile ++ lib/isc-pkcs11/$thread_dir/Makefile ++ lib/isc-pkcs11/$thread_dir/include/Makefile ++ lib/isc-pkcs11/$thread_dir/include/isc/Makefile ++ lib/isc-pkcs11/Makefile ++ lib/isc-pkcs11/include/Makefile ++ lib/isc-pkcs11/include/isc/Makefile ++ lib/isc-pkcs11/include/isc/platform.h ++ lib/isc-pkcs11/include/pk11/Makefile ++ lib/isc-pkcs11/include/pkcs11/Makefile ++ lib/isc-pkcs11/tests/Makefile ++ lib/isc-pkcs11/nls/Makefile ++ lib/isc-pkcs11/unix/Makefile ++ lib/isc-pkcs11/unix/include/Makefile ++ lib/isc-pkcs11/unix/include/isc/Makefile ++ lib/isc-pkcs11/unix/include/pkcs11/Makefile + lib/isccc/Makefile + lib/isccc/include/Makefile + lib/isccc/include/isccc/Makefile +diff --git a/lib/Makefile.in b/lib/Makefile.in +index 8dc1d38..8e48d5e 100644 +--- a/lib/Makefile.in ++++ b/lib/Makefile.in +@@ -23,7 +23,7 @@ top_srcdir = @top_srcdir@ + # Attempt to disable parallel processing. + .NOTPARALLEL: + .NO_PARALLEL: +-SUBDIRS = isc isccc dns isccfg bind9 lwres tests ++SUBDIRS = isc isccc dns isccfg bind9 lwres tests isc-pkcs11 dns-pkcs11 + TARGETS = + + @BIND9_MAKE_RULES@ +diff --git a/lib/dns-pkcs11/Makefile.in b/lib/dns-pkcs11/Makefile.in +index ae316c5..1a79768 100644 +--- a/lib/dns-pkcs11/Makefile.in ++++ b/lib/dns-pkcs11/Makefile.in +@@ -27,16 +27,16 @@ top_srcdir = @top_srcdir@ + + USE_ISC_SPNEGO = @USE_ISC_SPNEGO@ + +-CINCLUDES = -I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} \ ++CINCLUDES = -I. -I${top_srcdir}/lib/dns-pkcs11 -Iinclude ${DNS_PKCS11_INCLUDES} ${ISC_PKCS11_INCLUDES} \ + @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ + +-CDEFINES = -DUSE_MD5 @CRYPTO@ @USE_GSSAPI@ ${USE_ISC_SPNEGO} ++CDEFINES = -DUSE_MD5 @CRYPTO_PK11@ @USE_GSSAPI@ ${USE_ISC_SPNEGO} + + CWARNINGS = + +-ISCLIBS = ../../lib/isc/libisc.@A@ ++ISCLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + +-ISCDEPLIBS = ../../lib/isc/libisc.@A@ ++ISCDEPLIBS = ../../lib/isc-pkcs11/libisc-pkcs11.@A@ + + LIBS = @LIBS@ + +@@ -131,24 +131,24 @@ version.@O@: version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libdns.@SA@: ${OBJS} ++libdns-pkcs11.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libdns.la: ${OBJS} ++libdns-pkcs11.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns.la -rpath ${libdir} \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-pkcs11.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS} + +-timestamp: libdns.@A@ ++timestamp: libdns-pkcs11.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-pkcs11.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f libdns.@A@ timestamp +@@ -181,7 +181,7 @@ code.h: gen + ./gen -s ${srcdir} > code.h + + gen: gen.c +- ${BUILD_CC} ${BUILD_CFLAGS} -I${top_srcdir}/lib/isc/include \ ++ ${BUILD_CC} ${BUILD_CFLAGS} -I${top_srcdir}/lib/isc-pkcs11/include \ + ${BUILD_CPPFLAGS} ${BUILD_LDFLAGS} -o $@ ${srcdir}/gen.c ${BUILD_LIBS} + + rbtdb64.@O@: rbtdb.c +diff --git a/lib/export/Makefile.in b/lib/export/Makefile.in +index 1fd7216..a8a1342 100644 +--- a/lib/export/Makefile.in ++++ b/lib/export/Makefile.in +@@ -21,7 +21,7 @@ top_srcdir = @top_srcdir@ + # Attempt to disable parallel processing. + .NOTPARALLEL: + .NO_PARALLEL: +-SUBDIRS = isc dns isccfg irs samples ++SUBDIRS = isc dns isccfg irs samples isc-pkcs11 dns-pkcs11 + TARGETS = + + @BIND9_MAKE_RULES@ +diff --git a/lib/export/dns-pkcs11/Makefile.in b/lib/export/dns-pkcs11/Makefile.in +index 887acb9..0f8abd3 100644 +--- a/lib/export/dns-pkcs11/Makefile.in ++++ b/lib/export/dns-pkcs11/Makefile.in +@@ -15,7 +15,7 @@ + # $Id$ + + top_srcdir = @top_srcdir@ +-srcdir = @top_srcdir@/lib/dns ++srcdir = @top_srcdir@/lib/dns-pkcs11 + export_srcdir = @top_srcdir@/lib/export + + # Attempt to disable parallel processing. +@@ -28,16 +28,16 @@ export_srcdir = @top_srcdir@/lib/export + + @BIND9_MAKE_INCLUDES@ + +-CINCLUDES = -I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \ +- ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ ++CINCLUDES = -I. -I${top_srcdir}/lib/dns-pkcs11 -Iinclude ${DNS_PKCS11_INCLUDES} -I${export_srcdir}/isc-pkcs11/include \ ++ ${ISC_PKCS11_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ + +-CDEFINES = -DUSE_MD5 @CRYPTO@ @USE_GSSAPI@ ++CDEFINES = -DUSE_MD5 @CRYPTO_PK11@ @USE_GSSAPI@ + + CWARNINGS = + +-ISCLIBS = ../isc/libisc-export.@A@ ++ISCLIBS = ../isc-pkcs11/libisc-pkcs11-export.@A@ + +-ISCDEPLIBS = ../isc/libisc-export.@A@ ++ISCDEPLIBS = ../isc-pkcs11/libisc-pkcs11-export.@A@ + + LIBS = @LIBS@ + +@@ -118,29 +118,29 @@ version.@O@: ${srcdir}/version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libdns-export.@SA@: ${OBJS} ++libdns-pkcs11-export.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libdns-export.la: ${OBJS} ++libdns-pkcs11-export.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-export.la \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-pkcs11-export.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ +- ${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS} ++ ${OBJS} ${ISCLIBS} @DNS_CRYPTO_PK11_LIBS@ ${LIBS} + +-timestamp: libdns-export.@A@ ++timestamp: libdns-pkcs11-export.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-export.@A@ \ ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-pkcs11-export.@A@ \ + ${DESTDIR}${export_libdir}/ + + clean distclean:: +- rm -f libdns-export.@A@ timestamp ++ rm -f libdns-pkcs11-export.@A@ timestamp + rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h + rm -f include/dns/rdatastruct.h + +diff --git a/lib/export/isc-pkcs11/Makefile.in b/lib/export/isc-pkcs11/Makefile.in +index 4f4a9f7..f8224e7 100644 +--- a/lib/export/isc-pkcs11/Makefile.in ++++ b/lib/export/isc-pkcs11/Makefile.in +@@ -15,7 +15,7 @@ + # $Id: Makefile.in,v 1.8 2010/06/09 23:50:58 tbox Exp $ + + top_srcdir = @top_srcdir@ +-srcdir = @top_srcdir@/lib/isc ++srcdir = @top_srcdir@/lib/isc-pkcs11 + export_srcdir = @top_srcdir@/lib/export + + @BIND9_VERSION@ +@@ -25,9 +25,9 @@ export_srcdir = @top_srcdir@/lib/export + CINCLUDES = -I${srcdir}/unix/include \ + -I${srcdir}/@ISC_THREAD_DIR@/include \ + -I${srcdir}/@ISC_ARCH_DIR@/include \ +- -I${export_srcdir}/isc/include -I${srcdir}/include \ ++ -I${export_srcdir}/isc-pkcs11/include -I${srcdir}/include \ + @ISC_OPENSSL_INC@ +-CDEFINES = @CRYPTO@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \ ++CDEFINES = @CRYPTO_PK11@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \ + -DUSE_SOCKETIMPREGISTER -DUSE_TASKIMPREGISTER \ + -DUSE_TIMERIMPREGISTER + CWARNINGS = +@@ -119,26 +119,26 @@ version.@O@: ${srcdir}/version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libisc-export.@SA@: ${OBJS} ++libisc-pkcs11-export.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libisc-export.la: ${OBJS} ++libisc-pkcs11-export.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-export.la \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-pkcs11-export.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} + +-timestamp: libisc-export.@A@ ++timestamp: libisc-pkcs11-export.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-export.@A@ \ ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-pkcs11-export.@A@ \ + ${DESTDIR}${export_libdir} + + clean distclean:: +- rm -f libisc-export.@A@ libisc-export.la timestamp ++ rm -f libisc-pkcs11-export.@A@ libisc-pkcs11-export.la timestamp +diff --git a/lib/isc-pkcs11/Makefile.in b/lib/isc-pkcs11/Makefile.in +index df62ec9..d9f0107 100644 +--- a/lib/isc-pkcs11/Makefile.in ++++ b/lib/isc-pkcs11/Makefile.in +@@ -31,8 +31,8 @@ CINCLUDES = -I${srcdir}/unix/include \ + -I${srcdir}/@ISC_THREAD_DIR@/include \ + -I${srcdir}/@ISC_ARCH_DIR@/include \ + -I./include \ +- -I${srcdir}/include @ISC_OPENSSL_INC@ ${DNS_INCLUDES} +-CDEFINES = @CRYPTO@ -DPK11_LIB_LOCATION=\"${PROVIDER}\" ++ -I${srcdir}/include ${DNS_PKCS11_INCLUDES} ++CDEFINES = @CRYPTO_PK11@ -DPK11_LIB_LOCATION=\"${PROVIDER}\" + CWARNINGS = + + # Alphabetically +@@ -110,35 +110,35 @@ version.@O@: version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libisc.@SA@: ${OBJS} ${SYMTBLOBJS} ++libisc-pkcs11.@SA@: ${OBJS} ${SYMTBLOBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} ${SYMTBLOBJS} + ${RANLIB} $@ + +-libisc-nosymtbl.@SA@: ${OBJS} ++libisc-pkcs11-nosymtbl.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libisc.la: ${OBJS} ${SYMTBLOBJS} ++libisc-pkcs11.la: ${OBJS} ${SYMTBLOBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la -rpath ${libdir} \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-pkcs11.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${SYMTBLOBJS} ${LIBS} + +-libisc-nosymtbl.la: ${OBJS} ++libisc-pkcs11-nosymtbl.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-nosymtbl.la -rpath ${libdir} \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-pkcs11-nosymtbl.la -rpath ${libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} + +-timestamp: libisc.@A@ libisc-nosymtbl.@A@ ++timestamp: libisc-pkcs11.@A@ libisc-pkcs11-nosymtbl.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-pkcs11.@A@ ${DESTDIR}${libdir} + + clean distclean:: +- rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \ +- libisc-nosymtbl.la timestamp ++ rm -f libisc-pkcs11.@A@ libisc-pkcs11-nosymtbl.@A@ libisc-pkcs11.la \ ++ libisc-pkcs11-nosymtbl.la timestamp +diff --git a/make/includes.in b/make/includes.in +index f2f1b3f..639477c 100644 +--- a/make/includes.in ++++ b/make/includes.in +@@ -46,3 +46,13 @@ BIND9_INCLUDES = @BIND9_BIND9_BUILDINCLUDE@ \ + + TEST_INCLUDES = \ + -I${top_srcdir}/lib/tests/include ++ ++ISC_PKCS11_INCLUDES = @BIND9_ISC_BUILDINCLUDE@ \ ++ -I${top_srcdir}/lib/isc-pkcs11 \ ++ -I${top_srcdir}/lib/isc-pkcs11/include \ ++ -I${top_srcdir}/lib/isc-pkcs11/unix/include \ ++ -I${top_srcdir}/lib/isc-pkcs11/@ISC_THREAD_DIR@/include \ ++ -I${top_srcdir}/lib/isc-pkcs11/@ISC_ARCH_DIR@/include ++ ++DNS_PKCS11_INCLUDES = @BIND9_DNS_BUILDINCLUDE@ \ ++ -I${top_srcdir}/lib/dns-pkcs11/include diff --git a/SOURCES/bind-9.9-native-pkcs11.patch b/SOURCES/bind-9.9-native-pkcs11.patch new file mode 100644 index 0000000..c8024b3 --- /dev/null +++ b/SOURCES/bind-9.9-native-pkcs11.patch @@ -0,0 +1,25320 @@ +From e9ef042fc45d2004c99dd7642d5032fd5832b270 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Thu, 21 May 2015 10:52:03 +0200 +Subject: [PATCH] native PKCS#11 + +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + acconfig.h | 7 +- + bin/check/Makefile.in | 3 +- + bin/dig/Makefile.in | 13 +- + bin/dig/dighost.c | 11 +- + bin/dnssec/Makefile.in | 3 +- + bin/dnssec/dnssec-dsfromkey.c | 9 +- + bin/dnssec/dnssec-importkey.c | 93 +- + bin/dnssec/dnssec-importkey.docbook | 58 +- + bin/dnssec/dnssec-keyfromlabel.c | 31 +- + bin/dnssec/dnssec-keyfromlabel.docbook | 43 +- + bin/dnssec/dnssec-keygen.c | 21 +- + bin/dnssec/dnssec-keygen.docbook | 13 +- + bin/dnssec/dnssec-revoke.c | 14 +- + bin/dnssec/dnssec-revoke.docbook | 11 +- + bin/dnssec/dnssec-settime.c | 14 +- + bin/dnssec/dnssec-settime.docbook | 11 +- + bin/dnssec/dnssec-signzone.c | 14 +- + bin/dnssec/dnssec-signzone.docbook | 15 +- + bin/dnssec/dnssec-verify.c | 14 +- + bin/dnssec/dnssec-verify.docbook | 17 + + bin/dnssec/dnssectool.c | 2 +- + bin/named/Makefile.in | 2 +- + bin/named/include/named/globals.h | 4 +- + bin/named/main.c | 6 + + bin/named/named.docbook | 16 +- + bin/named/server.c | 9 +- + bin/nsupdate/Makefile.in | 6 +- + bin/pkcs11/Makefile.in | 67 +- + bin/pkcs11/pkcs11-destroy.8 | 10 +- + bin/pkcs11/pkcs11-destroy.c | 153 +- + bin/pkcs11/pkcs11-destroy.docbook | 19 +- + bin/pkcs11/pkcs11-destroy.html | 22 +- + bin/pkcs11/pkcs11-keygen.8 | 69 +- + bin/pkcs11/pkcs11-keygen.c | 687 +++++++-- + bin/pkcs11/pkcs11-keygen.docbook | 115 +- + bin/pkcs11/pkcs11-keygen.html | 90 +- + bin/pkcs11/pkcs11-list.c | 118 +- + bin/pkcs11/pkcs11-tokens.8 | 51 + + bin/pkcs11/pkcs11-tokens.c | 106 ++ + bin/pkcs11/pkcs11-tokens.docbook | 86 ++ + bin/pkcs11/pkcs11-tokens.html | 58 + + bin/rndc/Makefile.in | 3 +- + bin/tests/Makefile.in | 76 +- + bin/tests/dst/dst_test.c | 7 +- + bin/tests/dst/t_dst.c | 14 +- + bin/tests/pkcs11/Makefile.in | 49 + + bin/tests/pkcs11/benchmarks/Makefile.in | 79 + + bin/tests/pkcs11/benchmarks/create.c | 260 ++++ + bin/tests/pkcs11/benchmarks/find.c | 227 +++ + bin/tests/pkcs11/benchmarks/genrsa.c | 295 ++++ + bin/tests/pkcs11/benchmarks/login.c | 249 ++++ + bin/tests/pkcs11/benchmarks/privrsa.c | 360 +++++ + bin/tests/pkcs11/benchmarks/pubrsa.c | 281 ++++ + bin/tests/pkcs11/benchmarks/random.c | 192 +++ + bin/tests/pkcs11/benchmarks/session.c | 213 +++ + bin/tests/pkcs11/benchmarks/sha1.c | 214 +++ + bin/tests/pkcs11/benchmarks/sign.c | 368 +++++ + bin/tests/pkcs11/benchmarks/verify.c | 292 ++++ + bin/tests/pkcs11/pkcs11-hmacmd5.c | 332 +++++ + bin/tests/pkcs11/pkcs11-md5sum.c | 235 +++ + bin/tests/system/autosign/prereq.sh | 3 +- + bin/tests/system/cleanpkcs11.sh | 6 +- + bin/tests/system/conf.sh.in | 8 +- + bin/tests/system/dnssec/prereq.sh | 3 +- + bin/tests/system/ecdsa/prereq.sh.in | 15 +- + bin/tests/system/gost/prereq.sh.in | 15 +- + bin/tests/system/inline/clean.sh | 2 +- + bin/tests/system/metadata/prereq.sh | 3 +- + bin/tests/system/pending/prereq.sh | 23 +- + bin/tests/system/pkcs11/clean.sh | 5 +- + bin/tests/system/pkcs11/ns1/named.conf | 10 +- + bin/tests/system/pkcs11/setup.sh | 64 +- + bin/tests/system/pkcs11/tests.sh | 72 +- + bin/tests/system/pkcs11ssl/clean.sh | 20 + + bin/tests/system/pkcs11ssl/ns1/example.db.in | 29 + + bin/tests/system/pkcs11ssl/ns1/named.conf | 52 + + bin/tests/system/pkcs11ssl/prereq.sh | 34 + + bin/tests/system/pkcs11ssl/setup.sh | 46 + + bin/tests/system/pkcs11ssl/tests.sh | 71 + + bin/tests/system/pkcs11ssl/usepkcs11 | 1 + + bin/tests/system/rsabigexponent/Makefile.in | 2 +- + bin/tests/system/rsabigexponent/bigkey.c | 18 +- + bin/tests/system/rsabigexponent/prereq.sh | 3 +- + bin/tests/system/smartsign/prereq.sh | 3 +- + bin/tests/system/tkey/keycreate.c | 1 + + bin/tests/system/tkey/prereq.sh | 3 +- + config.h.in | 19 +- + configure.in | 383 ++++- + doc/arm/pkcs11.xml | 694 +++++---- + lib/dns/Makefile.in | 16 +- + lib/dns/dnssec.c | 12 +- + lib/dns/ds.c | 44 +- + lib/dns/dst_api.c | 73 +- + lib/dns/dst_gost.h | 57 + + lib/dns/dst_internal.h | 28 +- + lib/dns/dst_parse.c | 36 +- + lib/dns/dst_parse.h | 6 +- + lib/dns/dst_pkcs11.h | 43 + + lib/dns/dst_result.c | 3 +- + lib/dns/gssapi_link.c | 1 + + lib/dns/hmac_link.c | 47 +- + lib/dns/include/dst/dst.h | 10 + + lib/dns/include/dst/result.h | 3 +- + lib/dns/openssldh_link.c | 7 + + lib/dns/openssldsa_link.c | 36 +- + lib/dns/opensslecdsa_link.c | 73 +- + lib/dns/opensslgost_link.c | 180 ++- + lib/dns/opensslrsa_link.c | 35 +- + lib/dns/pkcs11.c | 50 + + lib/dns/pkcs11dh_link.c | 1140 +++++++++++++++ + lib/dns/pkcs11dsa_link.c | 1130 +++++++++++++++ + lib/dns/pkcs11ecdsa_link.c | 1189 ++++++++++++++++ + lib/dns/pkcs11gost_link.c | 949 +++++++++++++ + lib/dns/pkcs11rsa_link.c | 1583 +++++++++++++++++++++ + lib/dns/rdata/generic/dlv_32769.c | 9 + + lib/dns/rdata/generic/ds_43.c | 10 + + lib/dns/tests/Makefile.in | 14 +- + lib/dns/tests/gost_test.c | 232 +++ + lib/dns/tkey.c | 10 +- + lib/dns/tsig.c | 14 +- + lib/export/dns/Makefile.in | 4 +- + lib/export/isc/Makefile.in | 5 +- + lib/export/isc/unix/Makefile.in | 4 + + lib/isc/Makefile.in | 14 +- + lib/isc/entropy.c | 8 + + lib/isc/hmacmd5.c | 166 +++ + lib/isc/hmacsha.c | 375 +++++ + lib/isc/include/Makefile.in | 2 +- + lib/isc/include/isc/hmacmd5.h | 5 + + lib/isc/include/isc/hmacsha.h | 9 + + lib/isc/include/isc/md5.h | 5 + + lib/isc/include/isc/resultclass.h | 2 +- + lib/isc/include/isc/sha1.h | 5 + + lib/isc/include/isc/sha2.h | 6 + + lib/isc/include/pk11/Makefile.in | 38 + + lib/isc/include/pk11/constants.h | 107 ++ + lib/isc/include/pk11/internal.h | 46 + + lib/isc/include/pk11/pk11.h | 295 ++++ + lib/isc/include/pk11/result.h | 56 + + lib/isc/include/pkcs11/Makefile.in | 40 + + lib/isc/include/pkcs11/pkcs11.h | 299 ++++ + lib/isc/include/pkcs11/pkcs11f.h | 912 ++++++++++++ + lib/isc/include/pkcs11/pkcs11t.h | 1977 ++++++++++++++++++++++++++ + lib/isc/md5.c | 50 + + lib/isc/pk11.c | 1327 +++++++++++++++++ + lib/isc/pk11_result.c | 85 ++ + lib/isc/sha1.c | 50 +- + lib/isc/sha2.c | 279 ++++ + lib/isc/unix/Makefile.in | 4 +- + lib/isc/unix/include/Makefile.in | 2 +- + lib/isc/unix/include/pkcs11/Makefile.in | 33 + + lib/isc/unix/include/pkcs11/cryptoki.h | 66 + + lib/isc/unix/pk11_api.c | 673 +++++++++ + 153 files changed, 20271 insertions(+), 1183 deletions(-) + create mode 100644 bin/pkcs11/pkcs11-tokens.8 + create mode 100644 bin/pkcs11/pkcs11-tokens.c + create mode 100644 bin/pkcs11/pkcs11-tokens.docbook + create mode 100644 bin/pkcs11/pkcs11-tokens.html + create mode 100644 bin/tests/pkcs11/Makefile.in + create mode 100644 bin/tests/pkcs11/benchmarks/Makefile.in + create mode 100644 bin/tests/pkcs11/benchmarks/create.c + create mode 100644 bin/tests/pkcs11/benchmarks/find.c + create mode 100644 bin/tests/pkcs11/benchmarks/genrsa.c + create mode 100644 bin/tests/pkcs11/benchmarks/login.c + create mode 100644 bin/tests/pkcs11/benchmarks/privrsa.c + create mode 100644 bin/tests/pkcs11/benchmarks/pubrsa.c + create mode 100644 bin/tests/pkcs11/benchmarks/random.c + create mode 100644 bin/tests/pkcs11/benchmarks/session.c + create mode 100644 bin/tests/pkcs11/benchmarks/sha1.c + create mode 100644 bin/tests/pkcs11/benchmarks/sign.c + create mode 100644 bin/tests/pkcs11/benchmarks/verify.c + create mode 100644 bin/tests/pkcs11/pkcs11-hmacmd5.c + create mode 100644 bin/tests/pkcs11/pkcs11-md5sum.c + create mode 100644 bin/tests/system/pkcs11ssl/clean.sh + create mode 100644 bin/tests/system/pkcs11ssl/ns1/example.db.in + create mode 100644 bin/tests/system/pkcs11ssl/ns1/named.conf + create mode 100644 bin/tests/system/pkcs11ssl/prereq.sh + create mode 100644 bin/tests/system/pkcs11ssl/setup.sh + create mode 100644 bin/tests/system/pkcs11ssl/tests.sh + create mode 100644 bin/tests/system/pkcs11ssl/usepkcs11 + create mode 100644 lib/dns/dst_gost.h + create mode 100644 lib/dns/dst_pkcs11.h + create mode 100644 lib/dns/pkcs11.c + create mode 100644 lib/dns/pkcs11dh_link.c + create mode 100644 lib/dns/pkcs11dsa_link.c + create mode 100644 lib/dns/pkcs11ecdsa_link.c + create mode 100644 lib/dns/pkcs11gost_link.c + create mode 100644 lib/dns/pkcs11rsa_link.c + create mode 100644 lib/dns/tests/gost_test.c + create mode 100644 lib/isc/include/pk11/Makefile.in + create mode 100644 lib/isc/include/pk11/constants.h + create mode 100644 lib/isc/include/pk11/internal.h + create mode 100644 lib/isc/include/pk11/pk11.h + create mode 100644 lib/isc/include/pk11/result.h + create mode 100644 lib/isc/include/pkcs11/Makefile.in + create mode 100644 lib/isc/include/pkcs11/pkcs11.h + create mode 100644 lib/isc/include/pkcs11/pkcs11f.h + create mode 100644 lib/isc/include/pkcs11/pkcs11t.h + create mode 100644 lib/isc/pk11.c + create mode 100644 lib/isc/pk11_result.c + create mode 100644 lib/isc/unix/include/pkcs11/Makefile.in + create mode 100644 lib/isc/unix/include/pkcs11/cryptoki.h + create mode 100644 lib/isc/unix/pk11_api.c + +diff --git a/acconfig.h b/acconfig.h +index 3d412d9..c8e832a 100644 +--- a/acconfig.h ++++ b/acconfig.h +@@ -132,14 +132,11 @@ int sigwait(const unsigned int *set, int *sig); + /** define if you have strerror in the C library. */ + #undef HAVE_STRERROR + +-/** Define if you are running under Compaq TruCluster. */ +-#undef HAVE_TRUCLUSTER +- + /* Define if OpenSSL includes DSA support */ + #undef HAVE_OPENSSL_DSA + +-/* Define if OpenSSL includes ECDSA support */ +-#undef HAVE_OPENSSL_ECDSA ++/* Define if you have getpassphrase in the C library. */ ++#undef HAVE_GETPASSPHRASE + + /* Define to the length type used by the socket API (socklen_t, size_t, int). */ + #undef ISC_SOCKADDR_LEN_T +diff --git a/bin/check/Makefile.in b/bin/check/Makefile.in +index c191605..d585480 100644 +--- a/bin/check/Makefile.in ++++ b/bin/check/Makefile.in +@@ -75,7 +75,8 @@ named-checkconf@EXEEXT@: named-checkconf.@O@ check-tool.@O@ ${ISCDEPLIBS} \ + export LIBS0="${BIND9LIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ + ${FINALBUILDCMD} + +-named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ++named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ \ ++ ${ISCDEPLIBS} ${DNSDEPLIBS} + export BASEOBJS="named-checkzone.@O@ check-tool.@O@"; \ + export LIBS0="${ISCCFGLIBS} ${DNSLIBS}"; \ + ${FINALBUILDCMD} +diff --git a/bin/dig/Makefile.in b/bin/dig/Makefile.in +index 3864e06..43dd061 100644 +--- a/bin/dig/Makefile.in ++++ b/bin/dig/Makefile.in +@@ -28,7 +28,7 @@ READLINE_LIB = @READLINE_LIB@ + CINCLUDES = -I${srcdir}/include ${DNS_INCLUDES} ${BIND9_INCLUDES} \ + ${ISC_INCLUDES} ${LWRES_INCLUDES} ${ISCCFG_INCLUDES} + +-CDEFINES = -DVERSION=\"${VERSION}\" ++CDEFINES = -DVERSION=\"${VERSION}\" @CRYPTO@ + CWARNINGS = + + ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +@@ -44,13 +44,13 @@ BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ + ISCDEPLIBS = ../../lib/isc/libisc.@A@ + LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ + +-DEPLIBS = ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS} \ +- ${LWRESDEPLIBS} ++DEPLIBS = ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} \ ++ ${ISCCFGDEPLIBS} ${LWRESDEPLIBS} + +-LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ ++LIBS = ${LWRESLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ + ${ISCLIBS} @IDNLIBS@ @LIBS@ -lidn + +-NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ ++NOSYMLIBS = ${LWRESLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ + ${ISCNOSYMLIBS} @IDNLIBS@ @LIBS@ -lidn + + SUBDIRS = +@@ -75,14 +75,17 @@ EXT_CFLAGS = -DWITH_LIBIDN + + dig@EXEEXT@: dig.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="dig.@O@ dighost.@O@ ${UOBJS}"; \ ++ export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + + host@EXEEXT@: host.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="host.@O@ dighost.@O@ ${UOBJS}"; \ ++ export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + + nslookup@EXEEXT@: nslookup.@O@ dighost.@O@ ${UOBJS} ${DEPLIBS} + export BASEOBJS="nslookup.@O@ dighost.@O@ ${READLINE_LIB} ${UOBJS}"; \ ++ export LIBS0="${DNSLIBS}"; \ + ${FINALBUILDCMD} + + doc man:: ${MANOBJS} +diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c +index e2bb110..5c03d95 100644 +--- a/bin/dig/dighost.c ++++ b/bin/dig/dighost.c +@@ -105,6 +105,10 @@ + + #include <dig/dig.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #if ! defined(NS_INADDRSZ) + #define NS_INADDRSZ 4 + #endif +@@ -1347,6 +1351,11 @@ setup_libs(void) { + + debug("setup_libs()"); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif ++ dns_result_register(); ++ + result = isc_net_probeipv4(); + if (result == ISC_R_SUCCESS) + have_ipv4 = ISC_TRUE; +@@ -1403,8 +1412,6 @@ setup_libs(void) { + + result = isc_mutex_init(&lookup_lock); + check_result(result, "isc_mutex_init"); +- +- dns_result_register(); + } + + /*% +diff --git a/bin/dnssec/Makefile.in b/bin/dnssec/Makefile.in +index ecb0fae..64e1846 100644 +--- a/bin/dnssec/Makefile.in ++++ b/bin/dnssec/Makefile.in +@@ -25,7 +25,8 @@ top_srcdir = @top_srcdir@ + + CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} + +-CDEFINES = -DVERSION=\"${VERSION}\" @USE_PKCS11@ ++CDEFINES = -DVERSION=\"${VERSION}\" @USE_PKCS11@ @PKCS11_ENGINE@ \ ++ @CRYPTO@ -DPK11_LIB_LOCATION=\"@PKCS11_PROVIDER@\" + CWARNINGS = + + DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +diff --git a/bin/dnssec/dnssec-dsfromkey.c b/bin/dnssec/dnssec-dsfromkey.c +index bfedae8..df616ac 100644 +--- a/bin/dnssec/dnssec-dsfromkey.c ++++ b/bin/dnssec/dnssec-dsfromkey.c +@@ -49,6 +49,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + #ifndef PATH_MAX +@@ -370,6 +374,9 @@ main(int argc, char **argv) { + if (result != ISC_R_SUCCESS) + fatal("out of memory"); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +@@ -448,7 +455,7 @@ main(int argc, char **argv) { + else if (strcasecmp(algname, "SHA256") == 0 || + strcasecmp(algname, "SHA-256") == 0) + dtype = DNS_DSDIGEST_SHA256; +-#ifdef HAVE_OPENSSL_GOST ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) + else if (strcasecmp(algname, "GOST") == 0) + dtype = DNS_DSDIGEST_GOST; + #endif +diff --git a/bin/dnssec/dnssec-importkey.c b/bin/dnssec/dnssec-importkey.c +index 00f9200..73166c4 100644 +--- a/bin/dnssec/dnssec-importkey.c ++++ b/bin/dnssec/dnssec-importkey.c +@@ -47,6 +47,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + #ifndef PATH_MAX +@@ -61,7 +65,9 @@ static dns_fixedname_t fixed; + static dns_name_t *name = NULL; + static isc_mem_t *mctx = NULL; + static isc_boolean_t setpub = ISC_FALSE, setdel = ISC_FALSE; ++static isc_boolean_t setttl = ISC_FALSE; + static isc_stdtime_t pub = 0, del = 0; ++static dns_ttl_t ttl = 0; + + static isc_result_t + initname(char *setname) { +@@ -190,9 +196,10 @@ static void + emit(const char *dir, dns_rdata_t *rdata) { + isc_result_t result; + char keystr[DST_KEY_FORMATSIZE]; +- char newname[1024]; ++ char pubname[1024]; ++ char priname[1024]; + isc_buffer_t buf; +- dst_key_t *key = NULL; ++ dst_key_t *key = NULL, *tmp = NULL; + + isc_buffer_init(&buf, rdata->data, rdata->length); + isc_buffer_add(&buf, rdata->length); +@@ -201,18 +208,36 @@ emit(const char *dir, dns_rdata_t *rdata) { + fatal("dst_key_fromdns: %s", isc_result_totext(result)); + } + +- dst_key_setexternal(key, ISC_TRUE); +- if (setpub) +- dst_key_settime(key, DST_TIME_PUBLISH, pub); +- if (setdel) +- dst_key_settime(key, DST_TIME_DELETE, del); +- +- isc_buffer_init(&buf, newname, sizeof(newname)); ++ isc_buffer_init(&buf, pubname, sizeof(pubname)); + result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, dir, &buf); + if (result != ISC_R_SUCCESS) { + fatal("Failed to build public key filename: %s", + isc_result_totext(result)); + } ++ isc_buffer_init(&buf, priname, sizeof(priname)); ++ result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); ++ if (result != ISC_R_SUCCESS) { ++ fatal("Failed to build private key filename: %s", ++ isc_result_totext(result)); ++ } ++ ++ result = dst_key_fromfile(dst_key_name(key), dst_key_id(key), ++ dst_key_alg(key), ++ DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, ++ dir, mctx, &tmp); ++ if (result == ISC_R_SUCCESS) { ++ if (dst_key_isprivate(tmp) && !dst_key_isexternal(tmp)) ++ fatal("Private key already exists in %s", priname); ++ dst_key_free(&tmp); ++ } ++ ++ dst_key_setexternal(key, ISC_TRUE); ++ if (setpub) ++ dst_key_settime(key, DST_TIME_PUBLISH, pub); ++ if (setdel) ++ dst_key_settime(key, DST_TIME_DELETE, del); ++ if (setttl) ++ dst_key_setttl(key, ttl); + + result = dst_key_tofile(key, DST_TYPE_PUBLIC|DST_TYPE_PRIVATE, + dir); +@@ -221,8 +246,7 @@ emit(const char *dir, dns_rdata_t *rdata) { + fatal("Failed to write key %s: %s", keystr, + isc_result_totext(result)); + } +- +- printf("%s\n", newname); ++ printf("%s\n", pubname); + + isc_buffer_clear(&buf); + result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, dir, &buf); +@@ -230,7 +254,7 @@ emit(const char *dir, dns_rdata_t *rdata) { + fatal("Failed to build private key filename: %s", + isc_result_totext(result)); + } +- printf("%s\n", newname); ++ printf("%s\n", priname); + dst_key_free(&key); + } + +@@ -240,13 +264,21 @@ usage(void) ISC_PLATFORM_NORETURN_POST; + static void + usage(void) { + fprintf(stderr, "Usage:\n"); +- fprintf(stderr, " %s options [-K dir] file\n\n", program); ++ fprintf(stderr, " %s options [-K dir] keyfile\n\n", program); ++ fprintf(stderr, " %s options -f file [keyname]\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "Options:\n"); +- fprintf(stderr, " -v <verbose level>\n"); ++ fprintf(stderr, " -f file: read key from zone file\n"); + fprintf(stderr, " -K <directory>: directory in which to store " +- "the keyset files\n"); +- fprintf(stderr, " -f file: read keyset from zone file\n"); ++ "the key files\n"); ++ fprintf(stderr, " -L ttl: set default key TTL\n"); ++ fprintf(stderr, " -v <verbose level>\n"); ++ fprintf(stderr, " -h: print usage and exit\n"); ++ fprintf(stderr, "Timing options:\n"); ++ fprintf(stderr, " -P date/[+-]offset/none: set/unset key " ++ "publication date\n"); ++ fprintf(stderr, " -D date/[+-]offset/none: set/unset key " ++ "deletion date\n"); + + exit (-1); + } +@@ -274,15 +306,19 @@ main(int argc, char **argv) { + if (result != ISC_R_SUCCESS) + fatal("out of memory"); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; + +- while ((ch = isc_commandline_parse(argc, argv, "D:f:hK:P:v:")) != -1) { ++#define CMDLINE_FLAGS "D:f:hK:L:P:v:" ++ while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { + switch (ch) { +- case 'D': +- if (setdel) +- fatal("-D specified more than once"); ++ case 'D': ++ if (setdel) ++ fatal("-D specified more than once"); + + setdel = ISC_TRUE; + del = strtotime(isc_commandline_argument, now, now); +@@ -292,9 +328,16 @@ main(int argc, char **argv) { + if (strlen(dir) == 0U) + fatal("directory must be non-empty string"); + break; +- case 'P': +- if (setpub) +- fatal("-P specified more than once"); ++ case 'L': ++ if (strcmp(isc_commandline_argument, "none") == 0) ++ ttl = 0; ++ else ++ ttl = strtottl(isc_commandline_argument); ++ setttl = ISC_TRUE; ++ break; ++ case 'P': ++ if (setpub) ++ fatal("-P specified more than once"); + + setpub = ISC_TRUE; + pub = strtotime(isc_commandline_argument, now, now); +@@ -346,8 +389,8 @@ main(int argc, char **argv) { + dns_rdataset_init(&rdataset); + + if (filename != NULL) { +- if (argc < isc_commandline_index + 1 && filename != NULL) { +- /* using zone name as the zone file name */ ++ if (argc < isc_commandline_index + 1) { ++ /* using filename as zone name */ + namestr = filename; + } else + namestr = argv[isc_commandline_index]; +diff --git a/bin/dnssec/dnssec-importkey.docbook b/bin/dnssec/dnssec-importkey.docbook +index b8d160c..853db30 100644 +--- a/bin/dnssec/dnssec-importkey.docbook ++++ b/bin/dnssec/dnssec-importkey.docbook +@@ -44,22 +44,45 @@ + <refsynopsisdiv> + <cmdsynopsis> + <command>dnssec-importkey</command> +- <arg><option>-f <replaceable class="parameter">filename</replaceable></option></arg> + <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg> ++ <arg><option>-L <replaceable class="parameter">ttl</replaceable></option></arg> + <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg> + <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg> + <arg><option>-h</option></arg> + <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg> +- <arg><option>keyname</option></arg> ++ <arg choice="req"><option>keyfile</option></arg> ++ </cmdsynopsis> ++ <cmdsynopsis> ++ <command>dnssec-importkey</command> ++ <arg choice="req"><option>-f <replaceable class="parameter">filename</replaceable></option></arg> ++ <arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg> ++ <arg><option>-L <replaceable class="parameter">ttl</replaceable></option></arg> ++ <arg><option>-P <replaceable class="parameter">date/offset</replaceable></option></arg> ++ <arg><option>-D <replaceable class="parameter">date/offset</replaceable></option></arg> ++ <arg><option>-h</option></arg> ++ <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg> ++ <arg><option>dnsname</option></arg> + </cmdsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>DESCRIPTION</title> + <para><command>dnssec-importkey</command> +- read a DNSKEY record and generated a .key/.private key pair. +- Publication (<option>-P</option>) and deletions (<option>-D</option>) +- times can be set for the key. ++ reads a public DNSKEY record and generates a pair of ++ .key/.private files. The DNSKEY record may be read from an ++ existing .key file, in which case a corresponding .private file ++ will be generated, or it may be read from any other file or ++ from the standard input, in which case both .key and .private ++ files will be generated. ++ </para> ++ <para> ++ The newly-created .private file does <emphasis>not</command> ++ contain private key data, and cannot be used for signing. ++ However, having a .private file makes it possible to set ++ publication (<option>-P</option>) and deletion ++ (<option>-D</option>) times for the key, which means the ++ public key can be added to and removed from the DNSKEY RRset ++ on schedule even if the true private key is stored offline. + </para> + </refsect1> + +@@ -70,9 +93,16 @@ + <varlistentry> + <term>-f <replaceable class="parameter">filename</replaceable></term> + <listitem> +- <para> +- Filename to read the key from. +- </para> ++ <para> ++ Zone file mode: instead of a public keyfile name, the argument ++ is the DNS domain name of a zone master file, which can be read ++ from <option>file</option>. If the domain name is the same as ++ <option>file</option>, then it may be omitted. ++ </para> ++ <para> ++ If <option>file</option> is set to <literal>"-"</literal>, then ++ the zone data is read from the standard input. ++ </para> + </listitem> + </varlistentry> + +@@ -93,7 +123,7 @@ + into a DNSKEY RR. If the key is imported into a zone, + this is the TTL that will be used for it, unless there was + already a DNSKEY RRset in place, in which case the existing TTL +- would take precedence. importkey the default TTL to ++ would take precedence. Setting the default TTL to + <literal>0</literal> or <literal>none</literal> removes it. + </para> + </listitem> +@@ -160,6 +190,16 @@ + </refsect1> + + <refsect1> ++ <title>FILES</title> ++ <para> ++ A keyfile can be designed by the key identification ++ <filename>Knnnn.+aaa+iiiii</filename> or the full file name ++ <filename>Knnnn.+aaa+iiiii.key</filename> as generated by ++ <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>. ++ </para> ++ </refsect1> ++ ++ <refsect1> + <title>SEE ALSO</title> + <para><citerefentry> + <refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum> +diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c +index 3ad00d7..cc212e1 100644 +--- a/bin/dnssec/dnssec-keyfromlabel.c ++++ b/bin/dnssec/dnssec-keyfromlabel.c +@@ -43,6 +43,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + #define MAX_RSA 4096 /* should be long enough... */ +@@ -76,10 +80,15 @@ usage(void) { + "NSEC3RSASHA1 if using -3)\n"); + fprintf(stderr, " -3: use NSEC3-capable algorithm\n"); + fprintf(stderr, " -c class (default: IN)\n"); +-#ifdef USE_PKCS11 +- fprintf(stderr, " -E enginename (default: pkcs11)\n"); ++ fprintf(stderr, " -E <engine>:\n"); ++#if defined(PKCS11CRYPTO) ++ fprintf(stderr, " path to PKCS#11 provider library " ++ "(default is %s)\n", PK11_LIB_LOCATION); ++#elif defined(USE_PKCS11) ++ fprintf(stderr, " name of an OpenSSL engine to use " ++ "(default is \"pkcs11\")\n"); + #else +- fprintf(stderr, " -E enginename\n"); ++ fprintf(stderr, " name of an OpenSSL engine to use\n"); + #endif + fprintf(stderr, " -f keyflag: KSK | REVOKE\n"); + fprintf(stderr, " -K directory: directory in which to place " +@@ -116,7 +125,7 @@ main(int argc, char **argv) { + char *nametype = NULL, *type = NULL; + const char *directory = NULL; + #ifdef USE_PKCS11 +- const char *engine = "pkcs11"; ++ const char *engine = PKCS11_ENGINE; + #else + const char *engine = NULL; + #endif +@@ -161,6 +170,9 @@ main(int argc, char **argv) { + + RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +@@ -334,16 +346,15 @@ main(int argc, char **argv) { + if (argc > isc_commandline_index + 1) + fatal("extraneous arguments"); + +- if (strchr(label, ':') == NULL && +- engine != NULL && strlen(engine) != 0U) { ++ if (strchr(label, ':') == NULL) { + char *l; + int len; + +- len = strlen(label) + strlen(engine) + 2; ++ len = strlen(label) + 8; + l = isc_mem_allocate(mctx, len); + if (l == NULL) + fatal("cannot allocate memory"); +- snprintf(l, len, "%s:%s", engine, label); ++ snprintf(l, len, "pkcs11:%s", label); + isc_mem_free(mctx, label); + label = l; + } +@@ -460,7 +471,7 @@ main(int argc, char **argv) { + + /* associate the key */ + ret = dst_key_fromlabel(name, alg, flags, protocol, +- rdclass, engine, label, NULL, mctx, &key); ++ rdclass, "pkcs11", label, NULL, mctx, &key); + isc_entropy_stopcallbacksources(ectx); + + if (ret != ISC_R_SUCCESS) { +@@ -468,7 +479,7 @@ main(int argc, char **argv) { + char algstr[DNS_SECALG_FORMATSIZE]; + dns_name_format(name, namestr, sizeof(namestr)); + dns_secalg_format(alg, algstr, sizeof(algstr)); +- fatal("failed to get key %s/%s: %s\n", ++ fatal("failed to get key %s/%s: %s", + namestr, algstr, isc_result_totext(ret)); + /* NOTREACHED */ + exit(-1); +diff --git a/bin/dnssec/dnssec-keyfromlabel.docbook b/bin/dnssec/dnssec-keyfromlabel.docbook +index 0dd3c0e..c48a100 100644 +--- a/bin/dnssec/dnssec-keyfromlabel.docbook ++++ b/bin/dnssec/dnssec-keyfromlabel.docbook +@@ -133,8 +133,15 @@ + <term>-E <replaceable class="parameter">engine</replaceable></term> + <listitem> + <para> +- Specifies the name of the crypto hardware (OpenSSL engine). +- When compiled with PKCS#11 support it defaults to "pkcs11". ++ Specifies the cryptographic hardware to use. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". + </para> + </listitem> + </varlistentry> +@@ -143,9 +150,32 @@ + <term>-l <replaceable class="parameter">label</replaceable></term> + <listitem> + <para> +- Specifies the label of the key pair in the crypto hardware. +- The label may be preceded by an optional OpenSSL engine name, +- separated by a colon, as in "pkcs11:keylabel". ++ Specifies the label for a key pair in the crypto hardware. ++ </para> ++ <para> ++ When <acronym>BIND</acronym> 9 is built with OpenSSL-based ++ PKCS#11 support, the label is an arbitrary string that ++ identifies a particular key. It may be preceded by an ++ optional OpenSSL engine name, followed by a colon, as in ++ "pkcs11:<replaceable>keylabel<replaceable>". ++ </para> ++ <para> ++ When <acronym>BIND</acronym> 9 is built with native PKCS#11 ++ support, the label is a PKCS#11 URI string in the format ++ "pkcs11:<option>keyword</option>=<replaceable>value</replaceable><optional>;<option>keyword</option>=<replaceable>value</replaceable>;...</optional>" ++ Keywords include "token", which identifies the HSM; "object", which ++ identifies the key; and "pin-source", which identifies a file from ++ which the HSM's PIN code can be obtained. The label will be ++ stored in the on-disk "private" file. ++ </para> ++ <para> ++ If the label contains a ++ <option>pin-source</option> field, tools using the generated ++ key files will be able to use the HSM for signing and other ++ operations without any need for an operator to manually enter ++ a PIN. Note: Making the HSM's PIN accessible in this manner ++ may reduce the security advantage of using an HSM; be sure ++ this is what you want to do before making use of this feature. + </para> + </listitem> + </varlistentry> +@@ -429,7 +459,8 @@ + <refentrytitle>dnssec-signzone</refentrytitle><manvolnum>8</manvolnum> + </citerefentry>, + <citetitle>BIND 9 Administrator Reference Manual</citetitle>, +- <citetitle>RFC 4034</citetitle>. ++ <citetitle>RFC 4034</citetitle>, ++ <citetitle>The PKCS#11 URI Scheme (draft-pechanec-pkcs11uri-13)</citetitle>. + </para> + </refsect1> + +diff --git a/bin/dnssec/dnssec-keygen.c b/bin/dnssec/dnssec-keygen.c +index 7061829..97b96ee 100644 +--- a/bin/dnssec/dnssec-keygen.c ++++ b/bin/dnssec/dnssec-keygen.c +@@ -58,6 +58,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + #define MAX_RSA 4096 /* should be long enough... */ +@@ -119,10 +123,15 @@ usage(void) { + fprintf(stderr, " (DNSKEY generation defaults to ZONE)\n"); + fprintf(stderr, " -c <class>: (default: IN)\n"); + fprintf(stderr, " -d <digest bits> (0 => max, default)\n"); +-#ifdef USE_PKCS11 +- fprintf(stderr, " -E <engine name> (default \"pkcs11\")\n"); ++ fprintf(stderr, " -E <engine>:\n"); ++#if defined(PKCS11CRYPTO) ++ fprintf(stderr, " path to PKCS#11 provider library " ++ "(default is %s)\n", PK11_LIB_LOCATION); ++#elif defined(USE_PKCS11) ++ fprintf(stderr, " name of an OpenSSL engine to use " ++ "(default is \"pkcs11\")\n"); + #else +- fprintf(stderr, " -E <engine name>\n"); ++ fprintf(stderr, " name of an OpenSSL engine to use\n"); + #endif + fprintf(stderr, " -f <keyflag>: KSK | REVOKE\n"); + fprintf(stderr, " -g <generator>: use specified generator " +@@ -134,7 +143,6 @@ usage(void) { + "records with (default: 0)\n"); + fprintf(stderr, " -T <rrtype>: DNSKEY | KEY (default: DNSKEY; " + "use KEY for SIG(0))\n"); +- fprintf(stderr, " ECCGOST:\tignored\n"); + fprintf(stderr, " -t <type>: " + "AUTHCONF | NOAUTHCONF | NOAUTH | NOCONF " + "(default: AUTHCONF)\n"); +@@ -223,7 +231,7 @@ main(int argc, char **argv) { + isc_log_t *log = NULL; + isc_entropy_t *ectx = NULL; + #ifdef USE_PKCS11 +- const char *engine = "pkcs11"; ++ const char *engine = PKCS11_ENGINE; + #else + const char *engine = NULL; + #endif +@@ -250,6 +258,9 @@ main(int argc, char **argv) { + if (argc == 1) + usage(); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +diff --git a/bin/dnssec/dnssec-keygen.docbook b/bin/dnssec/dnssec-keygen.docbook +index bc50c02..4c693eb 100644 +--- a/bin/dnssec/dnssec-keygen.docbook ++++ b/bin/dnssec/dnssec-keygen.docbook +@@ -224,10 +224,15 @@ + <term>-E <replaceable class="parameter">engine</replaceable></term> + <listitem> + <para> +- Uses a crypto hardware (OpenSSL engine) for random number +- and, when supported, key generation. When compiled with PKCS#11 +- support it defaults to pkcs11; the empty name resets it to +- no engine. ++ Specifies the cryptographic hardware to use, when applicable. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". + </para> + </listitem> + </varlistentry> +diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c +index 7b11581..7b5aaee 100644 +--- a/bin/dnssec/dnssec-revoke.c ++++ b/bin/dnssec/dnssec-revoke.c +@@ -38,6 +38,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + const char *program = "dnssec-revoke"; +@@ -53,7 +57,10 @@ usage(void) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); +-#ifdef USE_PKCS11 ++#if defined(PKCS11CRYPTO) ++ fprintf(stderr, " -E engine: specify PKCS#11 provider " ++ "(default: %s)\n", PK11_LIB_LOCATION); ++#elif defined(USE_PKCS11) + fprintf(stderr, " -E engine: specify OpenSSL engine " + "(default \"pkcs11\")\n"); + #else +@@ -76,7 +83,7 @@ int + main(int argc, char **argv) { + isc_result_t result; + #ifdef USE_PKCS11 +- const char *engine = "pkcs11"; ++ const char *engine = PKCS11_ENGINE; + #else + const char *engine = NULL; + #endif +@@ -100,6 +107,9 @@ main(int argc, char **argv) { + if (result != ISC_R_SUCCESS) + fatal("Out of memory"); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +diff --git a/bin/dnssec/dnssec-revoke.docbook b/bin/dnssec/dnssec-revoke.docbook +index 4062f5e..0c1dd4e 100644 +--- a/bin/dnssec/dnssec-revoke.docbook ++++ b/bin/dnssec/dnssec-revoke.docbook +@@ -109,8 +109,15 @@ + <term>-E <replaceable class="parameter">engine</replaceable></term> + <listitem> + <para> +- Use the given OpenSSL engine. When compiled with PKCS#11 support +- it defaults to pkcs11; the empty name resets it to no engine. ++ Specifies the cryptographic hardware to use, when applicable. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". + </para> + </listitem> + </varlistentry> +diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c +index 108d803..c71cac7 100644 +--- a/bin/dnssec/dnssec-settime.c ++++ b/bin/dnssec/dnssec-settime.c +@@ -41,6 +41,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + const char *program = "dnssec-settime"; +@@ -57,7 +61,10 @@ usage(void) { + fprintf(stderr, " %s [options] keyfile\n\n", program); + fprintf(stderr, "Version: %s\n", VERSION); + fprintf(stderr, "General options:\n"); +-#ifdef USE_PKCS11 ++#if defined(PKCS11CRYPTO) ++ fprintf(stderr, " -E engine: specify PKCS#11 provider " ++ "(default: %s)\n", PK11_LIB_LOCATION); ++#elif defined(USE_PKCS11) + fprintf(stderr, " -E engine: specify OpenSSL engine " + "(default \"pkcs11\")\n"); + #else +@@ -119,7 +126,7 @@ int + main(int argc, char **argv) { + isc_result_t result; + #ifdef USE_PKCS11 +- const char *engine = "pkcs11"; ++ const char *engine = PKCS11_ENGINE; + #else + const char *engine = NULL; + #endif +@@ -165,6 +172,9 @@ main(int argc, char **argv) { + + setup_logging(verbose, mctx, &log); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +diff --git a/bin/dnssec/dnssec-settime.docbook b/bin/dnssec/dnssec-settime.docbook +index bc6870b..3540bf2 100644 +--- a/bin/dnssec/dnssec-settime.docbook ++++ b/bin/dnssec/dnssec-settime.docbook +@@ -153,8 +153,15 @@ + <term>-E <replaceable class="parameter">engine</replaceable></term> + <listitem> + <para> +- Use the given OpenSSL engine. When compiled with PKCS#11 support +- it defaults to pkcs11; the empty name resets it to no engine. ++ Specifies the cryptographic hardware to use, when applicable. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". + </para> + </listitem> + </varlistentry> +diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c +index 83456a7..128c753 100644 +--- a/bin/dnssec/dnssec-signzone.c ++++ b/bin/dnssec/dnssec-signzone.c +@@ -86,6 +86,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + #ifndef PATH_MAX +@@ -2938,7 +2942,10 @@ usage(void) { + fprintf(stderr, "verify generated signatures\n"); + fprintf(stderr, "\t-c class (IN)\n"); + fprintf(stderr, "\t-E engine:\n"); +-#ifdef USE_PKCS11 ++#if defined(PKCS11CRYPTO) ++ fprintf(stderr, "\t\tpath to PKCS#11 provider library " ++ "(default is %s)\n", PK11_LIB_LOCATION); ++#elif defined(USE_PKCS11) + fprintf(stderr, "\t\tname of an OpenSSL engine to use " + "(default is \"pkcs11\")\n"); + #else +@@ -3033,7 +3040,7 @@ main(int argc, char *argv[]) { + isc_log_t *log = NULL; + isc_boolean_t pseudorandom = ISC_FALSE; + #ifdef USE_PKCS11 +- const char *engine = "pkcs11"; ++ const char *engine = PKCS11_ENGINE; + #else + const char *engine = NULL; + #endif +@@ -3085,6 +3092,9 @@ main(int argc, char *argv[]) { + if (result != ISC_R_SUCCESS) + fatal("out of memory"); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +diff --git a/bin/dnssec/dnssec-signzone.docbook b/bin/dnssec/dnssec-signzone.docbook +index e427fc1..c46f43c 100644 +--- a/bin/dnssec/dnssec-signzone.docbook ++++ b/bin/dnssec/dnssec-signzone.docbook +@@ -176,10 +176,17 @@ + <term>-E <replaceable class="parameter">engine</replaceable></term> + <listitem> + <para> +- Uses a crypto hardware (OpenSSL engine) for the crypto operations +- it supports, for instance signing with private keys from +- a secure key store. When compiled with PKCS#11 support +- it defaults to pkcs11; the empty name resets it to no engine. ++ When applicable, specifies the hardware to use for ++ cryptographic operations, such as a secure key store used ++ for signing. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". + </para> + </listitem> + </varlistentry> +diff --git a/bin/dnssec/dnssec-verify.c b/bin/dnssec/dnssec-verify.c +index 682896c..817e380 100644 +--- a/bin/dnssec/dnssec-verify.c ++++ b/bin/dnssec/dnssec-verify.c +@@ -69,6 +69,10 @@ + + #include <dst/dst.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif ++ + #include "dnssectool.h" + + const char *program = "dnssec-verify"; +@@ -137,7 +141,10 @@ usage(void) { + fprintf(stderr, "\t\tfile format of input zonefile (text)\n"); + fprintf(stderr, "\t-c class (IN)\n"); + fprintf(stderr, "\t-E engine:\n"); +-#ifdef USE_PKCS11 ++#if defined(PKCS11CRYPTO) ++ fprintf(stderr, "\t\tpath to PKCS#11 provider library " ++ "(default is %s)\n", PK11_LIB_LOCATION); ++#elif defined(USE_PKCS11) + fprintf(stderr, "\t\tname of an OpenSSL engine to use " + "(default is \"pkcs11\")\n"); + #else +@@ -156,7 +163,7 @@ main(int argc, char *argv[]) { + isc_result_t result; + isc_log_t *log = NULL; + #ifdef USE_PKCS11 +- const char *engine = "pkcs11"; ++ const char *engine = PKCS11_ENGINE; + #else + const char *engine = NULL; + #endif +@@ -195,6 +202,9 @@ main(int argc, char *argv[]) { + if (result != ISC_R_SUCCESS) + fatal("out of memory"); + ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + dns_result_register(); + + isc_commandline_errprint = ISC_FALSE; +diff --git a/bin/dnssec/dnssec-verify.docbook b/bin/dnssec/dnssec-verify.docbook +index 0835df1..875f3ed 100644 +--- a/bin/dnssec/dnssec-verify.docbook ++++ b/bin/dnssec/dnssec-verify.docbook +@@ -78,6 +78,23 @@ + </varlistentry> + + <varlistentry> ++ <term>-E <replaceable class="parameter">engine</replaceable></term> ++ <listitem> ++ <para> ++ Specifies the cryptographic hardware to use, when applicable. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> + <term>-I <replaceable class="parameter">input-format</replaceable></term> + <listitem> + <para> +diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c +index 5f5f7d8..c68ae69 100644 +--- a/bin/dnssec/dnssectool.c ++++ b/bin/dnssec/dnssectool.c +@@ -319,7 +319,7 @@ strtotime(const char *str, isc_int64_t now, isc_int64_t base) { + isc_result_t result; + const char *orig = str; + char *endp; +- int n; ++ size_t n; + + if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') + return ((isc_stdtime_t) 0); +diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in +index 68c42a8..cd65777 100644 +--- a/bin/named/Makefile.in ++++ b/bin/named/Makefile.in +@@ -51,7 +51,7 @@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${ISCCFG_INCLUDES} ${ISCCC_INCLUDES} ${ISC_INCLUDES} \ + ${DLZDRIVER_INCLUDES} ${DBDRIVER_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = @CONTRIB_DLZ@ @USE_PKCS11@ @USE_OPENSSL@ ++CDEFINES = @CONTRIB_DLZ@ @USE_PKCS11@ @PKCS11_ENGINE@ @CRYPTO@ + + CWARNINGS = + +diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h +index cbc14d8..aad462d 100644 +--- a/bin/named/include/named/globals.h ++++ b/bin/named/include/named/globals.h +@@ -146,8 +146,8 @@ EXTERN const char * lwresd_g_defaultpidfile INIT(NS_LOCALSTATEDIR + + EXTERN const char * ns_g_username INIT(NULL); + +-#ifdef USE_PKCS11 +-EXTERN const char * ns_g_engine INIT("pkcs11"); ++#if defined(USE_PKCS11) ++EXTERN const char * ns_g_engine INIT(PKCS11_ENGINE); + #else + EXTERN const char * ns_g_engine INIT(NULL); + #endif +diff --git a/bin/named/main.c b/bin/named/main.c +index 15905ef..a00687f 100644 +--- a/bin/named/main.c ++++ b/bin/named/main.c +@@ -51,6 +51,9 @@ + #include <dns/view.h> + + #include <dst/result.h> ++#ifdef PKCS11CRYPTO ++#include <pk11/result.h> ++#endif + + #include <dlz/dlz_dlopen_driver.h> + +@@ -1081,6 +1084,9 @@ main(int argc, char *argv[]) { + dns_result_register(); + dst_result_register(); + isccc_result_register(); ++#ifdef PKCS11CRYPTO ++ pk11_result_register(); ++#endif + + parse_command_line(argc, argv); + +diff --git a/bin/named/named.docbook b/bin/named/named.docbook +index 1f08e19..8f46aac 100644 +--- a/bin/named/named.docbook ++++ b/bin/named/named.docbook +@@ -153,11 +153,17 @@ + <term>-E <replaceable class="parameter">engine-name</replaceable></term> + <listitem> + <para> +- Use a crypto hardware (OpenSSL engine) for the crypto operations +- it supports, for instance re-signing with private keys from +- a secure key store. When compiled with PKCS#11 support +- <replaceable class="parameter">engine-name</replaceable> +- defaults to pkcs11, the empty name resets it to no engine. ++ When applicable, specifies the hardware to use for ++ cryptographic operations, such as a secure key store used ++ for signing. ++ </para> ++ <para> ++ When BIND is built with OpenSSL PKCS#11 support, this defaults ++ to the string "pkcs11", which identifies an OpenSSL engine ++ that can drive a cryptographic accelerator or hardware service ++ module. When BIND is built with native PKCS#11 cryptography ++ (--enable-native-pkcs11), it defaults to the path of the PKCS#11 ++ provider library specified via "--with-pkcs11". + </para> + </listitem> + </varlistentry> +diff --git a/bin/named/server.c b/bin/named/server.c +index 56df6bf..227c646 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -6215,6 +6215,11 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { + server->in_roothints = NULL; + server->blackholeacl = NULL; + ++ /* Must be first. */ ++ CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy, ++ ns_g_engine, ISC_ENTROPY_GOODONLY), ++ "initializing DST"); ++ + CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL, + &server->in_roothints), + "setting up root hints"); +@@ -6231,10 +6236,6 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { + ISC_R_NOMEMORY : ISC_R_SUCCESS, + "allocating reload event"); + +- CHECKFATAL(dst_lib_init2(ns_g_mctx, ns_g_entropy, +- ns_g_engine, ISC_ENTROPY_GOODONLY), +- "initializing DST"); +- + server->tkeyctx = NULL; + CHECKFATAL(dns_tkeyctx_create(ns_g_mctx, ns_g_entropy, + &server->tkeyctx), +diff --git a/bin/nsupdate/Makefile.in b/bin/nsupdate/Makefile.in +index 09e6c14..e258ffc 100644 +--- a/bin/nsupdate/Makefile.in ++++ b/bin/nsupdate/Makefile.in +@@ -46,9 +46,11 @@ ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ + + DEPLIBS = ${DNSDEPLIBS} ${BIND9DEPLIBS} ${ISCDEPLIBS} ${ISCCFGDEPLIBS} + +-LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${ISCLIBS} @LIBS@ ++LIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ ++ ${ISCLIBS} @LIBS@ + +-NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${ISCNOSYMLIBS} @LIBS@ ++NOSYMLIBS = ${LWRESLIBS} ${DNSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} \ ++ ${ISCNOSYMLIBS} @LIBS@ + + SUBDIRS = + +diff --git a/bin/pkcs11/Makefile.in b/bin/pkcs11/Makefile.in +index 407d977..15d3fb5 100644 +--- a/bin/pkcs11/Makefile.in ++++ b/bin/pkcs11/Makefile.in +@@ -20,38 +20,51 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-PROVIDER = @PKCS11_PROVIDER@ ++CINCLUDES = ${ISC_INCLUDES} + +-CINCLUDES = -I${srcdir}/include -I${srcdir}/unix ++CDEFINES = + +-CDEFINES = -DPK11_LIB_LOCATION=\"${PROVIDER}\" ++ISCLIBS = ../../lib/isc/libisc.@A@ ++ ++ISCDEPLIBS = ../../lib/isc/libisc.@A@ ++ ++DEPLIBS = ${ISCDEPLIBS} + + # if FORCE_STATIC_PROVIDER: LIBS = ${PROVIDER} +-LIBS = -ldl ++LIBS = ${ISCLIBS} @LIBS@ + +-SUBDIRS = ++SUBDIRS = benchmarks + +-TARGETS = pkcs11-keygen@EXEEXT@ pkcs11-list@EXEEXT@ \ +- pkcs11-destroy@EXEEXT@ +-SRCS = pkcs11-keygen.c pkcs11-list.c pkcs11-destroy.c ++TARGETS = pkcs11-list@EXEEXT@ pkcs11-destroy@EXEEXT@ \ ++ pkcs11-keygen@EXEEXT@ pkcs11-tokens@EXEEXT@ ++SRCS = pkcs11-list.c pkcs11-destroy.c \ ++ pkcs11-keygen.c pkcs11-tokens.c ++OBJS = pkcs11-list.@O@ pkcs11-destroy.@O@ \ ++ pkcs11-keygen.@O@ pkcs11-tokens.@O@ + +-MANPAGES = pkcs11-keygen.8 pkcs11-list.8 pkcs11-destroy.8 +-HTMLPAGES = pkcs11-keygen.html pkcs11-list.html pkcs11-destroy.html ++MANPAGES = pkcs11-list.8 pkcs11-destroy.8 \ ++ pkcs11-keygen.8 pkcs11-tokens.8 ++HTMLPAGES = pkcs11-list.html pkcs11-destroy.html \ ++ pkcs11-keygen.html pkcs11-tokens.html + MANOBJS = ${MANPAGES} ${HTMLPAGES} + + @BIND9_MAKE_RULES@ + +-pkcs11-keygen@EXEEXT@: @srcdir@/pkcs11-keygen.c +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ +- -o $@ @srcdir@/pkcs11-keygen.c ${LIBS} +- +-pkcs11-list@EXEEXT@: @srcdir@/pkcs11-list.c +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ +- -o $@ @srcdir@/pkcs11-list.c ${LIBS} +- +-pkcs11-destroy@EXEEXT@: @srcdir@/pkcs11-destroy.c +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ +- -o $@ @srcdir@/pkcs11-destroy.c ${LIBS} ++pkcs11-list@EXEEXT@: @srcdir@/pkcs11-list.@O@ ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ @srcdir@/pkcs11-list.@O@ ${LIBS} ++ ++pkcs11-destroy@EXEEXT@: @srcdir@/pkcs11-destroy.@O@ ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ @srcdir@/pkcs11-destroy.@O@ ${LIBS} ++ ++pkcs11-keygen@EXEEXT@: @srcdir@/pkcs11-keygen.@O@ ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ @srcdir@/pkcs11-keygen.@O@ ${LIBS} ++ ++pkcs11-tokens@EXEEXT@: @srcdir@/pkcs11-tokens.@O@ ${DEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ @srcdir@/pkcs11-tokens.@O@ ${LIBS} + + doc man:: ${MANOBJS} + +@@ -63,12 +76,14 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 + + install:: ${TARGETS} installdirs +- ${INSTALL_PROGRAM} pkcs11-keygen@EXEEXT@ ${DESTDIR}${sbindir} +- ${INSTALL_PROGRAM} pkcs11-list@EXEEXT@ ${DESTDIR}${sbindir} +- ${INSTALL_PROGRAM} pkcs11-destroy@EXEEXT@ ${DESTDIR}${sbindir} +- ${INSTALL_DATA} ${srcdir}/pkcs11-keygen.8 ${DESTDIR}${mandir}/man8 ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-list@EXEEXT@ ${DESTDIR}${sbindir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-destroy@EXEEXT@ ${DESTDIR}${sbindir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-keygen@EXEEXT@ ${DESTDIR}${sbindir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} pkcs11-tokens@EXEEXT@ ${DESTDIR}${sbindir} + ${INSTALL_DATA} ${srcdir}/pkcs11-list.8 ${DESTDIR}${mandir}/man8 + ${INSTALL_DATA} ${srcdir}/pkcs11-destroy.8 ${DESTDIR}${mandir}/man8 ++ ${INSTALL_DATA} ${srcdir}/pkcs11-keygen.8 ${DESTDIR}${mandir}/man8 ++ ${INSTALL_DATA} ${srcdir}/pkcs11-tokens.8 ${DESTDIR}${mandir}/man8 + + clean distclean:: +- rm -f ${TARGETS} ++ rm -f ${OBJS} ${TARGETS} +diff --git a/bin/pkcs11/pkcs11-destroy.8 b/bin/pkcs11/pkcs11-destroy.8 +index aff35b3..25323ca 100644 +--- a/bin/pkcs11/pkcs11-destroy.8 ++++ b/bin/pkcs11/pkcs11-destroy.8 +@@ -32,7 +32,7 @@ + pkcs11\-destroy \- destroy PKCS#11 objects + .SH "SYNOPSIS" + .HP 15 +-\fBpkcs11\-destroy\fR [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] {\-i\ \fIID\fR | \-l\ \fIlabel\fR} [\fB\-p\ \fR\fB\fIPIN\fR\fR] ++\fBpkcs11\-destroy\fR [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] {\-i\ \fIID\fR | \-l\ \fIlabel\fR} [\fB\-p\ \fR\fB\fIPIN\fR\fR] [\fB\-w\ \fR\fB\fIseconds\fR\fR] + .SH "DESCRIPTION" + .PP + \fBpkcs11\-destroy\fR +@@ -41,7 +41,7 @@ destroys keys stored in a PKCS#11 device, identified by their + or + \fBlabel\fR. + .PP +-Matching keys are displayed before being destroyed. There is a five second delay to allow the user to interrupt the process before the destruction takes place. ++Matching keys are displayed before being destroyed. By default, there is a five second delay to allow the user to interrupt the process before the destruction takes place. + .SH "ARGUMENTS" + .PP + \-m \fImodule\fR +@@ -70,6 +70,12 @@ Specify the PIN for the device. If no PIN is provided on the command line, + \fBpkcs11\-destroy\fR + will prompt for it. + .RE ++.PP ++\-w \fIseconds\fR ++.RS 4 ++Specify how long to pause before carrying out key destruction. The default is five seconds. If set to ++0, destruction will be immediate. ++.RE + .SH "SEE ALSO" + .PP + \fBpkcs11\-list\fR(3), +diff --git a/bin/pkcs11/pkcs11-destroy.c b/bin/pkcs11/pkcs11-destroy.c +index 0f46a89..2905395 100644 +--- a/bin/pkcs11/pkcs11-destroy.c ++++ b/bin/pkcs11/pkcs11-destroy.c +@@ -40,7 +40,10 @@ + + /* $Id: pkcs11-destroy.c,v 1.8 2010/01/13 21:19:52 fdupont Exp $ */ + +-/* pkcs11-destroy [-m module] [-s $slot] [-i $id | -l $label] [-p $pin] */ ++/* ++ * pkcs11-destroy [-m module] [-s $slot] [-i $id | -l $label] ++ * [-p $pin] [ -w $wait ] ++ */ + + /*! \file */ + +@@ -52,74 +55,70 @@ + #include <errno.h> + #include <string.h> + #include <sys/types.h> +-#include "cryptoki.h" + +-#ifdef WIN32 +-#define sleep(x) Sleep(x) +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> + + #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) + #define getpassphrase(x) getpass(x) + #endif + + int +-main(int argc, char *argv[]) +-{ ++main(int argc, char *argv[]) { ++ isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession; +- CK_UTF8CHAR *pin = NULL; + CK_BYTE attr_id[2]; + CK_OBJECT_HANDLE akey[50]; ++ pk11_context_t pctx; ++ char *lib_name = NULL; + char *label = NULL; ++ char *pin = NULL; + int error = 0; +- unsigned int id = 0, i = 0; ++ unsigned int id = 0, i = 0, wait = 5; + int c, errflg = 0; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE search_template[] = { + {CKA_ID, &attr_id, sizeof(attr_id)} + }; +- char *pk11_provider; + unsigned int j, len; +- extern char *optarg; +- extern int optopt; +- +- pk11_provider = getenv("PKCS11_PROVIDER"); +- if (pk11_provider != NULL) +- pk11_libname = pk11_provider; + +- while ((c = getopt(argc, argv, ":m:s:i:l:p:")) != -1) { ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:i:l:p:w:")) != -1) { + switch (c) { + case 'm': +- pk11_libname = optarg; ++ lib_name = isc_commandline_argument; + break; + case 's': +- slot = atoi(optarg); ++ slot = atoi(isc_commandline_argument); + break; + case 'i': +- id = atoi(optarg); ++ id = atoi(isc_commandline_argument); + id &= 0xffff; + break; + case 'l': +- label = optarg; ++ label = isc_commandline_argument; + break; + case 'p': +- pin = (CK_UTF8CHAR *)optarg; ++ pin = isc_commandline_argument; ++ break; ++ case 'w': ++ wait = atoi(isc_commandline_argument); + break; + case ':': + fprintf(stderr, + "Option -%c requires an operand\n", +- optopt); ++ isc_commandline_option); + errflg++; + break; + case '?': + default: +- fprintf(stderr, "Unrecognised option: -%c\n", optopt); ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); + errflg++; + } + } +@@ -127,56 +126,49 @@ main(int argc, char *argv[]) + if (errflg || (id && (label != NULL))) { + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "\tpkcs11-destroy [-m module] [-s slot] " +- "[-i id | -l label] [-p pin]\n"); ++ "[-i id | -l label] [-p pin] [-w waittime]\n"); + exit(1); + } + + if (id) { +- printf("id %i\n", id); + attr_id[0] = (id >> 8) & 0xff; + attr_id[1] = id & 0xff; + } else if (label) { +- printf("label %s\n", label); + search_template[0].type = CKA_LABEL; + search_template[0].pValue = label; + search_template[0].ulValueLen = strlen(label); + } + +- /* Initialize the CRYPTOKI library */ +- rv = C_Initialize(NULL_PTR); +- if (rv != CKR_OK) { +- if (rv == 0xfe) +- fprintf(stderr, +- "Can't load or link module \"%s\"\n", +- pk11_libname); +- else +- fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); +- exit(1); +- } ++ pk11_result_register(); + +- /* Open a session on the slot found */ +- rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION, +- NULL_PTR, NULL_PTR, &hSession); +- if (rv != CKR_OK) { +- fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv); +- error = 1; +- goto exit_program; +- } ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); + + if (pin == NULL) +- pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: "); ++ pin = getpassphrase("Enter Pin: "); + + /* Login to the Token (Keystore) */ +- rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin)); +- memset(pin, 0, strlen((char *)pin)); +- if (rv != CKR_OK) { +- fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv); +- error = 1; +- goto exit_session; ++ result = pk11_get_session(&pctx, OP_ANY, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if (result == PK11_R_NORANDOMSERVICE || ++ result == PK11_R_NODIGESTSERVICE || ++ result == PK11_R_NOAESSERVICE) { ++ fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); ++ fprintf(stderr, "This HSM will not work with BIND 9 " ++ "using native PKCS#11.\n"); ++ } else if (result != ISC_R_SUCCESS) { ++ fprintf(stderr, "Unrecoverable error initializing " ++ "PKCS#11: %s\n", isc_result_totext(result)); ++ exit(1); + } + +- rv = C_FindObjectsInit(hSession, search_template, +- ((id != 0) || (label != NULL)) ? 1 : 0); ++ memset(pin, 0, strlen(pin)); ++ ++ hSession = pctx.session; ++ ++ rv = pkcs_C_FindObjectsInit(hSession, search_template, ++ ((id != 0) || (label != NULL)) ? 1 : 0); + + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv); +@@ -184,13 +176,19 @@ main(int argc, char *argv[]) + goto exit_session; + } + +- rv = C_FindObjects(hSession, akey, 50, &ulObjectCount); ++ rv = pkcs_C_FindObjects(hSession, akey, 50, &ulObjectCount); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_search; + } + ++ if (ulObjectCount == 0) { ++ printf("No matching key objects found.\n"); ++ goto exit_search; ++ } else ++ printf("Key object%s found:\n", ulObjectCount > 1 ? "s" : ""); ++ + for (i = 0; i < ulObjectCount; i++) { + CK_OBJECT_CLASS oclass = 0; + CK_BYTE labelbuf[64 + 1]; +@@ -204,7 +202,8 @@ main(int argc, char *argv[]) + memset(labelbuf, 0, sizeof(labelbuf)); + memset(idbuf, 0, sizeof(idbuf)); + +- rv = C_GetAttributeValue(hSession, akey[i], attr_template, 3); ++ rv = pkcs_C_GetAttributeValue(hSession, akey[i], ++ attr_template, 3); + if (rv != CKR_OK) { + fprintf(stderr, + "C_GetAttributeValue[%u]: rv = 0x%.8lX\n", +@@ -213,7 +212,7 @@ main(int argc, char *argv[]) + goto exit_search; + } + len = attr_template[2].ulValueLen; +- printf("object[%u]: class %lu label '%s' id[%lu] ", ++ printf(" object[%u]: class %lu, label '%s', id[%lu] ", + i, oclass, labelbuf, attr_template[2].ulValueLen); + if (len > 4) + len = 4; +@@ -227,32 +226,40 @@ main(int argc, char *argv[]) + printf("\n"); + } + +- /* give a chance to kill this */ +- printf("sleeping 5 seconds...\n"); +- sleep(5); ++ if (wait != 0) { ++ printf("WARNING: This action is irreversible! " ++ "Destroying key objects in %d seconds\n ", wait); ++ for (i = 0; i < wait; i++) { ++ printf("."); ++ fflush(stdout); ++ sleep(1); ++ } ++ printf("\n"); ++ } + + for (i = 0; i < ulObjectCount; i++) { +- rv = C_DestroyObject(hSession, akey[i]); ++ rv = pkcs_C_DestroyObject(hSession, akey[i]); + if (rv != CKR_OK) { + fprintf(stderr, +- "C_DestroyObject[%u]: rv = 0x%.8lX\n", ++ "C_DestroyObject[%u] failed: rv = 0x%.8lX\n", + i, rv); + error = 1; + } + } + ++ if (error == 0) ++ printf("Destruction complete.\n"); ++ + exit_search: +- rv = C_FindObjectsFinal(hSession); ++ rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv); + error = 1; + } + + exit_session: +- (void)C_CloseSession(hSession); +- +- exit_program: +- (void)C_Finalize(NULL_PTR); ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); + + exit(error); + } +diff --git a/bin/pkcs11/pkcs11-destroy.docbook b/bin/pkcs11/pkcs11-destroy.docbook +index b4c2048..45c0208 100644 +--- a/bin/pkcs11/pkcs11-destroy.docbook ++++ b/bin/pkcs11/pkcs11-destroy.docbook +@@ -37,6 +37,7 @@ + <docinfo> + <copyright> + <year>2009</year> ++ <year>2014</year> + <holder>Internet Systems Consortium, Inc. ("ISC")</holder> + </copyright> + </docinfo> +@@ -51,6 +52,7 @@ + <arg choice="plain">-l <replaceable class="parameter">label</replaceable></arg> + </group> + <arg><option>-p <replaceable class="parameter">PIN</replaceable></option></arg> ++ <arg><option>-w <replaceable class="parameter">seconds</replaceable></option></arg> + </cmdsynopsis> + </refsynopsisdiv> + +@@ -62,9 +64,9 @@ + <option>label</option>. + </para> + <para> +- Matching keys are displayed before being destroyed. There is a +- five second delay to allow the user to interrupt the process +- before the destruction takes place. ++ Matching keys are displayed before being destroyed. By default, ++ there is a five second delay to allow the user to interrupt the ++ process before the destruction takes place. + </para> + </refsect1> + +@@ -119,6 +121,17 @@ + </para> + </listitem> + </varlistentry> ++ ++ <varlistentry> ++ <term>-w <replaceable class="parameter">seconds</replaceable></term> ++ <listitem> ++ <para> ++ Specify how long to pause before carrying out key destruction. ++ The default is five seconds. If set to <literal>0</literal>, ++ destruction will be immediate. ++ </para> ++ </listitem> ++ </varlistentry> + </variablelist> + </refsect1> + +diff --git a/bin/pkcs11/pkcs11-destroy.html b/bin/pkcs11/pkcs11-destroy.html +index afc6e36..899b3e9 100644 +--- a/bin/pkcs11/pkcs11-destroy.html ++++ b/bin/pkcs11/pkcs11-destroy.html +@@ -29,23 +29,23 @@ + </div> + <div class="refsynopsisdiv"> + <h2>Synopsis</h2> +-<div class="cmdsynopsis"><p><code class="command">pkcs11-destroy</code> [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] { -i <em class="replaceable"><code>ID</code></em> | -l <em class="replaceable"><code>label</code></em> } [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>]</p></div> ++<div class="cmdsynopsis"><p><code class="command">pkcs11-destroy</code> [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] { -i <em class="replaceable"><code>ID</code></em> | -l <em class="replaceable"><code>label</code></em> } [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>] [<code class="option">-w <em class="replaceable"><code>seconds</code></em></code>]</p></div> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543384"></a><h2>DESCRIPTION</h2> ++<a name="id2543393"></a><h2>DESCRIPTION</h2> + <p> + <span><strong class="command">pkcs11-destroy</strong></span> destroys keys stored in a + PKCS#11 device, identified by their <code class="option">ID</code> or + <code class="option">label</code>. + </p> + <p> +- Matching keys are displayed before being destroyed. There is a +- five second delay to allow the user to interrupt the process +- before the destruction takes place. ++ Matching keys are displayed before being destroyed. By default, ++ there is a five second delay to allow the user to interrupt the ++ process before the destruction takes place. + </p> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543406"></a><h2>ARGUMENTS</h2> ++<a name="id2543415"></a><h2>ARGUMENTS</h2> + <div class="variablelist"><dl> + <dt><span class="term">-m <em class="replaceable"><code>module</code></em></span></dt> + <dd><p> +@@ -71,17 +71,23 @@ + Specify the PIN for the device. If no PIN is provided on the + command line, <span><strong class="command">pkcs11-destroy</strong></span> will prompt for it. + </p></dd> ++<dt><span class="term">-w <em class="replaceable"><code>seconds</code></em></span></dt> ++<dd><p> ++ Specify how long to pause before carrying out key destruction. ++ The default is five seconds. If set to <code class="literal">0</code>, ++ destruction will be immediate. ++ </p></dd> + </dl></div> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543507"></a><h2>SEE ALSO</h2> ++<a name="id2543537"></a><h2>SEE ALSO</h2> + <p> + <span class="citerefentry"><span class="refentrytitle">pkcs11-list</span>(3)</span>, + <span class="citerefentry"><span class="refentrytitle">pkcs11-keygen</span>(3)</span> + </p> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543533"></a><h2>AUTHOR</h2> ++<a name="id2543563"></a><h2>AUTHOR</h2> + <p><span class="corpauthor">Internet Systems Consortium</span> + </p> + </div> +diff --git a/bin/pkcs11/pkcs11-keygen.8 b/bin/pkcs11/pkcs11-keygen.8 +index 568e862..53de464 100644 +--- a/bin/pkcs11/pkcs11-keygen.8 ++++ b/bin/pkcs11/pkcs11-keygen.8 +@@ -23,80 +23,91 @@ + .\" Manual: BIND9 + .\" Source: BIND9 + .\" +-.TH "PKCS11\-KEYGEN" "8" "Sep 18, 2009" "BIND9" "BIND9" ++.TH "PKCS11\-ECGEN" "8" "Feb 30, 2012" "BIND9" "BIND9" + .\" disable hyphenation + .nh + .\" disable justification (adjust text to left margin only) + .ad l + .SH "NAME" +-pkcs11\-keygen \- generate RSA keys on a PKCS#11 device ++pkcs11\-keygen \- generate keys on a PKCS#11 device + .SH "SYNOPSIS" + .HP 14 +-\fBpkcs11\-keygen\fR [\fB\-P\fR] [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] [\fB\-e\fR] {\-b\ \fIkeysize\fR} {\-l\ \fIlabel\fR} [\fB\-i\ \fR\fB\fIid\fR\fR] [\fB\-p\ \fR\fB\fIPIN\fR\fR] ++\fBpkcs11\-keygen\fR {\-a\ \fIalgorithm\fR} [\fB\-b\ \fR\fB\fIkeysize\fR\fR] [\fB\-e\fR] [\fB\-i\ \fR\fB\fIid\fR\fR] [\fB\-m\ \fR\fB\fImodule\fR\fR] [\fB\-P\fR] [\fB\-p\ \fR\fB\fIPIN\fR\fR] [\fB\-q\fR] [\fB\-S\fR] [\fB\-s\ \fR\fB\fIslot\fR\fR] {label} + .SH "DESCRIPTION" + .PP + \fBpkcs11\-keygen\fR +-causes a PKCS#11 device to generate a new RSA key pair with the specified ++causes a PKCS#11 device to generate a new key pair with the given + \fBlabel\fR +-and with ++(which must be unique) and with + \fBkeysize\fR +-bits of modulus. ++bits of prime. + .SH "ARGUMENTS" + .PP +-\-P +-.RS 4 +-Set the new private key to be non\-sensitive and extractable. The allows the private key data to be read from the PKCS#11 device. The default is for private keys to be sensitive and non\-extractable. +-.RE +-.PP +-\-m \fImodule\fR ++\-a \fIalgorithm\fR + .RS 4 +-Specify the PKCS#11 provider module. This must be the full path to a shared library object implementing the PKCS#11 API for the device. ++Specify the key algorithm class: Supported classes are RSA, DSA, DH, and ECC. In addition to these strings, the ++\fBalgorithm\fR ++can be specified as a DNSSEC signing algorithm that will be used with this key; for example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps to ECC. The default class is "RSA". + .RE + .PP +-\-s \fIslot\fR ++\-b \fIkeysize\fR + .RS 4 +-Open the session with the given PKCS#11 slot. The default is slot 0. ++Create the key pair with ++\fBkeysize\fR ++bits of prime. For ECC keys, the only valid values are 256 and 384, and the default is 256. + .RE + .PP + \-e + .RS 4 +-Use a large exponent. ++For RSA keys only, use a large exponent. + .RE + .PP +-\-b \fIkeysize\fR ++\-i \fIid\fR + .RS 4 +-Create the key pair with +-\fBkeysize\fR +-bits of modulus. ++Create key objects with id. The id is either an unsigned short 2 byte or an unsigned long 4 byte number. + .RE + .PP +-\-l \fIlabel\fR ++\-m \fImodule\fR + .RS 4 +-Create key objects with the given label. This name must be unique. ++Specify the PKCS#11 provider module. This must be the full path to a shared library object implementing the PKCS#11 API for the device. + .RE + .PP +-\-i \fIid\fR ++\-P + .RS 4 +-Create key objects with id. The id is either an unsigned short 2 byte or an unsigned long 4 byte number. ++Set the new private key to be non\-sensitive and extractable. The allows the private key data to be read from the PKCS#11 device. The default is for private keys to be sensitive and non\-extractable. + .RE + .PP + \-p \fIPIN\fR + .RS 4 + Specify the PIN for the device. If no PIN is provided on the command line, +-\fBpkcs11\-keygen\fR ++\fBpkcs11\-ecgen\fR + will prompt for it. + .RE ++.PP ++\-e ++.RS 4 ++Quiet mode: suppress unnecessary output. ++.RE ++.PP ++\-S ++.RS 4 ++For Diffie\-Hellman (DH) keys only, use a special prime of 768, 1024 or 1536 bit size and base (aka generator) 2. If not specified, bit size will default to 1024. ++.RE ++.PP ++\-s \fIslot\fR ++.RS 4 ++Open the session with the given PKCS#11 slot. The default is slot 0. ++.RE + .SH "SEE ALSO" + .PP ++\fBpkcs11\-rsagen\fR(3), ++\fBpkcs11\-dsagen\fR(3), + \fBpkcs11\-list\fR(3), + \fBpkcs11\-destroy\fR(3), + \fBdnssec\-keyfromlabel\fR(3), +-.SH "CAVEAT" +-.PP +-Some PKCS#11 providers crash with big public exponent. + .SH "AUTHOR" + .PP + Internet Systems Consortium + .SH "COPYRIGHT" +-Copyright \(co 2009 Internet Systems Consortium, Inc. ("ISC") ++Copyright \(co 2012 Internet Systems Consortium, Inc. ("ISC") + .br +diff --git a/bin/pkcs11/pkcs11-keygen.c b/bin/pkcs11/pkcs11-keygen.c +index 1ffb343..cc91776 100644 +--- a/bin/pkcs11/pkcs11-keygen.c ++++ b/bin/pkcs11/pkcs11-keygen.c +@@ -40,18 +40,19 @@ + + /* $Id: pkcs11-keygen.c,v 1.9 2009/10/26 23:36:53 each Exp $ */ + +-/* pkcs11-keygen - pkcs11 rsa key generator +-* +-* create RSASHA1 key in the keystore of an SCA6000 +-* The calculation of key tag is left to the script +-* that converts the key into a DNSKEY RR and inserts +-* it into a zone file. +-* +-* usage: +-* pkcs11-keygen [-P] [-m module] [-s slot] [-e] -b keysize +-* -l label [-i id] [-p pin] +-* +-*/ ++/* pkcs11-keygen - PKCS#11 key generator ++ * ++ * Create a key in the keystore of an HSM ++ * ++ * The calculation of key tag is left to the script ++ * that converts the key into a DNSKEY RR and inserts ++ * it into a zone file. ++ * ++ * usage: ++ * pkcs11-keygen [-P] [-m module] [-s slot] [-e] [-b keysize] ++ * [-i id] [-p pin] -l label ++ * ++ */ + + /*! \file */ + +@@ -63,15 +64,16 @@ + #include <errno.h> + #include <string.h> + #include <sys/types.h> +-#include "cryptoki.h" + +-#ifdef WIN32 +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++#define WANT_DH_PRIMES ++#define WANT_ECC_CURVES ++#include <pk11/constants.h> + + #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) + #define getpassphrase(x) getpass(x) +@@ -81,188 +83,478 @@ + static CK_BBOOL truevalue = TRUE; + static CK_BBOOL falsevalue = FALSE; + ++/* Key class: RSA, ECC, DSA, DH, or unknown */ ++typedef enum { ++ key_unknown, ++ key_rsa, ++ key_dsa, ++ key_dh, ++ key_ecc ++} key_class_t; ++ ++/* ++ * Private key template: usable for most key classes without ++ * modificaton; override CKA_SIGN with CKA_DERIVE for DH ++ */ ++#define PRIVATE_LABEL 0 ++#define PRIVATE_SIGN 1 ++#define PRIVATE_DERIVE 1 ++#define PRIVATE_TOKEN 2 ++#define PRIVATE_PRIVATE 3 ++#define PRIVATE_SENSITIVE 4 ++#define PRIVATE_EXTRACTABLE 5 ++#define PRIVATE_ID 6 ++#define PRIVATE_ATTRS 7 ++static CK_ATTRIBUTE private_template[] = { ++ {CKA_LABEL, NULL_PTR, 0}, ++ {CKA_SIGN, &truevalue, sizeof(truevalue)}, ++ {CKA_TOKEN, &truevalue, sizeof(truevalue)}, ++ {CKA_PRIVATE, &truevalue, sizeof(truevalue)}, ++ {CKA_SENSITIVE, &truevalue, sizeof(truevalue)}, ++ {CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue)}, ++ {CKA_ID, NULL_PTR, 0} ++}; ++ ++/* ++ * Public key template for RSA keys ++ */ ++#define RSA_LABEL 0 ++#define RSA_VERIFY 1 ++#define RSA_TOKEN 2 ++#define RSA_PRIVATE 3 ++#define RSA_MODULUS_BITS 4 ++#define RSA_PUBLIC_EXPONENT 5 ++#define RSA_ID 6 ++#define RSA_ATTRS 7 ++static CK_ATTRIBUTE rsa_template[] = { ++ {CKA_LABEL, NULL_PTR, 0}, ++ {CKA_VERIFY, &truevalue, sizeof(truevalue)}, ++ {CKA_TOKEN, &truevalue, sizeof(truevalue)}, ++ {CKA_PRIVATE, &falsevalue, sizeof(falsevalue)}, ++ {CKA_MODULUS_BITS, NULL_PTR, 0}, ++ {CKA_PUBLIC_EXPONENT, NULL_PTR, 0}, ++ {CKA_ID, NULL_PTR, 0} ++}; ++ ++/* ++ * Public key template for ECC keys ++ */ ++#define ECC_LABEL 0 ++#define ECC_VERIFY 1 ++#define ECC_TOKEN 2 ++#define ECC_PRIVATE 3 ++#define ECC_PARAMS 4 ++#define ECC_ID 5 ++#define ECC_ATTRS 6 ++static CK_ATTRIBUTE ecc_template[] = { ++ {CKA_LABEL, NULL_PTR, 0}, ++ {CKA_VERIFY, &truevalue, sizeof(truevalue)}, ++ {CKA_TOKEN, &truevalue, sizeof(truevalue)}, ++ {CKA_PRIVATE, &falsevalue, sizeof(falsevalue)}, ++ {CKA_EC_PARAMS, NULL_PTR, 0}, ++ {CKA_ID, NULL_PTR, 0} ++}; ++ ++/* ++ * Public key template for DSA keys ++ */ ++#define DSA_LABEL 0 ++#define DSA_VERIFY 1 ++#define DSA_TOKEN 2 ++#define DSA_PRIVATE 3 ++#define DSA_PRIME 4 ++#define DSA_SUBPRIME 5 ++#define DSA_BASE 6 ++#define DSA_ID 7 ++#define DSA_ATTRS 8 ++static CK_ATTRIBUTE dsa_template[] = { ++ {CKA_LABEL, NULL_PTR, 0}, ++ {CKA_VERIFY, &truevalue, sizeof(truevalue)}, ++ {CKA_TOKEN, &truevalue, sizeof(truevalue)}, ++ {CKA_PRIVATE, &falsevalue, sizeof(falsevalue)}, ++ {CKA_PRIME, NULL_PTR, 0}, ++ {CKA_SUBPRIME, NULL_PTR, 0}, ++ {CKA_BASE, NULL_PTR, 0}, ++ {CKA_ID, NULL_PTR, 0} ++}; ++#define DSA_PARAM_PRIME 0 ++#define DSA_PARAM_SUBPRIME 1 ++#define DSA_PARAM_BASE 2 ++#define DSA_PARAM_ATTRS 3 ++static CK_ATTRIBUTE dsa_param_template[] = { ++ {CKA_PRIME, NULL_PTR, 0}, ++ {CKA_SUBPRIME, NULL_PTR, 0}, ++ {CKA_BASE, NULL_PTR, 0}, ++}; ++#define DSA_DOMAIN_PRIMEBITS 0 ++#define DSA_DOMAIN_PRIVATE 1 ++#define DSA_DOMAIN_ATTRS 2 ++static CK_ATTRIBUTE dsa_domain_template[] = { ++ {CKA_PRIME_BITS, NULL_PTR, 0}, ++ {CKA_PRIVATE, &falsevalue, sizeof(falsevalue)}, ++}; ++ ++/* ++ * Public key template for DH keys ++ */ ++#define DH_LABEL 0 ++#define DH_VERIFY 1 ++#define DH_TOKEN 2 ++#define DH_PRIVATE 3 ++#define DH_PRIME 4 ++#define DH_BASE 5 ++#define DH_ID 6 ++#define DH_ATTRS 7 ++static CK_ATTRIBUTE dh_template[] = { ++ {CKA_LABEL, NULL_PTR, 0}, ++ {CKA_VERIFY, &truevalue, sizeof(truevalue)}, ++ {CKA_TOKEN, &truevalue, sizeof(truevalue)}, ++ {CKA_PRIVATE, &falsevalue, sizeof(falsevalue)}, ++ {CKA_PRIME, NULL_PTR, 0}, ++ {CKA_BASE, NULL_PTR, 0}, ++ {CKA_ID, NULL_PTR, 0} ++}; ++#define DH_PARAM_PRIME 0 ++#define DH_PARAM_BASE 1 ++#define DH_PARAM_ATTRS 2 ++static CK_ATTRIBUTE dh_param_template[] = { ++ {CKA_PRIME, NULL_PTR, 0}, ++ {CKA_BASE, NULL_PTR, 0}, ++}; ++#define DH_DOMAIN_PRIMEBITS 0 ++#define DH_DOMAIN_ATTRS 1 ++static CK_ATTRIBUTE dh_domain_template[] = { ++ {CKA_PRIME_BITS, NULL_PTR, 0}, ++}; ++ ++/* ++ * Convert from text to key class. Accepts the names of DNSSEC ++ * signing algorithms, so e.g., ECDSAP256SHA256 maps to ECC and ++ * NSEC3RSASHA1 maps to RSA. ++ */ ++static key_class_t ++keyclass_fromtext(const char *name) { ++ if (name == NULL) ++ return (key_unknown); ++ ++ if (strncasecmp(name, "rsa", 3) == 0 || ++ strncasecmp(name, "nsec3rsa", 8) == 0) ++ return (key_rsa); ++ else if (strncasecmp(name, "dsa", 3) == 0 || ++ strncasecmp(name, "nsec3dsa", 8) == 0) ++ return (key_dsa); ++ else if (strcasecmp(name, "dh") == 0) ++ return (key_dh); ++ else if (strncasecmp(name, "ecc", 3) == 0 || ++ strncasecmp(name, "ecdsa", 5) == 0) ++ return (key_ecc); ++ else ++ return (key_unknown); ++} ++ ++static void ++usage() { ++ fprintf(stderr, ++ "Usage:\n" ++ "\tpkcs11-keygen -a algorithm -b keysize -l label\n" ++ "\t [-P] [-m module] " ++ "[-s slot] [-e] [-S] [-i id] [-p PIN]\n"); ++ exit(2); ++} ++ + int +-main(int argc, char *argv[]) +-{ ++main(int argc, char *argv[]) { ++ isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; +- CK_MECHANISM genmech; ++ CK_MECHANISM mech, dpmech; + CK_SESSION_HANDLE hSession; +- CK_UTF8CHAR *pin = NULL; +- CK_ULONG modulusbits = 0; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ CK_ULONG bits = 0; + CK_CHAR *label = NULL; +- CK_OBJECT_HANDLE privatekey, publickey; +- CK_BYTE public_exponent[5]; +- CK_ULONG expsize = 3; ++ CK_OBJECT_HANDLE privatekey, publickey, domainparams; ++ CK_BYTE exponent[5]; ++ CK_ULONG expsize = 0; ++ pk11_context_t pctx; + int error = 0; + int c, errflg = 0; +- int hide = 1; +- int idlen = 0; ++ int hide = 1, special = 0, quiet = 0; ++ int idlen = 0, id_offset = 0; ++ unsigned int i; + unsigned long id = 0; + CK_BYTE idbuf[4]; + CK_ULONG ulObjectCount; +- /* Set search template */ + CK_ATTRIBUTE search_template[] = { + {CKA_LABEL, NULL_PTR, 0} + }; +- CK_ATTRIBUTE publickey_template[] = { +- {CKA_LABEL, NULL_PTR, 0}, +- {CKA_VERIFY, &truevalue, sizeof(truevalue)}, +- {CKA_TOKEN, &truevalue, sizeof(truevalue)}, +- {CKA_MODULUS_BITS, &modulusbits, sizeof(modulusbits)}, +- {CKA_PUBLIC_EXPONENT, &public_exponent, expsize}, +- {CKA_ID, &idbuf, idlen} +- }; +- CK_ULONG publickey_attrcnt = 6; +- CK_ATTRIBUTE privatekey_template[] = { +- {CKA_LABEL, NULL_PTR, 0}, +- {CKA_SIGN, &truevalue, sizeof(truevalue)}, +- {CKA_TOKEN, &truevalue, sizeof(truevalue)}, +- {CKA_PRIVATE, &truevalue, sizeof(truevalue)}, +- {CKA_SENSITIVE, &truevalue, sizeof(truevalue)}, +- {CKA_EXTRACTABLE, &falsevalue, sizeof(falsevalue)}, +- {CKA_ID, &idbuf, idlen} +- }; +- CK_ULONG privatekey_attrcnt = 7; +- char *pk11_provider; +- extern char *optarg; +- extern int optopt; + +- pk11_provider = getenv("PKCS11_PROVIDER"); +- if (pk11_provider != NULL) +- pk11_libname = pk11_provider; ++ CK_ATTRIBUTE *public_template = NULL; ++ CK_ATTRIBUTE *domain_template = NULL; ++ CK_ATTRIBUTE *param_template = NULL; ++ CK_ULONG public_attrcnt = 0, private_attrcnt = PRIVATE_ATTRS; ++ CK_ULONG domain_attrcnt = 0, param_attrcnt = 0; ++ key_class_t keyclass = key_rsa; ++ pk11_optype_t op_type = OP_ANY; + +- while ((c = getopt(argc, argv, ":Pm:s:b:ei:l:p:")) != -1) { ++#define OPTIONS ":a:b:ei:l:m:Pp:qSs:" ++ while ((c = isc_commandline_parse(argc, argv, OPTIONS)) != -1) { + switch (c) { ++ case 'a': ++ keyclass = keyclass_fromtext(isc_commandline_argument); ++ break; + case 'P': + hide = 0; + break; + case 'm': +- pk11_libname = optarg; ++ lib_name = isc_commandline_argument; + break; + case 's': +- slot = atoi(optarg); ++ slot = atoi(isc_commandline_argument); + break; + case 'e': + expsize = 5; + break; + case 'b': +- modulusbits = atoi(optarg); ++ bits = atoi(isc_commandline_argument); + break; + case 'l': +- label = (CK_CHAR *)optarg; ++ /* -l option is retained for backward compatibility * */ ++ label = (CK_CHAR *)isc_commandline_argument; + break; + case 'i': +- id = strtoul(optarg, NULL, 0); ++ id = strtoul(isc_commandline_argument, NULL, 0); + idlen = 4; + break; + case 'p': +- pin = (CK_UTF8CHAR *)optarg; ++ pin = isc_commandline_argument; ++ break; ++ case 'q': ++ quiet = 1; ++ break; ++ case 'S': ++ special = 1; + break; + case ':': + fprintf(stderr, + "Option -%c requires an operand\n", +- optopt); ++ isc_commandline_option); + errflg++; + break; + case '?': + default: +- fprintf(stderr, "Unrecognised option: -%c\n", optopt); ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); + errflg++; + } + } + +- if (errflg || !modulusbits || (label == NULL)) { +- fprintf(stderr, "Usage:\n"); +- fprintf(stderr, "\tpkcs11-keygen -b keysize -l label\n"); +- fprintf(stderr, "\t [-P] [-m module] " +- "[-s slot] [-e] [-i id] [-p PIN]\n"); ++ if (label == NULL && isc_commandline_index < argc) ++ label = (CK_CHAR *)argv[isc_commandline_index]; ++ ++ if (errflg || (label == NULL)) ++ usage(); ++ ++ if (expsize != 0 && keyclass != key_rsa) { ++ fprintf(stderr, "The -e option is only compatible " ++ "with RSA key generation\n"); + exit(2); + } ++ ++ if (special != 0 && keyclass != key_dh) { ++ fprintf(stderr, "The -S option is only compatible " ++ "with Diffie-Hellman key generation\n"); ++ exit(2); ++ } ++ ++ switch (keyclass) { ++ case key_rsa: ++ op_type = OP_RSA; ++ if (expsize == 0) ++ expsize = 3; ++ if (bits == 0) ++ usage(); ++ ++ mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; ++ mech.pParameter = NULL; ++ mech.ulParameterLen = 0; ++ ++ public_template = rsa_template; ++ public_attrcnt = RSA_ATTRS; ++ id_offset = RSA_ID; ++ ++ /* Set public exponent to F4 or F5 */ ++ exponent[0] = 0x01; ++ exponent[1] = 0x00; ++ if (expsize == 3) ++ exponent[2] = 0x01; ++ else { ++ exponent[2] = 0x00; ++ exponent[3] = 0x00; ++ exponent[4] = 0x01; ++ } ++ ++ public_template[RSA_MODULUS_BITS].pValue = &bits; ++ public_template[RSA_MODULUS_BITS].ulValueLen = sizeof(bits); ++ public_template[RSA_PUBLIC_EXPONENT].pValue = &exponent; ++ public_template[RSA_PUBLIC_EXPONENT].ulValueLen = expsize; ++ break; ++ case key_ecc: ++ op_type = OP_EC; ++ if (bits == 0) ++ bits = 256; ++ else if (bits != 256 && bits != 384) { ++ fprintf(stderr, "ECC keys only support bit sizes of " ++ "256 and 384\n"); ++ exit(2); ++ } ++ ++ mech.mechanism = CKM_EC_KEY_PAIR_GEN; ++ mech.pParameter = NULL; ++ mech.ulParameterLen = 0; ++ ++ public_template = ecc_template; ++ public_attrcnt = ECC_ATTRS; ++ id_offset = ECC_ID; ++ ++ if (bits == 256) { ++ public_template[4].pValue = pk11_ecc_prime256v1; ++ public_template[4].ulValueLen = ++ sizeof(pk11_ecc_prime256v1); ++ } else { ++ public_template[4].pValue = pk11_ecc_secp384r1; ++ public_template[4].ulValueLen = ++ sizeof(pk11_ecc_secp384r1); ++ } ++ ++ break; ++ case key_dsa: ++ op_type = OP_DSA; ++ if (bits == 0) ++ usage(); ++ ++ dpmech.mechanism = CKM_DSA_PARAMETER_GEN; ++ dpmech.pParameter = NULL; ++ dpmech.ulParameterLen = 0; ++ mech.mechanism = CKM_DSA_KEY_PAIR_GEN; ++ mech.pParameter = NULL; ++ mech.ulParameterLen = 0; ++ ++ public_template = dsa_template; ++ public_attrcnt = DSA_ATTRS; ++ id_offset = DSA_ID; ++ ++ domain_template = dsa_domain_template; ++ domain_attrcnt = DSA_DOMAIN_ATTRS; ++ param_template = dsa_param_template; ++ param_attrcnt = DSA_PARAM_ATTRS; ++ ++ domain_template[DSA_DOMAIN_PRIMEBITS].pValue = &bits; ++ domain_template[DSA_DOMAIN_PRIMEBITS].ulValueLen = sizeof(bits); ++ break; ++ case key_dh: ++ op_type = OP_DH; ++ if (special && bits == 0) ++ bits = 1024; ++ else if (special && ++ bits != 768 && bits != 1024 && bits != 1536) ++ { ++ fprintf(stderr, "When using the special prime (-S) " ++ "option, only key sizes of\n" ++ "768, 1024 or 1536 are supported.\n"); ++ exit(2); ++ } else if (bits == 0) ++ usage(); ++ ++ dpmech.mechanism = CKM_DH_PKCS_PARAMETER_GEN; ++ dpmech.pParameter = NULL; ++ dpmech.ulParameterLen = 0; ++ mech.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN; ++ mech.pParameter = NULL; ++ mech.ulParameterLen = 0; ++ ++ /* Override CKA_SIGN attribute */ ++ private_template[PRIVATE_DERIVE].type = CKA_DERIVE; ++ ++ public_template = dh_template; ++ public_attrcnt = DH_ATTRS; ++ id_offset = DH_ID; ++ ++ domain_template = dh_domain_template; ++ domain_attrcnt = DH_DOMAIN_ATTRS; ++ param_template = dh_param_template; ++ param_attrcnt = DH_PARAM_ATTRS; ++ ++ domain_template[DH_DOMAIN_PRIMEBITS].pValue = &bits; ++ domain_template[DH_DOMAIN_PRIMEBITS].ulValueLen = sizeof(bits); ++ break; ++ case key_unknown: ++ usage(); ++ } + + search_template[0].pValue = label; + search_template[0].ulValueLen = strlen((char *)label); +- publickey_template[0].pValue = label; +- publickey_template[0].ulValueLen = strlen((char *)label); +- privatekey_template[0].pValue = label; +- privatekey_template[0].ulValueLen = strlen((char *)label); +- +- /* Set public exponent to F4 or F5 */ +- public_exponent[0] = 0x01; +- public_exponent[1] = 0x00; +- if (expsize == 3) +- public_exponent[2] = 0x01; +- else { +- publickey_template[4].ulValueLen = expsize; +- public_exponent[2] = 0x00; +- public_exponent[3] = 0x00; +- public_exponent[4] = 0x01; +- } +- +- /* Set up mechanism for generating key pair */ +- genmech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; +- genmech.pParameter = NULL_PTR; +- genmech.ulParameterLen = 0; ++ public_template[0].pValue = label; ++ public_template[0].ulValueLen = strlen((char *)label); ++ private_template[0].pValue = label; ++ private_template[0].ulValueLen = strlen((char *)label); + + if (idlen == 0) { +- publickey_attrcnt--; +- privatekey_attrcnt--; +- } else if (id <= 0xffff) { +- idlen = 2; +- publickey_template[5].ulValueLen = idlen; +- privatekey_template[6].ulValueLen = idlen; +- idbuf[0] = (CK_BYTE)(id >> 8); +- idbuf[1] = (CK_BYTE)id; ++ public_attrcnt--; ++ private_attrcnt--; + } else { +- idbuf[0] = (CK_BYTE)(id >> 24); +- idbuf[1] = (CK_BYTE)(id >> 16); +- idbuf[2] = (CK_BYTE)(id >> 8); +- idbuf[3] = (CK_BYTE)id; +- } +- +- /* Initialize the CRYPTOKI library */ +- rv = C_Initialize(NULL_PTR); ++ if (id <= 0xffff) { ++ idlen = 2; ++ idbuf[0] = (CK_BYTE)(id >> 8); ++ idbuf[1] = (CK_BYTE)id; ++ } else { ++ idbuf[0] = (CK_BYTE)(id >> 24); ++ idbuf[1] = (CK_BYTE)(id >> 16); ++ idbuf[2] = (CK_BYTE)(id >> 8); ++ idbuf[3] = (CK_BYTE)id; ++ } + +- if (rv != CKR_OK) { +- if (rv == 0xfe) +- fprintf(stderr, +- "Can't load or link module \"%s\"\n", +- pk11_libname); +- else +- fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); +- exit(1); ++ public_template[id_offset].pValue = idbuf; ++ public_template[id_offset].ulValueLen = idlen; ++ private_template[PRIVATE_ID].pValue = idbuf; ++ private_template[PRIVATE_ID].ulValueLen = idlen; + } + +- /* Open a session on the slot found */ +- rv = C_OpenSession(slot, CKF_RW_SESSION+CKF_SERIAL_SESSION, +- NULL_PTR, NULL_PTR, &hSession); ++ pk11_result_register(); + +- if (rv != CKR_OK) { +- fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv); +- error = 1; +- goto exit_program; +- } ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); + +- /* Login to the Token (Keystore) */ + if (pin == NULL) +- pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: "); ++ pin = getpassphrase("Enter Pin: "); + +- rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin)); +- memset(pin, 0, strlen((char *)pin)); +- if (rv != CKR_OK) { +- fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv); +- error = 1; +- goto exit_session; ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if (result == PK11_R_NORANDOMSERVICE || ++ result == PK11_R_NODIGESTSERVICE || ++ result == PK11_R_NOAESSERVICE) { ++ fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); ++ fprintf(stderr, "This HSM will not work with BIND 9 " ++ "using native PKCS#11.\n"); ++ } else if (result != ISC_R_SUCCESS) { ++ fprintf(stderr, "Unrecoverable error initializing " ++ "PKCS#11: %s\n", isc_result_totext(result)); ++ exit(1); + } + ++ /* Login to the Token (Keystore) */ ++ memset(pin, 0, strlen(pin)); ++ hSession = pctx.session; ++ + /* check if a key with the same id already exists */ +- rv = C_FindObjectsInit(hSession, search_template, 1); ++ rv = pkcs_C_FindObjectsInit(hSession, search_template, 1); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv); + error = 1; + goto exit_session; + } +- rv = C_FindObjects(hSession, &privatekey, 1, &ulObjectCount); ++ rv = pkcs_C_FindObjects(hSession, &privatekey, 1, &ulObjectCount); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjects: Error = 0x%.8lX\n", rv); + error = 1; +@@ -276,33 +568,140 @@ main(int argc, char *argv[]) + + /* Set attributes if the key is not to be hidden */ + if (!hide) { +- privatekey_template[4].pValue = &falsevalue; +- privatekey_template[5].pValue = &truevalue; ++ private_template[4].pValue = &falsevalue; ++ private_template[5].pValue = &truevalue; ++ } ++ ++ if (keyclass == key_rsa || keyclass == key_ecc) ++ goto generate_keys; ++ ++ /* ++ * Special setup for Diffie-Hellman keys ++ */ ++ if (special != 0) { ++ public_template[DH_BASE].pValue = pk11_dh_bn2; ++ public_template[DH_BASE].ulValueLen = sizeof(pk11_dh_bn2); ++ if (bits == 768) { ++ public_template[DH_PRIME].pValue = pk11_dh_bn768; ++ public_template[DH_PRIME].ulValueLen = ++ sizeof(pk11_dh_bn768); ++ } else if (bits == 1024) { ++ public_template[DH_PRIME].pValue = pk11_dh_bn1024; ++ public_template[DH_PRIME].ulValueLen = ++ sizeof(pk11_dh_bn1024); ++ } else { ++ public_template[DH_PRIME].pValue = pk11_dh_bn1536; ++ public_template[DH_PRIME].ulValueLen = ++ sizeof(pk11_dh_bn1536); ++ } ++ param_attrcnt = 0; ++ goto generate_keys; ++ } ++ ++ /* Generate Domain parameters */ ++ rv = pkcs_C_GenerateKey(hSession, &dpmech, domain_template, ++ domain_attrcnt, &domainparams); ++ ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_GenerateKey: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_search; ++ } ++ ++ /* Get Domain parameters */ ++ rv = pkcs_C_GetAttributeValue(hSession, domainparams, ++ param_template, param_attrcnt); ++ ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_GetAttributeValue0: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_domain; ++ } ++ ++ /* Allocate space for parameter attributes */ ++ for (i = 0; i < param_attrcnt; i++) ++ param_template[i].pValue = malloc(param_template[i].ulValueLen); ++ ++ rv = pkcs_C_GetAttributeValue(hSession, domainparams, ++ dsa_param_template, DSA_PARAM_ATTRS); ++ ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_GetAttributeValue1: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_params; ++ } ++ ++ switch (keyclass) { ++ case key_dsa: ++ public_template[DSA_PRIME].pValue = ++ param_template[DSA_PARAM_PRIME].pValue; ++ public_template[DSA_PRIME].ulValueLen = ++ param_template[DSA_PARAM_PRIME].ulValueLen; ++ public_template[DSA_SUBPRIME].pValue = ++ param_template[DSA_PARAM_SUBPRIME].pValue; ++ public_template[DSA_SUBPRIME].ulValueLen = ++ param_template[DSA_PARAM_SUBPRIME].ulValueLen; ++ public_template[DSA_BASE].pValue = ++ param_template[DSA_PARAM_BASE].pValue; ++ public_template[DSA_BASE].ulValueLen = ++ param_template[DSA_PARAM_BASE].ulValueLen; ++ break; ++ case key_dh: ++ public_template[DH_PRIME].pValue = ++ param_template[DH_PARAM_PRIME].pValue; ++ public_template[DH_PRIME].ulValueLen = ++ param_template[DH_PARAM_PRIME].ulValueLen; ++ public_template[DH_BASE].pValue = ++ param_template[DH_PARAM_BASE].pValue; ++ public_template[DH_BASE].ulValueLen = ++ param_template[DH_PARAM_BASE].ulValueLen; ++ default: ++ break; + } + ++ generate_keys: + /* Generate Key pair for signing/verifying */ +- rv = C_GenerateKeyPair(hSession, &genmech, +- publickey_template, publickey_attrcnt, +- privatekey_template, privatekey_attrcnt, ++ rv = pkcs_C_GenerateKeyPair(hSession, &mech, ++ public_template, public_attrcnt, ++ private_template, private_attrcnt, + &publickey, &privatekey); + + if (rv != CKR_OK) { + fprintf(stderr, "C_GenerateKeyPair: Error = 0x%.8lX\n", rv); + error = 1; ++ } else if (!quiet) ++ printf("Key pair generation complete.\n"); ++ ++ exit_params: ++ /* Free parameter attributes */ ++ if (keyclass == key_dsa || keyclass == key_dh) ++ for (i = 0; i < param_attrcnt; i++) ++ free(param_template[i].pValue); ++ ++ exit_domain: ++ /* Destroy domain parameters */ ++ if (keyclass == key_dsa || (keyclass == key_dh && !special)) { ++ rv = pkcs_C_DestroyObject(hSession, domainparams); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_DestroyObject: Error = 0x%.8lX\n", rv); ++ error = 1; ++ } + } +- ++ + exit_search: +- rv = C_FindObjectsFinal(hSession); ++ rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv); + error = 1; + } + + exit_session: +- (void)C_CloseSession(hSession); +- +- exit_program: +- (void)C_Finalize(NULL_PTR); ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); + + exit(error); + } +diff --git a/bin/pkcs11/pkcs11-keygen.docbook b/bin/pkcs11/pkcs11-keygen.docbook +index 7c4ba08..d62ba2f 100644 +--- a/bin/pkcs11/pkcs11-keygen.docbook ++++ b/bin/pkcs11/pkcs11-keygen.docbook +@@ -18,25 +18,26 @@ + --> + + <!-- $Id: pkcs11-keygen.docbook,v 1.3 2009/10/05 12:23:11 fdupont Exp $ --> +-<refentry id="man.pkcs11-keygen"> ++<refentry id="man.pkcs11-ecgen"> + <refentryinfo> +- <date>Sep 18, 2009</date> ++ <date>Feb 30, 2012</date> + </refentryinfo> + + <refmeta> +- <refentrytitle><application>pkcs11-keygen</application></refentrytitle> ++ <refentrytitle><application>pkcs11-ecgen</application></refentrytitle> + <manvolnum>8</manvolnum> + <refmiscinfo>BIND9</refmiscinfo> + </refmeta> + + <refnamediv> + <refname><application>pkcs11-keygen</application></refname> +- <refpurpose>generate RSA keys on a PKCS#11 device</refpurpose> ++ <refpurpose>generate keys on a PKCS#11 device</refpurpose> + </refnamediv> + + <docinfo> + <copyright> + <year>2009</year> ++ <year>2014</year> + <holder>Internet Systems Consortium, Inc. ("ISC")</holder> + </copyright> + </docinfo> +@@ -44,14 +45,17 @@ + <refsynopsisdiv> + <cmdsynopsis> + <command>pkcs11-keygen</command> +- <arg><option>-P</option></arg> +- <arg><option>-m <replaceable class="parameter">module</replaceable></option></arg> +- <arg><option>-s <replaceable class="parameter">slot</replaceable></option></arg> ++ <arg choice="req">-a <replaceable class="parameter">algorithm</replaceable></arg> ++ <arg><option>-b <replaceable class="parameter">keysize</replaceable></option></arg> + <arg><option>-e</option></arg> +- <arg choice="req">-b <replaceable class="parameter">keysize</replaceable></arg> +- <arg choice="req">-l <replaceable class="parameter">label</replaceable></arg> + <arg><option>-i <replaceable class="parameter">id</replaceable></option></arg> ++ <arg><option>-m <replaceable class="parameter">module</replaceable></option></arg> ++ <arg><option>-P</option></arg> + <arg><option>-p <replaceable class="parameter">PIN</replaceable></option></arg> ++ <arg><option>-q</option></arg> ++ <arg><option>-S</option></arg> ++ <arg><option>-s <replaceable class="parameter">slot</replaceable></option></arg> ++ <arg choice="req">label</arg> + </cmdsynopsis> + </refsynopsisdiv> + +@@ -59,8 +63,8 @@ + <title>DESCRIPTION</title> + <para> + <command>pkcs11-keygen</command> causes a PKCS#11 device to generate +- a new RSA key pair with the specified <option>label</option> and +- with <option>keysize</option> bits of modulus. ++ a new key pair with the given <option>label</option> (which must be ++ unique) and with <option>keysize</option> bits of prime. + </para> + </refsect1> + +@@ -68,83 +72,109 @@ + <title>ARGUMENTS</title> + <variablelist> + <varlistentry> +- <term>-P</term> ++ <term>-a <replaceable class="parameter">algorithm</replaceable></term> + <listitem> + <para> +- Set the new private key to be non-sensitive and extractable. +- The allows the private key data to be read from the PKCS#11 +- device. The default is for private keys to be sensitive and +- non-extractable. ++ Specify the key algorithm class: Supported classes are RSA, ++ DSA, DH, and ECC. In addition to these strings, the ++ <option>algorithm</option> can be specified as a DNSSEC ++ signing algorithm that will be used with this key; for ++ example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps ++ to ECC. The default class is "RSA". + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-m <replaceable class="parameter">module</replaceable></term> ++ <term>-b <replaceable class="parameter">keysize</replaceable></term> + <listitem> + <para> +- Specify the PKCS#11 provider module. This must be the full +- path to a shared library object implementing the PKCS#11 API +- for the device. ++ Create the key pair with <option>keysize</option> bits of ++ prime. For ECC keys, the only valid values are 256 and 384, ++ and the default is 256. + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-s <replaceable class="parameter">slot</replaceable></term> ++ <term>-e</term> + <listitem> + <para> +- Open the session with the given PKCS#11 slot. The default is +- slot 0. ++ For RSA keys only, use a large exponent. + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-e</term> ++ <term>-i <replaceable class="parameter">id</replaceable></term> + <listitem> + <para> +- Use a large exponent. ++ Create key objects with id. The id is either ++ an unsigned short 2 byte or an unsigned long 4 byte number. + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-b <replaceable class="parameter">keysize</replaceable></term> ++ <term>-m <replaceable class="parameter">module</replaceable></term> + <listitem> + <para> +- Create the key pair with <option>keysize</option> bits of +- modulus. ++ Specify the PKCS#11 provider module. This must be the full ++ path to a shared library object implementing the PKCS#11 API ++ for the device. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-P</term> ++ <listitem> ++ <para> ++ Set the new private key to be non-sensitive and extractable. ++ The allows the private key data to be read from the PKCS#11 ++ device. The default is for private keys to be sensitive and ++ non-extractable. + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-l <replaceable class="parameter">label</replaceable></term> ++ <term>-p <replaceable class="parameter">PIN</replaceable></term> + <listitem> + <para> +- Create key objects with the given label. +- This name must be unique. ++ Specify the PIN for the device. If no PIN is provided on ++ the command line, <command>pkcs11-ecgen</command> will ++ prompt for it. + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-i <replaceable class="parameter">id</replaceable></term> ++ <term>-q</term> + <listitem> + <para> +- Create key objects with id. The id is either +- an unsigned short 2 byte or an unsigned long 4 byte number. ++ Quiet mode: suppress unnecessary output. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> ++ <term>-S</term> ++ <listitem> ++ <para> ++ For Diffie-Hellman (DH) keys only, use a special prime of ++ 768, 1024 or 1536 bit size and base (aka generator) 2. ++ If not specified, bit size will default to 1024. + </para> + </listitem> + </varlistentry> + + <varlistentry> +- <term>-p <replaceable class="parameter">PIN</replaceable></term> ++ <term>-s <replaceable class="parameter">slot</replaceable></term> + <listitem> + <para> +- Specify the PIN for the device. If no PIN is provided on the +- command line, <command>pkcs11-keygen</command> will prompt for it. ++ Open the session with the given PKCS#11 slot. The default is ++ slot 0. + </para> + </listitem> + </varlistentry> +@@ -155,6 +185,12 @@ + <title>SEE ALSO</title> + <para> + <citerefentry> ++ <refentrytitle>pkcs11-rsagen</refentrytitle><manvolnum>3</manvolnum> ++ </citerefentry>, ++ <citerefentry> ++ <refentrytitle>pkcs11-dsagen</refentrytitle><manvolnum>3</manvolnum> ++ </citerefentry>, ++ <citerefentry> + <refentrytitle>pkcs11-list</refentrytitle><manvolnum>3</manvolnum> + </citerefentry>, + <citerefentry> +@@ -167,11 +203,6 @@ + </refsect1> + + <refsect1> +- <title>CAVEAT</title> +- <para>Some PKCS#11 providers crash with big public exponent.</para> +- </refsect1> +- +- <refsect1> + <title>AUTHOR</title> + <para><corpauthor>Internet Systems Consortium</corpauthor> + </para> +diff --git a/bin/pkcs11/pkcs11-keygen.html b/bin/pkcs11/pkcs11-keygen.html +index 41378fc..c7fdecf 100644 +--- a/bin/pkcs11/pkcs11-keygen.html ++++ b/bin/pkcs11/pkcs11-keygen.html +@@ -18,36 +18,53 @@ + <html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> +-<title>pkcs11-keygen</title> ++<title>pkcs11-ecgen</title> + <meta name="generator" content="DocBook XSL Stylesheets V1.71.1"> + </head> + <body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en"> +-<a name="man.pkcs11-keygen"></a><div class="titlepage"></div> ++<a name="man.pkcs11-ecgen"></a><div class="titlepage"></div> + <div class="refnamediv"> + <h2>Name</h2> +-<p><span class="application">pkcs11-keygen</span> — generate RSA keys on a PKCS#11 device</p> ++<p><span class="application">pkcs11-keygen</span> — generate keys on a PKCS#11 device</p> + </div> + <div class="refsynopsisdiv"> + <h2>Synopsis</h2> +-<div class="cmdsynopsis"><p><code class="command">pkcs11-keygen</code> [<code class="option">-P</code>] [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] [<code class="option">-e</code>] {-b <em class="replaceable"><code>keysize</code></em>} {-l <em class="replaceable"><code>label</code></em>} [<code class="option">-i <em class="replaceable"><code>id</code></em></code>] [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>]</p></div> ++<div class="cmdsynopsis"><p><code class="command">pkcs11-keygen</code> {-a <em class="replaceable"><code>algorithm</code></em>} [<code class="option">-b <em class="replaceable"><code>keysize</code></em></code>] [<code class="option">-e</code>] [<code class="option">-i <em class="replaceable"><code>id</code></em></code>] [<code class="option">-m <em class="replaceable"><code>module</code></em></code>] [<code class="option">-P</code>] [<code class="option">-p <em class="replaceable"><code>PIN</code></em></code>] [<code class="option">-q</code>] [<code class="option">-S</code>] [<code class="option">-s <em class="replaceable"><code>slot</code></em></code>] {label}</p></div> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543397"></a><h2>DESCRIPTION</h2> ++<a name="id2543410"></a><h2>DESCRIPTION</h2> + <p> + <span><strong class="command">pkcs11-keygen</strong></span> causes a PKCS#11 device to generate +- a new RSA key pair with the specified <code class="option">label</code> and +- with <code class="option">keysize</code> bits of modulus. ++ a new key pair with the given <code class="option">label</code> (which must be ++ unique) and with <code class="option">keysize</code> bits of prime. + </p> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543416"></a><h2>ARGUMENTS</h2> ++<a name="id2543430"></a><h2>ARGUMENTS</h2> + <div class="variablelist"><dl> +-<dt><span class="term">-P</span></dt> ++<dt><span class="term">-a <em class="replaceable"><code>algorithm</code></em></span></dt> + <dd><p> +- Set the new private key to be non-sensitive and extractable. +- The allows the private key data to be read from the PKCS#11 +- device. The default is for private keys to be sensitive and +- non-extractable. ++ Specify the key algorithm class: Supported classes are RSA, ++ DSA, DH, and ECC. In addition to these strings, the ++ <code class="option">algorithm</code> can be specified as a DNSSEC ++ signing algorithm that will be used with this key; for ++ example, NSEC3RSASHA1 maps to RSA, and ECDSAP256SHA256 maps ++ to ECC. The default class is "RSA". ++ </p></dd> ++<dt><span class="term">-b <em class="replaceable"><code>keysize</code></em></span></dt> ++<dd><p> ++ Create the key pair with <code class="option">keysize</code> bits of ++ prime. For ECC keys, the only valid values are 256 and 384, ++ and the default is 256. ++ </p></dd> ++<dt><span class="term">-e</span></dt> ++<dd><p> ++ For RSA keys only, use a large exponent. ++ </p></dd> ++<dt><span class="term">-i <em class="replaceable"><code>id</code></em></span></dt> ++<dd><p> ++ Create key objects with id. The id is either ++ an unsigned short 2 byte or an unsigned long 4 byte number. + </p></dd> + <dt><span class="term">-m <em class="replaceable"><code>module</code></em></span></dt> + <dd><p> +@@ -55,51 +72,48 @@ + path to a shared library object implementing the PKCS#11 API + for the device. + </p></dd> +-<dt><span class="term">-s <em class="replaceable"><code>slot</code></em></span></dt> +-<dd><p> +- Open the session with the given PKCS#11 slot. The default is +- slot 0. +- </p></dd> +-<dt><span class="term">-e</span></dt> ++<dt><span class="term">-P</span></dt> + <dd><p> +- Use a large exponent. ++ Set the new private key to be non-sensitive and extractable. ++ The allows the private key data to be read from the PKCS#11 ++ device. The default is for private keys to be sensitive and ++ non-extractable. + </p></dd> +-<dt><span class="term">-b <em class="replaceable"><code>keysize</code></em></span></dt> ++<dt><span class="term">-p <em class="replaceable"><code>PIN</code></em></span></dt> + <dd><p> +- Create the key pair with <code class="option">keysize</code> bits of +- modulus. ++ Specify the PIN for the device. If no PIN is provided on ++ the command line, <span><strong class="command">pkcs11-ecgen</strong></span> will ++ prompt for it. + </p></dd> +-<dt><span class="term">-l <em class="replaceable"><code>label</code></em></span></dt> ++<dt><span class="term">-q</span></dt> + <dd><p> +- Create key objects with the given label. +- This name must be unique. ++ Quiet mode: suppress unnecessary output. + </p></dd> +-<dt><span class="term">-i <em class="replaceable"><code>id</code></em></span></dt> ++<dt><span class="term">-S</span></dt> + <dd><p> +- Create key objects with id. The id is either +- an unsigned short 2 byte or an unsigned long 4 byte number. ++ For Diffie-Hellman (DH) keys only, use a special prime of ++ 768, 1024 or 1536 bit size and base (aka generator) 2. ++ If not specified, bit size will default to 1024. + </p></dd> +-<dt><span class="term">-p <em class="replaceable"><code>PIN</code></em></span></dt> ++<dt><span class="term">-s <em class="replaceable"><code>slot</code></em></span></dt> + <dd><p> +- Specify the PIN for the device. If no PIN is provided on the +- command line, <span><strong class="command">pkcs11-keygen</strong></span> will prompt for it. ++ Open the session with the given PKCS#11 slot. The default is ++ slot 0. + </p></dd> + </dl></div> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543563"></a><h2>SEE ALSO</h2> ++<a name="id2543605"></a><h2>SEE ALSO</h2> + <p> ++ <span class="citerefentry"><span class="refentrytitle">pkcs11-rsagen</span>(3)</span>, ++ <span class="citerefentry"><span class="refentrytitle">pkcs11-dsagen</span>(3)</span>, + <span class="citerefentry"><span class="refentrytitle">pkcs11-list</span>(3)</span>, + <span class="citerefentry"><span class="refentrytitle">pkcs11-destroy</span>(3)</span>, + <span class="citerefentry"><span class="refentrytitle">dnssec-keyfromlabel</span>(3)</span>, + </p> + </div> + <div class="refsect1" lang="en"> +-<a name="id2543598"></a><h2>CAVEAT</h2> +-<p>Some PKCS#11 providers crash with big public exponent.</p> +-</div> +-<div class="refsect1" lang="en"> +-<a name="id2543609"></a><h2>AUTHOR</h2> ++<a name="id2543657"></a><h2>AUTHOR</h2> + <p><span class="corpauthor">Internet Systems Consortium</span> + </p> + </div> +diff --git a/bin/pkcs11/pkcs11-list.c b/bin/pkcs11/pkcs11-list.c +index 336bf41..bc6ad28 100644 +--- a/bin/pkcs11/pkcs11-list.c ++++ b/bin/pkcs11/pkcs11-list.c +@@ -52,74 +52,68 @@ + #include <errno.h> + #include <string.h> + #include <sys/types.h> +-#include "cryptoki.h" + +-#ifdef WIN32 +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> + + #if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) + #define getpassphrase(x) getpass(x) + #endif + + int +-main(int argc, char *argv[]) +-{ ++main(int argc, char *argv[]) { ++ isc_result_t result; + CK_RV rv; + CK_SLOT_ID slot = 0; + CK_SESSION_HANDLE hSession; +- CK_UTF8CHAR *pin = NULL; + CK_BYTE attr_id[2]; + CK_OBJECT_HANDLE akey[50]; ++ pk11_context_t pctx; ++ char *lib_name = NULL; + char *label = NULL; +- int error = 0, public = 0, all = 0; ++ char *pin = NULL; ++ isc_boolean_t error = ISC_FALSE, logon = ISC_TRUE, all = ISC_FALSE; + unsigned int i = 0, id = 0; + int c, errflg = 0; + CK_ULONG ulObjectCount; + CK_ATTRIBUTE search_template[] = { + {CKA_ID, &attr_id, sizeof(attr_id)} + }; +- char *pk11_provider; +- extern char *optarg; +- extern int optopt; + +- pk11_provider = getenv("PKCS11_PROVIDER"); +- if (pk11_provider != NULL) +- pk11_libname = pk11_provider; +- +- while ((c = getopt(argc, argv, ":m:s:i:l:p:P")) != -1) { ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:i:l:p:P")) != -1) { + switch (c) { + case 'P': +- public = 1; ++ logon = ISC_FALSE; + break; + case 'm': +- pk11_libname = optarg; ++ lib_name = isc_commandline_argument; + break; + case 's': +- slot = atoi(optarg); ++ slot = atoi(isc_commandline_argument); + break; + case 'i': +- id = atoi(optarg); ++ id = atoi(isc_commandline_argument); + id &= 0xffff; + break; + case 'l': +- label = optarg; ++ label = isc_commandline_argument; + break; + case 'p': +- pin = (CK_UTF8CHAR *)optarg; ++ pin = isc_commandline_argument; + break; + case ':': + fprintf(stderr, "Option -%c requires an operand\n", +- optopt); ++ isc_commandline_option); + errflg++; + break; + case '?': + default: +- fprintf(stderr, "Unrecognised option: -%c\n", optopt); ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); + errflg++; + } + } +@@ -132,7 +126,7 @@ main(int argc, char *argv[]) + } + + if (!id && (label == NULL)) +- all = 1; ++ all = ISC_TRUE; + + if (slot) + printf("slot %lu\n", slot); +@@ -148,41 +142,37 @@ main(int argc, char *argv[]) + search_template[0].ulValueLen = strlen(label); + } + ++ pk11_result_register(); ++ + /* Initialize the CRYPTOKI library */ +- rv = C_Initialize(NULL_PTR); +- if (rv != CKR_OK) { +- if (rv == 0xfe) +- fprintf(stderr, +- "Can't load or link module \"%s\"\n", +- pk11_libname); +- else +- fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (logon && pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, OP_ANY, ISC_FALSE, ISC_FALSE, ++ logon, pin, slot); ++ if (result == PK11_R_NORANDOMSERVICE || ++ result == PK11_R_NODIGESTSERVICE || ++ result == PK11_R_NOAESSERVICE) { ++ fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); ++ fprintf(stderr, "This HSM will not work with BIND 9 " ++ "using native PKCS#11.\n"); ++ } else if (result != ISC_R_SUCCESS) { ++ fprintf(stderr, "Unrecoverable error initializing " ++ "PKCS#11: %s\n", isc_result_totext(result)); ++ fprintf(stderr, "Unrecoverable error initializing " ++ "PKCS#11: %s\n", isc_result_totext(result)); + exit(1); + } + +- /* Open a session on the slot found */ +- rv = C_OpenSession(slot, CKF_SERIAL_SESSION, +- NULL_PTR, NULL_PTR, &hSession); +- if (rv != CKR_OK) { +- fprintf(stderr, "C_OpenSession: Error = 0x%.8lX\n", rv); +- error = 1; +- goto exit_program; +- } ++ if (pin != NULL) ++ memset(pin, 0, strlen(pin)); + +- /* Login to the Token (Keystore) */ +- if (!public) { +- if (pin == NULL) +- pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: "); +- rv = C_Login(hSession, CKU_USER, pin, strlen((char *)pin)); +- memset(pin, 0, strlen((char *)pin)); +- if (rv != CKR_OK) { +- fprintf(stderr, "C_Login: Error = 0x%.8lX\n", rv); +- error = 1; +- goto exit_session; +- } +- } ++ hSession = pctx.session; + +- rv = C_FindObjectsInit(hSession, search_template, all ? 0 : 1); ++ rv = pkcs_C_FindObjectsInit(hSession, search_template, all ? 0 : 1); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsInit: Error = 0x%.8lX\n", rv); + error = 1; +@@ -191,7 +181,7 @@ main(int argc, char *argv[]) + + ulObjectCount = 1; + while (ulObjectCount) { +- rv = C_FindObjects(hSession, akey, 50, &ulObjectCount); ++ rv = pkcs_C_FindObjects(hSession, akey, 50, &ulObjectCount); + if (rv != CKR_OK) { + fprintf(stderr, + "C_FindObjects: Error = 0x%.8lX\n", +@@ -215,7 +205,7 @@ main(int argc, char *argv[]) + memset(labelbuf, 0, sizeof(labelbuf)); + memset(idbuf, 0, sizeof(idbuf)); + +- rv = C_GetAttributeValue(hSession, akey[i], ++ rv = pkcs_C_GetAttributeValue(hSession, akey[i], + template, 3); + if (rv != CKR_OK) { + fprintf(stderr, +@@ -260,17 +250,15 @@ main(int argc, char *argv[]) + } + + exit_search: +- rv = C_FindObjectsFinal(hSession); ++ rv = pkcs_C_FindObjectsFinal(hSession); + if (rv != CKR_OK) { + fprintf(stderr, "C_FindObjectsFinal: Error = 0x%.8lX\n", rv); + error = 1; + } + + exit_session: +- (void)C_CloseSession(hSession); +- +- exit_program: +- (void)C_Finalize(NULL_PTR); ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); + + exit(error); + } +diff --git a/bin/pkcs11/pkcs11-tokens.8 b/bin/pkcs11/pkcs11-tokens.8 +new file mode 100644 +index 0000000..7c2be83 +--- /dev/null ++++ b/bin/pkcs11/pkcs11-tokens.8 +@@ -0,0 +1,51 @@ ++.\" Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++.\" ++.\" Permission to use, copy, modify, and/or distribute this software for any ++.\" purpose with or without fee is hereby granted, provided that the above ++.\" copyright notice and this permission notice appear in all copies. ++.\" ++.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++.\" PERFORMANCE OF THIS SOFTWARE. ++.\" ++.\" $Id$ ++.\" ++.hy 0 ++.ad l ++.\" Title: pkcs11\-tokens ++.\" Author: ++.\" Generator: DocBook XSL Stylesheets v1.71.1 <http://docbook.sf.net/> ++.\" Date: August 25, 2013 ++.\" Manual: BIND9 ++.\" Source: BIND9 ++.\" ++.TH "PKCS11\-TOKENS" "8" "August 25, 2013" "BIND9" "BIND9" ++.\" disable hyphenation ++.nh ++.\" disable justification (adjust text to left margin only) ++.ad l ++.SH "NAME" ++pkcs11\-tokens \- list PKCS#11 available tokens ++.SH "SYNOPSIS" ++.HP 14 ++\fBpkcs11\-tokens\fR [\fB\-m\ \fR\fB\fImodule\fR\fR] ++.SH "DESCRIPTION" ++.PP ++\fBpkcs11\-tokens\fR ++lists the PKCS#11 available tokens with defaults from the slot/token scan performed at application initialization. ++.SH "ARGUMENTS" ++.PP ++\-m \fImodule\fR ++.RS 4 ++Specify the PKCS#11 provider module. This must be the full path to a shared library object implementing the PKCS#11 API for the device. ++.RE ++.SH "AUTHOR" ++.PP ++Internet Systems Consortium ++.SH "COPYRIGHT" ++Copyright \(co 2013 Internet Systems Consortium, Inc. ("ISC") ++.br +diff --git a/bin/pkcs11/pkcs11-tokens.c b/bin/pkcs11/pkcs11-tokens.c +new file mode 100644 +index 0000000..ff4e030 +--- /dev/null ++++ b/bin/pkcs11/pkcs11-tokens.c +@@ -0,0 +1,106 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++/* pkcs11-tokens [-m module] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <fcntl.h> ++#include <errno.h> ++#include <string.h> ++#include <sys/types.h> ++ ++#include <isc/commandline.h> ++#include <isc/mem.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ char *lib_name = NULL; ++ int c, errflg = 0; ++ isc_mem_t *mctx = NULL; ++ pk11_context_t pctx; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case ':': ++ fprintf(stderr, "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, "\tpkcs11-tokens [-m module]\n"); ++ exit(1); ++ } ++ ++ if (isc_mem_create(0, 0, &mctx) != ISC_R_SUCCESS) { ++ fprintf(stderr, "isc_mem_create() failed\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ result = pk11_get_session(&pctx, OP_ANY, ISC_FALSE, ISC_FALSE, ++ ISC_FALSE, NULL, 0); ++ if (result == PK11_R_NORANDOMSERVICE || ++ result == PK11_R_NODIGESTSERVICE || ++ result == PK11_R_NOAESSERVICE) { ++ fprintf(stderr, "Warning: %s\n", isc_result_totext(result)); ++ fprintf(stderr, "This HSM will not work with BIND 9 " ++ "using native PKCS#11.\n\n"); ++ } else if (result != ISC_R_SUCCESS) { ++ fprintf(stderr, "Unrecoverable error initializing " ++ "PKCS#11: %s\n", isc_result_totext(result)); ++ exit(1); ++ } ++ ++ pk11_dump_tokens(); ++ ++ if (pctx.handle != NULL) ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ isc_mem_destroy(&mctx); ++ ++ exit(0); ++} +diff --git a/bin/pkcs11/pkcs11-tokens.docbook b/bin/pkcs11/pkcs11-tokens.docbook +new file mode 100644 +index 0000000..44dc7cd +--- /dev/null ++++ b/bin/pkcs11/pkcs11-tokens.docbook +@@ -0,0 +1,86 @@ ++<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" ++ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" ++ [<!ENTITY mdash "—">]> ++<!-- ++ - Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ - ++ - Permission to use, copy, modify, and/or distribute this software for any ++ - purpose with or without fee is hereby granted, provided that the above ++ - copyright notice and this permission notice appear in all copies. ++ - ++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ - PERFORMANCE OF THIS SOFTWARE. ++--> ++ ++<!-- $Id$ --> ++<refentry id="man.pkcs11-tokens"> ++ <refentryinfo> ++ <date>August 25, 2013</date> ++ </refentryinfo> ++ ++ <refmeta> ++ <refentrytitle><application>pkcs11-tokens</application></refentrytitle> ++ <manvolnum>8</manvolnum> ++ <refmiscinfo>BIND9</refmiscinfo> ++ </refmeta> ++ ++ <refnamediv> ++ <refname><application>pkcs11-tokens</application></refname> ++ <refpurpose>list PKCS#11 available tokens</refpurpose> ++ </refnamediv> ++ ++ <docinfo> ++ <copyright> ++ <year>2013</year> ++ <holder>Internet Systems Consortium, Inc. ("ISC")</holder> ++ </copyright> ++ </docinfo> ++ ++ <refsynopsisdiv> ++ <cmdsynopsis> ++ <command>pkcs11-tokens</command> ++ <arg><option>-m <replaceable class="parameter">module</replaceable></option></arg> ++ </cmdsynopsis> ++ </refsynopsisdiv> ++ ++ <refsect1> ++ <title>DESCRIPTION</title> ++ <para> ++ <command>pkcs11-tokens</command> ++ lists the PKCS#11 available tokens with defaults from the slot/token ++ scan performed at application initialization. ++ </para> ++ </refsect1> ++ ++ <refsect1> ++ <title>ARGUMENTS</title> ++ <variablelist> ++ <varlistentry> ++ <term>-m <replaceable class="parameter">module</replaceable></term> ++ <listitem> ++ <para> ++ Specify the PKCS#11 provider module. This must be the full ++ path to a shared library object implementing the PKCS#11 API ++ for the device. ++ </para> ++ </listitem> ++ </varlistentry> ++ </variablelist> ++ </refsect1> ++ ++ <refsect1> ++ <title>AUTHOR</title> ++ <para><corpauthor>Internet Systems Consortium</corpauthor> ++ </para> ++ </refsect1> ++ ++</refentry><!-- ++ - Local variables: ++ - mode: sgml ++ - End: ++--> +diff --git a/bin/pkcs11/pkcs11-tokens.html b/bin/pkcs11/pkcs11-tokens.html +new file mode 100644 +index 0000000..45d7243 +--- /dev/null ++++ b/bin/pkcs11/pkcs11-tokens.html +@@ -0,0 +1,58 @@ ++<!-- ++ - Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ - ++ - Permission to use, copy, modify, and/or distribute this software for any ++ - purpose with or without fee is hereby granted, provided that the above ++ - copyright notice and this permission notice appear in all copies. ++ - ++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ - PERFORMANCE OF THIS SOFTWARE. ++--> ++<!-- $Id$ --> ++<html> ++<head> ++<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> ++<title>pkcs11-tokens</title> ++<meta name="generator" content="DocBook XSL Stylesheets V1.71.1"> ++</head> ++<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="refentry" lang="en"> ++<a name="man.pkcs11-tokens"></a><div class="titlepage"></div> ++<div class="refnamediv"> ++<h2>Name</h2> ++<p><span class="application">pkcs11-tokens</span> — list PKCS#11 available tokens</p> ++</div> ++<div class="refsynopsisdiv"> ++<h2>Synopsis</h2> ++<div class="cmdsynopsis"><p><code class="command">pkcs11-tokens</code> [<code class="option">-m <em class="replaceable"><code>module</code></em></code>]</p></div> ++</div> ++<div class="refsect1" lang="en"> ++<a name="id2543342"></a><h2>DESCRIPTION</h2> ++<p> ++ <span><strong class="command">pkcs11-tokens</strong></span> ++ lists the PKCS#11 available tokens with defaults from the slot/token ++ scan performed at application initialization. ++ </p> ++</div> ++<div class="refsect1" lang="en"> ++<a name="id2543355"></a><h2>ARGUMENTS</h2> ++<div class="variablelist"><dl> ++<dt><span class="term">-m <em class="replaceable"><code>module</code></em></span></dt> ++<dd><p> ++ Specify the PKCS#11 provider module. This must be the full ++ path to a shared library object implementing the PKCS#11 API ++ for the device. ++ </p></dd> ++</dl></div> ++</div> ++<div class="refsect1" lang="en"> ++<a name="id2543382"></a><h2>AUTHOR</h2> ++<p><span class="corpauthor">Internet Systems Consortium</span> ++ </p> ++</div> ++</div></body> ++</html> +diff --git a/bin/rndc/Makefile.in b/bin/rndc/Makefile.in +index f6100df..bc0657a 100644 +--- a/bin/rndc/Makefile.in ++++ b/bin/rndc/Makefile.in +@@ -45,7 +45,8 @@ BIND9DEPLIBS = ../../lib/bind9/libbind9.@A@ + LIBS = ${ISCLIBS} @LIBS@ + NOSYMLIBS = ${ISCNOSYMLIBS} @LIBS@ + +-RNDCDEPLIBS = ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} ${DNSDEPLIBS} ${ISCDEPLIBS} ++RNDCDEPLIBS = ${ISCCFGDEPLIBS} ${ISCCCDEPLIBS} ${BIND9DEPLIBS} \ ++ ${DNSDEPLIBS} ${ISCDEPLIBS} + + CONFDEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS} + +diff --git a/bin/tests/Makefile.in b/bin/tests/Makefile.in +index bc040a3..2020bf4 100644 +--- a/bin/tests/Makefile.in ++++ b/bin/tests/Makefile.in +@@ -42,7 +42,7 @@ LWRESDEPLIBS = ../../lib/lwres/liblwres.@A@ + LIBS = @LIBS@ + + SUBDIRS = atomic db dst master mem hashes names net rbt resolver \ +- sockaddr tasks timers system ++ sockaddr tasks timers system @PKCS11_TOOLS@ + + # Test programs that are built by default: + # cfg_test is needed for regenerating doc/misc/options +@@ -173,139 +173,139 @@ backtrace_test@EXEEXT@: backtrace_test_nosymtbl@EXEEXT@ + nsecify@EXEEXT@: nsecify.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ nsecify.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + byaddr_test@EXEEXT@: byaddr_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byaddr_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + byname_test@EXEEXT@: byname_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ byname_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + lex_test@EXEEXT@: lex_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lex_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + lfsr_test@EXEEXT@: lfsr_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lfsr_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + log_test@EXEEXT@: log_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ log_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + name_test@EXEEXT@: name_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ name_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + hash_test@EXEEXT@: hash_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ hash_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + entropy_test@EXEEXT@: entropy_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + entropy2_test@EXEEXT@: entropy2_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ entropy2_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + sock_test@EXEEXT@: sock_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sock_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + sym_test@EXEEXT@: sym_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sym_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + task_test@EXEEXT@: task_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ task_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + shutdown_test@EXEEXT@: shutdown_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ shutdown_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + timer_test@EXEEXT@: timer_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ timer_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + ratelimiter_test@EXEEXT@: ratelimiter_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ratelimiter_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + rbt_test@EXEEXT@: rbt_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rbt_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + rdata_test@EXEEXT@: rdata_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rdata_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + rwlock_test@EXEEXT@: rwlock_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ rwlock_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + wire_test@EXEEXT@: wire_test.@O@ printmsg.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ wire_test.@O@ printmsg.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + master_test@EXEEXT@: master_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ master_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + db_test@EXEEXT@: db_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ db_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + compress_test@EXEEXT@: compress_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ compress_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + mempool_test@EXEEXT@: mempool_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ mempool_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + serial_test@EXEEXT@: serial_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ serial_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + zone_test@EXEEXT@: zone_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ zone_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + fsaccess_test@EXEEXT@: fsaccess_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ fsaccess_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + inter_test@EXEEXT@: inter_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ inter_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + keyboard_test@EXEEXT@: keyboard_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ keyboard_test.@O@ \ + ${ISCLIBS} ${LIBS} +- ++ + lwresconf_test@EXEEXT@: lwresconf_test.@O@ ${ISCDEPLIBS} ${LWRESDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lwresconf_test.@O@ \ + ${LWRESLIBS} ${ISCLIBS} ${LIBS} +- ++ + lwres_test@EXEEXT@: lwres_test.@O@ ${ISCDEPLIBS} ${LWRESDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ lwres_test.@O@ \ +- ${LWRESLIBS} ${ISCLIBS} ${LIBS} +- +-gxbn_test@EXEEXT@: gxbn_test.@O@ ${LWRESDEPLIBS} ++ ${LWRESLIBS} ${ISCLIBS} ${LIBS} ++ ++ gxbn_test@EXEEXT@: gxbn_test.@O@ ${LWRESDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ gxbn_test.@O@ \ + ${LWRESLIBS} ${ISCLIBS} ${LIBS} +- +-gxba_test@EXEEXT@: gxba_test.@O@ ${LWRESDEPLIBS} ++ ++ gxba_test@EXEEXT@: gxba_test.@O@ ${LWRESDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ gxba_test.@O@ \ + ${LWRESLIBS} ${ISCLIBS} ${LIBS} +- ++ + sig0_test@EXEEXT@: sig0_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ sig0_test.@O@ \ + ${DNSLIBS} ${ISCLIBS} ${LIBS} +- ++ + cfg_test@EXEEXT@: cfg_test.@O@ ${ISCCFGDEPLIBS} ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ cfg_test.@O@ \ + ${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} ${LIBS} +diff --git a/bin/tests/dst/dst_test.c b/bin/tests/dst/dst_test.c +index bf305d8..240dc6f 100644 +--- a/bin/tests/dst/dst_test.c ++++ b/bin/tests/dst/dst_test.c +@@ -30,6 +30,7 @@ + #include <isc/string.h> /* Required for HP/UX (and others?) */ + + #include <dns/fixedname.h> ++#include <dns/log.h> + #include <dns/name.h> + #include <dns/result.h> + +@@ -58,7 +59,8 @@ use(dst_key_t *key, isc_mem_t *mctx) { + isc_buffer_add(&databuf, strlen(data)); + isc_buffer_usedregion(&databuf, &datareg); + +- ret = dst_context_create(key, mctx, &ctx); ++ ret = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_GENERAL, ISC_TRUE, &ctx); + if (ret != ISC_R_SUCCESS) { + printf("contextcreate(%d) returned: %s\n", dst_key_alg(key), + isc_result_totext(ret)); +@@ -78,7 +80,8 @@ use(dst_key_t *key, isc_mem_t *mctx) { + + isc_buffer_forward(&sigbuf, 1); + isc_buffer_remainingregion(&sigbuf, &sigreg); +- ret = dst_context_create(key, mctx, &ctx); ++ ret = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_GENERAL, ISC_FALSE, &ctx); + if (ret != ISC_R_SUCCESS) { + printf("contextcreate(%d) returned: %s\n", dst_key_alg(key), + isc_result_totext(ret)); +diff --git a/bin/tests/dst/t_dst.c b/bin/tests/dst/t_dst.c +index e431c95..59c7835 100644 +--- a/bin/tests/dst/t_dst.c ++++ b/bin/tests/dst/t_dst.c +@@ -108,7 +108,8 @@ use(dst_key_t *key, isc_mem_t *mctx, isc_result_t exp_result, int *nfails) { + isc_buffer_add(&databuf, strlen(data)); + isc_buffer_usedregion(&databuf, &datareg); + +- ret = dst_context_create(key, mctx, &ctx); ++ ret = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_GENERAL, ISC_TRUE, &ctx); + if (ret != exp_result) { + t_info("dst_context_create(%d) returned (%s) expected (%s)\n", + dst_key_alg(key), dst_result_totext(ret), +@@ -137,7 +138,8 @@ use(dst_key_t *key, isc_mem_t *mctx, isc_result_t exp_result, int *nfails) { + dst_context_destroy(&ctx); + + isc_buffer_remainingregion(&sigbuf, &sigreg); +- ret = dst_context_create(key, mctx, &ctx); ++ ret = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_GENERAL, ISC_FALSE, &ctx); + if (ret != ISC_R_SUCCESS) { + t_info("dst_context_create(%d) returned (%s)\n", + dst_key_alg(key), dst_result_totext(ret)); +@@ -783,7 +785,9 @@ t2_sigchk(char *datapath, char *sigpath, char *keyname, + memset(sig, 0, sizeof(sig)); + isc_buffer_init(&sigbuf, sig, sizeof(sig)); + +- isc_result = dst_context_create(key, mctx, &ctx); ++ isc_result = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_GENERAL, ++ ISC_TRUE, &ctx); + if (isc_result != ISC_R_SUCCESS) { + t_info("dst_context_create(%d) failed %s\n", + dst_result_totext(isc_result)); +@@ -849,7 +853,9 @@ t2_sigchk(char *datapath, char *sigpath, char *keyname, + if (strstr(expected_result, "!")) + exp_res = 1; + +- isc_result = dst_context_create(key, mctx, &ctx); ++ isc_result = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_GENERAL, ++ ISC_FALSE, &ctx); + if (isc_result != ISC_R_SUCCESS) { + t_info("dst_context_create returned %s\n", + isc_result_totext(isc_result)); +diff --git a/bin/tests/pkcs11/Makefile.in b/bin/tests/pkcs11/Makefile.in +new file mode 100644 +index 0000000..0a6281f +--- /dev/null ++++ b/bin/tests/pkcs11/Makefile.in +@@ -0,0 +1,49 @@ ++# Copyright (C) 2009, 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_MAKE_INCLUDES@ ++ ++PROVIDER = @PKCS11_PROVIDER@ ++ ++CINCLUDES = ${ISC_INCLUDES} ++ ++CDEFINES = -DPK11_LIB_LOCATION=\"${PROVIDER}\" ++ ++ISCLIBS = ../../../lib/isc/libisc.@A@ ++ ++LIBS = ${ISCLIBS} @LIBS@ ++ ++SUBDIRS = benchmarks ++ ++TARGETS = pkcs11-md5sum@EXEEXT@ pkcs11-hmacmd5@EXEEXT@ ++SRCS = pkcs11-md5sum.c pkcs11-hmacmd5.c ++ ++@BIND9_MAKE_RULES@ ++ ++pkcs11-md5sum@EXEEXT@: @srcdir@/pkcs11-md5sum.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ @srcdir@/pkcs11-md5sum.c ${LIBS} ++ ++pkcs11-hmacmd5@EXEEXT@: @srcdir@/pkcs11-hmacmd5.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} \ ++ -o $@ @srcdir@/pkcs11-hmacmd5.c ${LIBS} ++ ++test: ++ ++clean distclean:: ++ rm -f ${TARGETS} +diff --git a/bin/tests/pkcs11/benchmarks/Makefile.in b/bin/tests/pkcs11/benchmarks/Makefile.in +new file mode 100644 +index 0000000..cd0347c +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/Makefile.in +@@ -0,0 +1,79 @@ ++# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# $Id$ ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_MAKE_INCLUDES@ ++ ++PROVIDER = @PKCS11_PROVIDER@ ++ ++CINCLUDES = ${ISC_INCLUDES} ++ ++CDEFINES = -DPK11_LIB_LOCATION=\"${PROVIDER}\" ++ ++ISCLIBS = ../../../../lib/isc/libisc.@A@ ++ ++LIBS = ${ISCLIBS} @LIBS@ ++ ++SUBDIRS = ++ ++TARGETS = session@EXEEXT@ login@EXEEXT@ random@EXEEXT@ \ ++ sha1@EXEEXT@ create@EXEEXT@ find@EXEEXT@ \ ++ pubrsa@EXEEXT@ privrsa@EXEEXT@ genrsa@EXEEXT@ \ ++ sign@EXEEXT@ verify@EXEEXT@ ++ ++SRCS = session.c login.c random.c sha1.c create.c find.c \ ++ pubrsa.c privrsa.c genrsa.c sign.c verify.c ++ ++@BIND9_MAKE_RULES@ ++ ++session@EXEEXT@: @srcdir@/session.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/session.c ${LIBS} ++ ++login@EXEEXT@: @srcdir@/login.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/login.c ${LIBS} ++ ++random@EXEEXT@: @srcdir@/random.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/random.c ${LIBS} ++ ++sha1@EXEEXT@: @srcdir@/sha1.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/sha1.c ${LIBS} ++ ++create@EXEEXT@: @srcdir@/create.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/create.c ${LIBS} ++ ++find@EXEEXT@: @srcdir@/find.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/find.c ${LIBS} ++ ++pubrsa@EXEEXT@: @srcdir@/pubrsa.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/pubrsa.c ${LIBS} ++ ++privrsa@EXEEXT@: @srcdir@/privrsa.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/privrsa.c ${LIBS} ++ ++genrsa@EXEEXT@: @srcdir@/genrsa.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/genrsa.c ${LIBS} ++ ++sign@EXEEXT@: @srcdir@/sign.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/sign.c ${LIBS} ++ ++verify@EXEEXT@: @srcdir@/verify.c ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o $@ @srcdir@/verify.c ${LIBS} ++ ++clean distclean:: ++ rm -f ${TARGETS} +diff --git a/bin/tests/pkcs11/benchmarks/create.c b/bin/tests/pkcs11/benchmarks/create.c +new file mode 100644 +index 0000000..d0d8c77 +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/create.c +@@ -0,0 +1,260 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* create [-m module] [-s $slot] [-p pin] [-t] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE buf[1024]; ++char label[16]; ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE *hKey; ++ CK_OBJECT_CLASS kClass = CKO_DATA; ++ CK_ULONG len = sizeof(buf); ++ CK_ATTRIBUTE kTemplate[] = ++ { ++ { CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_LABEL, (CK_BYTE_PTR) label, (CK_ULONG) sizeof(label) }, ++ { CKA_VALUE, buf, (CK_ULONG) sizeof(buf) } ++ }; ++ pk11_context_t pctx; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ int ontoken = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 't': ++ ontoken = 1; ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tcreate [-m module] [-s slot] [-t] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Allocate hanles */ ++ hKey = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (hKey == NULL) { ++ perror("malloc"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) ++ hKey[i] = CK_INVALID_HANDLE; ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, OP_ANY, ISC_TRUE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ /* Randomize the buffer */ ++ rv = pkcs_C_GenerateRandom(hSession, buf, len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); ++ goto exit_objects; ++ } ++ ++ if (ontoken) ++ kTemplate[1].pValue = &truevalue; ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_objects; ++ } ++ ++ for (i = 0; i < count; i++) { ++ (void) snprintf(label, sizeof(label), "obj%u", i); ++ kTemplate[3].ulValueLen = strlen(label); ++ rv = pkcs_C_CreateObject(hSession, kTemplate, 5, &hKey[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_CreateObject[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_objects; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_objects; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u created objects in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g created objects/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_objects: ++ for (i = 0; i < count; i++) { ++ /* Destroy objects */ ++ if (hKey[i] == CK_INVALID_HANDLE) ++ continue; ++ rv = pkcs_C_DestroyObject(hSession, hKey[i]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_DestroyObject[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ errflg = 1; ++ } ++ } ++ ++ free(hKey); ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/find.c b/bin/tests/pkcs11/benchmarks/find.c +new file mode 100644 +index 0000000..e22b17e +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/find.c +@@ -0,0 +1,227 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* find [-m module] [-s $slot] [-p pin] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE label[] = "foo??bar!!"; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_ATTRIBUTE sTemplate[] = ++ { ++ { CKA_LABEL, label, (CK_ULONG) sizeof(label) }, ++ }; ++ CK_OBJECT_HANDLE sKey = CK_INVALID_HANDLE; ++ CK_ULONG found = 0; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RSA; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:n:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tfind [-m module] [-s slot] [-p pin] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_objects; ++ } ++ ++ for (i = 0; !error && (i < count); i++) { ++ rv = pkcs_C_FindObjectsInit(hSession, sTemplate, 1); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_FindObjectsInit[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ ++ rv = pkcs_C_FindObjects(hSession, &sKey, 1, &found); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_FindObjects[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ /* no break here! */ ++ } ++ ++ rv = pkcs_C_FindObjectsFinal(hSession); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_FindObjectsFinal[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_objects; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u object searches in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g object searches/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_objects: ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/genrsa.c b/bin/tests/pkcs11/benchmarks/genrsa.c +new file mode 100644 +index 0000000..e9d3c2a +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/genrsa.c +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* genrsa [-m module] [-s $slot] [-p pin] [-t] [-b bits] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; ++ CK_OBJECT_HANDLE *pubKey; ++ CK_OBJECT_HANDLE *privKey; ++ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; ++ CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE kType = CKK_RSA; ++ CK_ULONG bits = 1024; ++ CK_BYTE exponent[] = { 0x01, 0x00, 0x01 }; ++ CK_ATTRIBUTE pubTemplate[] = ++ { ++ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, ++ { CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS_BITS, &bits, (CK_ULONG) sizeof(bits) }, ++ { CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) } ++ }; ++ CK_ATTRIBUTE privTemplate[] = ++ { ++ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, ++ { CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ }; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RSA; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ int ontoken = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tb:n:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 't': ++ ontoken = 1; ++ break; ++ case 'b': ++ bits = (CK_ULONG)atoi(isc_commandline_argument); ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tgenrsa [-m module] [-s slot] [-p pin] " ++ "[-t] [-b bits] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Allocate hanles */ ++ pubKey = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (pubKey == NULL) { ++ perror("malloc"); ++ exit(1); ++ } ++ privKey = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (privKey == NULL) { ++ free(pubKey); ++ perror("malloc"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) { ++ pubKey[i] = CK_INVALID_HANDLE; ++ privKey[i] = CK_INVALID_HANDLE; ++ } ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ if (ontoken) { ++ pubTemplate[2].pValue = &truevalue; ++ privTemplate[2].pValue = &truevalue; ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_keys; ++ } ++ ++ for (i = 0; i < count; i++) { ++ rv = pkcs_C_GenerateKeyPair(hSession, &mech, ++ pubTemplate, 7, ++ privTemplate, 5, ++ &pubKey[i], &privKey[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_GenerateKeyPair[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_keys; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_keys; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u generated RSA in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g generated RSA/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_keys: ++ for (i = 0; i < count; i++) { ++ /* Destroy keys */ ++ if (pubKey[i] == CK_INVALID_HANDLE) ++ goto destroy_priv; ++ rv = pkcs_C_DestroyObject(hSession, pubKey[i]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_DestroyObject[pub%u]: Error = 0x%.8lX\n", ++ i, rv); ++ errflg = 1; ++ } ++ destroy_priv: ++ if (privKey[i] == CK_INVALID_HANDLE) ++ continue; ++ rv = pkcs_C_DestroyObject(hSession, privKey[i]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_DestroyObject[priv%u]: Error = 0x%.8lX\n", ++ i, rv); ++ errflg = 1; ++ } ++ } ++ ++ free(pubKey); ++ free(privKey); ++ ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/login.c b/bin/tests/pkcs11/benchmarks/login.c +new file mode 100644 +index 0000000..fe597fa +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/login.c +@@ -0,0 +1,249 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* login [-m module] [-s $slot] [-p pin] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++int ++main(int argc, char *argv[]) { ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE *hSession; ++ CK_UTF8CHAR *pin = NULL; ++ char *lib_name = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ unsigned int count = 1000; ++ unsigned int i, j; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:n:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = (CK_UTF8CHAR *)isc_commandline_argument; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tlogin [-m module] [-s slot] [-p pin] [-n count]\n"); ++ exit(1); ++ } ++ ++ /* allocate sessions */ ++ hSession = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (hSession == NULL) { ++ perror("malloc"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) ++ hSession[i] = CK_INVALID_HANDLE; ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = (CK_UTF8CHAR *)getpassphrase("Enter Pin: "); ++ ++ rv = pkcs_C_Initialize(NULL_PTR); ++ if (rv != CKR_OK) { ++ if (rv == 0xfe) ++ fprintf(stderr, ++ "Can't load or link module \"%s\"\n", ++ pk11_get_lib_name()); ++ else ++ fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); ++ free(hSession); ++ exit(1); ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_program; ++ } ++ ++ /* loop */ ++ for (i = 0; i < count; i++) { ++ /* Open sessions */ ++ rv = pkcs_C_OpenSession(slot, CKF_SERIAL_SESSION, ++ NULL_PTR, NULL_PTR, &hSession[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_OpenSession[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_program; ++ break; ++ } ++ ++ /* Logon */ ++ rv = pkcs_C_Login(hSession[i], CKU_USER, ++ pin, strlen((char *)pin)); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_Login[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_program; ++ break; ++ } ++ ++ /* Logoff */ ++ rv = pkcs_C_Logout(hSession[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_Logout[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_program; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_program; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u logins in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g logins/s\n", ++ i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ for (j = 0; j < i; j++) { ++ if (hSession[j] == CK_INVALID_HANDLE) ++ continue; ++ /* Close sessions */ ++ rv = pkcs_C_CloseSession(hSession[j]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_CloseSession[%u]: Error = 0x%.8lX\n", ++ j, rv); ++ errflg = 1; ++ } ++ } ++ ++ exit_program: ++ free(hSession); ++ ++ rv = pkcs_C_Finalize(NULL_PTR); ++ if (rv != CKR_OK) ++ fprintf(stderr, "C_Finalize: Error = 0x%.8lX\n", rv); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/privrsa.c b/bin/tests/pkcs11/benchmarks/privrsa.c +new file mode 100644 +index 0000000..c50d8d2 +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/privrsa.c +@@ -0,0 +1,360 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* privrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE modulus[] = { ++ 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, ++ 0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b, ++ 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, ++ 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, ++ 0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96, ++ 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, ++ 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, ++ 0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd, ++ 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, ++ 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, ++ 0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45, ++ 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, ++ 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, ++ 0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d, ++ 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, ++ 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, ++ 0xbf ++}; ++CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 }; ++CK_BYTE privexp[] = { ++ 0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02, ++ 0xb8, 0xf1, 0xd6, 0x92, 0x03, 0xee, 0x50, 0x33, ++ 0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e, ++ 0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63, ++ 0x9f, 0x91, 0xe6, 0x3f, 0x44, 0xb8, 0x77, 0x1b, ++ 0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d, ++ 0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e, ++ 0x34, 0xa8, 0x40, 0xea, 0x51, 0x72, 0x8a, 0xea, ++ 0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c, ++ 0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7, ++ 0x19, 0xce, 0x89, 0x08, 0x87, 0x14, 0xef, 0xcc, ++ 0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd, ++ 0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f, ++ 0x26, 0xac, 0x2e, 0x52, 0x02, 0x07, 0xfb, 0x1d, ++ 0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52, ++ 0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c, ++ 0x41 ++}; ++CK_BYTE prime1[] = { ++ 0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde, ++ 0xc2, 0x74, 0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58, ++ 0xcd, 0xe9, 0x8e, 0x97, 0xbe, 0xfe, 0xe8, 0x6f, ++ 0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56, 0x84, 0x36, ++ 0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5, ++ 0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1, ++ 0xeb, 0xed, 0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed, ++ 0x17, 0x7c, 0xd3, 0xa6, 0x35, 0x6e, 0xa6, 0xd8, ++ 0x21 ++}; ++CK_BYTE prime2[] = { ++ 0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9, ++ 0x09, 0xeb, 0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa, ++ 0xfa, 0x3c, 0x61, 0x7e, 0xc1, 0xf8, 0x8c, 0x5e, ++ 0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f, 0x4f, 0xab, ++ 0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21, ++ 0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88, ++ 0xe6, 0xf8, 0xbe, 0x61, 0x38, 0x99, 0xca, 0x36, ++ 0x0d, 0x3e, 0x42, 0x0f, 0x63, 0x4d, 0x73, 0xf0, ++ 0xdf ++}; ++CK_BYTE exp_1[] = { ++ 0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35, ++ 0xfe, 0x2b, 0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13, ++ 0x26, 0x04, 0xe4, 0x18, 0x9d, 0x76, 0x92, 0x9a, ++ 0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b, 0x53, 0x2f, ++ 0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21, ++ 0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42, ++ 0xbd, 0x80, 0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f, ++ 0x85, 0xf0, 0x9c, 0x55, 0x60, 0xb4, 0x9e, 0xc1 ++}; ++CK_BYTE exp_2[] = { ++ 0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c, ++ 0x6d, 0xde, 0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb, ++ 0xb5, 0x54, 0x85, 0x59, 0xcf, 0x7a, 0x56, 0xdb, ++ 0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc, 0xc3, 0xb9, ++ 0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24, ++ 0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a, ++ 0x16, 0x52, 0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c, ++ 0x5a, 0xa4, 0xc4, 0x66, 0x27, 0xe0, 0x96, 0x64, ++ 0x7f ++}; ++CK_BYTE coeff[] = { ++ 0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b, ++ 0x99, 0xd7, 0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94, ++ 0x9d, 0x56, 0x0a, 0x05, 0x55, 0x7d, 0x93, 0x04, ++ 0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3, 0xf1, 0xd5, ++ 0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9, ++ 0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5, ++ 0xcc, 0x1b, 0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67, ++ 0x0c, 0x00, 0x09, 0x56, 0x8c, 0x33, 0x57, 0xf9, ++ 0x8c ++}; ++ ++char label[16]; ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE *hKey; ++ CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE kType = CKK_RSA; ++ CK_ATTRIBUTE kTemplate[] = ++ { ++ { CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) }, ++ { CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_LABEL, (CK_BYTE_PTR) label, (CK_ULONG) sizeof(label) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) }, ++ { CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG) sizeof(pubexp) }, ++ { CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG) sizeof(privexp) }, ++ { CKA_PRIME_1, prime1, (CK_ULONG) sizeof(prime1) }, ++ { CKA_PRIME_2, prime2, (CK_ULONG) sizeof(prime2) }, ++ { CKA_EXPONENT_1, exp_1, (CK_ULONG) sizeof(exp_1) }, ++ { CKA_EXPONENT_2, exp_2, (CK_ULONG) sizeof(exp_2) }, ++ { CKA_COEFFICIENT, coeff, (CK_ULONG) sizeof(coeff) } ++ }; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RSA; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ int ontoken = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 't': ++ ontoken = 1; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tprivrsa [-m module] [-s slot] [-p pin] " ++ "[-t] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Allocate hanles */ ++ hKey = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (hKey == NULL) { ++ perror("malloc"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) ++ hKey[i] = CK_INVALID_HANDLE; ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ free(hKey); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ if (ontoken) ++ kTemplate[2].pValue = &truevalue; ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_objects; ++ } ++ ++ for (i = 0; i < count; i++) { ++ (void) snprintf(label, sizeof(label), "obj%u", i); ++ kTemplate[4].ulValueLen = strlen(label); ++ rv = pkcs_C_CreateObject(hSession, kTemplate, 14, &hKey[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_CreateObject[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_objects; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_objects; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u private RSA keys in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g private RSA keys/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_objects: ++ for (i = 0; i < count; i++) { ++ /* Destroy objects */ ++ if (hKey[i] == CK_INVALID_HANDLE) ++ continue; ++ rv = pkcs_C_DestroyObject(hSession, hKey[i]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_DestroyObject[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ errflg = 1; ++ } ++ } ++ ++ free(hKey); ++ ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/pubrsa.c b/bin/tests/pkcs11/benchmarks/pubrsa.c +new file mode 100644 +index 0000000..b27a999 +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/pubrsa.c +@@ -0,0 +1,281 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* pubrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE modulus[] = { ++ 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, ++ 0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b, ++ 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, ++ 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, ++ 0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96, ++ 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, ++ 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, ++ 0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd, ++ 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, ++ 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, ++ 0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45, ++ 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, ++ 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, ++ 0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d, ++ 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, ++ 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, ++ 0xbf ++}; ++CK_BYTE exponent[] = { 0x01, 0x00, 0x01 }; ++ ++char label[16]; ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE *hKey; ++ CK_OBJECT_CLASS kClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE kType = CKK_RSA; ++ CK_ATTRIBUTE kTemplate[] = ++ { ++ { CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) }, ++ { CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_LABEL, (CK_BYTE_PTR) label, (CK_ULONG) sizeof(label) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) }, ++ { CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) } ++ }; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RSA; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ int ontoken = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 't': ++ ontoken = 1; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tpubrsa [-m module] [-s slot] [-p pin] " ++ "[-t] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Allocate hanles */ ++ hKey = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (hKey == NULL) { ++ perror("malloc"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) ++ hKey[i] = CK_INVALID_HANDLE; ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ free(hKey); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ if (ontoken) ++ kTemplate[2].pValue = &truevalue; ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_objects; ++ } ++ ++ for (i = 0; i < count; i++) { ++ (void) snprintf(label, sizeof(label), "obj%u", i); ++ kTemplate[4].ulValueLen = strlen(label); ++ rv = pkcs_C_CreateObject(hSession, kTemplate, 8, &hKey[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_CreateObject[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_objects; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_objects; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u public RSA keys in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g public RSA keys/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_objects: ++ for (i = 0; i < count; i++) { ++ /* Destroy objects */ ++ if (hKey[i] == CK_INVALID_HANDLE) ++ continue; ++ rv = pkcs_C_DestroyObject(hSession, hKey[i]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_DestroyObject[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ errflg = 1; ++ } ++ } ++ ++ free(hKey); ++ ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/random.c b/bin/tests/pkcs11/benchmarks/random.c +new file mode 100644 +index 0000000..10d6db0 +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/random.c +@@ -0,0 +1,192 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* random [-m module] [-s $slot] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE buf[1024]; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_ULONG len = sizeof(buf); ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RAND; ++ char *lib_name = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\trandom [-m module] [-s slot] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, ++ ISC_FALSE, NULL, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ hSession = pctx.session; ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_session; ++ } ++ ++ for (i = 0; i < count; i++) { ++ /* Get random bytes */ ++ rv = pkcs_C_GenerateRandom(hSession, buf, len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_GenerateRandom[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_session; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%uK random bytes in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g random bytes/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_session: ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/session.c b/bin/tests/pkcs11/benchmarks/session.c +new file mode 100644 +index 0000000..74bd63a +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/session.c +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* session [-m module] [-s $slot] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++int ++main(int argc, char *argv[]) { ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE *hSession; ++ char *lib_name = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tsession [-m module] [-s slot] [-n count]\n"); ++ exit(1); ++ } ++ ++ /* Allocate sessions */ ++ hSession = (CK_SESSION_HANDLE *) ++ malloc(count * sizeof(CK_SESSION_HANDLE)); ++ if (hSession == NULL) { ++ perror("malloc"); ++ exit(1); ++ } ++ for (i = 0; i < count; i++) ++ hSession[i] = CK_INVALID_HANDLE; ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ rv = pkcs_C_Initialize(NULL_PTR); ++ if (rv != CKR_OK) { ++ if (rv == 0xfe) ++ fprintf(stderr, ++ "Can't load or link module \"%s\"\n", ++ pk11_get_lib_name()); ++ else ++ fprintf(stderr, "C_Initialize: Error = 0x%.8lX\n", rv); ++ free(hSession); ++ exit(1); ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_program; ++ } ++ ++ /* loop */ ++ for (i = 0; i < count; i++) { ++ /* Open sessions */ ++ rv = pkcs_C_OpenSession(slot, CKF_SERIAL_SESSION, ++ NULL_PTR, NULL_PTR, &hSession[i]); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_OpenSession[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ if (i == 0) ++ goto exit_program; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_program; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u sessions in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g sessions/s\n", ++ i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ for (i = 0; i < count; i++) { ++ /* Close sessions */ ++ if (hSession[i] == CK_INVALID_HANDLE) ++ continue; ++ rv = pkcs_C_CloseSession(hSession[i]); ++ if ((rv != CKR_OK) && !errflg) { ++ fprintf(stderr, ++ "C_CloseSession[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ errflg = 1; ++ } ++ } ++ ++ exit_program: ++ free(hSession); ++ ++ rv = pkcs_C_Finalize(NULL_PTR); ++ if (rv != CKR_OK) ++ fprintf(stderr, "C_Finalize: Error = 0x%.8lX\n", rv); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/sha1.c b/bin/tests/pkcs11/benchmarks/sha1.c +new file mode 100644 +index 0000000..756aadb +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/sha1.c +@@ -0,0 +1,214 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* sha1 [-m module] [-s $slot] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE buf[1024]; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 }; ++ CK_ULONG len = sizeof(buf); ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_DIGEST; ++ char *lib_name = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:n:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tssha1 [-m module] [-s slot] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, ++ ISC_FALSE, NULL, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ hSession = pctx.session; ++ ++ /* Randomize the buffer */ ++ rv = pkcs_C_GenerateRandom(hSession, buf, len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); ++ goto exit_session; ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_session; ++ } ++ ++ /* Initialize Digest */ ++ rv = pkcs_C_DigestInit(hSession, &mech); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_DigestInit: Error = 0x%.8lX\n", rv); ++ goto exit_session; ++ } ++ ++ ++ for (i = 0; i < count; i++) { ++ /* Digest buffer */ ++ rv = pkcs_C_DigestUpdate(hSession, buf, len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_DigestUpdate[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ } ++ ++ /* Finalize Digest (unconditionally) */ ++ len = 20U; ++ rv = pkcs_C_DigestFinal(hSession, buf, &len); ++ if ((rv != CKR_OK) && !error) ++ fprintf(stderr, "C_DigestFinal: Error = 0x%.8lX\n", rv); ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_session; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%uK digested bytes in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g digested bytes/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_session: ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/sign.c b/bin/tests/pkcs11/benchmarks/sign.c +new file mode 100644 +index 0000000..8425ba9 +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/sign.c +@@ -0,0 +1,368 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* signrsa [-m module] [-s $slot] [-p pin] [-t] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE modulus[] = { ++ 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, ++ 0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b, ++ 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, ++ 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, ++ 0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96, ++ 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, ++ 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, ++ 0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd, ++ 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, ++ 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, ++ 0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45, ++ 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, ++ 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, ++ 0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d, ++ 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, ++ 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, ++ 0xbf ++}; ++CK_BYTE pubexp[] = { 0x01, 0x00, 0x01 }; ++CK_BYTE privexp[] = { ++ 0x00, 0xae, 0x02, 0xf1, 0x47, 0xa8, 0x07, 0x02, ++ 0xb8, 0xf1, 0xd6, 0x92, 0x03, 0xee, 0x50, 0x33, ++ 0xab, 0x67, 0x9e, 0x3b, 0xb1, 0x57, 0xc7, 0x3e, ++ 0xc4, 0x86, 0x46, 0x61, 0xf1, 0xf8, 0xb6, 0x63, ++ 0x9f, 0x91, 0xe6, 0x3f, 0x44, 0xb8, 0x77, 0x1b, ++ 0xbe, 0x4c, 0x3c, 0xb8, 0x9f, 0xf7, 0x45, 0x7d, ++ 0xbf, 0x4f, 0xef, 0x3b, 0xcc, 0xda, 0x1a, 0x4e, ++ 0x34, 0xa8, 0x40, 0xea, 0x51, 0x72, 0x8a, 0xea, ++ 0x47, 0x06, 0x04, 0xd0, 0x62, 0x31, 0xa0, 0x6c, ++ 0x09, 0x60, 0xf9, 0xc7, 0x95, 0x88, 0x4a, 0xd7, ++ 0x19, 0xce, 0x89, 0x08, 0x87, 0x14, 0xef, 0xcc, ++ 0x0a, 0xef, 0x72, 0xb9, 0x21, 0xf5, 0xf0, 0xcd, ++ 0x6d, 0xe5, 0xfa, 0x15, 0x7f, 0xae, 0x33, 0x9f, ++ 0x26, 0xac, 0x2e, 0x52, 0x02, 0x07, 0xfb, 0x1d, ++ 0x4b, 0xec, 0x9a, 0x6b, 0x3b, 0x26, 0x1f, 0x52, ++ 0xfc, 0x47, 0xf8, 0x66, 0x33, 0xfa, 0x50, 0x6c, ++ 0x41 ++}; ++CK_BYTE prime1[] = { ++ 0x00, 0xe8, 0x98, 0xeb, 0xa1, 0xf0, 0xce, 0xde, ++ 0xc2, 0x74, 0x01, 0x18, 0x2b, 0xd3, 0x8f, 0x58, ++ 0xcd, 0xe9, 0x8e, 0x97, 0xbe, 0xfe, 0xe8, 0x6f, ++ 0xd6, 0x0c, 0x0a, 0x47, 0xf8, 0x56, 0x84, 0x36, ++ 0x15, 0xe6, 0x75, 0x1c, 0x69, 0x48, 0x8b, 0xf5, ++ 0x0f, 0x84, 0xd2, 0x60, 0x8b, 0xa2, 0x2a, 0xa1, ++ 0xeb, 0xed, 0xbe, 0x2d, 0xe9, 0x41, 0x0b, 0xed, ++ 0x17, 0x7c, 0xd3, 0xa6, 0x35, 0x6e, 0xa6, 0xd8, ++ 0x21 ++}; ++CK_BYTE prime2[] = { ++ 0x00, 0xca, 0x15, 0x6a, 0x43, 0x5e, 0x83, 0xc9, ++ 0x09, 0xeb, 0x14, 0x1e, 0x46, 0x46, 0x97, 0xfa, ++ 0xfa, 0x3c, 0x61, 0x7e, 0xc1, 0xf8, 0x8c, 0x5e, ++ 0xcb, 0xbf, 0xe4, 0xb9, 0x78, 0x7f, 0x4f, 0xab, ++ 0x82, 0x15, 0x53, 0xaa, 0x04, 0xee, 0x11, 0x21, ++ 0x2e, 0x23, 0x08, 0xa0, 0x14, 0x6d, 0x3a, 0x88, ++ 0xe6, 0xf8, 0xbe, 0x61, 0x38, 0x99, 0xca, 0x36, ++ 0x0d, 0x3e, 0x42, 0x0f, 0x63, 0x4d, 0x73, 0xf0, ++ 0xdf ++}; ++CK_BYTE exp_1[] = { ++ 0x66, 0x2d, 0xb7, 0x65, 0xbe, 0x99, 0xc2, 0x35, ++ 0xfe, 0x2b, 0xf4, 0xe8, 0x5b, 0xd9, 0xdf, 0x13, ++ 0x26, 0x04, 0xe4, 0x18, 0x9d, 0x76, 0x92, 0x9a, ++ 0x9f, 0x53, 0x6c, 0xe6, 0x65, 0x6b, 0x53, 0x2f, ++ 0x2f, 0xbc, 0x46, 0xac, 0xe1, 0x97, 0xca, 0x21, ++ 0xf5, 0x21, 0x4e, 0x14, 0x49, 0x3b, 0x1d, 0x42, ++ 0xbd, 0x80, 0x0c, 0x3f, 0x29, 0xba, 0x09, 0x7f, ++ 0x85, 0xf0, 0x9c, 0x55, 0x60, 0xb4, 0x9e, 0xc1 ++}; ++CK_BYTE exp_2[] = { ++ 0x00, 0x87, 0x22, 0x74, 0xf1, 0xe2, 0x15, 0x3c, ++ 0x6d, 0xde, 0x7e, 0x90, 0x94, 0x2c, 0x06, 0xdb, ++ 0xb5, 0x54, 0x85, 0x59, 0xcf, 0x7a, 0x56, 0xdb, ++ 0xd9, 0x62, 0x54, 0x20, 0x56, 0xdc, 0xc3, 0xb9, ++ 0x0b, 0xff, 0x18, 0xf8, 0x7b, 0xdd, 0x7b, 0x24, ++ 0xf6, 0x06, 0x45, 0x71, 0x4e, 0xd7, 0x90, 0x2a, ++ 0x16, 0x52, 0x46, 0x75, 0x1a, 0xf5, 0x74, 0x8c, ++ 0x5a, 0xa4, 0xc4, 0x66, 0x27, 0xe0, 0x96, 0x64, ++ 0x7f ++}; ++CK_BYTE coeff[] = { ++ 0x00, 0xd0, 0x1f, 0xb3, 0x47, 0x40, 0x93, 0x8b, ++ 0x99, 0xd7, 0xb5, 0xc6, 0x09, 0x82, 0x65, 0x94, ++ 0x9d, 0x56, 0x0a, 0x05, 0x55, 0x7d, 0x93, 0x04, ++ 0xa4, 0x26, 0xee, 0x42, 0x86, 0xa3, 0xf1, 0xd5, ++ 0x7a, 0x42, 0x84, 0x3c, 0x21, 0x96, 0x9a, 0xd9, ++ 0x36, 0xd4, 0x62, 0x01, 0xb0, 0x8b, 0x77, 0xe5, ++ 0xcc, 0x1b, 0xd2, 0x12, 0xd2, 0x9c, 0x89, 0x67, ++ 0x0c, 0x00, 0x09, 0x56, 0x8c, 0x33, 0x57, 0xf9, ++ 0x8c ++}; ++ ++CK_BYTE buf[1024]; ++CK_BYTE sig[128]; ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_ULONG len; ++ CK_ULONG slen; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS kClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE kType = CKK_RSA; ++ CK_ATTRIBUTE kTemplate[] = ++ { ++ { CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) }, ++ { CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) }, ++ { CKA_PUBLIC_EXPONENT, pubexp, (CK_ULONG) sizeof(pubexp) }, ++ { CKA_PRIVATE_EXPONENT, privexp, (CK_ULONG) sizeof(privexp) }, ++ { CKA_PRIME_1, prime1, (CK_ULONG) sizeof(prime1) }, ++ { CKA_PRIME_2, prime2, (CK_ULONG) sizeof(prime2) }, ++ { CKA_EXPONENT_1, exp_1, (CK_ULONG) sizeof(exp_1) }, ++ { CKA_EXPONENT_2, exp_2, (CK_ULONG) sizeof(exp_2) }, ++ { CKA_COEFFICIENT, coeff, (CK_ULONG) sizeof(coeff) } ++ }; ++ CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 }; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RSA; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ int ontoken = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 't': ++ ontoken = 1; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tsign [-m module] [-s slot] [-p pin] " ++ "[-t] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ /* Create the private RSA key */ ++ if (ontoken) ++ kTemplate[2].pValue = &truevalue; ++ ++ rv = pkcs_C_CreateObject(hSession, kTemplate, 13, &hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv); ++ goto exit_key; ++ } ++ ++ /* Randomize the buffer */ ++ len = (CK_ULONG) sizeof(buf); ++ rv = pkcs_C_GenerateRandom(hSession, buf, len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); ++ goto exit_key; ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_key; ++ } ++ ++ for (i = 0; i < count; i++) { ++ /* Initialize Sign */ ++ rv = pkcs_C_SignInit(hSession, &mech, hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_SignInit[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ ++ /* Perform Sign */ ++ slen = (CK_ULONG) sizeof(sig); ++ rv = pkcs_C_Sign(hSession, buf, len, sig, &slen); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_Sign[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_key; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u RSA signs in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g RSA signs/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_key: ++ if (hKey != CK_INVALID_HANDLE) { ++ rv = pkcs_C_DestroyObject(hSession, hKey); ++ if (rv != CKR_OK) ++ fprintf(stderr, ++ "C_DestroyObject: Error = 0x%.8lX\n", ++ rv); ++ } ++ ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/benchmarks/verify.c b/bin/tests/pkcs11/benchmarks/verify.c +new file mode 100644 +index 0000000..0a8f2c2 +--- /dev/null ++++ b/bin/tests/pkcs11/benchmarks/verify.c +@@ -0,0 +1,292 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* verify [-m module] [-s $slot] [-p pin] [-t] [-n count] */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <time.h> ++#include <unistd.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#ifndef HAVE_CLOCK_GETTIME ++#ifndef CLOCK_REALTIME ++#define CLOCK_REALTIME 0 ++#endif ++ ++int ++clock_gettime(int32_t id, struct timespec *tp) ++{ ++ struct timeval tv; ++ int result; ++ ++ result = gettimeofday(&tv, NULL); ++ if (result) ++ return (result); ++ tp->tv_sec = tv.tv_sec; ++ tp->tv_nsec = (long) tv.tv_usec * 1000; ++ return (result); ++} ++#endif ++ ++CK_BYTE modulus[] = { ++ 0x00, 0xb7, 0x9c, 0x1f, 0x05, 0xa3, 0xc2, 0x99, ++ 0x44, 0x82, 0x20, 0x78, 0x43, 0x7f, 0x5f, 0x3b, ++ 0x10, 0xd7, 0x9e, 0x61, 0x42, 0xd2, 0x7a, 0x90, ++ 0x50, 0x8a, 0x99, 0x33, 0xe7, 0xca, 0xc8, 0x5f, ++ 0x16, 0x1c, 0x56, 0xf8, 0xc1, 0x06, 0x2f, 0x96, ++ 0xe7, 0x54, 0xf2, 0x85, 0x89, 0x41, 0x36, 0xf5, ++ 0x4c, 0xa4, 0x0d, 0x62, 0xd3, 0x42, 0x51, 0x6b, ++ 0x9f, 0xdc, 0x36, 0xcb, 0xad, 0x56, 0xf4, 0xbd, ++ 0x2a, 0x60, 0x33, 0xb1, 0x7a, 0x99, 0xad, 0x08, ++ 0x9f, 0x95, 0xe8, 0xe5, 0x14, 0xd9, 0x68, 0x79, ++ 0xca, 0x4e, 0x72, 0xeb, 0xfb, 0x2c, 0xf1, 0x45, ++ 0xd3, 0x33, 0x65, 0xe7, 0xc5, 0x11, 0xdd, 0xe7, ++ 0x09, 0x83, 0x13, 0xd5, 0x17, 0x1b, 0xf4, 0xbd, ++ 0x49, 0xdd, 0x8a, 0x3c, 0x3c, 0xf7, 0xa1, 0x5d, ++ 0x7b, 0xb4, 0xd3, 0x80, 0x25, 0xf4, 0x05, 0x8f, ++ 0xbc, 0x2c, 0x2a, 0x47, 0xff, 0xd1, 0xc8, 0x34, ++ 0xbf ++}; ++CK_BYTE exponent[] = { 0x01, 0x00, 0x01 }; ++ ++CK_BYTE buf[1024]; ++CK_BYTE sig[128]; ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession = CK_INVALID_HANDLE; ++ CK_ULONG len; ++ CK_ULONG slen; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS kClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE kType = CKK_RSA; ++ CK_ATTRIBUTE kTemplate[] = ++ { ++ { CKA_CLASS, &kClass, (CK_ULONG) sizeof(kClass) }, ++ { CKA_KEY_TYPE, &kType, (CK_ULONG) sizeof(kType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS, modulus, (CK_ULONG) sizeof(modulus) }, ++ { CKA_PUBLIC_EXPONENT, exponent, (CK_ULONG) sizeof(exponent) } ++ }; ++ CK_MECHANISM mech = { CKM_SHA1_RSA_PKCS, NULL, 0 }; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_RSA; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ int c, errflg = 0; ++ int ontoken = 0; ++ unsigned int count = 1000; ++ unsigned int i; ++ struct timespec starttime; ++ struct timespec endtime; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:p:tn:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 't': ++ ontoken = 1; ++ break; ++ case 'n': ++ count = atoi(isc_commandline_argument); ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tverify [-m module] [-s slot] [-p pin] " ++ "[-t] [-n count]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_TRUE, ++ ISC_TRUE, (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NODIGESTSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ /* Create the private RSA key */ ++ if (ontoken) ++ kTemplate[2].pValue = &truevalue; ++ ++ rv = pkcs_C_CreateObject(hSession, kTemplate, 7, &hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_key; ++ } ++ ++ /* Randomize the buffer */ ++ len = (CK_ULONG) sizeof(buf); ++ rv = pkcs_C_GenerateRandom(hSession, buf, len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_GenerateRandom: Error = 0x%.8lX\n", rv); ++ goto exit_key; ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &starttime) < 0) { ++ perror("clock_gettime(start)"); ++ goto exit_key; ++ } ++ ++ for (i = 0; i < count; i++) { ++ /* Initialize Verify */ ++ rv = pkcs_C_VerifyInit(hSession, &mech, hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_VerifyInit[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ ++ /* Perform Verify */ ++ slen = (CK_ULONG) sizeof(sig); ++ rv = pkcs_C_Verify(hSession, buf, len, sig, slen); ++ if ((rv != CKR_OK) && (rv != CKR_SIGNATURE_INVALID)) { ++ fprintf(stderr, ++ "C_Verify[%u]: Error = 0x%.8lX\n", ++ i, rv); ++ error = 1; ++ break; ++ } ++ } ++ ++ if (clock_gettime(CLOCK_REALTIME, &endtime) < 0) { ++ perror("clock_gettime(end)"); ++ goto exit_key; ++ } ++ ++ endtime.tv_sec -= starttime.tv_sec; ++ endtime.tv_nsec -= starttime.tv_nsec; ++ while (endtime.tv_nsec < 0) { ++ endtime.tv_sec -= 1; ++ endtime.tv_nsec += 1000000000; ++ } ++ printf("%u RSA verify in %ld.%09lds\n", i, ++ endtime.tv_sec, endtime.tv_nsec); ++ if (i > 0) ++ printf("%g RSA verify/s\n", ++ 1024 * i / ((double) endtime.tv_sec + ++ (double) endtime.tv_nsec / 1000000000.)); ++ ++ exit_key: ++ if (hKey != CK_INVALID_HANDLE) { ++ rv = pkcs_C_DestroyObject(hSession, hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_DestroyObject: Error = 0x%.8lX\n", ++ rv); ++ errflg = 1; ++ } ++ } ++ ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/pkcs11-hmacmd5.c b/bin/tests/pkcs11/pkcs11-hmacmd5.c +new file mode 100644 +index 0000000..00a1df1 +--- /dev/null ++++ b/bin/tests/pkcs11/pkcs11-hmacmd5.c +@@ -0,0 +1,332 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* ++ * pkcs11-hmacmd5 ++ * ++ * Prints the MD5 HMAC of the standard input, using the PKCS#11 device. ++ * ++ * Usage: ++ * pkcs11-hmacmd5 [-m module] [-s $slot] [-n] [-p $pin] ++ * -m: PKCS#11 provider module. This must be the full ++ * path to a shared library object implementing the ++ * PKCS#11 API for a device. ++ * -s: Slot ++ * -p: PIN ++ * -n: don't log in to the PKCS#11 device ++ * -k: key name for the HMAC ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <fcntl.h> ++#include <errno.h> ++#include <string.h> ++#include <sys/types.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++/* Define static key template values */ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++#define BLOCKSIZE 32768 ++ ++char buffer[BLOCKSIZE + 72]; ++char digest[16]; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession; ++ CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 }; ++ CK_ULONG len; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_MD5_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, 0 } ++ }; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_DIGEST; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ isc_boolean_t logon = ISC_TRUE; ++ int c, errflg = 0; ++ char *key = NULL; ++ size_t sum = 0; ++ unsigned int i; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:np:k:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'n': ++ logon = ISC_FALSE; ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case 'k': ++ key = isc_commandline_argument; ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg || (key == NULL)) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tpkcs11-hmacmd5 [-m module] [-s slot] " ++ "[-n|-p pin] -k key\n"); ++ exit(1); ++ } ++ ++ /* Decode the key */ ++ for (i = 0; i < BLOCKSIZE / 2; i++) { ++ switch (c = *key++) { ++ case 0: ++ goto key_done; ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ if ((i & 1) == 0) ++ buffer[i >> 1] = (c - '0') << 4; ++ else ++ buffer[i >> 1] |= c - '0'; ++ break; ++ case 'A': ++ case 'B': ++ case 'C': ++ case 'D': ++ case 'E': ++ case 'F': ++ if ((i & 1) == 0) ++ buffer[i >> 1] = (c - 'A' + 10) << 4; ++ else ++ buffer[i >> 1] |= c - 'A' + 10; ++ break; ++ case 'a': ++ case 'b': ++ case 'c': ++ case 'd': ++ case 'e': ++ case 'f': ++ if ((i & 1) == 0) ++ buffer[i >> 1] = (c - 'a' + 10) << 4; ++ else ++ buffer[i >> 1] |= c - 'a' + 10; ++ break; ++ default: ++ fprintf(stderr, "Not hexdigit '%c' in key\n", c); ++ exit(1); ++ } ++ } ++ key_done: ++ if ((i & 1) != 0) { ++ fprintf(stderr, "Even number of hexdigits in key\n"); ++ exit(1); ++ } ++ len = i >> 1; ++ keyTemplate[5].pValue = buffer; ++ keyTemplate[5].ulValueLen = (CK_ULONG) len; ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (logon && pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, logon, ++ (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ rv = pkcs_C_CreateObject(hSession, keyTemplate, (CK_ULONG) 6, &hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_CreateObject: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_session; ++ } ++ if (hKey == CK_INVALID_HANDLE) { ++ fprintf(stderr, "C_CreateObject failed\n"); ++ error = 1; ++ goto exit_session; ++ } ++ ++ rv = pkcs_C_SignInit(hSession, &mech, hKey); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_SignInit: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_sign; ++ } ++ ++ for (;;) { ++ size_t n; ++ ++ for (;;) { ++ n = fread(buffer + sum, 1, BLOCKSIZE - sum, stdin); ++ sum += n; ++ if (sum == BLOCKSIZE) ++ break; ++ if (n == 0) { ++ if (ferror(stdin)) { ++ fprintf(stderr, "fread failed\n"); ++ error = 1; ++ goto exit_sign; ++ } ++ goto partial_block; ++ } ++ if (feof(stdin)) ++ goto partial_block; ++ } ++ ++ rv = pkcs_C_SignUpdate(hSession, (CK_BYTE_PTR) buffer, ++ (CK_ULONG) BLOCKSIZE); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_SignUpdate: Error = 0x%.8lX\n", ++ rv); ++ error = 1; ++ goto exit_sign; ++ } ++ } ++ ++partial_block: ++ if (sum > 0) { ++ rv = pkcs_C_SignUpdate(hSession, (CK_BYTE_PTR) buffer, ++ (CK_ULONG) sum); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_SignUpdate: Error = 0x%.8lX\n", ++ rv); ++ error = 1; ++ goto exit_sign; ++ } ++ } ++ ++ len = 16; ++ rv = pkcs_C_SignFinal(hSession, (CK_BYTE_PTR) digest, &len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_SignFinal: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_sign; ++ } ++ if (len != 16) { ++ fprintf(stderr, "C_SignFinal: bad length = %lu\n", len); ++ error = 1; ++ } ++ ++ for (i = 0; i < 16; i++) ++ printf("%02x", digest[i] & 0xff); ++ printf("\n"); ++ ++ exit_sign: ++ rv = pkcs_C_DestroyObject(hSession, hKey); ++ if ((error == 0) && (rv != CKR_OK)) { ++ fprintf(stderr, "C_DestroyObject: Error = 0x%.8lX\n", rv); ++ error = 1; ++ } ++ ++ exit_session: ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/pkcs11/pkcs11-md5sum.c b/bin/tests/pkcs11/pkcs11-md5sum.c +new file mode 100644 +index 0000000..fd50648 +--- /dev/null ++++ b/bin/tests/pkcs11/pkcs11-md5sum.c +@@ -0,0 +1,235 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* $Id$ */ ++ ++/* ++ * pkcs11-md5sum ++ * ++ * Prints the MD5 checksum of the standard input, using the PKCS#11 device. ++ * ++ * Usage: ++ * pkcs11-md5sum [-m module] [-s $slot] [-n] [-p $pin] ++ * -m: PKCS#11 provider module. This must be the full ++ * path to a shared library object implementing the ++ * PKCS#11 API for a device. ++ * -s: Slot ++ * -p: PIN ++ * -n: don't log in to the PKCS#11 device ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <fcntl.h> ++#include <errno.h> ++#include <string.h> ++#include <sys/types.h> ++ ++#include <isc/commandline.h> ++#include <isc/result.h> ++#include <isc/types.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/result.h> ++ ++#if !(defined(HAVE_GETPASSPHRASE) || (defined (__SVR4) && defined (__sun))) ++#define getpassphrase(x) getpass(x) ++#endif ++ ++#define BLOCKSIZE 32768 ++ ++char buffer[BLOCKSIZE + 72]; ++char digest[16]; ++ ++int ++main(int argc, char *argv[]) { ++ isc_result_t result; ++ CK_RV rv; ++ CK_SLOT_ID slot = 0; ++ CK_SESSION_HANDLE hSession; ++ CK_MECHANISM mech = { CKM_MD5, NULL, 0 }; ++ CK_ULONG len; ++ pk11_context_t pctx; ++ pk11_optype_t op_type = OP_DIGEST; ++ char *lib_name = NULL; ++ char *pin = NULL; ++ int error = 0; ++ isc_boolean_t logon = ISC_TRUE; ++ int c, errflg = 0; ++ size_t sum = 0; ++ unsigned int i; ++ ++ while ((c = isc_commandline_parse(argc, argv, ":m:s:np:")) != -1) { ++ switch (c) { ++ case 'm': ++ lib_name = isc_commandline_argument; ++ break; ++ case 's': ++ op_type = OP_ANY; ++ slot = atoi(isc_commandline_argument); ++ break; ++ case 'n': ++ logon = ISC_FALSE; ++ break; ++ case 'p': ++ pin = isc_commandline_argument; ++ break; ++ case ':': ++ fprintf(stderr, ++ "Option -%c requires an operand\n", ++ isc_commandline_option); ++ errflg++; ++ break; ++ case '?': ++ default: ++ fprintf(stderr, "Unrecognised option: -%c\n", ++ isc_commandline_option); ++ errflg++; ++ } ++ } ++ ++ if (errflg) { ++ fprintf(stderr, "Usage:\n"); ++ fprintf(stderr, ++ "\tpkcs11-md5sum [-m module] [-s slot] [-n|-p pin]\n"); ++ exit(1); ++ } ++ ++ pk11_result_register(); ++ ++ /* Initialize the CRYPTOKI library */ ++ if (lib_name != NULL) ++ pk11_set_lib_name(lib_name); ++ ++ if (logon && pin == NULL) ++ pin = getpassphrase("Enter Pin: "); ++ ++ result = pk11_get_session(&pctx, op_type, ISC_FALSE, ISC_FALSE, logon, ++ (const char *) pin, slot); ++ if ((result != ISC_R_SUCCESS) && ++ (result != PK11_R_NORANDOMSERVICE) && ++ (result != PK11_R_NOAESSERVICE)) { ++ fprintf(stderr, "Error initializing PKCS#11: %s\n", ++ isc_result_totext(result)); ++ exit(1); ++ } ++ ++ if (pin != NULL) ++ memset(pin, 0, strlen((char *)pin)); ++ ++ hSession = pctx.session; ++ ++ rv = pkcs_C_DigestInit(hSession, &mech); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_DigestInit: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_session; ++ } ++ ++ for (;;) { ++ size_t n; ++ ++ for (;;) { ++ n = fread(buffer + sum, 1, BLOCKSIZE - sum, stdin); ++ sum += n; ++ if (sum == BLOCKSIZE) ++ break; ++ if (n == 0) { ++ if (ferror(stdin)) { ++ fprintf(stderr, "fread failed\n"); ++ error = 1; ++ goto exit_session; ++ } ++ goto partial_block; ++ } ++ if (feof(stdin)) ++ goto partial_block; ++ } ++ ++ rv = pkcs_C_DigestUpdate(hSession, (CK_BYTE_PTR) buffer, ++ (CK_ULONG) BLOCKSIZE); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_DigestUpdate: Error = 0x%.8lX\n", ++ rv); ++ error = 1; ++ goto exit_session; ++ } ++ } ++ ++partial_block: ++ if (sum > 0) { ++ rv = pkcs_C_DigestUpdate(hSession, (CK_BYTE_PTR) buffer, ++ (CK_ULONG) sum); ++ if (rv != CKR_OK) { ++ fprintf(stderr, ++ "C_DigestUpdate: Error = 0x%.8lX\n", ++ rv); ++ error = 1; ++ goto exit_session; ++ } ++ } ++ ++ len = 16; ++ rv = pkcs_C_DigestFinal(hSession, (CK_BYTE_PTR) digest, &len); ++ if (rv != CKR_OK) { ++ fprintf(stderr, "C_DigestFinal: Error = 0x%.8lX\n", rv); ++ error = 1; ++ goto exit_session; ++ } ++ if (len != 16) { ++ fprintf(stderr, "C_DigestFinal: bad length = %lu\n", len); ++ error = 1; ++ } ++ ++ for (i = 0; i < 16; i++) ++ printf("%02x", digest[i] & 0xff); ++ printf("\n"); ++ ++ exit_session: ++ pk11_return_session(&pctx); ++ (void) pk11_finalize(); ++ ++ exit(error); ++} +diff --git a/bin/tests/system/autosign/prereq.sh b/bin/tests/system/autosign/prereq.sh +index 34cd4a1..53807a2 100644 +--- a/bin/tests/system/autosign/prereq.sh ++++ b/bin/tests/system/autosign/prereq.sh +@@ -25,6 +25,7 @@ if $KEYGEN -q -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1 + then + rm -f Kfoo* + else +- echo "I:This test requires that --with-openssl was used." >&2 ++ echo "I:This test requires cryptography" >&2 ++ echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2 + exit 1 + fi +diff --git a/bin/tests/system/cleanpkcs11.sh b/bin/tests/system/cleanpkcs11.sh +index e1cbc6f..ba541ed 100644 +--- a/bin/tests/system/cleanpkcs11.sh ++++ b/bin/tests/system/cleanpkcs11.sh +@@ -16,6 +16,10 @@ + + # $Id: cleanpkcs11.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $ + ++SYSTEMTESTTOP=. ++. $SYSTEMTESTTOP/conf.sh ++ ++ + if [ ! -x ../../pkcs11/pkcs11-destroy ]; then exit 1; fi + +-../../pkcs11/pkcs11-destroy -s ${SLOT:-0} -p 1234 ++$PK11DEL -w0 > /dev/null 2>&1 +diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in +index d6e902f..c40e8f1 100644 +--- a/bin/tests/system/conf.sh.in ++++ b/bin/tests/system/conf.sh.in +@@ -47,9 +47,9 @@ CHECKDS=$TOP/bin/python/dnssec-checkds + COVERAGE=$TOP/bin/python/dnssec-coverage + CHECKZONE=$TOP/bin/check/named-checkzone + CHECKCONF=$TOP/bin/check/named-checkconf +-PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -s ${SLOT:-0} -p 1234" +-PK11LIST="$TOP/bin/pkcs11/pkcs11-list -s ${SLOT:-0} -p 1234" +-PK11DEL="$TOP/bin/pkcs11/pkcs11-destroy -s ${SLOT:-0} -p 1234" ++PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -q -s ${SLOT:-0} -p ${HSMPIN:-1234}" ++PK11LIST="$TOP/bin/pkcs11/pkcs11-list -s ${SLOT:-0} -p ${HSMPIN:-1234}" ++PK11DEL="$TOP/bin/pkcs11/pkcs11-destroy -s ${SLOT:-0} -p ${HSMPIN:-1234} -w 0" + JOURNALPRINT=$TOP/bin/tools/named-journalprint + VERIFY=$TOP/bin/dnssec/dnssec-verify + ARPANAME=$TOP/bin/tools/arpaname +@@ -63,7 +63,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin + database dlv dlvauto dlz dlzexternal dname dns64 dnssec ecdsa + formerr forward glue gost ixfr inline limits logfileconfig + lwresd masterfile masterformat metadata notify nsupdate pending +- pkcs11 redirect resolver rndc rpz rrl rrsetorder rsabigexponent ++ @PKCS11_TEST@ redirect resolver rndc rpz rrl rrsetorder rsabigexponent + smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown + upforwd verify views wildcard xfer xferquota zero zonechecks" + +diff --git a/bin/tests/system/dnssec/prereq.sh b/bin/tests/system/dnssec/prereq.sh +index cb7c0c7..113e372 100644 +--- a/bin/tests/system/dnssec/prereq.sh ++++ b/bin/tests/system/dnssec/prereq.sh +@@ -23,6 +23,7 @@ if $KEYGEN -q -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1 + then + rm -f Kfoo* + else +- echo "I:This test requires that --with-openssl was used." >&2 ++ echo "I:This test requires cryptography" >&2 ++ echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2 + exit 1 + fi +diff --git a/bin/tests/system/ecdsa/prereq.sh.in b/bin/tests/system/ecdsa/prereq.sh.in +index 434b53c..4214a30 100644 +--- a/bin/tests/system/ecdsa/prereq.sh.in ++++ b/bin/tests/system/ecdsa/prereq.sh.in +@@ -16,9 +16,16 @@ + + # $Id$ + +-OPENSSL_ECDSA="@OPENSSL_ECDSA@" +-if test -z "$OPENSSL_ECDSA" +-then +- echo "I:This test requires a openssl version with ecdsa support." >&2 ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++../../../tools/genrandom 400 random.data ++ ++fail=0 ++$KEYGEN -q -a ecdsap256sha256 test > /dev/null 2>&1 || fail=1 ++rm -f Ktest* random.data ++ ++if [ $fail != 0 ] ++ then ++ echo "I:This test requires support for ECDSA cryptography." >&2 + exit 255 + fi +diff --git a/bin/tests/system/gost/prereq.sh.in b/bin/tests/system/gost/prereq.sh.in +index 98ec507..0e4079e 100644 +--- a/bin/tests/system/gost/prereq.sh.in ++++ b/bin/tests/system/gost/prereq.sh.in +@@ -16,9 +16,16 @@ + + # $Id: prereq.sh.in,v 1.4 2010/12/27 13:38:43 marka Exp $ + +-OPENSSL_GOST="@OPENSSL_GOST@" +-if test -z "$OPENSSL_GOST" +-then +- echo "I:This test requires a openssl version with gost support." >&2 ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++../../../tools/genrandom 400 random.data ++ ++fail=0 ++$KEYGEN -q -a eccgost test > /dev/null 2>&1 || fail=1 ++rm -f Ktest* random.data ++ ++if [ $fail != 0 ] ++ then ++ echo "I:This test requires support for GOST cryptography." >&2 + exit 255 + fi +diff --git a/bin/tests/system/inline/clean.sh b/bin/tests/system/inline/clean.sh +index dae21e5..b6dda0b 100644 +--- a/bin/tests/system/inline/clean.sh ++++ b/bin/tests/system/inline/clean.sh +@@ -74,7 +74,7 @@ rm -f ns5/bits.bk.signed + rm -f ns5/bits.bk.signed.jnl + rm -f */*.jbk + rm -f random.data +-rm -f dig.out.ns*.test* ++rm -f dig.out.ns* + rm -f signing.out* + rm -f freeze.test* + rm -f thaw.test* +diff --git a/bin/tests/system/metadata/prereq.sh b/bin/tests/system/metadata/prereq.sh +index b7ce1ea..006bcf5 100644 +--- a/bin/tests/system/metadata/prereq.sh ++++ b/bin/tests/system/metadata/prereq.sh +@@ -22,6 +22,7 @@ if $KEYGEN -q -r random.data foo > /dev/null 2>&1 + then + rm -f Kfoo* + else +- echo "I:This test requires that --with-openssl was used." >&2 ++ echo "I:This test requires cryptography" >&2 ++ echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2 + exit 1 + fi +diff --git a/bin/tests/system/pending/prereq.sh b/bin/tests/system/pending/prereq.sh +index 0b6998e..f0848d7 100644 +--- a/bin/tests/system/pending/prereq.sh ++++ b/bin/tests/system/pending/prereq.sh +@@ -16,12 +16,25 @@ + + # $Id: prereq.sh,v 1.3 2009/11/18 23:48:06 tbox Exp $ + ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh + ../../../tools/genrandom 400 random.data + +-if $KEYGEN -q -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1 +-then +- rm -f Kfoo* ++rsafail=0 eccfail=0 ++ ++$KEYGEN -q -r random.data foo > /dev/null 2>&1 || rsafail=1 ++rm -f Kfoo* ++ ++$KEYGEN -q -a ECDSAP256SHA256 -r random.data foo > /dev/null 2>&1 || eccfail=1 ++rm -f Kfoo* ++ ++if [ $rsafail = 0 -a $eccfail = 0 ]; then ++ echo both > supported ++elif [ $rsafail = 1 -a $eccfail = 1 ]; then ++ echo "I:This test requires PKCS#11 support for either RSA or ECDSA cryptography." >&2 ++ exit 255 ++elif [ $rsafail = 0 ]; then ++ echo rsaonly > supported + else +- echo "I:This test requires that --with-openssl was used." >&2 +- exit 1 ++ echo ecconly > supported + fi +diff --git a/bin/tests/system/pkcs11/clean.sh b/bin/tests/system/pkcs11/clean.sh +index d7a557b..29d0149 100644 +--- a/bin/tests/system/pkcs11/clean.sh ++++ b/bin/tests/system/pkcs11/clean.sh +@@ -17,5 +17,6 @@ + # $Id: clean.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $ + + rm -f K* ns1/K* keyset-* dsset-* ns1/*.db ns1/*.signed ns1/*.jnl +-rm -f dig.out random.data +-rm -f ns1/key ns1/named.memstats ++rm -f dig.out random.data pin ++rm -f ns1/*.key ns1/named.memstats ++rm -f supported +diff --git a/bin/tests/system/pkcs11/ns1/named.conf b/bin/tests/system/pkcs11/ns1/named.conf +index 09a850f..48b8adf 100644 +--- a/bin/tests/system/pkcs11/ns1/named.conf ++++ b/bin/tests/system/pkcs11/ns1/named.conf +@@ -39,8 +39,14 @@ controls { + inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; }; + }; + +-zone "example." { ++zone "rsa.example." { ++ type master; ++ file "rsa.example.db.signed"; ++ allow-update { any; }; ++}; ++ ++zone "ecc.example." { + type master; +- file "example.db.signed"; ++ file "ecc.example.db.signed"; + allow-update { any; }; + }; +diff --git a/bin/tests/system/pkcs11/setup.sh b/bin/tests/system/pkcs11/setup.sh +index c044d75..a17a83d 100644 +--- a/bin/tests/system/pkcs11/setup.sh ++++ b/bin/tests/system/pkcs11/setup.sh +@@ -21,21 +21,59 @@ SYSTEMTESTTOP=.. + + RANDFILE=random.data + +-zone=example + infile=ns1/example.db.in +-zonefile=ns1/example.db + +-$PK11GEN -b 1024 -l robie-zsk1 -i 01 +-$PK11GEN -b 1024 -l robie-zsk2 -i 02 +-$PK11GEN -b 2048 -l robie-ksk ++/bin/echo -n ${HSMPIN:-1234}> pin ++PWD=`pwd` + +-zsk1=`$KEYFRLAB -a RSASHA1 -l robie-zsk1 example` +-zsk2=`$KEYFRLAB -a RSASHA1 -l robie-zsk2 example` +-ksk=`$KEYFRLAB -a RSASHA1 -f ksk -l robie-ksk example` ++supported=`cat supported` + +-cat $infile $zsk1.key $ksk.key > $zonefile +-$SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile > /dev/null 2> signer.err || cat signer.err +-rm -f signer.err ++zone=rsa.example ++zonefile=ns1/rsa.example.db ++if [ "$supported" != "ecconly" ]; then ++ $PK11GEN -a RSA -b 1024 -l robie-rsa-zsk1 -i 01 ++ $PK11GEN -a RSA -b 1024 -l robie-rsa-zsk2 -i 02 ++ $PK11GEN -a RSA -b 2048 -l robie-rsa-ksk ++ ++ rsazsk1=`$KEYFRLAB -a RSASHA1 \ ++ -l "object=robie-rsa-zsk1;pin-source=$PWD/pin" rsa.example` ++ rsazsk2=`$KEYFRLAB -a RSASHA1 \ ++ -l "object=robie-rsa-zsk2;pin-source=$PWD/pin" rsa.example` ++ rsaksk=`$KEYFRLAB -a RSASHA1 -f ksk \ ++ -l "object=robie-rsa-ksk;pin-source=$PWD/pin" rsa.example` ++ ++ cat $infile $rsazsk1.key $rsaksk.key > $zonefile ++ $SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \ ++ > /dev/null 2> signer.err || cat signer.err ++ cp $rsazsk2.key ns1/rsa.key ++ mv Krsa* ns1 ++else ++ # RSA not available and will not be tested; make a placeholder ++ cp $infile ${zonefile}.signed ++fi ++ ++zone=ecc.example ++zonefile=ns1/ecc.example.db ++if [ "$supported" != "rsaonly" ]; then ++ $PK11GEN -a ECC -b 256 -l robie-ecc-zsk1 -i 03 ++ $PK11GEN -a ECC -b 256 -l robie-ecc-zsk2 -i 04 ++ $PK11GEN -a ECC -b 384 -l robie-ecc-ksk + +-cp $zsk2.key ns1/key +-mv Kexample* ns1 ++ ecczsk1=`$KEYFRLAB -a ECDSAP256SHA256 \ ++ -l "object=robie-ecc-zsk1;pin-source=$PWD/pin" ecc.example` ++ ecczsk2=`$KEYFRLAB -a ECDSAP256SHA256 \ ++ -l "object=robie-ecc-zsk2;pin-source=$PWD/pin" ecc.example` ++ eccksk=`$KEYFRLAB -a ECDSAP384SHA384 -f ksk \ ++ -l "object=robie-ecc-ksk;pin-source=$PWD/pin" ecc.example` ++ ++ cat $infile $ecczsk1.key $eccksk.key > $zonefile ++ $SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \ ++ > /dev/null 2> signer.err || cat signer.err ++ cp $ecczsk2.key ns1/ecc.key ++ mv Kecc* ns1 ++else ++ # ECC not available and will not be tested; make a placeholder ++ cp $infile ${zonefile}.signed ++fi ++ ++rm -f signer.err +diff --git a/bin/tests/system/pkcs11/tests.sh b/bin/tests/system/pkcs11/tests.sh +index 4694afc..01f1523 100644 +--- a/bin/tests/system/pkcs11/tests.sh ++++ b/bin/tests/system/pkcs11/tests.sh +@@ -26,47 +26,59 @@ DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p 5300" + status=0 + ret=0 + +-zonefile=ns1/example.db ++supported=`cat supported` ++case $supported in ++ rsaonly) algs="rsa" ;; ++ ecconly) algs="ecc" ;; ++ both) algs="rsa ecc" ;; ++esac + +-echo "I:testing PKCS#11 key generation" ++for alg in $algs; do ++ zonefile=ns1/$alg.example.db ++ echo "I:testing PKCS#11 key generation ($alg)" ++ count=`$PK11LIST | grep robie-$alg-ksk | wc -l` ++ if [ $count != 2 ]; then echo "I:failed"; status=1; fi + +-count=`$PK11LIST | grep robie-ksk | wc -l` +-if [ $count != 2 ]; then echo "I:failed"; status=1; fi ++ echo "I:testing offline signing with PKCS#11 keys ($alg)" + +-echo "I:testing offline signing with PKCS#11 keys" ++ count=`grep RRSIG $zonefile.signed | wc -l` ++ if [ $count != 12 ]; then echo "I:failed"; status=1; fi + +-count=`grep RRSIG $zonefile.signed | wc -l` +-if [ $count != 12 ]; then echo "I:failed"; status=1; fi ++ echo "I:testing inline signing with PKCS#11 keys ($alg)" + +-echo "I:testing inline signing with PKCS#11 keys" ++ $NSUPDATE > /dev/null <<END || status=1 + +-$NSUPDATE > /dev/null <<END || status=1 + server 10.53.0.1 5300 + ttl 300 +-zone example. +-update add `grep -v ';' ns1/key` ++zone $alg.example. ++update add `grep -v ';' ns1/${alg}.key` + send + END + +-echo "I:waiting 20 seconds for key changes to take effect" +-sleep 20 +- +-$DIG $DIGOPTS ns.example. @10.53.0.1 a > dig.out || ret=1 +-if [ $ret != 0 ]; then echo "I:failed"; fi +-status=`expr $status + $ret` +-count=`grep RRSIG dig.out | wc -l` +-if [ $count != 4 ]; then echo "I:failed"; status=1; fi +- +-echo "I:testing PKCS#11 key destroy" +- +-ret=0 +-$PK11DEL -l robie-zsk1 || ret=1 +-$PK11DEL -i 02 || ret=1 +-if [ $ret != 0 ]; then echo "I:failed"; fi +-status=`expr $status + $ret` +-count=`$PK11LIST | grep robie-zsk | wc -l` +-if [ $count != 0 ]; then echo "I:failed"; fi +-status=`expr $status + $count` ++ echo "I:waiting 20 seconds for key changes to take effect" ++ sleep 20 ++ ++ $DIG $DIGOPTS ns.$alg.example. @10.53.0.1 a > dig.out || ret=1 ++ if [ $ret != 0 ]; then echo "I:failed"; fi ++ status=`expr $status + $ret` ++ count=`grep RRSIG dig.out | wc -l` ++ if [ $count != 4 ]; then echo "I:failed"; status=1; fi ++ ++ echo "I:testing PKCS#11 key destroy ($alg)" ++ ret=0 ++ $PK11DEL -l robie-$alg-ksk -w0 > /dev/null 2>&1 || ret=1 ++ $PK11DEL -l robie-$alg-zsk1 -w0 > /dev/null 2>&1 || ret=1 ++ case $alg in ++ rsa) id=02 ;; ++ ecc) id=04 ;; ++ esac ++ $PK11DEL -i $id -w0 > /dev/null 2>&1 || ret=1 ++ if [ $ret != 0 ]; then echo "I:failed"; fi ++ status=`expr $status + $ret` ++ count=`$PK11LIST | grep robie-$alg | wc -l` ++ if [ $count != 0 ]; then echo "I:failed"; fi ++ status=`expr $status + $count` ++done + + echo "I:exit status: $status" + exit $status +diff --git a/bin/tests/system/pkcs11ssl/clean.sh b/bin/tests/system/pkcs11ssl/clean.sh +new file mode 100644 +index 0000000..14ec725 +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/clean.sh +@@ -0,0 +1,20 @@ ++#!/bin/sh ++# ++# Copyright (C) 2010, 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++rm -f K* ns1/K* keyset-* dsset-* ns1/*.db ns1/*.signed ns1/*.jnl ++rm -f dig.out random.data pin ++rm -f ns1/*.key ns1/named.memstats ++rm -f supported +diff --git a/bin/tests/system/pkcs11ssl/ns1/example.db.in b/bin/tests/system/pkcs11ssl/ns1/example.db.in +new file mode 100644 +index 0000000..7166fa8 +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/ns1/example.db.in +@@ -0,0 +1,29 @@ ++; Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") ++; ++; Permission to use, copy, modify, and/or distribute this software for any ++; purpose with or without fee is hereby granted, provided that the above ++; copyright notice and this permission notice appear in all copies. ++; ++; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++; PERFORMANCE OF THIS SOFTWARE. ++ ++; $Id: example.db.in,v 1.3 2010/06/08 23:50:24 tbox Exp $ ++ ++$TTL 300 ; 5 minutes ++@ IN SOA ns root ( ++ 2000082401 ; serial ++ 1800 ; refresh (30 minutes) ++ 1800 ; retry (30 minutes) ++ 1814400 ; expire (3 weeks) ++ 3600 ; minimum (1 hour) ++ ) ++ NS ns ++ns A 10.53.0.1 ++ ++txt TXT "recursed" ++ +diff --git a/bin/tests/system/pkcs11ssl/ns1/named.conf b/bin/tests/system/pkcs11ssl/ns1/named.conf +new file mode 100644 +index 0000000..90b8117 +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/ns1/named.conf +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id: named.conf,v 1.3 2010/06/08 23:50:24 tbox Exp $ */ ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.1; ++ notify-source 10.53.0.1; ++ transfer-source 10.53.0.1; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.1; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ notify no; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++zone "rsa.example." { ++ type master; ++ file "rsa.example.db.signed"; ++ allow-update { any; }; ++}; ++ ++zone "ecc.example." { ++ type master; ++ file "ecc.example.db.signed"; ++ allow-update { any; }; ++}; +diff --git a/bin/tests/system/pkcs11ssl/prereq.sh b/bin/tests/system/pkcs11ssl/prereq.sh +new file mode 100644 +index 0000000..b5133f4 +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/prereq.sh +@@ -0,0 +1,34 @@ ++#!/bin/sh ++# ++# Copyright (C) 2010, 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# $Id: prereq.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $ ++ ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++../../../tools/genrandom 400 random.data ++ ++echo rsaonly > supported ++exit 0 ++ ++rsafail=0 eccfail=0 ++ ++$KEYGEN -q -r random.data foo > /dev/null 2>&1 || rsafail=1 ++rm -f Kfoo* ++ ++if [ $rsafail = 1 ]; then ++ echo "I:This test requires OpenSSL built with PKCS#11 support." >&2 ++ exit 255 ++fi +diff --git a/bin/tests/system/pkcs11ssl/setup.sh b/bin/tests/system/pkcs11ssl/setup.sh +new file mode 100644 +index 0000000..c13b275 +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/setup.sh +@@ -0,0 +1,46 @@ ++#!/bin/sh ++# ++# Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++ ++RANDFILE=random.data ++infile=ns1/example.db.in ++ ++/bin/echo -n ${HSMPIN:-1234}> pin ++PWD=`pwd` ++ ++zone=rsa.example ++zonefile=ns1/rsa.example.db ++ ++$PK11GEN -a RSA -b 1024 -l robie-rsa-zsk1 -i 01 ++$PK11GEN -a RSA -b 1024 -l robie-rsa-zsk2 -i 02 ++$PK11GEN -a RSA -b 2048 -l robie-rsa-ksk ++ ++rsazsk1=`$KEYFRLAB -a RSASHA1 \ ++ -l "robie-rsa-zsk1" rsa.example` ++rsazsk2=`$KEYFRLAB -a RSASHA1 \ ++ -l "robie-rsa-zsk2" rsa.example` ++rsaksk=`$KEYFRLAB -a RSASHA1 -f ksk \ ++ -l "robie-rsa-ksk" rsa.example` ++ ++cat $infile $rsazsk1.key $rsaksk.key > $zonefile ++$SIGNER -a -P -g -r $RANDFILE -o $zone $zonefile \ ++ > /dev/null 2> signer.err || cat signer.err ++cp $rsazsk2.key ns1/rsa.key ++mv Krsa* ns1 ++ ++rm -f signer.err +diff --git a/bin/tests/system/pkcs11ssl/tests.sh b/bin/tests/system/pkcs11ssl/tests.sh +new file mode 100644 +index 0000000..7785d5a +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/tests.sh +@@ -0,0 +1,71 @@ ++#!/bin/sh ++# ++# Copyright (C) 2010, 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# $Id: tests.sh,v 1.3 2010/06/08 23:50:24 tbox Exp $ ++ ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++ ++RANDFILE=random.data ++ ++DIGOPTS="+tcp +noadd +nosea +nostat +nocmd +dnssec -p 5300" ++ ++status=0 ++ret=0 ++ ++alg=rsa ++zonefile=ns1/rsa.example.db ++echo "I:testing PKCS#11 key generation (rsa)" ++count=`$PK11LIST | grep robie-rsa-ksk | wc -l` ++if [ $count != 2 ]; then echo "I:failed"; status=1; fi ++ ++echo "I:testing offline signing with PKCS#11 keys (rsa)" ++ ++count=`grep RRSIG $zonefile.signed | wc -l` ++if [ $count != 12 ]; then echo "I:failed"; status=1; fi ++ ++echo "I:testing inline signing with PKCS#11 keys (rsa)" ++ ++$NSUPDATE > /dev/null <<END || status=1 ++server 10.53.0.1 5300 ++ttl 300 ++zone rsa.example. ++update add `grep -v ';' ns1/${alg}.key` ++send ++END ++ ++echo "I:waiting 20 seconds for key changes to take effect" ++sleep 20 ++ ++$DIG $DIGOPTS ns.rsa.example. @10.53.0.1 a > dig.out || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++count=`grep RRSIG dig.out | wc -l` ++if [ $count != 4 ]; then echo "I:failed"; status=1; fi ++ ++echo "I:testing PKCS#11 key destroy (rsa)" ++ret=0 ++$PK11DEL -l robie-rsa-ksk -w0 > /dev/null 2>&1 || ret=1 ++$PK11DEL -l robie-rsa-zsk1 -w0 > /dev/null 2>&1 || ret=1 ++$PK11DEL -i $id -w0 > /dev/null 2>&1 || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++count=`$PK11LIST | grep robie-rsa | wc -l` ++if [ $count != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $count` ++ ++echo "I:exit status: $status" ++exit $status +diff --git a/bin/tests/system/pkcs11ssl/usepkcs11 b/bin/tests/system/pkcs11ssl/usepkcs11 +new file mode 100644 +index 0000000..ef46412 +--- /dev/null ++++ b/bin/tests/system/pkcs11ssl/usepkcs11 +@@ -0,0 +1 @@ ++This test relies on PKCS#11! +diff --git a/bin/tests/system/rsabigexponent/Makefile.in b/bin/tests/system/rsabigexponent/Makefile.in +index d32eb15..ce8958b 100644 +--- a/bin/tests/system/rsabigexponent/Makefile.in ++++ b/bin/tests/system/rsabigexponent/Makefile.in +@@ -24,7 +24,7 @@ top_srcdir = @top_srcdir@ + + CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} @DST_OPENSSL_INC@ + +-CDEFINES = @USE_OPENSSL@ ++CDEFINES = @CRYPTO@ + CWARNINGS = + + DNSLIBS = ../../../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +diff --git a/bin/tests/system/rsabigexponent/bigkey.c b/bin/tests/system/rsabigexponent/bigkey.c +index aa2e8ec..436254c 100644 +--- a/bin/tests/system/rsabigexponent/bigkey.c ++++ b/bin/tests/system/rsabigexponent/bigkey.c +@@ -16,7 +16,7 @@ + + /* $Id$ */ + +-#ifdef OPENSSL ++#if defined(OPENSSL) || defined(PKCS11CRYPTO) + #include <config.h> + + #include <stdio.h> +@@ -44,8 +44,16 @@ + #include <dst/dst.h> + #include <dst/result.h> + ++#ifdef OPENSSL + #include <openssl/opensslv.h> + #if OPENSSL_VERSION_NUMBER <= 0x00908000L ++#define USE_FIX_KEY_FILES ++#endif ++#else ++#define USE_FIX_KEY_FILES ++#endif ++ ++#ifdef USE_FIX_KEY_FILES + + /* + * Use a fixed key file pair if OpenSSL doesn't support > 32 bit exponents. +@@ -235,16 +243,16 @@ main(int argc, char **argv) { + } + #endif + +-#else /* OPENSSL */ ++#else /* OPENSSL || PKCS11CRYPTO */ + + #include <stdio.h> + #include <stdlib.h> + + int +-main(int argc, char **argv) { +- fprintf(stderr, "Compiled without OpenSSL\n"); ++main() { ++ fprintf(stderr, "Compiled without Crypto\n"); + exit(1); + } + +-#endif /* OPENSSL */ ++#endif /* OPENSSL || PKCS11CRYPTO */ + /*! \file */ +diff --git a/bin/tests/system/rsabigexponent/prereq.sh b/bin/tests/system/rsabigexponent/prereq.sh +index 8edbf1d..6259fb6 100644 +--- a/bin/tests/system/rsabigexponent/prereq.sh ++++ b/bin/tests/system/rsabigexponent/prereq.sh +@@ -22,6 +22,7 @@ if ./bigkey > /dev/null 2>&1 + then + rm -f Kexample.* + else +- echo "I:This test requires that --with-openssl was used." >&2 ++ echo "I:This test requires cryptography" >&2 ++ echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2 + exit 1 + fi +diff --git a/bin/tests/system/smartsign/prereq.sh b/bin/tests/system/smartsign/prereq.sh +index e47b769..9ed2fa8 100644 +--- a/bin/tests/system/smartsign/prereq.sh ++++ b/bin/tests/system/smartsign/prereq.sh +@@ -22,6 +22,7 @@ if $KEYGEN -q -r random.data foo > /dev/null 2>&1 + then + rm -f Kfoo* + else +- echo "I:This test requires that --with-openssl was used." >&2 ++ echo "I:This test requires cryptography" >&2 ++ echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2 + exit 1 + fi +diff --git a/bin/tests/system/tkey/keycreate.c b/bin/tests/system/tkey/keycreate.c +index ff2c2ee..af17582 100644 +--- a/bin/tests/system/tkey/keycreate.c ++++ b/bin/tests/system/tkey/keycreate.c +@@ -228,6 +228,7 @@ main(int argc, char *argv[]) { + dns_result_register(); + + mctx = NULL; ++ isc_mem_debugging = ISC_MEM_DEBUGRECORD; + RUNCHECK(isc_mem_create(0, 0, &mctx)); + + ectx = NULL; +diff --git a/bin/tests/system/tkey/prereq.sh b/bin/tests/system/tkey/prereq.sh +index fca4a27..66295fe 100644 +--- a/bin/tests/system/tkey/prereq.sh ++++ b/bin/tests/system/tkey/prereq.sh +@@ -23,6 +23,7 @@ if $KEYGEN -a RSAMD5 -b 512 -n zone -r random.data foo > /dev/null 2>&1 + then + rm -f foo* + else +- echo "I:This test requires that --with-openssl was used." >&2 ++ echo "I:This test requires cryptography" >&2 ++ echo "I:--with-openssl, or --with-pkcs11 and --enable-native-pkcs11" >&2 + exit 1 + fi +diff --git a/config.h.in b/config.h.in +index 4139e1d..f2eb59a 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -132,14 +132,11 @@ int sigwait(const unsigned int *set, int *sig); + /** define if you have strerror in the C library. */ + #undef HAVE_STRERROR + +-/** Define if you are running under Compaq TruCluster. */ +-#undef HAVE_TRUCLUSTER +- + /* Define if OpenSSL includes DSA support */ + #undef HAVE_OPENSSL_DSA + +-/* Define if OpenSSL includes ECDSA support */ +-#undef HAVE_OPENSSL_ECDSA ++/* Define if you have getpassphrase in the C library. */ ++#undef HAVE_GETPASSPHRASE + + /* Define to the length type used by the socket API (socklen_t, size_t, int). */ + #undef ISC_SOCKADDR_LEN_T +@@ -187,6 +184,9 @@ int sigwait(const unsigned int *set, int *sig); + /* Define to 1 if you have the `chroot' function. */ + #undef HAVE_CHROOT + ++/* Define if clock_gettime is available. */ ++#undef HAVE_CLOCK_GETTIME ++ + /* Define to 1 if you have the <devpoll.h> header file. */ + #undef HAVE_DEVPOLL_H + +@@ -292,6 +292,12 @@ int sigwait(const unsigned int *set, int *sig); + /* Define if your OpenSSL version supports GOST. */ + #undef HAVE_OPENSSL_GOST + ++/* Define if your PKCS11 provider supports ECDSA. */ ++#undef HAVE_PKCS11_ECDSA ++ ++/* Define if your PKCS11 provider supports GOST. */ ++#undef HAVE_PKCS11_GOST ++ + /* Define to 1 if you have the `readline' function. */ + #undef HAVE_READLINE + +@@ -418,6 +424,9 @@ int sigwait(const unsigned int *set, int *sig); + (O_NDELAY/O_NONBLOCK). */ + #undef PORT_NONBLOCK + ++/* Define if GOST private keys are encoded in ASN.1. */ ++#undef PREFER_GOSTASN1 ++ + /* The size of `void *', as computed by sizeof. */ + /* #undef SIZEOF_VOID_P */ + +diff --git a/configure.in b/configure.in +index 8a06905..24eafb7 100644 +--- a/configure.in ++++ b/configure.in +@@ -640,25 +640,76 @@ AC_ARG_WITH(openssl, + (Required for DNSSEC)], + use_openssl="$withval", use_openssl="auto") + ++# ++# was --enable-native-pkcs11 specified? ++# (note it implies both --without-openssl and --with-pkcs11) ++# ++AC_ARG_ENABLE(native-pkcs11, ++ [ --enable-native-pkcs11 use native PKCS11 for all crypto [[default=no]]], ++ want_native_pkcs11="$enableval", want_native_pkcs11="no") ++ ++AC_ARG_WITH(pkcs11, ++[ --with-pkcs11[=PATH] Build with PKCS11 support [yes|no|path] ++ (PATH is for the PKCS11 provider)], ++ use_pkcs11="$withval", use_pkcs11="auto") ++ + openssldirs="/usr /usr/local /usr/local/ssl /usr/pkg /usr/sfw" + if test "$use_openssl" = "auto" + then +- for d in $openssldirs +- do +- if test -f $d/include/openssl/opensslv.h +- then +- use_openssl=$d +- break +- fi +- done ++ if test "$want_native_pkcs11" = "yes" ++ then ++ use_openssl="native_pkcs11" ++ else ++ for d in $openssldirs ++ do ++ if test -f $d/include/openssl/opensslv.h ++ then ++ use_openssl=$d ++ break ++ fi ++ done ++ fi + fi + OPENSSL_ECDSA="" + OPENSSL_GOST="" ++AC_ARG_WITH(gost, ++[ --with-gost Crypto GOST [yes|no|raw|asn1].], ++ with_gost="$withval", with_gost="auto") ++AC_ARG_WITH(ecdsa, [ --with-ecdsa OpenSSL ECDSA], ++ with_ecdsa="$withval", with_ecdsa="auto") ++ ++gosttype="raw" ++case "$with_gost" in ++ raw) ++ with_gost="yes" ++ ;; ++ asn1) ++ AC_DEFINE(PREFER_GOSTASN1, 1, ++ [Define if GOST private keys are encoded in ASN.1.]) ++ gosttype="asn1" ++ with_gost="yes" ++ ;; ++ auto|yes|no) ++ ;; ++ *) ++ AC_MSG_ERROR(unknown GOST private key encoding) ++ ;; ++esac ++ + case "$use_openssl" in ++ native_pkcs11) ++ AC_MSG_RESULT(disabled because of native PKCS11) ++ DST_OPENSSL_INC="" ++ CRYPTO="" ++ OPENSSLGOSTLINKOBJS="" ++ OPENSSLGOSTLINKSRS="" ++ OPENSSLLINKOBJS="" ++ OPENSSLLINKSRCS="" ++ ;; + no) + AC_MSG_RESULT(no) + DST_OPENSSL_INC="" +- USE_OPENSSL="" ++ CRYPTO="" + OPENSSLGOSTLINKOBJS="" + OPENSSLGOSTLINKSRS="" + OPENSSLLINKOBJS="" +@@ -666,7 +717,7 @@ case "$use_openssl" in + ;; + auto) + DST_OPENSSL_INC="" +- USE_OPENSSL="" ++ CRYPTO="" + OPENSSLGOSTLINKOBJS="" + OPENSSLGOSTLINKSRS="" + OPENSSLLINKOBJS="" +@@ -676,6 +727,11 @@ case "$use_openssl" in + If you don't want OpenSSL, use --without-openssl]) + ;; + *) ++ if test "$want_native_pkcs11" = "yes" ++ then ++ AC_MSG_RESULT() ++ AC_MSG_ERROR([OpenSSL and native PKCS11 cannot be used together.]) ++ fi + if test "$use_openssl" = "yes" + then + # User did not specify a path - guess it +@@ -697,7 +753,7 @@ If you don't want OpenSSL, use --without-openssl]) + then + AC_MSG_ERROR(["$use_openssl/include/openssl/opensslv.h" not found]) + fi +- USE_OPENSSL='-DOPENSSL' ++ CRYPTO='-DOPENSSL' + if test "$use_openssl" = "/usr" + then + DST_OPENSSL_INC="" +@@ -733,6 +789,7 @@ If you don't want OpenSSL, use --without-openssl]) + fi + AC_MSG_RESULT(using OpenSSL from $use_openssl/lib and $use_openssl/include) + ++ saved_cc="$CC" + saved_cflags="$CFLAGS" + saved_libs="$LIBS" + CFLAGS="$CFLAGS $DST_OPENSSL_INC" +@@ -839,8 +896,7 @@ int main() { + [AC_MSG_RESULT(no) + have_ecdsa="no"], + [AC_MSG_RESULT(using --with-ecdsa)]) +- AC_ARG_WITH(ecdsa, [ --with-ecdsa OpenSSL ECDSA], +- with_ecdsa="$withval", with_ecdsa="auto") ++ + case "$with_ecdsa" in + yes) + case "$have_ecdsa" in +@@ -869,6 +925,15 @@ int main() { + + AC_MSG_CHECKING(for OpenSSL GOST support) + have_gost="" ++ case "$use_pkcs11" in ++ auto|no) ++ ;; ++ *) ++ if $use_threads; then ++ CC="$CC -pthread" ++ fi ++ ;; ++ esac + AC_TRY_RUN([ + #include <openssl/conf.h> + #include <openssl/engine.h> +@@ -896,8 +961,7 @@ int main() { + [AC_MSG_RESULT(no) + have_gost="no"], + [AC_MSG_RESULT(using --with-gost)]) +- AC_ARG_WITH(gost, [ --with-gost OpenSSL GOST], +- with_gost="$withval", with_gost="auto") ++ + case "$with_gost" in + yes) + case "$have_gost" in +@@ -910,7 +974,7 @@ int main() { + *) + case "$have_gost" in + yes|no) ;; +- *) AC_MSG_ERROR([need --with-gost=[[yes or no]]]) ;; ++ *) AC_MSG_ERROR([need --with-gost=[[yes, no, raw or asn1]]]) ;; + esac + ;; + esac +@@ -938,7 +1002,6 @@ esac + # it as needed) if it is found. + # + +-AC_SUBST(USE_OPENSSL) + AC_SUBST(DST_OPENSSL_INC) + AC_SUBST(OPENSSLGOSTLINKOBJS) + AC_SUBST(OPENSSLGOSTLINKSRCS) +@@ -958,7 +1021,7 @@ AC_ARG_ENABLE(openssl-hash, + want_openssl_hash="$enableval", want_openssl_hash="no") + case $want_openssl_hash in + yes) +- if test "$USE_OPENSSL" = "" ++ if test "$CRYPTO" = "" + then + AC_MSG_ERROR([No OpenSSL for hash functions]) + fi +@@ -973,6 +1036,41 @@ esac + AC_SUBST(ISC_PLATFORM_OPENSSLHASH) + AC_SUBST(ISC_OPENSSL_INC) + ++AC_ARG_WITH(libtool, ++ [ --with-libtool use GNU libtool], ++ use_libtool="$withval", use_libtool="no") ++ ++case $use_libtool in ++ yes) ++ AM_PROG_LIBTOOL ++ O=lo ++ A=la ++ LIBTOOL_MKDEP_SED='s;\.o;\.lo;' ++ LIBTOOL_MODE_COMPILE='--mode=compile --tag=CC' ++ LIBTOOL_MODE_INSTALL='--mode=install --tag=CC' ++ LIBTOOL_MODE_LINK='--mode=link --tag=CC' ++ case "$host" in ++ *) LIBTOOL_ALLOW_UNDEFINED= ;; ++ esac ++ case "$host" in ++ *-ibm-aix*) LIBTOOL_IN_MAIN="-Wl,-bI:T_testlist.imp" ;; ++ *) LIBTOOL_IN_MAIN= ;; ++ esac; ++ ;; ++ *) ++ O=o ++ A=a ++ LIBTOOL= ++ AC_SUBST(LIBTOOL) ++ LIBTOOL_MKDEP_SED= ++ LIBTOOL_MODE_COMPILE= ++ LIBTOOL_MODE_INSTALL= ++ LIBTOOL_MODE_LINK= ++ LIBTOOL_ALLOW_UNDEFINED= ++ LIBTOOL_IN_MAIN= ++ ;; ++esac ++ + # + # PKCS11 (aka crypto hardware) support + # +@@ -980,25 +1078,102 @@ AC_SUBST(ISC_OPENSSL_INC) + # + + AC_MSG_CHECKING(for PKCS11 support) +-AC_ARG_WITH(pkcs11, +-[ --with-pkcs11[=PATH] Build with PKCS11 support [yes|no|path] +- (PATH is for the PKCS11 provider)], +- use_pkcs11="$withval", use_pkcs11="no") ++ ++if test "$use_pkcs11" = "auto" ++then ++ if test "$want_native_pkcs11" = "yes" ++ then ++ use_pkcs11="yes" ++ else ++ use_pkcs11="no" ++ fi ++fi + + case "$use_pkcs11" in + no|'') +- AC_MSG_RESULT(disabled) +- USE_PKCS11='' +- PKCS11_TOOLS='' ++ AC_MSG_RESULT(no) ++ USE_PKCS11="" ++ PKCS11_TEST="" ++ PKCS11_TOOLS="" ++ ISC_PK11_C="" ++ ISC_PK11_O="" ++ ISC_PK11_API_C="" ++ ISC_PK11_API_O="" ++ ISC_PK11_RESULT_C="" ++ ISC_PK11_RESULT_O="" ++ ISC_ISCPK11_API_C="" ++ ISC_ISCPK11_API_O="" + ;; + yes|*) +- AC_MSG_RESULT(using OpenSSL with PKCS11 support) ++ AC_MSG_RESULT(yes) ++ if ! $use_threads; then ++ AC_MSG_ERROR([PKCS11 requires thread support]) ++ fi ++ if test "$CRYPTO" != "" ++ then ++ AC_MSG_CHECKING(for OpenSSL with PKCS11 support) ++ saved_cc="$CC" ++ saved_cflags="$CFLAGS" ++ saved_libs="$LIBS" ++ CC="$CC -pthread" ++ CFLAGS="$CFLAGS $DST_OPENSSL_INC" ++ LIBS="$LIBS $DNS_OPENSSL_LIBS" ++ AC_TRY_RUN([ ++#include <openssl/conf.h> ++#include <openssl/engine.h> ++int main() { ++ ENGINE *e; ++ ++ OPENSSL_config(NULL); ++ e = ENGINE_by_id("pkcs11"); ++ if (e == NULL) ++ return (1); ++ if (ENGINE_init(e) <= 0) ++ return (1); ++ return (0); ++} ++], ++ [AC_MSG_RESULT(yes) ++ PKCS11_TEST=pkcs11ssl ++ PKCS11_ENGINE='-DPKCS11_ENGINE="\"pkcs11\""'], ++ [AC_MSG_RESULT(no) ++ PKCS11_TEST='' ++ PKCS11_ENGINE='-DPKCS11_ENGINE=NULL'], ++ [AC_MSG_RESULT(cross compile, defaulting to no) ++ PKCS11_TEST='' ++ PKCS11_ENGINE='-DPKCS11_ENGINE=NULL']) ++ CC="$saved_cc" ++ CFLAGS="$saved_cflags" ++ LIBS="$saved_libs" ++ else ++ PKCS11_TEST='' ++ PKCS11_ENGINE='-DPKCS11_ENGINE=NULL' ++ ++ fi + USE_PKCS11='-DUSE_PKCS11' + PKCS11_TOOLS=pkcs11 +- ;; ++ AC_CHECK_FUNC(getpassphrase, AC_DEFINE(HAVE_GETPASSPHRASE),) ++ ISC_PK11_C="pk11.c" ++ ISC_PK11_O="pk11.$O" ++ ISC_PK11_API_C="pk11_api.c" ++ ISC_PK11_API_O="pk11_api.$O" ++ ISC_PK11_RESULT_C="pk11_result.c" ++ ISC_PK11_RESULT_O="pk11_result.$O" ++ ISC_ISCPK11_API_C="unix/pk11_api.c" ++ ISC_ISCPK11_API_O="unix/pk11_api.$O" ++ ;; + esac + AC_SUBST(USE_PKCS11) + AC_SUBST(PKCS11_TOOLS) ++AC_SUBST(PKCS11_ENGINE) ++AC_SUBST(ISC_PK11_C) ++AC_SUBST(ISC_PK11_O) ++AC_SUBST(ISC_PK11_API_C) ++AC_SUBST(ISC_PK11_API_O) ++AC_SUBST(ISC_PK11_RESULT_C) ++AC_SUBST(ISC_PK11_RESULT_O) ++AC_SUBST(ISC_ISCPK11_API_C) ++AC_SUBST(ISC_ISCPK11_API_O) + + AC_MSG_CHECKING(for PKCS11 tools) + case "$use_pkcs11" in +@@ -1006,13 +1181,77 @@ case "$use_pkcs11" in + AC_MSG_RESULT(disabled) + PKCS11_PROVIDER="undefined" + ;; +- *) +- AC_MSG_RESULT(PKCS11 provider is "$use_pkcs11") ++ yes|'') ++ PKCS11_PROVIDER="undefined" ++ AC_MSG_RESULT(enabled) ++ ;; ++ *) + PKCS11_PROVIDER="$use_pkcs11" ++ AC_MSG_RESULT([enabled, PKCS11 provider is $PKCS11_PROVIDER]) + ;; + esac + AC_SUBST(PKCS11_PROVIDER) + ++ ++PKCS11_ECDSA="" ++PKCS11_GOST="" ++AC_MSG_CHECKING(for native PKCS11) ++ ++case "$want_native_pkcs11" in ++ yes) ++ AC_MSG_RESULT(using native PKCS11 crypto) ++ CRYPTO="-DPKCS11CRYPTO" ++ PKCS11LINKOBJS='${PKCS11LINKOBJS}' ++ PKCS11LINKSRCS='${PKCS11LINKSRCS}' ++ PKCS11_TEST=pkcs11 ++ AC_MSG_CHECKING(for PKCS11 ECDSA) ++ case "$with_ecdsa" in ++ no) ++ AC_MSG_RESULT([disabled]) ++ ;; ++ *) ++ AC_MSG_RESULT(enabled) ++ PKCS11_ECDSA="yes" ++ AC_DEFINE(HAVE_PKCS11_ECDSA, 1, ++ [Define if your PKCS11 provider supports ECDSA.]) ++ ;; ++ esac ++ AC_MSG_CHECKING(for PKCS11 GOST) ++ case "$with_gost" in ++ yes) ++ AC_MSG_RESULT(enabled) ++ PKCS11_GOST="yes" ++ AC_DEFINE(HAVE_PKCS11_GOST, 1, ++ [Define if your PKCS11 provider supports GOST.]) ++ ;; ++ *) ++ AC_MSG_RESULT([disabled]) ++ ;; ++ esac ++ ;; ++ no|'') ++ AC_MSG_RESULT(disabled) ++ ;; ++esac ++ ++AC_SUBST(PKCS11LINKOBJS) ++AC_SUBST(PKCS11LINKSRCS) ++AC_SUBST(CRYPTO) ++AC_SUBST(PKCS11_ECDSA) ++AC_SUBST(PKCS11_GOST) ++AC_SUBST(PKCS11_TEST) ++ ++# for PKCS11 benchmarks ++have_clock_gt=no ++AC_CHECK_FUNC(clock_gettime,have_clock_gt=yes,) ++if test "$have_clock_gt" = "no"; then ++ AC_CHECK_LIB(rt,clock_gettime,have_clock_gt=ye,,) ++ fi ++if test "$have_clock_gt" = "yes"; then ++ AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if clock_gettime is available.]) ++fi ++ ++ + AC_MSG_CHECKING(for GSSAPI library) + AC_ARG_WITH(gssapi, + [ --with-gssapi=PATH Specify path for system-supplied GSSAPI [[default=yes]]], +@@ -1245,6 +1484,21 @@ case "$use_randomdev" in + esac + + # ++# Only check dsa signature generation on these platforms when performing ++# system tests. ++# ++CHECK_DSA=0 ++if grep "#define PATH_RANDOMDEV " confdefs.h > /dev/null ++then ++ case "$host" in ++ *darwin*|*freebsd*) ++ CHECK_DSA=1 ++ ;; ++ esac ++fi ++AC_SUBST(CHECK_DSA) ++ ++# + # Do we have arc4random() ? + # + AC_CHECK_FUNC(arc4random, AC_DEFINE(HAVE_ARC4RANDOM)) +@@ -1633,41 +1887,6 @@ esac + AC_SUBST(PURIFY) + + +-AC_ARG_WITH(libtool, +- [ --with-libtool use GNU libtool], +- use_libtool="$withval", use_libtool="no") +- +-case $use_libtool in +- yes) +- AM_PROG_LIBTOOL +- O=lo +- A=la +- LIBTOOL_MKDEP_SED='s;\.o;\.lo;' +- LIBTOOL_MODE_COMPILE='--mode=compile --tag=CC' +- LIBTOOL_MODE_INSTALL='--mode=install --tag=CC' +- LIBTOOL_MODE_LINK='--mode=link --tag=CC' +- case "$host" in +- *) LIBTOOL_ALLOW_UNDEFINED= ;; +- esac +- case "$host" in +- *-ibm-aix*) LIBTOOL_IN_MAIN="-Wl,-bI:T_testlist.imp" ;; +- *) LIBTOOL_IN_MAIN= ;; +- esac; +- ;; +- *) +- O=o +- A=a +- LIBTOOL= +- AC_SUBST(LIBTOOL) +- LIBTOOL_MKDEP_SED= +- LIBTOOL_MODE_COMPILE= +- LIBTOOL_MODE_INSTALL= +- LIBTOOL_MODE_LINK= +- LIBTOOL_ALLOW_UNDEFINED= +- LIBTOOL_IN_MAIN= +- ;; +-esac +- + # + # enable/disable dumping stack backtrace. Also check if the system supports + # glibc-compatible backtrace() function. +@@ -3419,6 +3638,9 @@ BIND9_CONFIGARGS="`echo $BIND9_CONFIGARGS | sed 's/^ //'`" + BIND9_CONFIGARGS="CONFIGARGS=${BIND9_CONFIGARGS}" + AC_SUBST(BIND9_CONFIGARGS) + ++AC_SUBST_FILE(LIBISCPK11_API) ++LIBISCPK11_API="$srcdir/lib/iscpk11/api" ++ + AC_SUBST_FILE(LIBISC_API) + LIBISC_API="$srcdir/lib/isc/api" + +@@ -3728,6 +3950,8 @@ AC_CONFIG_FILES([ + bin/tests/mem/Makefile + bin/tests/names/Makefile + bin/tests/net/Makefile ++ bin/tests/pkcs11/Makefile ++ bin/tests/pkcs11/benchmarks/Makefile + bin/tests/rbt/Makefile + bin/tests/resolver/Makefile + bin/tests/sockaddr/Makefile +@@ -3811,11 +4035,14 @@ AC_CONFIG_FILES([ + lib/isc/include/Makefile + lib/isc/include/isc/Makefile + lib/isc/include/isc/platform.h ++ lib/isc/include/pk11/Makefile ++ lib/isc/include/pkcs11/Makefile + lib/isc/tests/Makefile + lib/isc/nls/Makefile + lib/isc/unix/Makefile + lib/isc/unix/include/Makefile + lib/isc/unix/include/isc/Makefile ++ lib/isc/unix/include/pkcs11/Makefile + lib/isccc/Makefile + lib/isccc/include/Makefile + lib/isccc/include/isccc/Makefile +@@ -3885,12 +4112,8 @@ test "$use_pkcs11" = "no" || echo " PKCS#11/Cryptoki support (--with-pkcs11)" + if test "$enable_full_report" = "yes"; then + test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" || \ + echo " IPv6 support (--enable-ipv6)" +- test "X$USE_OPENSSL" = "X" || \ ++ test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" || \ + echo " OpenSSL cryptography/DNSSEC (--with-openssl)" +- test "$OPENSSL_GOST" != "yes" || \ +- echo " GOST algorithm support (--with-gost)" +- test "$OPENSSL_ECDSA" != "yes" || \ +- echo " ECDSA algorithm support (--with-ecdsa)" + test "X$PYTHON" = "X" || echo " Python tools (--with-python)" + test "X$libxml2_libs" = "X" || echo " XML statistics (--with-libxml2)" + fi +@@ -3923,24 +4146,28 @@ test "$enable_filter" = "yes" || \ + test "$use_gssapi" = "no" && echo " GSS-API (--with-gssapi)" + test "$want_backtrace" = "yes" || \ + echo " Print backtrace on crash (--enable-backtrace)" +-test "$use_pkcs11" = "no" && echo " PKCS#11/Cryptoki support (--with-pkcs11)" + +-test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" && \ +- echo " IPv6 support (--enable-ipv6)" +-test "X$USE_OPENSSL" = "X" && \ +- echo " OpenSSL cryptography/DNSSEC (--with-openssl)" +-test "X$USE_OPENSSL" != "X" -a "$OPENSSL_GOST" != "yes" && \ ++test "X$CRYPTO" = "X" -o "$want_native_pkcs11" = "yes" && \ ++ echo " OpenSSL cryptography/DNSSEC (--with-openssl)" ++test "$want_native_pkcs11" != "yes" && \ ++ echo " Native PKCS#11 cryptography/DNSSEC (--enable-native-pkcs11)" ++test "X$CRYPTO" = "X" -o "$OPENSSL_GOST" = "yes" -o "$PKCS11_GOST" = "yes" || \ + echo " GOST algorithm support (--with-gost)" +-test "X$USE_OPENSSL" != "X" -a "$OPENSSL_ECDSA" != "yes" && \ ++test "X$CRYPTO" = "X" -o "$OPENSSL_ECDSA" = "yes" -o "$PKCS11_ECDSA" = "yes" || \ + echo " ECDSA algorithm support (--with-ecdsa)" ++test "$use_pkcs11" = "no" && echo " PKCS#11/Cryptoki support (--with-pkcs11)" ++test "$enable_ipv6" = "no" -o "$found_ipv6" = "no" && \ ++ echo " IPv6 support (--enable-ipv6)" + test "X$PYTHON" = "X" && echo " Python tools (--with-python)" + test "X$libxml2_libs" = "X" && echo " XML statistics (--with-libxml2)" + + echo "========================================================================" + +-if test "X$USE_OPENSSL" = "X"; then ++if test "X$CRYPTO" = "X"; then + cat << \EOF +-BIND is being built without OpenSSL. This means it will not have DNSSEC support. ++BIND 9 is being built without cryptography support. This means it will ++not have DNSSEC support. Use --with-openssl, or --with-pkcs11 and ++--enable-native-pkcs11 to enable cryptography. + EOF + fi + +diff --git a/doc/arm/pkcs11.xml b/doc/arm/pkcs11.xml +index b4e22bb..5388a29 100644 +--- a/doc/arm/pkcs11.xml ++++ b/doc/arm/pkcs11.xml +@@ -20,162 +20,259 @@ + <!-- $Id: pkcs11.xml,v 1.7 2012/01/16 22:50:12 each Exp $ --> + + <sect1 id="pkcs11"> +- <title>PKCS #11 (Cryptoki) support</title> +- <para>PKCS #11 (Public Key Cryptography Standard #11) defines a +- platform- independent API for the control of hardware security +- modules (HSMs) and other cryptographic support devices.</para> +- <para>BIND 9 is known to work with two HSMs: The Sun SCA 6000 +- cryptographic acceleration board, tested under Solaris x86, and +- the AEP Keyper network-attached key storage device, tested with +- Debian Linux, Solaris x86 and Windows Server 2003.</para> ++ <title>PKCS#11 (Cryptoki) support</title> ++ <para> ++ PKCS#11 (Public Key Cryptography Standard #11) defines a ++ platform-independent API for the control of hardware security ++ modules (HSMs) and other cryptographic support devices. ++ </para> ++ <para> ++ BIND 9 is known to work with three HSMs: The AEP Keyper, which has ++ been tested with Debian Linux, Solaris x86 and Windows Server 2003; ++ the Thales nShield, tested with Debian Linux; and the Sun SCA 6000 ++ cryptographic acceleration board, tested with Solaris x86. In ++ addition, BIND can be used with SoftHSM, a software-based HSM ++ simulator produced by the OpenDNSSEC project. ++ </para> ++ <para> ++ PKCS#11 makes use of a "provider library": a dynamically loadable ++ library which provides a low-level PKCS#11 interface to drive the HSM ++ hardware. The PKCS#11 provider library comes from the HSM vendor, and ++ it is specific to the HSM to be controlled. ++ </para> ++ <para> ++ There are two available mechanisms for PKCS#11 support in BIND 9: ++ OpenSSL-based PKCS#11 and native PKCS#11. When using the first ++ mechanism, BIND uses a modified version of OpenSSL, which loads ++ the provider library and operates the HSM indirectly; any ++ cryptographic operations not supported by the HSM can be carried ++ out by OpenSSL instead. The second mechanism enables BIND to bypass ++ OpenSSL completely; BIND loads the provider library itself, and uses ++ the PKCS#11 API to drive the HSM directly. ++ </para> + <sect2> + <title>Prerequisites</title> +- <para>See the HSM vendor documentation for information about +- installing, initializing, testing and troubleshooting the +- HSM.</para> +- <para>BIND 9 uses OpenSSL for cryptography, but stock OpenSSL +- does not yet fully support PKCS #11. However, a PKCS #11 engine +- for OpenSSL is available from the OpenSolaris project. It has +- been modified by ISC to work with with BIND 9, and to provide +- new features such as PIN management and key by +- reference.</para> +- <para>The patched OpenSSL depends on a "PKCS #11 provider". +- This is a shared library object, providing a low-level PKCS #11 +- interface to the HSM hardware. It is dynamically loaded by +- OpenSSL at runtime. The PKCS #11 provider comes from the HSM +- vendor, and is specific to the HSM to be controlled.</para> +- <para>There are two "flavors" of PKCS #11 support provided by +- the patched OpenSSL, one of which must be chosen at +- configuration time. The correct choice depends on the HSM +- hardware:</para> ++ <para> ++ See the documentation provided by your HSM vendor for ++ information about installing, initializing, testing and ++ troubleshooting the HSM. ++ </para> ++ </sect2> ++ <sect2> ++ <title>Native PKCS#11</title> ++ <para> ++ Native PKCS#11 mode will only work with an HSM capable of carrying ++ out <emphasis>every</emphasis> cryptographic operation BIND 9 may ++ need. The HSM's provider library must have a complete implementation ++ of the PKCS#11 API, so that all these functions are accessible. As of ++ this writing, only the Thales nShield HSM and the latest development ++ version of SoftHSM can be used in this fashion. For other HSM's, ++ including the AEP Keyper, Sun SCA 6000 and older versions of SoftHSM, ++ use OpenSSL-based PKCS#11. (Note: As more HSMs become capable of ++ supporting native PKCS#11, it is expected that OpenSSL-based ++ PKCS#11 will eventually be deprecated.) ++ </para> ++ <para> ++ To build BIND with native PKCS#11, configure as follows: ++ </para> ++ <screen> ++$ <userinput>cd bind9</userinput> ++$ <userinput>./configure --enable-native-pkcs11 \ ++ --with-pkcs11=<replaceable>provider-library-path</replaceable></userinput> ++ </screen> ++ <para> ++ This will cause all BIND tools, including <command>named</command> ++ and the <command>dnssec-*</command> and <command>pkcs11-*</command> ++ tools, to use the PKCS#11 provider library specified in ++ <replaceable>provider-library-path</replaceable> for cryptography. ++ (The provider library path can be overridden using the ++ <option>-E</option> in <command>named</command> and the ++ <command>dnssec-*</command> tools, or the <option>-m</option> in ++ the <command>pkcs11-*</command> tools.) ++ </para> ++ </sect2> ++ <sect2> ++ <title>OpenSSL-based PKCS#11</title> ++ <para> ++ OpenSSL-based PKCS#11 mode uses a modified version of the ++ OpenSSL library; stock OpenSSL does not fully support PKCS#11. ++ ISC provides a patch to OpenSSL to correct this. This patch is ++ based on work originally done by the OpenSolaris project; it has been ++ modified by ISC to provide new features such as PIN management and ++ key-by-reference. ++ </para> ++ <para> ++ There are two "flavors" of PKCS#11 support provided by ++ the patched OpenSSL, one of which must be chosen at ++ configuration time. The correct choice depends on the HSM ++ hardware: ++ </para> + <itemizedlist> + <listitem> +- <para>Use 'crypto-accelerator' with HSMs that have hardware +- cryptographic acceleration features, such as the SCA 6000 +- board. This causes OpenSSL to run all supported +- cryptographic operations in the HSM.</para> ++ <para> ++ Use 'crypto-accelerator' with HSMs that have hardware ++ cryptographic acceleration features, such as the SCA 6000 ++ board. This causes OpenSSL to run all supported ++ cryptographic operations in the HSM. ++ </para> + </listitem> + <listitem> +- <para>Use 'sign-only' with HSMs that are designed to +- function primarily as secure key storage devices, but lack +- hardware acceleration. These devices are highly secure, but +- are not necessarily any faster at cryptography than the +- system CPU — often, they are slower. It is therefore +- most efficient to use them only for those cryptographic +- functions that require access to the secured private key, +- such as zone signing, and to use the system CPU for all +- other computationally-intensive operations. The AEP Keyper +- is an example of such a device.</para> ++ <para> ++ Use 'sign-only' with HSMs that are designed to ++ function primarily as secure key storage devices, but lack ++ hardware acceleration. These devices are highly secure, but ++ are not necessarily any faster at cryptography than the ++ system CPU — often, they are slower. It is therefore ++ most efficient to use them only for those cryptographic ++ functions that require access to the secured private key, ++ such as zone signing, and to use the system CPU for all ++ other computationally-intensive operations. The AEP Keyper ++ is an example of such a device. ++ </para> + </listitem> + </itemizedlist> +- <para>The modified OpenSSL code is included in the BIND 9 release, +- in the form of a context diff against the latest verions of +- OpenSSL. OpenSSL 0.9.8, 1.0.0 and 1.0.1 are supported; there are +- separate diffs for each version. In the examples to follow, +- we use OpenSSL 0.9.8, but the same methods work with OpenSSL 1.0.0 +- and 1.0.1. ++ <para> ++ The modified OpenSSL code is included in the BIND 9 release, ++ in the form of a context diff against the latest verions of ++ OpenSSL. OpenSSL 0.9.8, 1.0.0, and 1.0.1 are supported; there are ++ separate diffs for each version. In the examples to follow, ++ we use OpenSSL 0.9.8, but the same methods work with OpenSSL ++ 1.0.0 and 1.0.1. + </para> + <note> +- The latest OpenSSL versions at the time of the BIND release +- are 0.9.8y, 1.0.0k and 1.0.1e. +- ISC will provide an updated patch as new versions of OpenSSL ++ The latest OpenSSL versions as of this writing (January 2014) ++ are 0.9.8y, 1.0.0l, and 1.0.1f. ++ ISC will provide updated patches as new versions of OpenSSL + are released. The version number in the following examples +- is expected to change.</note> ++ is expected to change. ++ </note> + <para> +- Before building BIND 9 with PKCS #11 support, it will be +- necessary to build OpenSSL with this patch in place and inform +- it of the path to the HSM-specific PKCS #11 provider +- library.</para> +- <para>Obtain OpenSSL 0.9.8s:</para> +- <screen> +-$ <userinput>wget <ulink>http://www.openssl.org/source/openssl-0.9.8s.tar.gz</ulink></userinput> +-</screen> +- <para>Extract the tarball:</para> +- <screen> +-$ <userinput>tar zxf openssl-0.9.8s.tar.gz</userinput> ++ Before building BIND 9 with PKCS#11 support, it will be ++ necessary to build OpenSSL with the patch in place, and configure ++ it with the path to your HSM's PKCS#11 provider library. ++ </para> ++ </sect3> ++ <title>Patching OpenSSL</title> ++ <screen> ++$ <userinput>wget <ulink>http://www.openssl.org/source/openssl-0.9.8y.tar.gz</ulink></userinput> ++ </screen> ++ <para>Extract the tarball:</para> ++ <screen> ++$ <userinput>tar zxf openssl-0.9.8y.tar.gz</userinput> + </screen> +- <para>Apply the patch from the BIND 9 release:</para> +- <screen> +-$ <userinput>patch -p1 -d openssl-0.9.8s \ +- < bind9/bin/pkcs11/openssl-0.9.8s-patch</userinput> ++ <para>Apply the patch from the BIND 9 release:</para> ++ <screen> ++$ <userinput>patch -p1 -d openssl-0.9.8y \ ++ < bind9/bin/pkcs11/openssl-0.9.8y-patch</userinput> + </screen> +- <note>(Note that the patch file may not be compatible with the +- "patch" utility on all operating systems. You may need to +- install GNU patch.)</note> +- <para>When building OpenSSL, place it in a non-standard +- location so that it does not interfere with OpenSSL libraries +- elsewhere on the system. In the following examples, we choose +- to install into "/opt/pkcs11/usr". We will use this location +- when we configure BIND 9.</para> ++ <note> ++ Note that the patch file may not be compatible with the ++ "patch" utility on all operating systems. You may need to ++ install GNU patch. ++ </note> ++ <para> ++ When building OpenSSL, place it in a non-standard ++ location so that it does not interfere with OpenSSL libraries ++ elsewhere on the system. In the following examples, we choose ++ to install into "/opt/pkcs11/usr". We will use this location ++ when we configure BIND 9. ++ </para> ++ <para> ++ Later, when building BIND 9, the location of the custom-built ++ OpenSSL library will need to be specified via configure. ++ </para> ++ </sect3> + <sect3> + <!-- Example 1 --> + <title>Building OpenSSL for the AEP Keyper on Linux</title> +- <para>The AEP Keyper is a highly secure key storage device, +- but does not provide hardware cryptographic acceleration. It +- can carry out cryptographic operations, but it is probably +- slower than your system's CPU. Therefore, we choose the +- 'sign-only' flavor when building OpenSSL.</para> +- <para>The Keyper-specific PKCS #11 provider library is +- delivered with the Keyper software. In this example, we place +- it /opt/pkcs11/usr/lib:</para> ++ <para> ++ The AEP Keyper is a highly secure key storage device, ++ but does not provide hardware cryptographic acceleration. It ++ can carry out cryptographic operations, but it is probably ++ slower than your system's CPU. Therefore, we choose the ++ 'sign-only' flavor when building OpenSSL. ++ </para> ++ <para> ++ The Keyper-specific PKCS#11 provider library is ++ delivered with the Keyper software. In this example, we place ++ it /opt/pkcs11/usr/lib: ++ </para> + <screen> + $ <userinput>cp pkcs11.GCC4.0.2.so.4.05 /opt/pkcs11/usr/lib/libpkcs11.so</userinput> + </screen> +- <para>This library is only available for Linux as a 32-bit +- binary. If we are compiling on a 64-bit Linux system, it is +- necessary to force a 32-bit build, by specifying -m32 in the +- build options.</para> +- <para>Finally, the Keyper library requires threads, so we +- must specify -pthread.</para> ++ <para> ++ This library is only available for Linux as a 32-bit ++ binary. If we are compiling on a 64-bit Linux system, it is ++ necessary to force a 32-bit build, by specifying -m32 in the ++ build options. ++ </para> ++ <para> ++ Finally, the Keyper library requires threads, so we ++ must specify -pthread. ++ </para> + <screen> +-$ <userinput>cd openssl-0.9.8s</userinput> ++$ <userinput>cd openssl-0.9.8y</userinput> + $ <userinput>./Configure linux-generic32 -m32 -pthread \ + --pk11-libname=/opt/pkcs11/usr/lib/libpkcs11.so \ + --pk11-flavor=sign-only \ + --prefix=/opt/pkcs11/usr</userinput> + </screen> +- <para>After configuring, run "<command>make</command>" +- and "<command>make test</command>". If "<command>make +- test</command>" fails with "pthread_atfork() not found", you forgot to +- add the -pthread above.</para> ++ <para> ++ After configuring, run "<command>make</command>" ++ and "<command>make test</command>". If "<command>make ++ test</command>" fails with "pthread_atfork() not found", you forgot to ++ add the -pthread above. ++ </para> + </sect3> + <sect3> + <!-- Example 2 --> + <title>Building OpenSSL for the SCA 6000 on Solaris</title> +- <para>The SCA-6000 PKCS #11 provider is installed as a system +- library, libpkcs11. It is a true crypto accelerator, up to 4 +- times faster than any CPU, so the flavor shall be +- 'crypto-accelerator'.</para> +- <para>In this example, we are building on Solaris x86 on an +- AMD64 system.</para> ++ <para> ++ The SCA-6000 PKCS#11 provider is installed as a system ++ library, libpkcs11. It is a true crypto accelerator, up to 4 ++ times faster than any CPU, so the flavor shall be ++ 'crypto-accelerator'. ++ </para> ++ <para> ++ In this example, we are building on Solaris x86 on an ++ AMD64 system. ++ </para> + <screen> +-$ <userinput>cd openssl-0.9.8s</userinput> ++$ <userinput>cd openssl-0.9.8y</userinput> + $ <userinput>./Configure solaris64-x86_64-cc \ + --pk11-libname=/usr/lib/64/libpkcs11.so \ + --pk11-flavor=crypto-accelerator \ + --prefix=/opt/pkcs11/usr</userinput> + </screen> +- <para>(For a 32-bit build, use "solaris-x86-cc" and +- /usr/lib/libpkcs11.so.)</para> +- <para>After configuring, run +- <command>make</command> and +- <command>make test</command>.</para> ++ <para> ++ (For a 32-bit build, use "solaris-x86-cc" and /usr/lib/libpkcs11.so.) ++ </para> ++ <para> ++ After configuring, run ++ <command>make</command> and ++ <command>make test</command>. ++ </para> + </sect3> + <sect3> + <!-- Example 3 --> + <title>Building OpenSSL for SoftHSM</title> +- <para>SoftHSM is a software library provided by the OpenDNSSEC +- project (http://www.opendnssec.org) which provides a PKCS#11 +- interface to a virtual HSM, implemented in the form of encrypted +- data on the local filesystem. It uses the Botan library for +- encryption and SQLite3 for data storage. Though less secure +- than a true HSM, it can provide more secure key storage than +- traditional key files, and can allow you to experiment with +- PKCS#11 when an HSM is not available.</para> +- <para>The SoftHSM cryptographic store must be installed and +- initialized before using it with OpenSSL, and the SOFTHSM_CONF +- environment variable must always point to the SoftHSM configuration +- file:</para> ++ <para> ++ SoftHSM is a software library provided by the OpenDNSSEC ++ project (http://www.opendnssec.org) which provides a PKCS#11 ++ interface to a virtual HSM, implemented in the form of encrypted ++ data on the local filesystem. SoftHSM can be configured to use ++ either OpenSSL or the Botan library for encryption, and SQLite3 ++ for data storage. Though less secure than a true HSM, it can ++ provide more secure key storage than traditional key files, ++ and can allow you to experiment with PKCS#11 when an HSM is ++ not available. ++ </para> ++ <para> ++ The SoftHSM cryptographic store must be installed and ++ initialized before using it with OpenSSL, and the SOFTHSM_CONF ++ environment variable must always point to the SoftHSM configuration ++ file: ++ </para> + <screen> + $ <userinput> cd softhsm-1.3.0 </userinput> + $ <userinput> configure --prefix=/opt/pkcs11/usr </userinput> +@@ -185,25 +282,31 @@ $ <userinput> export SOFTHSM_CONF=/opt/pkcs11/softhsm.conf </userinput> + $ <userinput> echo "0:/opt/pkcs11/softhsm.db" > $SOFTHSM_CONF </userinput> + $ <userinput> /opt/pkcs11/usr/bin/softhsm --init-token 0 --slot 0 --label softhsm </userinput> + </screen> +- <para>SoftHSM can perform all cryptographic operations, but +- since it only uses your system CPU, there is no need to use it +- for anything but signing. Therefore, we choose the 'sign-only' +- flavor when building OpenSSL.</para> ++ <para> ++ SoftHSM can perform all cryptographic operations, but ++ since it only uses your system CPU, there is no advantage to using ++ it for anything but signing. Therefore, we choose the 'sign-only' ++ flavor when building OpenSSL. ++ </para> + <screen> +-$ <userinput>cd openssl-0.9.8s</userinput> ++$ <userinput>cd openssl-0.9.8y</userinput> + $ <userinput>./Configure linux-x86_64 -pthread \ +- --pk11-libname=/opt/pkcs11/usr/lib/libpkcs11.so \ ++ --pk11-libname=/opt/pkcs11/usr/lib/libsofthsm.so \ + --pk11-flavor=sign-only \ + --prefix=/opt/pkcs11/usr</userinput> + </screen> +- <para>After configuring, run "<command>make</command>" +- and "<command>make test</command>".</para> ++ <para> ++ After configuring, run "<command>make</command>" ++ and "<command>make test</command>". ++ </para> + </sect3> +- <para>Once you have built OpenSSL, run +- "<command>apps/openssl engine pkcs11</command>" to confirm +- that PKCS #11 support was compiled in correctly. The output +- should be one of the following lines, depending on the flavor +- selected:</para> ++ <para> ++ Once you have built OpenSSL, run ++ "<command>apps/openssl engine pkcs11</command>" to confirm ++ that PKCS#11 support was compiled in correctly. The output ++ should be one of the following lines, depending on the flavor ++ selected: ++ </para> + <screen> + (pkcs11) PKCS #11 engine support (sign only) + </screen> +@@ -211,29 +314,31 @@ $ <userinput>./Configure linux-x86_64 -pthread \ + <screen> + (pkcs11) PKCS #11 engine support (crypto accelerator) + </screen> +- <para>Next, run +- "<command>apps/openssl engine pkcs11 -t</command>". This will +- attempt to initialize the PKCS #11 engine. If it is able to +- do so successfully, it will report +- <quote><literal>[ available ]</literal></quote>.</para> +- <para>If the output is correct, run +- "<command>make install</command>" which will install the +- modified OpenSSL suite to +- <filename>/opt/pkcs11/usr</filename>.</para> +- </sect2> +- <sect2> +- <title>Building BIND 9 with PKCS#11</title> +- <para>When building BIND 9, the location of the custom-built +- OpenSSL library must be specified via configure.</para> ++ <para> ++ Next, run ++ "<command>apps/openssl engine pkcs11 -t</command>". This will ++ attempt to initialize the PKCS#11 engine. If it is able to ++ do so successfully, it will report ++ <quote><literal>[ available ]</literal></quote>. ++ </para> ++ <para> ++ If the output is correct, run ++ "<command>make install</command>" which will install the ++ modified OpenSSL suite to <filename>/opt/pkcs11/usr</filename>. ++ </para> + <sect3> + <!-- Example 4 --> + <title>Configuring BIND 9 for Linux with the AEP Keyper</title> +- <para>To link with the PKCS #11 provider, threads must be +- enabled in the BIND 9 build.</para> +- <para>The PKCS #11 library for the AEP Keyper is currently +- only available as a 32-bit binary. If we are building on a +- 64-bit host, we must force a 32-bit build by adding "-m32" to +- the CC options on the "configure" command line.</para> ++ <para> ++ To link with the PKCS#11 provider, threads must be ++ enabled in the BIND 9 build. ++ </para> ++ <para> ++ The PKCS#11 library for the AEP Keyper is currently ++ only available as a 32-bit binary. If we are building on a ++ 64-bit host, we must force a 32-bit build by adding "-m32" to ++ the CC options on the "configure" command line. ++ </para> + <screen> + $ <userinput>cd ../bind9</userinput> + $ <userinput>./configure CC="gcc -m32" --enable-threads \ +@@ -244,8 +349,10 @@ $ <userinput>./configure CC="gcc -m32" --enable-threads \ + <sect3> + <!-- Example 5 --> + <title>Configuring BIND 9 for Solaris with the SCA 6000</title> +- <para>To link with the PKCS #11 provider, threads must be +- enabled in the BIND 9 build.</para> ++ <para> ++ To link with the PKCS#11 provider, threads must be ++ enabled in the BIND 9 build. ++ </para> + <screen> + $ <userinput>cd ../bind9</userinput> + $ <userinput>./configure CC="cc -xarch=amd64" --enable-threads \ +@@ -253,11 +360,13 @@ $ <userinput>./configure CC="cc -xarch=amd64" --enable-threads \ + --with-pkcs11=/usr/lib/64/libpkcs11.so</userinput> + </screen> + <para>(For a 32-bit build, omit CC="cc -xarch=amd64".)</para> +- <para>If configure complains about OpenSSL not working, you +- may have a 32/64-bit architecture mismatch. Or, you may have +- incorrectly specified the path to OpenSSL (it should be the +- same as the --prefix argument to the OpenSSL +- Configure).</para> ++ <para> ++ If configure complains about OpenSSL not working, you ++ may have a 32/64-bit architecture mismatch. Or, you may have ++ incorrectly specified the path to OpenSSL (it should be the ++ same as the --prefix argument to the OpenSSL ++ Configure). ++ </para> + </sect3> + <sect3> + <!-- Example 6 --> +@@ -266,63 +375,85 @@ $ <userinput>./configure CC="cc -xarch=amd64" --enable-threads \ + $ <userinput>cd ../bind9</userinput> + $ <userinput>./configure --enable-threads \ + --with-openssl=/opt/pkcs11/usr \ +- --with-pkcs11=/opt/pkcs11/usr/lib/libpkcs11.so</userinput> ++ --with-pkcs11=/opt/pkcs11/usr/lib/libsofthsm.so</userinput> + </screen> + </sect3> +- <para>After configuring, run +- "<command>make</command>", +- "<command>make test</command>" and +- "<command>make install</command>".</para> +- <para>(Note: If "make test" fails in the "pkcs11" system test, you may +- have forgotten to set the SOFTHSM_CONF environment variable.)</para> ++ <para> ++ After configuring, run ++ "<command>make</command>", ++ "<command>make test</command>" and ++ "<command>make install</command>". ++ </para> ++ <para> ++ (Note: If "make test" fails in the "pkcs11" system test, you may ++ have forgotten to set the SOFTHSM_CONF environment variable.) ++ </para> + </sect2> + <sect2> +- <title>PKCS #11 Tools</title> +- <para>BIND 9 includes a minimal set of tools to operate the +- HSM, including +- <command>pkcs11-keygen</command> to generate a new key pair +- within the HSM, +- <command>pkcs11-list</command> to list objects currently +- available, and +- <command>pkcs11-destroy</command> to remove objects.</para> +- <para>In UNIX/Linux builds, these tools are built only if BIND +- 9 is configured with the --with-pkcs11 option. (NOTE: If +- --with-pkcs11 is set to "yes", rather than to the path of the +- PKCS #11 provider, then the tools will be built but the +- provider will be left undefined. Use the -m option or the +- PKCS11_PROVIDER environment variable to specify the path to the +- provider.)</para> ++ <title>PKCS#11 Tools</title> ++ <para> ++ BIND 9 includes a minimal set of tools to operate the ++ HSM, including ++ <command>pkcs11-keygen</command> to generate a new key pair ++ within the HSM, ++ <command>pkcs11-list</command> to list objects currently ++ available, ++ <command>pkcs11-destroy</command> to remove objects, and ++ <command>pkcs11-tokens</command> to list available tokens. ++ </para> ++ <para> ++ In UNIX/Linux builds, these tools are built only if BIND ++ 9 is configured with the --with-pkcs11 option. (Note: If ++ --with-pkcs11 is set to "yes", rather than to the path of the ++ PKCS#11 provider, then the tools will be built but the ++ provider will be left undefined. Use the -m option or the ++ PKCS11_PROVIDER environment variable to specify the path to the ++ provider.) ++ </para> + </sect2> + <sect2> + <title>Using the HSM</title> +- <para>First, we must set up the runtime environment so the +- OpenSSL and PKCS #11 libraries can be loaded:</para> ++ <para> ++ For OpenSSL-based PKCS#11, we must first set up the runtime ++ environment so the OpenSSL and PKCS#11 libraries can be loaded: ++ </para> + <screen> + $ <userinput>export LD_LIBRARY_PATH=/opt/pkcs11/usr/lib:${LD_LIBRARY_PATH}</userinput> + </screen> +- <para>When operating an AEP Keyper, it is also necessary to +- specify the location of the "machine" file, which stores +- information about the Keyper for use by PKCS #11 provider +- library. If the machine file is in +- <filename>/opt/Keyper/PKCS11Provider/machine</filename>, +- use:</para> ++ <para> ++ This causes <command>named</command> and other binaries to load ++ the OpenSSL library from <filename>/opt/pkcs11/usr/lib</filename> ++ rather than from the default location. This step is not necessary ++ when using native PKCS#11. ++ </para> ++ <para> ++ Some HSMs require other environment variables to be set. ++ For example, when operating an AEP Keyper, it is necessary to ++ specify the location of the "machine" file, which stores ++ information about the Keyper for use by the provider ++ library. If the machine file is in ++ <filename>/opt/Keyper/PKCS11Provider/machine</filename>, ++ use: ++ </para> + <screen> + $ <userinput>export KEYPER_LIBRARY_PATH=/opt/Keyper/PKCS11Provider</userinput> + </screen> +- <!-- TODO: why not defined at compile time? --> +- <para>These environment variables must be set whenever running +- any tool that uses the HSM, including +- <command>pkcs11-keygen</command>, +- <command>pkcs11-list</command>, +- <command>pkcs11-destroy</command>, +- <command>dnssec-keyfromlabel</command>, +- <command>dnssec-signzone</command>, +- <command>dnssec-keygen</command>(which will use the HSM for +- random number generation), and +- <command>named</command>.</para> +- <para>We can now create and use keys in the HSM. In this case, +- we will create a 2048 bit key and give it the label +- "sample-ksk":</para> ++ <para> ++ Such environment variables must be set whenever running ++ any tool that uses the HSM, including ++ <command>pkcs11-keygen</command>, ++ <command>pkcs11-list</command>, ++ <command>pkcs11-destroy</command>, ++ <command>dnssec-keyfromlabel</command>, ++ <command>dnssec-signzone</command>, ++ <command>dnssec-keygen</command>, and ++ <command>named</command>. ++ </para> ++ <para> ++ We can now create and use keys in the HSM. In this case, ++ we will create a 2048 bit key and give it the label ++ "sample-ksk": ++ </para> + <screen> + $ <userinput>pkcs11-keygen -b 2048 -l sample-ksk</userinput> + </screen> +@@ -333,44 +464,56 @@ Enter PIN: + object[0]: handle 2147483658 class 3 label[8] 'sample-ksk' id[0] + object[1]: handle 2147483657 class 2 label[8] 'sample-ksk' id[0] + </screen> +- <para>Before using this key to sign a zone, we must create a +- pair of BIND 9 key files. The "dnssec-keyfromlabel" utility +- does this. In this case, we will be using the HSM key +- "sample-ksk" as the key-signing key for "example.net":</para> ++ <para> ++ Before using this key to sign a zone, we must create a ++ pair of BIND 9 key files. The "dnssec-keyfromlabel" utility ++ does this. In this case, we will be using the HSM key ++ "sample-ksk" as the key-signing key for "example.net": ++ </para> + <screen> + $ <userinput>dnssec-keyfromlabel -l sample-ksk -f KSK example.net</userinput> + </screen> +- <para>The resulting K*.key and K*.private files can now be used +- to sign the zone. Unlike normal K* files, which contain both +- public and private key data, these files will contain only the +- public key data, plus an identifier for the private key which +- remains stored within the HSM. The HSM handles signing with the +- private key.</para> +- <para>If you wish to generate a second key in the HSM for use +- as a zone-signing key, follow the same procedure above, using a +- different keylabel, a smaller key size, and omitting "-f KSK" +- from the dnssec-keyfromlabel arguments:</para> ++ <para> ++ The resulting K*.key and K*.private files can now be used ++ to sign the zone. Unlike normal K* files, which contain both ++ public and private key data, these files will contain only the ++ public key data, plus an identifier for the private key which ++ remains stored within the HSM. Signing with the private key takes ++ place inside the HSM. ++ </para> ++ <para> ++ If you wish to generate a second key in the HSM for use ++ as a zone-signing key, follow the same procedure above, using a ++ different keylabel, a smaller key size, and omitting "-f KSK" ++ from the dnssec-keyfromlabel arguments: ++ </para> + <screen> + $ <userinput>pkcs11-keygen -b 1024 -l sample-zsk</userinput> + $ <userinput>dnssec-keyfromlabel -l sample-zsk example.net</userinput> + </screen> +- <para>Alternatively, you may prefer to generate a conventional +- on-disk key, using dnssec-keygen:</para> ++ <para> ++ Alternatively, you may prefer to generate a conventional ++ on-disk key, using dnssec-keygen: ++ </para> + <screen> + $ <userinput>dnssec-keygen example.net</userinput> + </screen> +- <para>This provides less security than an HSM key, but since +- HSMs can be slow or cumbersome to use for security reasons, it +- may be more efficient to reserve HSM keys for use in the less +- frequent key-signing operation. The zone-signing key can be +- rolled more frequently, if you wish, to compensate for a +- reduction in key security.</para> +- <para>Now you can sign the zone. (Note: If not using the -S +- option to +- <command>dnssec-signzone</command>, it will be necessary to add +- the contents of both +- <filename>K*.key</filename> files to the zone master file before +- signing it.)</para> ++ <para> ++ This provides less security than an HSM key, but since ++ HSMs can be slow or cumbersome to use for security reasons, it ++ may be more efficient to reserve HSM keys for use in the less ++ frequent key-signing operation. The zone-signing key can be ++ rolled more frequently, if you wish, to compensate for a ++ reduction in key security. (Note: When using native PKCS#11, ++ there is no speed advantage to using on-disk keys, as cryptographic ++ operations will be done by the HSM regardless.) ++ </para> ++ <para> ++ Now you can sign the zone. (Note: If not using the -S ++ option to <command>dnssec-signzone</command>, it will be ++ necessary to add the contents of both <filename>K*.key</filename> ++ files to the zone master file before signing it.) ++ </para> + <screen> + $ <userinput>dnssec-signzone -S example.net</userinput> + Enter PIN: +@@ -383,36 +526,50 @@ example.net.signed + </sect2> + <sect2> + <title>Specifying the engine on the command line</title> +- <para>The OpenSSL engine can be specified in +- <command>named</command> and all of the BIND +- <command>dnssec-*</command> tools by using the "-E +- <engine>" command line option. If BIND 9 is built with +- the --with-pkcs11 option, this option defaults to "pkcs11". +- Specifying the engine will generally not be necessary unless +- for some reason you wish to use a different OpenSSL +- engine.</para> +- <para>If you wish to disable use of the "pkcs11" engine — +- for troubleshooting purposes, or because the HSM is unavailable +- — set the engine to the empty string. For example:</para> ++ <para> ++ When using OpenSSL-based PKCS#11, the "engine" to be used by ++ OpenSSL can be specified in <command>named</command> and all of ++ the BIND <command>dnssec-*</command> tools by using the "-E ++ <engine>" command line option. If BIND 9 is built with ++ the --with-pkcs11 option, this option defaults to "pkcs11". ++ Specifying the engine will generally not be necessary unless ++ for some reason you wish to use a different OpenSSL ++ engine. ++ </para> ++ <para> ++ If you wish to disable use of the "pkcs11" engine — ++ for troubleshooting purposes, or because the HSM is unavailable ++ — set the engine to the empty string. For example: ++ </para> + <screen> + $ <userinput>dnssec-signzone -E '' -S example.net</userinput> + </screen> +- <para>This causes +- <command>dnssec-signzone</command> to run as if it were compiled +- without the --with-pkcs11 option.</para> ++ <para> ++ This causes ++ <command>dnssec-signzone</command> to run as if it were compiled ++ without the --with-pkcs11 option. ++ </para> ++ <para> ++ When built with native PKCS#11 mode, the "engine" option has a ++ different meaning: it specifies the path to the PKCS#11 provider ++ library. This may be useful when testing a new provider library. ++ </para> + </sect2> + <sect2> + <title>Running named with automatic zone re-signing</title> +- <para>If you want +- <command>named</command> to dynamically re-sign zones using HSM +- keys, and/or to to sign new records inserted via nsupdate, then +- named must have access to the HSM PIN. This can be accomplished +- by placing the PIN into the openssl.cnf file (in the above +- examples, +- <filename>/opt/pkcs11/usr/ssl/openssl.cnf</filename>).</para> +- <para>The location of the openssl.cnf file can be overridden by +- setting the OPENSSL_CONF environment variable before running +- named.</para> ++ <para> ++ If you want <command>named</command> to dynamically re-sign zones ++ using HSM keys, and/or to to sign new records inserted via nsupdate, ++ then named must have access to the HSM PIN. In OpenSSL-based PKCS#11, ++ this is accomplished by placing the PIN into the openssl.cnf file ++ (in the above examples, ++ <filename>/opt/pkcs11/usr/ssl/openssl.cnf</filename>). ++ </para> ++ <para> ++ The location of the openssl.cnf file can be overridden by ++ setting the OPENSSL_CONF environment variable before running ++ named. ++ </para> + <para>Sample openssl.cnf:</para> + <programlisting> + openssl_conf = openssl_def +@@ -423,22 +580,25 @@ $ <userinput>dnssec-signzone -E '' -S example.net</userinput> + [ pkcs11_section ] + PIN = <replaceable><PLACE PIN HERE></replaceable> + </programlisting> +- <para>This will also allow the dnssec-* tools to access the HSM +- without PIN entry. (The pkcs11-* tools access the HSM directly, +- not via OpenSSL, so a PIN will still be required to use +- them.)</para> +-<!-- +-If the PIN is not known, I believe the first time named needs the +-PIN to open a key, it'll ask you to type in the PIN, which will be +-a problem because it probably won't be running on a terminal +---> ++ <para> ++ This will also allow the dnssec-* tools to access the HSM ++ without PIN entry. (The pkcs11-* tools access the HSM directly, ++ not via OpenSSL, so a PIN will still be required to use ++ them.) ++ </para> ++ <para> ++ In native PKCS#11 mode, the PIN can be provided in a file specified ++ as an attribute of the key's label. For example, if a key had the label ++ <userinput>pkcs11:object=local-zsk;pin-source=/etc/hsmpin"</userinput>, ++ then the PIN would be read from the file ++ <filename>/etc/hsmpin</filename>. ++ </para> + <warning> +- <para>Placing the HSM's PIN in a text file in +- this manner may reduce the security advantage of using an +- HSM. Be sure this is what you want to do before configuring +- OpenSSL in this way.</para> ++ <para> ++ Placing the HSM's PIN in a text file in this manner may reduce the ++ security advantage of using an HSM. Be sure this is what you want to ++ do before configuring OpenSSL in this way. ++ </para> + </warning> + </sect2> +- <!-- TODO: what is alternative then for named dynamic re-signing? --> +- <!-- TODO: what happens if PIN is not known? named will log about it? --> + </sect1> +diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in +index 0c5e93b..41fac95 100644 +--- a/lib/dns/Makefile.in ++++ b/lib/dns/Makefile.in +@@ -27,10 +27,10 @@ top_srcdir = @top_srcdir@ + + USE_ISC_SPNEGO = @USE_ISC_SPNEGO@ + +-CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} \ +- ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ ++CINCLUDES = -I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} \ ++ @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ + +-CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ ${USE_ISC_SPNEGO} ++CDEFINES = -DUSE_MD5 @CRYPTO@ @USE_GSSAPI@ ${USE_ISC_SPNEGO} + + CWARNINGS = + +@@ -47,7 +47,10 @@ OPENSSLLINKOBJS = openssl_link.@O@ openssldh_link.@O@ openssldsa_link.@O@ \ + opensslecdsa_link.@O@ @OPENSSLGOSTLINKOBJS@ \ + opensslrsa_link.@O@ + +-DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ \ ++PKCS11LINKOBJS = pkcs11dh_link.@O@ pkcs11dsa_link.@O@ pkcs11rsa_link.@O@ \ ++ pkcs11ecdsa_link.@O@ pkcs11gost_link.@O@ pkcs11.@O@ ++ ++DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ @PKCS11LINKOBJS@ \ + dst_api.@O@ dst_lib.@O@ dst_parse.@O@ dst_result.@O@ \ + gssapi_link.@O@ gssapictx.@O@ hmac_link.@O@ key.@O@ + +@@ -79,7 +82,10 @@ OPENSSLGOSTLINKSRCS = opensslgost_link.c + OPENSSLLINKSRCS = openssl_link.c openssldh_link.c openssldsa_link.c \ + opensslecdsa_link.c @OPENSSLGOSTLINKSRCS@ opensslrsa_link.c + +-DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ \ ++PKCS11LINKSRCS = pkcs11dh_link.c pkcs11dsa_link.c pkcs11rsa_link.c \ ++ pkcs11ecdsa_link.c pkcs11gost_link.c pkcs11.c ++ ++DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ @PKCS11LINKSRCS@ \ + dst_api.c dst_lib.c dst_parse.c \ + dst_result.c gssapi_link.c gssapictx.c \ + hmac_link.c key.c +diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c +index cf97404..00a0080 100644 +--- a/lib/dns/dnssec.c ++++ b/lib/dns/dnssec.c +@@ -275,7 +275,8 @@ dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + if (ret != ISC_R_SUCCESS) + goto cleanup_databuf; + +- ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx); ++ ret = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx); + if (ret != ISC_R_SUCCESS) + goto cleanup_databuf; + +@@ -470,7 +471,8 @@ dns_dnssec_verify3(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key, + } + + again: +- ret = dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx); ++ ret = dst_context_create4(key, mctx, DNS_LOGCATEGORY_DNSSEC, ++ ISC_FALSE, maxbits, &ctx); + if (ret != ISC_R_SUCCESS) + goto cleanup_struct; + +@@ -872,7 +874,8 @@ dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) { + + isc_buffer_init(&databuf, data, sizeof(data)); + +- RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx)); ++ RETERR(dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_DNSSEC, ISC_TRUE, &ctx)); + + /* + * Digest the fields of the SIG - we can cheat and use +@@ -1022,7 +1025,8 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, + goto failure; + } + +- RETERR(dst_context_create2(key, mctx, DNS_LOGCATEGORY_DNSSEC, &ctx)); ++ RETERR(dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_DNSSEC, ISC_FALSE, &ctx)); + + /* + * Digest the SIG(0) record, except for the signature. +diff --git a/lib/dns/ds.c b/lib/dns/ds.c +index e72ecbb..b51476b 100644 +--- a/lib/dns/ds.c ++++ b/lib/dns/ds.c +@@ -38,11 +38,8 @@ + + #include <dst/dst.h> + +-#ifdef HAVE_OPENSSL_GOST +-#include <dst/result.h> +-#include <openssl/evp.h> +- +-extern const EVP_MD * EVP_gost(void); ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) ++#include "dst_gost.h" + #endif + + isc_result_t +@@ -59,9 +56,8 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, + isc_sha1_t sha1; + isc_sha256_t sha256; + isc_sha384_t sha384; +-#ifdef HAVE_OPENSSL_GOST +- EVP_MD_CTX ctx; +- const EVP_MD *md; ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) ++ isc_gost_t gost; + #endif + + REQUIRE(key != NULL); +@@ -88,29 +84,23 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, + isc_sha1_final(&sha1, digest); + break; + +-#ifdef HAVE_OPENSSL_GOST +-#define CHECK(x) \ +- if ((x) != 1) { \ +- EVP_MD_CTX_cleanup(&ctx); \ +- return (DST_R_CRYPTOFAILURE); \ +- } ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) ++#define RETERR(x) do { \ ++ isc_result_t ret = (x); \ ++ if (ret != ISC_R_SUCCESS) { \ ++ isc_gost_invalidate(&gost); \ ++ return (ret); \ ++ } \ ++} while (0) + + case DNS_DSDIGEST_GOST: +- md = EVP_gost(); +- if (md == NULL) +- return (DST_R_CRYPTOFAILURE); +- EVP_MD_CTX_init(&ctx); +- CHECK(EVP_DigestInit(&ctx, md)); ++ RETERR(isc_gost_init(&gost)); + dns_name_toregion(name, &r); +- CHECK(EVP_DigestUpdate(&ctx, +- (const void *) r.base, +- (size_t) r.length)); ++ RETERR(isc_gost_update(&gost, r.base, r.length)); + dns_rdata_toregion(key, &r); + INSIST(r.length >= 4); +- CHECK(EVP_DigestUpdate(&ctx, +- (const void *) r.base, +- (size_t) r.length)); +- CHECK(EVP_DigestFinal(&ctx, digest, NULL)); ++ RETERR(isc_gost_update(&gost, r.base, r.length)); ++ RETERR(isc_gost_final(&gost, digest)); + break; + #endif + +@@ -147,7 +137,7 @@ dns_ds_buildrdata(dns_name_t *owner, dns_rdata_t *key, + ds.length = ISC_SHA1_DIGESTLENGTH; + break; + +-#ifdef HAVE_OPENSSL_GOST ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) + case DNS_DSDIGEST_GOST: + ds.length = ISC_GOST_DIGESTLENGTH; + break; +diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c +index 6416273..d96473f 100644 +--- a/lib/dns/dst_api.c ++++ b/lib/dns/dst_api.c +@@ -75,9 +75,7 @@ + #define DST_AS_STR(t) ((t).value.as_textregion.base) + + static dst_func_t *dst_t_func[DST_MAX_ALGS]; +-#ifdef BIND9 + static isc_entropy_t *dst_entropy_pool = NULL; +-#endif + static unsigned int dst_entropy_flags = 0; + static isc_boolean_t dst_initialized = ISC_FALSE; + +@@ -169,7 +167,7 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx, + #endif + REQUIRE(dst_initialized == ISC_FALSE); + +-#ifndef OPENSSL ++#if !defined(OPENSSL) && !defined(PKCS11CRYPTO) + UNUSED(engine); + #endif + +@@ -234,7 +232,24 @@ dst_lib_init2(isc_mem_t *mctx, isc_entropy_t *ectx, + RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA256])); + RETERR(dst__opensslecdsa_init(&dst_t_func[DST_ALG_ECDSA384])); + #endif +-#endif /* OPENSSL */ ++#elif PKCS11CRYPTO ++ RETERR(dst__pkcs11_init(mctx, engine)); ++ RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSAMD5])); ++ RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA1])); ++ RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_NSEC3RSASHA1])); ++ RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA256])); ++ RETERR(dst__pkcs11rsa_init(&dst_t_func[DST_ALG_RSASHA512])); ++ RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_DSA])); ++ RETERR(dst__pkcs11dsa_init(&dst_t_func[DST_ALG_NSEC3DSA])); ++ RETERR(dst__pkcs11dh_init(&dst_t_func[DST_ALG_DH])); ++#ifdef HAVE_PKCS11_ECDSA ++ RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA256])); ++ RETERR(dst__pkcs11ecdsa_init(&dst_t_func[DST_ALG_ECDSA384])); ++#endif ++#ifdef HAVE_PKCS11_GOST ++ RETERR(dst__pkcs11gost_init(&dst_t_func[DST_ALG_ECCGOST])); ++#endif ++#endif /* if OPENSSL, elif PKCS11CRYPTO */ + #ifdef GSSAPI + RETERR(dst__gssapi_init(&dst_t_func[DST_ALG_GSSAPI])); + #endif +@@ -259,7 +274,9 @@ dst_lib_destroy(void) { + dst_t_func[i]->cleanup(); + #ifdef OPENSSL + dst__openssl_destroy(); +-#endif ++#elif PKCS11CRYPTO ++ (void) dst__pkcs11_destroy(); ++#endif /* if OPENSSL, elif PKCS11CRYPTO */ + if (dst__memory_pool != NULL) + isc_mem_detach(&dst__memory_pool); + #ifdef BIND9 +@@ -279,13 +296,31 @@ dst_algorithm_supported(unsigned int alg) { + + isc_result_t + dst_context_create(dst_key_t *key, isc_mem_t *mctx, dst_context_t **dctxp) { +- return (dst_context_create2(key, mctx, +- DNS_LOGCATEGORY_GENERAL, dctxp)); ++ return (dst_context_create4(key, mctx, DNS_LOGCATEGORY_GENERAL, ++ ISC_TRUE, 0, dctxp)); + } + + isc_result_t + dst_context_create2(dst_key_t *key, isc_mem_t *mctx, +- isc_logcategory_t *category, dst_context_t **dctxp) { ++ isc_logcategory_t *category, dst_context_t **dctxp) ++{ ++ return (dst_context_create4(key, mctx, category, ISC_TRUE, 0, dctxp)); ++} ++ ++isc_result_t ++dst_context_create3(dst_key_t *key, isc_mem_t *mctx, ++ isc_logcategory_t *category, isc_boolean_t useforsigning, ++ dst_context_t **dctxp) ++{ ++ return (dst_context_create4(key, mctx, category, ++ useforsigning, 0, dctxp)); ++} ++ ++isc_result_t ++dst_context_create4(dst_key_t *key, isc_mem_t *mctx, ++ isc_logcategory_t *category, isc_boolean_t useforsigning, ++ int maxbits, dst_context_t **dctxp) ++{ + dst_context_t *dctx; + isc_result_t result; + +@@ -294,7 +329,7 @@ dst_context_create2(dst_key_t *key, isc_mem_t *mctx, + REQUIRE(mctx != NULL); + REQUIRE(dctxp != NULL && *dctxp == NULL); + +- if (key->func->createctx == NULL) ++ if (key->func->createctx == NULL && key->func->createctx2 == NULL) + return (DST_R_UNSUPPORTEDALG); + if (key->keydata.generic == NULL) + return (DST_R_NULLKEY); +@@ -305,7 +340,14 @@ dst_context_create2(dst_key_t *key, isc_mem_t *mctx, + dctx->key = key; + dctx->mctx = mctx; + dctx->category = category; +- result = key->func->createctx(key, dctx); ++ if (useforsigning) ++ dctx->use = DO_SIGN; ++ else ++ dctx->use = DO_VERIFY; ++ if (key->func->createctx2 != NULL) ++ result = key->func->createctx2(key, maxbits, dctx); ++ else ++ result = key->func->createctx(key, dctx); + if (result != ISC_R_SUCCESS) { + isc_mem_put(mctx, dctx, sizeof(dst_context_t)); + return (result); +@@ -1796,7 +1838,7 @@ algorithm_status(unsigned int alg) { + + if (dst_algorithm_supported(alg)) + return (ISC_R_SUCCESS); +-#ifndef OPENSSL ++#if !defined(OPENSSL) && !defined(PKCS11CRYPTO) + if (alg == DST_ALG_RSAMD5 || alg == DST_ALG_RSASHA1 || + alg == DST_ALG_DSA || alg == DST_ALG_DH || + alg == DST_ALG_HMACMD5 || alg == DST_ALG_NSEC3DSA || +@@ -1842,11 +1884,18 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { + + if (len == 0) + return (ISC_R_SUCCESS); ++ ++#ifdef PKCS11CRYPTO ++ UNUSED(pseudo); ++ UNUSED(flags); ++ return (pk11_rand_bytes(buf, len)); ++#else /* PKCS11CRYPTO */ + if (pseudo) + flags &= ~ISC_ENTROPY_GOODONLY; + else + flags |= ISC_ENTROPY_BLOCKING; + return (isc_entropy_getdata(dst_entropy_pool, buf, len, NULL, flags)); ++#endif /* PKCS11CRYPTO */ + #else + UNUSED(buf); + UNUSED(len); +@@ -1858,7 +1907,7 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { + + unsigned int + dst__entropy_status(void) { +-#ifdef BIND9 ++#ifndef PKCS11CRYPTO + #ifdef GSSAPI + unsigned int flags = dst_entropy_flags; + isc_result_t ret; +diff --git a/lib/dns/dst_gost.h b/lib/dns/dst_gost.h +new file mode 100644 +index 0000000..37a4200 +--- /dev/null ++++ b/lib/dns/dst_gost.h +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef DST_GOST_H ++#define DST_GOST_H 1 ++ ++#include <isc/lang.h> ++#include <isc/log.h> ++#include <dst/result.h> ++ ++#define ISC_GOST_DIGESTLENGTH 32U ++ ++#ifdef HAVE_OPENSSL_GOST ++#include <openssl/evp.h> ++ ++typedef EVP_MD_CTX isc_gost_t; ++#endif ++#ifdef HAVE_PKCS11_GOST ++#include <pk11/pk11.h> ++ ++typedef pk11_context_t isc_gost_t; ++#endif ++ ++ISC_LANG_BEGINDECLS ++ ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) ++ ++isc_result_t ++isc_gost_init(isc_gost_t *ctx); ++ ++void ++isc_gost_invalidate(isc_gost_t *ctx); ++ ++isc_result_t ++isc_gost_update(isc_gost_t *ctx, const unsigned char *data, unsigned int len); ++ ++isc_result_t ++isc_gost_final(isc_gost_t *ctx, unsigned char *digest); ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* HAVE_OPENSSL_GOST || HAVE_PKCS11_GOST */ ++ ++#endif /* DST_GOST_H */ +diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h +index 49ca424..b15135e 100644 +--- a/lib/dns/dst_internal.h ++++ b/lib/dns/dst_internal.h +@@ -84,6 +84,12 @@ typedef struct dst_hmacsha256_key dst_hmacsha256_key_t; + typedef struct dst_hmacsha384_key dst_hmacsha384_key_t; + typedef struct dst_hmacsha512_key dst_hmacsha512_key_t; + ++/*% ++ * Indicate whether a DST context will be used for signing ++ * or for verification ++ */ ++typedef enum { DO_SIGN, DO_VERIFY } dst_use_t; ++ + /*% DST Key Structure */ + struct dst_key { + unsigned int magic; +@@ -112,6 +118,8 @@ struct dst_key { + DSA *dsa; + DH *dh; + EVP_PKEY *pkey; ++#elif PKCS11CRYPTO ++ pk11_object_t *pkey; + #endif + dst_hmacmd5_key_t *hmacmd5; + dst_hmacsha1_key_t *hmacsha1; +@@ -139,6 +147,7 @@ struct dst_key { + + struct dst_context { + unsigned int magic; ++ dst_use_t use; + dst_key_t *key; + isc_mem_t *mctx; + isc_logcategory_t *category; +@@ -157,6 +166,8 @@ struct dst_context { + isc_hmacsha512_t *hmacsha512ctx; + #ifdef OPENSSL + EVP_MD_CTX *evp_md_ctx; ++#elif PKCS11CRYPTO ++ pk11_context_t *pk11_ctx; + #endif + } ctxdata; + }; +@@ -166,6 +177,8 @@ struct dst_func { + * Context functions + */ + isc_result_t (*createctx)(dst_key_t *key, dst_context_t *dctx); ++ isc_result_t (*createctx2)(dst_key_t *key, int maxbits, ++ dst_context_t *dctx); + void (*destroyctx)(dst_context_t *dctx); + isc_result_t (*adddata)(dst_context_t *dctx, const isc_region_t *data); + +@@ -209,6 +222,7 @@ struct dst_func { + * Initializers + */ + isc_result_t dst__openssl_init(const char *engine); ++#define dst__pkcs11_init pk11_initialize + + isc_result_t dst__hmacmd5_init(struct dst_func **funcp); + isc_result_t dst__hmacsha1_init(struct dst_func **funcp); +@@ -218,20 +232,30 @@ isc_result_t dst__hmacsha384_init(struct dst_func **funcp); + isc_result_t dst__hmacsha512_init(struct dst_func **funcp); + isc_result_t dst__opensslrsa_init(struct dst_func **funcp, + unsigned char algorithm); ++isc_result_t dst__pkcs11rsa_init(struct dst_func **funcp); + isc_result_t dst__openssldsa_init(struct dst_func **funcp); ++isc_result_t dst__pkcs11dsa_init(struct dst_func **funcp); + isc_result_t dst__openssldh_init(struct dst_func **funcp); ++isc_result_t dst__pkcs11dh_init(struct dst_func **funcp); + isc_result_t dst__gssapi_init(struct dst_func **funcp); ++#ifdef HAVE_OPENSSL_ECDSA ++isc_result_t dst__opensslecdsa_init(struct dst_func **funcp); ++#endif ++#ifdef HAVE_PKCS11_ECDSA ++isc_result_t dst__pkcs11ecdsa_init(struct dst_func **funcp); ++#endif + #ifdef HAVE_OPENSSL_GOST + isc_result_t dst__opensslgost_init(struct dst_func **funcp); + #endif +-#ifdef HAVE_OPENSSL_ECDSA +-isc_result_t dst__opensslecdsa_init(struct dst_func **funcp); ++#ifdef HAVE_PKCS11_GOST ++isc_result_t dst__pkcs11gost_init(struct dst_func **funcp); + #endif + + /*% + * Destructors + */ + void dst__openssl_destroy(void); ++#define dst__pkcs11_destroy pk11_finalize + + /*% + * Memory allocators using the DST memory pool. +diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c +index 6348cc1..ec622d9 100644 +--- a/lib/dns/dst_parse.c ++++ b/lib/dns/dst_parse.c +@@ -93,7 +93,6 @@ static struct parse_map map[] = { + {TAG_RSA_COEFFICIENT, "Coefficient:"}, + {TAG_RSA_ENGINE, "Engine:" }, + {TAG_RSA_LABEL, "Label:" }, +- {TAG_RSA_PIN, "PIN:" }, + + {TAG_DH_PRIME, "Prime(p):"}, + {TAG_DH_GENERATOR, "Generator(g):"}, +@@ -107,8 +106,11 @@ static struct parse_map map[] = { + {TAG_DSA_PUBLIC, "Public_value(y):"}, + + {TAG_GOST_PRIVASN1, "GostAsn1:"}, ++ {TAG_GOST_PRIVRAW, "PrivateKey:"}, + + {TAG_ECDSA_PRIVATEKEY, "PrivateKey:"}, ++ {TAG_ECDSA_ENGINE, "Engine:" }, ++ {TAG_ECDSA_LABEL, "Label:" }, + + {TAG_HMACMD5_KEY, "Key:"}, + {TAG_HMACMD5_BITS, "Bits:"}, +@@ -262,22 +264,42 @@ check_gost(const dst_private_t *priv, isc_boolean_t external) { + + if (priv->nelements != GOST_NTAGS) + return (-1); +- if (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) ++ if ((priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 0)) && ++ (priv->elements[0].tag != TAG(DST_ALG_ECCGOST, 1))) + return (-1); + return (0); + } + + static int + check_ecdsa(const dst_private_t *priv, isc_boolean_t external) { ++ int i, j; ++ isc_boolean_t have[ECDSA_NTAGS]; ++ isc_boolean_t ok; ++ unsigned int mask; + + if (external) + return ((priv->nelements == 0) ? 0 : -1); + +- if (priv->nelements != ECDSA_NTAGS) +- return (-1); +- if (priv->elements[0].tag != TAG(DST_ALG_ECDSA256, 0)) +- return (-1); +- return (0); ++ for (i = 0; i < ECDSA_NTAGS; i++) ++ have[i] = ISC_FALSE; ++ for (j = 0; j < priv->nelements; j++) { ++ for (i = 0; i < ECDSA_NTAGS; i++) ++ if (priv->elements[j].tag == TAG(DST_ALG_ECDSA256, i)) ++ break; ++ if (i == ECDSA_NTAGS) ++ return (-1); ++ have[i] = ISC_TRUE; ++ } ++ ++ mask = ~0; ++ mask <<= sizeof(mask) * 8 - TAG_SHIFT; ++ mask >>= sizeof(mask) * 8 - TAG_SHIFT; ++ ++ if (have[TAG_ECDSA_ENGINE & mask]) ++ ok = have[TAG_ECDSA_LABEL & mask]; ++ else ++ ok = have[TAG_ECDSA_PRIVATEKEY & mask]; ++ return (ok ? 0 : -1 ); + } + + static int +diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h +index f048bf0..a8a5641 100644 +--- a/lib/dns/dst_parse.h ++++ b/lib/dns/dst_parse.h +@@ -63,7 +63,6 @@ + #define TAG_RSA_COEFFICIENT ((DST_ALG_RSAMD5 << TAG_SHIFT) + 7) + #define TAG_RSA_ENGINE ((DST_ALG_RSAMD5 << TAG_SHIFT) + 8) + #define TAG_RSA_LABEL ((DST_ALG_RSAMD5 << TAG_SHIFT) + 9) +-#define TAG_RSA_PIN ((DST_ALG_RSAMD5 << TAG_SHIFT) + 10) + + #define DH_NTAGS 4 + #define TAG_DH_PRIME ((DST_ALG_DH << TAG_SHIFT) + 0) +@@ -80,9 +79,12 @@ + + #define GOST_NTAGS 1 + #define TAG_GOST_PRIVASN1 ((DST_ALG_ECCGOST << TAG_SHIFT) + 0) ++#define TAG_GOST_PRIVRAW ((DST_ALG_ECCGOST << TAG_SHIFT) + 1) + +-#define ECDSA_NTAGS 1 ++#define ECDSA_NTAGS 4 + #define TAG_ECDSA_PRIVATEKEY ((DST_ALG_ECDSA256 << TAG_SHIFT) + 0) ++#define TAG_ECDSA_ENGINE ((DST_ALG_ECDSA256 << TAG_SHIFT) + 1) ++#define TAG_ECDSA_LABEL ((DST_ALG_ECDSA256 << TAG_SHIFT) + 2) + + #define OLD_HMACMD5_NTAGS 1 + #define HMACMD5_NTAGS 2 +diff --git a/lib/dns/dst_pkcs11.h b/lib/dns/dst_pkcs11.h +new file mode 100644 +index 0000000..1c35b6b +--- /dev/null ++++ b/lib/dns/dst_pkcs11.h +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef DST_PKCS11_H ++#define DST_PKCS11_H 1 ++ ++#include <isc/lang.h> ++#include <isc/log.h> ++#include <isc/result.h> ++ ++ISC_LANG_BEGINDECLS ++ ++isc_result_t ++dst__pkcs11_toresult(const char *funcname, const char *file, int line, ++ isc_result_t fallback, CK_RV rv); ++ ++#define PK11_CALL(func, args, fallback) \ ++ ((void) (((rv = (func) args) == CKR_OK) || \ ++ ((ret = dst__pkcs11_toresult(#func, __FILE__, __LINE__, \ ++ fallback, rv)), 0))) ++ ++#define PK11_RET(func, args, fallback) \ ++ ((void) (((rv = (func) args) == CKR_OK) || \ ++ ((ret = dst__pkcs11_toresult(#func, __FILE__, __LINE__, \ ++ fallback, rv)), 0))); \ ++ if (rv != CKR_OK) goto err; ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* DST_PKCS11_H */ +diff --git a/lib/dns/dst_result.c b/lib/dns/dst_result.c +index 30aa1fa..79fa7d3 100644 +--- a/lib/dns/dst_result.c ++++ b/lib/dns/dst_result.c +@@ -50,7 +50,8 @@ static const char *text[DST_R_NRESULTS] = { + "failure computing a shared secret", /*%< 18 */ + "no randomness available", /*%< 19 */ + "bad key type", /*%< 20 */ +- "no engine" /*%< 21 */ ++ "no engine", /*%< 21 */ ++ "illegal operation for an external key",/*%< 22 */ + }; + + #define DST_RESULT_RESULTSET 2 +diff --git a/lib/dns/gssapi_link.c b/lib/dns/gssapi_link.c +index 5ad81cd..1c35959 100644 +--- a/lib/dns/gssapi_link.c ++++ b/lib/dns/gssapi_link.c +@@ -358,6 +358,7 @@ gssapi_dump(dst_key_t *key, isc_mem_t *mctx, char **buffer, int *length) { + + static dst_func_t gssapi_functions = { + gssapi_create_signverify_ctx, ++ NULL, /*%< createctx2 */ + gssapi_destroy_signverify_ctx, + gssapi_adddata, + gssapi_sign, +diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c +index 1f1a0ca..7a56c79 100644 +--- a/lib/dns/hmac_link.c ++++ b/lib/dns/hmac_link.c +@@ -282,6 +282,9 @@ hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (result != ISC_R_SUCCESS) + return (result); + ++ if (key->external) ++ result = DST_R_EXTERNALKEY; ++ + key->key_bits = 0; + for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { + switch (priv.elements[i].tag) { +@@ -310,6 +313,7 @@ hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t hmacmd5_functions = { + hmacmd5_createctx, ++ NULL, /*%< createctx2 */ + hmacmd5_destroyctx, + hmacmd5_adddata, + hmacmd5_sign, +@@ -528,6 +532,9 @@ hmacsha1_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.hmacsha1 == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ + hkey = key->keydata.hmacsha1; + + priv.elements[cnt].tag = TAG_HMACSHA1_KEY; +@@ -559,8 +566,11 @@ hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (result != ISC_R_SUCCESS) + return (result); + ++ if (key->external) ++ result = DST_R_EXTERNALKEY; ++ + key->key_bits = 0; +- for (i = 0; i < priv.nelements; i++) { ++ for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA1_KEY: + isc_buffer_init(&b, priv.elements[i].data, +@@ -587,6 +597,7 @@ hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t hmacsha1_functions = { + hmacsha1_createctx, ++ NULL, /*%< createctx2 */ + hmacsha1_destroyctx, + hmacsha1_adddata, + hmacsha1_sign, +@@ -807,6 +818,9 @@ hmacsha224_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.hmacsha224 == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ + hkey = key->keydata.hmacsha224; + + priv.elements[cnt].tag = TAG_HMACSHA224_KEY; +@@ -838,6 +852,9 @@ hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (result != ISC_R_SUCCESS) + return (result); + ++ if (key->external) ++ result = DST_R_EXTERNALKEY; ++ + key->key_bits = 0; + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { +@@ -866,6 +883,7 @@ hmacsha224_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t hmacsha224_functions = { + hmacsha224_createctx, ++ NULL, /*%< createctx2 */ + hmacsha224_destroyctx, + hmacsha224_adddata, + hmacsha224_sign, +@@ -1086,6 +1104,9 @@ hmacsha256_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.hmacsha256 == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ + hkey = key->keydata.hmacsha256; + + priv.elements[cnt].tag = TAG_HMACSHA256_KEY; +@@ -1117,8 +1138,11 @@ hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (result != ISC_R_SUCCESS) + return (result); + ++ if (key->external) ++ result = DST_R_EXTERNALKEY; ++ + key->key_bits = 0; +- for (i = 0; i < priv.nelements; i++) { ++ for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA256_KEY: + isc_buffer_init(&b, priv.elements[i].data, +@@ -1145,6 +1169,7 @@ hmacsha256_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t hmacsha256_functions = { + hmacsha256_createctx, ++ NULL, /*%< createctx2 */ + hmacsha256_destroyctx, + hmacsha256_adddata, + hmacsha256_sign, +@@ -1365,6 +1390,9 @@ hmacsha384_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.hmacsha384 == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ + hkey = key->keydata.hmacsha384; + + priv.elements[cnt].tag = TAG_HMACSHA384_KEY; +@@ -1396,8 +1424,11 @@ hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (result != ISC_R_SUCCESS) + return (result); + ++ if (key->external) ++ result = DST_R_EXTERNALKEY; ++ + key->key_bits = 0; +- for (i = 0; i < priv.nelements; i++) { ++ for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA384_KEY: + isc_buffer_init(&b, priv.elements[i].data, +@@ -1424,6 +1455,7 @@ hmacsha384_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t hmacsha384_functions = { + hmacsha384_createctx, ++ NULL, /*%< createctx2 */ + hmacsha384_destroyctx, + hmacsha384_adddata, + hmacsha384_sign, +@@ -1644,6 +1676,9 @@ hmacsha512_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.hmacsha512 == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ + hkey = key->keydata.hmacsha512; + + priv.elements[cnt].tag = TAG_HMACSHA512_KEY; +@@ -1675,8 +1710,11 @@ hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (result != ISC_R_SUCCESS) + return (result); + ++ if (key->external) ++ result = DST_R_EXTERNALKEY; ++ + key->key_bits = 0; +- for (i = 0; i < priv.nelements; i++) { ++ for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { + switch (priv.elements[i].tag) { + case TAG_HMACSHA512_KEY: + isc_buffer_init(&b, priv.elements[i].data, +@@ -1703,6 +1741,7 @@ hmacsha512_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t hmacsha512_functions = { + hmacsha512_createctx, ++ NULL, /*%< createctx2 */ + hmacsha512_destroyctx, + hmacsha512_adddata, + hmacsha512_sign, +diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h +index 1fdce4c..bdbd269 100644 +--- a/lib/dns/include/dst/dst.h ++++ b/lib/dns/include/dst/dst.h +@@ -175,6 +175,16 @@ isc_result_t + dst_context_create2(dst_key_t *key, isc_mem_t *mctx, + isc_logcategory_t *category, dst_context_t **dctxp); + ++isc_result_t ++dst_context_create3(dst_key_t *key, isc_mem_t *mctx, ++ isc_logcategory_t *category, isc_boolean_t useforsigning, ++ dst_context_t **dctxp); ++ ++isc_result_t ++dst_context_create4(dst_key_t *key, isc_mem_t *mctx, ++ isc_logcategory_t *category, isc_boolean_t useforsigning, ++ int maxbits, dst_context_t **dctxp); ++ + /*%< + * Creates a context to be used for a sign or verify operation. + * +diff --git a/lib/dns/include/dst/result.h b/lib/dns/include/dst/result.h +index 00640a1..cf9428f 100644 +--- a/lib/dns/include/dst/result.h ++++ b/lib/dns/include/dst/result.h +@@ -57,8 +57,9 @@ + #define DST_R_NORANDOMNESS (ISC_RESULTCLASS_DST + 19) + #define DST_R_BADKEYTYPE (ISC_RESULTCLASS_DST + 20) + #define DST_R_NOENGINE (ISC_RESULTCLASS_DST + 21) ++#define DST_R_EXTERNALKEY (ISC_RESULTCLASS_DST + 22) + +-#define DST_R_NRESULTS 22 /* Number of results */ ++#define DST_R_NRESULTS 23 /* Number of results */ + + ISC_LANG_BEGINDECLS + +diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c +index 36b8a41..55752da 100644 +--- a/lib/dns/openssldh_link.c ++++ b/lib/dns/openssldh_link.c +@@ -463,6 +463,9 @@ openssldh_tofile(const dst_key_t *key, const char *directory) { + if (key->keydata.dh == NULL) + return (DST_R_NULLKEY); + ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ + dh = key->keydata.dh; + + memset(bufs, 0, sizeof(bufs)); +@@ -528,6 +531,9 @@ openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + if (ret != ISC_R_SUCCESS) + return (ret); + ++ if (key->external) ++ DST_RET(DST_R_EXTERNALKEY); ++ + dh = DH_new(); + if (dh == NULL) + DST_RET(ISC_R_NOMEMORY); +@@ -630,6 +636,7 @@ openssldh_cleanup(void) { + + static dst_func_t openssldh_functions = { + NULL, /*%< createctx */ ++ NULL, /*%< createctx2 */ + NULL, /*%< destroyctx */ + NULL, /*%< adddata */ + NULL, /*%< openssldh_sign */ +diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c +index a24baae..fd6e91e 100644 +--- a/lib/dns/openssldsa_link.c ++++ b/lib/dns/openssldsa_link.c +@@ -522,7 +522,7 @@ openssldsa_tofile(const dst_key_t *key, const char *directory) { + + if (key->keydata.dsa == NULL) + return (DST_R_NULLKEY); +- ++ + if (key->external) { + priv.nelements = 0; + return (dst__privstruct_writefile(key, &priv, directory)); +@@ -573,20 +573,31 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + isc_mem_t *mctx = key->mctx; + #define DST_RET(a) {ret = a; goto err;} + +- UNUSED(pub); +- + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + ++ if (key->external) { ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ key->key_size = pub->key_size; ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ISC_R_SUCCESS); ++ } ++ + dsa = DSA_new(); + if (dsa == NULL) + DST_RET(ISC_R_NOMEMORY); + dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; + key->keydata.dsa = dsa; + +- for (i=0; i < priv.nelements; i++) { ++ for (i = 0; i < priv.nelements; i++) { + BIGNUM *bn; + bn = BN_bin2bn(priv.elements[i].data, + priv.elements[i].length, NULL); +@@ -612,22 +623,8 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + } + } + dst__privstruct_free(&priv, mctx); +- +- if (key->external) { +- if (pub == NULL) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- dsa->q = pub->keydata.dsa->q; +- pub->keydata.dsa->q = NULL; +- dsa->p = pub->keydata.dsa->p; +- pub->keydata.dsa->p = NULL; +- dsa->g = pub->keydata.dsa->g; +- pub->keydata.dsa->g = NULL; +- dsa->pub_key = pub->keydata.dsa->pub_key; +- pub->keydata.dsa->pub_key = NULL; +- } +- ++ memset(&priv, 0, sizeof(priv)); + key->key_size = BN_num_bits(dsa->p); +- + return (ISC_R_SUCCESS); + + err: +@@ -639,6 +636,7 @@ openssldsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t openssldsa_functions = { + openssldsa_createctx, ++ NULL, /*%< createctx2 */ + openssldsa_destroyctx, + openssldsa_adddata, + openssldsa_sign, +diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c +index 7eff9a0..c64cc55 100644 +--- a/lib/dns/opensslecdsa_link.c ++++ b/lib/dns/opensslecdsa_link.c +@@ -18,7 +18,7 @@ + + #include <config.h> + +-#ifdef HAVE_OPENSSL_ECDSA ++#if defined(OPENSSL) && defined(HAVE_OPENSSL_ECDSA) + + #if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384) + #error "ECDSA without EVP for SHA2?" +@@ -474,7 +474,7 @@ opensslecdsa_tofile(const dst_key_t *key, const char *directory) { + priv.elements[0].length = BN_num_bytes(privkey); + BN_bn2bin(privkey, buf); + priv.elements[0].data = buf; +- priv.nelements = ECDSA_NTAGS; ++ priv.nelements = 1; + ret = dst__privstruct_writefile(key, &priv, directory); + + err: +@@ -519,60 +519,50 @@ static isc_result_t + opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; + isc_result_t ret; +- EVP_PKEY *pkey, *pubpkey; +- EC_KEY *eckey = NULL, *pubeckey = NULL; +- const EC_POINT *pubkey; +- BIGNUM *privkey; ++ EVP_PKEY *pkey; ++ EC_KEY *eckey = NULL; ++ BIGNUM *privkey = NULL; + int group_nid; + isc_mem_t *mctx = key->mctx; + + REQUIRE(key->key_alg == DST_ALG_ECDSA256 || + key->key_alg == DST_ALG_ECDSA384); + +- if (key->key_alg == DST_ALG_ECDSA256) +- group_nid = NID_X9_62_prime256v1; +- else +- group_nid = NID_secp384r1; +- +- eckey = EC_KEY_new_by_curve_name(group_nid); +- if (eckey == NULL) +- return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); +- + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + goto err; + + if (key->external) { +- /* +- * Copy the public key to this new key. +- */ +- if (pub == NULL) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- pubpkey = pub->keydata.pkey; +- pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey); +- if (pubeckey == NULL) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- pubkey = EC_KEY_get0_public_key(pubeckey); +- if (pubkey == NULL) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- if (EC_KEY_set_public_key(eckey, pubkey) != 1) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- if (EC_KEY_check_key(eckey) != 1) ++ if (priv.nelements != 0) + DST_RET(DST_R_INVALIDPRIVATEKEY); +- } else { +- privkey = BN_bin2bn(priv.elements[0].data, +- priv.elements[0].length, NULL); +- if (privkey == NULL) +- DST_RET(ISC_R_NOMEMORY); +- if (!EC_KEY_set_private_key(eckey, privkey)) +- DST_RET(ISC_R_NOMEMORY); +- if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) ++ if (pub == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); ++ return (ISC_R_SUCCESS); + } +- ++ ++ if (key->key_alg == DST_ALG_ECDSA256) ++ group_nid = NID_X9_62_prime256v1; ++ else ++ group_nid = NID_secp384r1; ++ ++ eckey = EC_KEY_new_by_curve_name(group_nid); ++ if (eckey == NULL) ++ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ ++ privkey = BN_bin2bn(priv.elements[0].data, ++ priv.elements[0].length, NULL); ++ if (privkey == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ if (!EC_KEY_set_private_key(eckey, privkey)) ++ DST_RET(ISC_R_NOMEMORY); ++ if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ + pkey = EVP_PKEY_new(); + if (pkey == NULL) + DST_RET (ISC_R_NOMEMORY); +@@ -584,10 +574,10 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + ret = ISC_R_SUCCESS; + + err: ++ if (privkey != NULL) ++ BN_clear_free(privkey); + if (eckey != NULL) + EC_KEY_free(eckey); +- if (pubeckey != NULL) +- EC_KEY_free(pubeckey); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ret); +@@ -595,6 +585,7 @@ opensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + static dst_func_t opensslecdsa_functions = { + opensslecdsa_createctx, ++ NULL, /*%< createctx2 */ + opensslecdsa_destroyctx, + opensslecdsa_adddata, + opensslecdsa_sign, +diff --git a/lib/dns/opensslgost_link.c b/lib/dns/opensslgost_link.c +index 325a7c0..9b4ff55 100644 +--- a/lib/dns/opensslgost_link.c ++++ b/lib/dns/opensslgost_link.c +@@ -30,6 +30,7 @@ + #include "dst_internal.h" + #include "dst_openssl.h" + #include "dst_parse.h" ++#include "dst_gost.h" + + #include <openssl/err.h> + #include <openssl/objects.h> +@@ -44,6 +45,60 @@ const EVP_MD *EVP_gost(void) { + return (opensslgost_digest); + } + ++/* ISC methods */ ++ ++isc_result_t ++isc_gost_init(isc_gost_t *ctx) { ++ const EVP_MD *md; ++ int ret; ++ ++ INSIST(ctx != NULL); ++ ++ md = EVP_gost(); ++ if (md == NULL) ++ return (DST_R_CRYPTOFAILURE); ++ EVP_MD_CTX_init(ctx); ++ ret = EVP_DigestInit(ctx, md); ++ if (ret != 1) ++ return (DST_R_CRYPTOFAILURE); ++ return (ISC_R_SUCCESS); ++} ++ ++void ++isc_gost_invalidate(isc_gost_t *ctx) { ++ EVP_MD_CTX_cleanup(ctx); ++} ++ ++isc_result_t ++isc_gost_update(isc_gost_t *ctx, const unsigned char *data, ++ unsigned int len) ++{ ++ int ret; ++ ++ INSIST(ctx != NULL); ++ INSIST(data != NULL); ++ ++ ret = EVP_DigestUpdate(ctx, (const void *) data, (size_t) len); ++ if (ret != 1) ++ return (DST_R_CRYPTOFAILURE); ++ return (ISC_R_SUCCESS); ++} ++ ++isc_result_t ++isc_gost_final(isc_gost_t *ctx, unsigned char *digest) { ++ int ret; ++ ++ INSIST(ctx != NULL); ++ INSIST(digest != NULL); ++ ++ ret = EVP_DigestFinal(ctx, digest, NULL); ++ if (ret != 1) ++ return (DST_R_CRYPTOFAILURE); ++ return (ISC_R_SUCCESS); ++} ++ ++/* DST methods */ ++ + #define DST_RET(a) {ret = a; goto err;} + + static isc_result_t opensslgost_todns(const dst_key_t *key, +@@ -285,6 +340,8 @@ opensslgost_fromdns(dst_key_t *key, isc_buffer_t *data) { + return (ISC_R_SUCCESS); + } + ++#ifdef PREFER_GOSTASN1 ++ + static isc_result_t + opensslgost_tofile(const dst_key_t *key, const char *directory) { + EVP_PKEY *pkey; +@@ -318,7 +375,7 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) { + priv.elements[0].tag = TAG_GOST_PRIVASN1; + priv.elements[0].length = len; + priv.elements[0].data = der; +- priv.nelements = GOST_NTAGS; ++ priv.nelements = 1; + + result = dst__privstruct_writefile(key, &priv, directory); + fail: +@@ -327,42 +384,146 @@ opensslgost_tofile(const dst_key_t *key, const char *directory) { + return (result); + } + ++#else ++ ++static isc_result_t ++opensslgost_tofile(const dst_key_t *key, const char *directory) { ++ EVP_PKEY *pkey; ++ EC_KEY *eckey; ++ const BIGNUM *privkey; ++ dst_private_t priv; ++ isc_result_t ret; ++ unsigned char *buf = NULL; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ ++ pkey = key->keydata.pkey; ++ eckey = EVP_PKEY_get0(pkey); ++ if (eckey == NULL) ++ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ privkey = EC_KEY_get0_private_key(eckey); ++ if (privkey == NULL) ++ return (ISC_R_FAILURE); ++ ++ buf = isc_mem_get(key->mctx, BN_num_bytes(privkey)); ++ if (buf == NULL) ++ return (ISC_R_NOMEMORY); ++ ++ priv.elements[0].tag = TAG_GOST_PRIVRAW; ++ priv.elements[0].length = BN_num_bytes(privkey); ++ BN_bn2bin(privkey, buf); ++ priv.elements[0].data = buf; ++ priv.nelements = 1; ++ ++ ret = dst__privstruct_writefile(key, &priv, directory); ++ ++ if (buf != NULL) ++ isc_mem_put(key->mctx, buf, BN_num_bytes(privkey)); ++ return (ret); ++} ++#endif ++ ++static unsigned char gost_dummy_key[71] = { ++ 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, ++ 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, ++ 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, ++ 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, ++ 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20, 0x1b, ++ 0x3f, 0x94, 0xf7, 0x1a, 0x5f, 0x2f, 0xe7, 0xe5, ++ 0x74, 0x0b, 0x8c, 0xd4, 0xb7, 0x18, 0xdd, 0x65, ++ 0x68, 0x26, 0xd1, 0x54, 0xfb, 0x77, 0xba, 0x63, ++ 0x72, 0xd9, 0xf0, 0x63, 0x87, 0xe0, 0xd6 ++}; ++ + static isc_result_t + opensslgost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + dst_private_t priv; + isc_result_t ret; + isc_mem_t *mctx = key->mctx; + EVP_PKEY *pkey = NULL; ++ EC_KEY *eckey; ++ const EC_POINT *pubkey = NULL; ++ BIGNUM *privkey = NULL; + const unsigned char *p; + +- UNUSED(pub); +- + /* read private key file */ + ret = dst__privstruct_parse(key, DST_ALG_ECCGOST, lexer, mctx, &priv); + if (ret != ISC_R_SUCCESS) + return (ret); + + if (key->external) { +- INSIST(priv.nelements == 0); ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); + if (pub == NULL) + DST_RET(DST_R_INVALIDPRIVATEKEY); + key->keydata.pkey = pub->keydata.pkey; + pub->keydata.pkey = NULL; +- } else { +- INSIST(priv.elements[0].tag == TAG_GOST_PRIVASN1); ++ key->key_size = pub->key_size; ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ISC_R_SUCCESS); ++ } ++ ++ INSIST((priv.elements[0].tag == TAG_GOST_PRIVASN1) || ++ (priv.elements[0].tag == TAG_GOST_PRIVRAW)); ++ ++ if (priv.elements[0].tag == TAG_GOST_PRIVASN1) { + p = priv.elements[0].data; + if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, + (long) priv.elements[0].length) == NULL) +- DST_RET(dst__openssl_toresult2("d2i_PrivateKey", +- DST_R_INVALIDPRIVATEKEY)); +- key->keydata.pkey = pkey; ++ DST_RET(dst__openssl_toresult2( ++ "d2i_PrivateKey", ++ DST_R_INVALIDPRIVATEKEY)); ++ } else { ++ if ((pub != NULL) && (pub->keydata.pkey != NULL)) { ++ eckey = EVP_PKEY_get0(pub->keydata.pkey); ++ pubkey = EC_KEY_get0_public_key(eckey); ++ } ++ ++ privkey = BN_bin2bn(priv.elements[0].data, ++ priv.elements[0].length, NULL); ++ if (privkey == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ++ /* can't create directly the whole key */ ++ p = gost_dummy_key; ++ if (d2i_PrivateKey(NID_id_GostR3410_2001, &pkey, &p, ++ (long) sizeof(gost_dummy_key)) == NULL) ++ DST_RET(dst__openssl_toresult2( ++ "d2i_PrivateKey", ++ DST_R_INVALIDPRIVATEKEY)); ++ ++ eckey = EVP_PKEY_get0(pkey); ++ if (eckey == NULL) ++ return (dst__openssl_toresult(DST_R_OPENSSLFAILURE)); ++ if (!EC_KEY_set_private_key(eckey, privkey)) ++ DST_RET(ISC_R_NOMEMORY); ++ ++ /* have to (re)set the public key */ ++#ifdef notyet ++ (void) gost2001_compute_public(eckey); ++#else ++ if ((pubkey != NULL) && !EC_KEY_set_public_key(eckey, pubkey)) ++ DST_RET(ISC_R_NOMEMORY); ++#endif ++ BN_clear_free(privkey); ++ privkey = NULL; + } ++ key->keydata.pkey = pkey; + key->key_size = EVP_PKEY_bits(pkey); + dst__privstruct_free(&priv, mctx); + memset(&priv, 0, sizeof(priv)); + return (ISC_R_SUCCESS); + + err: ++ if (privkey != NULL) ++ BN_clear_free(privkey); + if (pkey != NULL) + EVP_PKEY_free(pkey); + opensslgost_destroy(key); +@@ -382,6 +543,7 @@ opensslgost_cleanup(void) { + + static dst_func_t opensslgost_functions = { + opensslgost_createctx, ++ NULL, /*%< createctx2 */ + opensslgost_destroyctx, + opensslgost_adddata, + opensslgost_sign, +diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c +index 894c7ae..1edeb8d 100644 +--- a/lib/dns/opensslrsa_link.c ++++ b/lib/dns/opensslrsa_link.c +@@ -1196,6 +1196,24 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + EVP_PKEY *pkey = NULL; + #endif + ++ /* read private key file */ ++ ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ if (key->external) { ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ key->key_size = pub->key_size; ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ISC_R_SUCCESS); ++ } ++ + #if USE_EVP + if (pub != NULL && pub->keydata.pkey != NULL) + pubrsa = EVP_PKEY_get1_RSA(pub->keydata.pkey); +@@ -1206,14 +1224,6 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + } + #endif + +- /* read private key file */ +- ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); +- if (ret != ISC_R_SUCCESS) +- goto err; +- +- if (key->external && priv.nelements != 0) +- DST_RET(DST_R_INVALIDPRIVATEKEY); +- + for (i = 0; i < priv.nelements; i++) { + switch (priv.elements[i].tag) { + case TAG_RSA_ENGINE: +@@ -1297,8 +1307,6 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + continue; + case TAG_RSA_LABEL: + continue; +- case TAG_RSA_PIN: +- continue; + default: + bn = BN_bin2bn(priv.elements[i].data, + priv.elements[i].length, NULL); +@@ -1338,10 +1346,8 @@ opensslrsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { + + if (rsa_check(rsa, pubrsa) != ISC_R_SUCCESS) + DST_RET(DST_R_INVALIDPRIVATEKEY); +- if (!key->external) { +- if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) +- DST_RET(ISC_R_RANGE); +- } ++ if (BN_num_bits(rsa->e) > RSA_MAX_PUBEXP_BITS) ++ DST_RET(ISC_R_RANGE); + key->key_size = BN_num_bits(rsa->n); + if (pubrsa != NULL) + RSA_free(pubrsa); +@@ -1448,6 +1454,7 @@ opensslrsa_fromlabel(dst_key_t *key, const char *engine, const char *label, + + static dst_func_t opensslrsa_functions = { + opensslrsa_createctx, ++ NULL, /*%< createctx2 */ + opensslrsa_destroyctx, + opensslrsa_adddata, + opensslrsa_sign, +diff --git a/lib/dns/pkcs11.c b/lib/dns/pkcs11.c +new file mode 100644 +index 0000000..7aa15fa +--- /dev/null ++++ b/lib/dns/pkcs11.c +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifdef PKCS11CRYPTO ++ ++#include <config.h> ++ ++#include <dns/log.h> ++#include <dns/result.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++ ++#include "dst_pkcs11.h" ++ ++isc_result_t ++dst__pkcs11_toresult(const char *funcname, const char *file, int line, ++ isc_result_t fallback, CK_RV rv) ++{ ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, ++ DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, ++ "%s:%d: %s: Error = 0x%.8lX\n", ++ file, line, funcname, rv); ++ if (rv == CKR_HOST_MEMORY) ++ return (ISC_R_NOMEMORY); ++ return (fallback); ++} ++ ++ ++#else /* PKCS11CRYPTO */ ++ ++#include <isc/util.h> ++ ++EMPTY_TRANSLATION_UNIT ++ ++#endif /* PKCS11CRYPTO */ ++/*! \file */ +diff --git a/lib/dns/pkcs11dh_link.c b/lib/dns/pkcs11dh_link.c +new file mode 100644 +index 0000000..87afc02 +--- /dev/null ++++ b/lib/dns/pkcs11dh_link.c +@@ -0,0 +1,1140 @@ ++/* ++ * Portions Copyright (C) 20012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * ++ * Portions Copyright (C) 1995-2000 by Network Associates, Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#ifdef PKCS11CRYPTO ++ ++#include <config.h> ++ ++#include <ctype.h> ++ ++#include <isc/mem.h> ++#include <isc/string.h> ++#include <isc/util.h> ++ ++#include <dst/result.h> ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++#define WANT_DH_PRIMES ++#include <pk11/constants.h> ++ ++#include <pkcs11/pkcs11.h> ++ ++/* ++ * PKCS#3 DH keys: ++ * mechanisms: ++ * CKM_DH_PKCS_PARAMETER_GEN, ++ * CKM_DH_PKCS_KEY_PAIR_GEN, ++ * CKM_DH_PKCS_DERIVE ++ * domain parameters: ++ * object class CKO_DOMAIN_PARAMETERS ++ * key type CKK_DH ++ * attribute CKA_PRIME (prime p) ++ * attribute CKA_BASE (base g) ++ * optional attribute CKA_PRIME_BITS (p length in bits) ++ * public key: ++ * object class CKO_PUBLIC_KEY ++ * key type CKK_DH ++ * attribute CKA_PRIME (prime p) ++ * attribute CKA_BASE (base g) ++ * attribute CKA_VALUE (public value y) ++ * private key: ++ * object class CKO_PRIVATE_KEY ++ * key type CKK_DH ++ * attribute CKA_PRIME (prime p) ++ * attribute CKA_BASE (base g) ++ * attribute CKA_VALUE (private value x) ++ * optional attribute CKA_VALUE_BITS (x length in bits) ++ * reuse CKA_PRIVATE_EXPONENT for key pair private value ++ */ ++ ++#define CKA_VALUE2 CKA_PRIVATE_EXPONENT ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++#define DST_RET(a) {ret = a; goto err;} ++ ++static void pkcs11dh_destroy(dst_key_t *key); ++static isc_result_t pkcs11dh_todns(const dst_key_t *key, isc_buffer_t *data); ++ ++static isc_result_t ++pkcs11dh_loadpriv(const dst_key_t *key, ++ CK_SESSION_HANDLE session, ++ CK_OBJECT_HANDLE *hKey) ++{ ++ CK_RV rv; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_DH; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_DERIVE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_PRIME, NULL, 0 }, ++ { CKA_BASE, NULL, 0 }, ++ { CKA_VALUE, NULL, 0 } ++ }; ++ CK_ATTRIBUTE *attr; ++ const pk11_object_t *priv; ++ isc_result_t ret; ++ unsigned int i; ++ ++ priv = key->keydata.pkey; ++ if ((priv->object != CK_INVALID_HANDLE) && priv->ontoken) { ++ *hKey = priv->object; ++ return (ISC_R_SUCCESS); ++ } ++ ++ attr = pk11_attribute_bytype(priv, CKA_PRIME); ++ if (attr == NULL) ++ return (DST_R_INVALIDPRIVATEKEY); ++ keyTemplate[6].pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, attr->pValue, attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ ++ attr = pk11_attribute_bytype(priv, CKA_BASE); ++ if (attr == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ keyTemplate[7].pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (keyTemplate[7].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[7].pValue, attr->pValue, attr->ulValueLen); ++ keyTemplate[7].ulValueLen = attr->ulValueLen; ++ ++ attr = pk11_attribute_bytype(priv, CKA_VALUE2); ++ if (attr == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ keyTemplate[8].pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (keyTemplate[8].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[8].pValue, attr->pValue, attr->ulValueLen); ++ keyTemplate[8].ulValueLen = attr->ulValueLen; ++ ++ PK11_CALL(pkcs_C_CreateObject, ++ (session, keyTemplate, (CK_ULONG) 9, hKey), ++ DST_R_COMPUTESECRETFAILURE); ++ if (rv == CKR_OK) ++ ret = ISC_R_SUCCESS; ++ ++ err: ++ for (i = 6; i <= 8; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(key->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11dh_computesecret(const dst_key_t *pub, const dst_key_t *priv, ++ isc_buffer_t *secret) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_DH_PKCS_DERIVE, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; ++ CK_OBJECT_HANDLE hDerived = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_ATTRIBUTE *attr; ++ CK_ULONG secLen; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE_LEN, &secLen, (CK_ULONG) sizeof(secLen) } ++ }; ++ CK_ATTRIBUTE valTemplate[] = ++ { ++ { CKA_VALUE, NULL, 0 } ++ }; ++ CK_BYTE *secValue; ++ pk11_context_t ctx; ++ isc_result_t ret; ++ unsigned int i; ++ isc_region_t r; ++ ++ REQUIRE(pub->keydata.pkey != NULL); ++ REQUIRE(priv->keydata.pkey != NULL); ++ REQUIRE(priv->keydata.pkey->repr != NULL); ++ attr = pk11_attribute_bytype(pub->keydata.pkey, CKA_PRIME); ++ if (attr == NULL) ++ return (DST_R_INVALIDPUBLICKEY); ++ REQUIRE(attr != NULL); ++ secLen = attr->ulValueLen; ++ attr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE); ++ if (attr == NULL) ++ return (DST_R_INVALIDPUBLICKEY); ++ ++ ret = pk11_get_session(&ctx, OP_DH, ISC_TRUE, ISC_FALSE, ISC_FALSE, ++ NULL, pk11_get_best_token(OP_DH)); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ mech.ulParameterLen = attr->ulValueLen; ++ mech.pParameter = isc_mem_get(pub->mctx, mech.ulParameterLen); ++ if (mech.pParameter == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(mech.pParameter, attr->pValue, mech.ulParameterLen); ++ ++ ret = pkcs11dh_loadpriv(priv, ctx.session, &hKey); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ PK11_RET(pkcs_C_DeriveKey, ++ (ctx.session, &mech, hKey, ++ keyTemplate, (CK_ULONG) 6, &hDerived), ++ DST_R_COMPUTESECRETFAILURE); ++ ++ attr = valTemplate; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (ctx.session, hDerived, attr, (CK_ULONG) 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(pub->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (ctx.session, hDerived, attr, (CK_ULONG) 1), ++ DST_R_CRYPTOFAILURE); ++ ++ /* strip leading zeros */ ++ secValue = (CK_BYTE_PTR) attr->pValue; ++ for (i = 0; i < attr->ulValueLen; i++) ++ if (secValue[i] != 0) ++ break; ++ isc_buffer_availableregion(secret, &r); ++ if (r.length < attr->ulValueLen - i) ++ DST_RET(ISC_R_NOSPACE); ++ memcpy(r.base, secValue + i, attr->ulValueLen - i); ++ isc_buffer_add(secret, attr->ulValueLen - i); ++ ret = ISC_R_SUCCESS; ++ ++ err: ++ if (hDerived != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx.session, hDerived); ++ if (valTemplate[0].pValue != NULL) { ++ memset(valTemplate[0].pValue, 0, valTemplate[0].ulValueLen); ++ isc_mem_put(pub->mctx, ++ valTemplate[0].pValue, ++ valTemplate[0].ulValueLen); ++ } ++ if ((hKey != CK_INVALID_HANDLE) && !priv->keydata.pkey->ontoken) ++ (void) pkcs_C_DestroyObject(ctx.session, hKey); ++ if (mech.pParameter != NULL) { ++ memset(mech.pParameter, 0, mech.ulParameterLen); ++ isc_mem_put(pub->mctx, mech.pParameter, mech.ulParameterLen); ++ } ++ pk11_return_session(&ctx); ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11dh_compare(const dst_key_t *key1, const dst_key_t *key2) { ++ pk11_object_t *dh1, *dh2; ++ CK_ATTRIBUTE *attr1, *attr2; ++ ++ dh1 = key1->keydata.pkey; ++ dh2 = key2->keydata.pkey; ++ ++ if ((dh1 == NULL) && (dh2 == NULL)) ++ return (ISC_TRUE); ++ else if ((dh1 == NULL) || (dh2 == NULL)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dh1, CKA_PRIME); ++ attr2 = pk11_attribute_bytype(dh2, CKA_PRIME); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dh1, CKA_BASE); ++ attr2 = pk11_attribute_bytype(dh2, CKA_BASE); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dh1, CKA_VALUE); ++ attr2 = pk11_attribute_bytype(dh2, CKA_VALUE); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dh1, CKA_VALUE2); ++ attr2 = pk11_attribute_bytype(dh2, CKA_VALUE2); ++ if (((attr1 != NULL) || (attr2 != NULL)) && ++ ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) ++ return (ISC_FALSE); ++ ++ if (!dh1->ontoken && !dh2->ontoken) ++ return (ISC_TRUE); ++ else if (dh1->ontoken || dh2->ontoken || ++ (dh1->object != dh2->object)) ++ return (ISC_FALSE); ++ ++ return (ISC_TRUE); ++} ++ ++static isc_boolean_t ++pkcs11dh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) { ++ pk11_object_t *dh1, *dh2; ++ CK_ATTRIBUTE *attr1, *attr2; ++ ++ dh1 = key1->keydata.pkey; ++ dh2 = key2->keydata.pkey; ++ ++ if ((dh1 == NULL) && (dh2 == NULL)) ++ return (ISC_TRUE); ++ else if ((dh1 == NULL) || (dh2 == NULL)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dh1, CKA_PRIME); ++ attr2 = pk11_attribute_bytype(dh2, CKA_PRIME); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dh1, CKA_BASE); ++ attr2 = pk11_attribute_bytype(dh2, CKA_BASE); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ return (ISC_TRUE); ++} ++ ++static isc_result_t ++pkcs11dh_generate(dst_key_t *key, int generator, void (*callback)(int)) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_DH_PKCS_PARAMETER_GEN, NULL, 0 }; ++ CK_OBJECT_HANDLE domainparams = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS dClass = CKO_DOMAIN_PARAMETERS; ++ CK_KEY_TYPE keyType = CKK_DH; ++ CK_ULONG bits = 0; ++ CK_ATTRIBUTE dTemplate[] = ++ { ++ { CKA_CLASS, &dClass, (CK_ULONG) sizeof(dClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIME_BITS, &bits, (CK_ULONG) sizeof(bits) } ++ }; ++ CK_ATTRIBUTE pTemplate[] = ++ { ++ { CKA_PRIME, NULL, 0 }, ++ { CKA_BASE, NULL, 0 } ++ }; ++ CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; ++ CK_ATTRIBUTE pubTemplate[] = ++ { ++ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, ++ { CKA_KEY_TYPE,&keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIME, NULL, 0 }, ++ { CKA_BASE, NULL, 0 }, ++ }; ++ CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY; ++ CK_ATTRIBUTE privTemplate[] = ++ { ++ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_DERIVE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *dh = NULL; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ ++ UNUSED(callback); ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_DH, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_DH)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ bits = key->key_size; ++ if ((generator == 0) && ++ ((bits == 768) || (bits == 1024) || (bits == 1536))) { ++ if (bits == 768) { ++ pubTemplate[4].pValue = ++ isc_mem_get(key->mctx, sizeof(pk11_dh_bn768)); ++ if (pubTemplate[4].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(pubTemplate[4].pValue, ++ pk11_dh_bn768, sizeof(pk11_dh_bn768)); ++ pubTemplate[4].ulValueLen = sizeof(pk11_dh_bn768); ++ } else if (bits == 1024) { ++ pubTemplate[4].pValue = ++ isc_mem_get(key->mctx, sizeof(pk11_dh_bn1024)); ++ if (pubTemplate[4].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(pubTemplate[4].pValue, ++ pk11_dh_bn1024, sizeof(pk11_dh_bn1024)); ++ pubTemplate[4].ulValueLen = sizeof(pk11_dh_bn1024); ++ } else { ++ pubTemplate[4].pValue = ++ isc_mem_get(key->mctx, sizeof(pk11_dh_bn1536)); ++ if (pubTemplate[4].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(pubTemplate[4].pValue, ++ pk11_dh_bn1536, sizeof(pk11_dh_bn1536)); ++ pubTemplate[4].ulValueLen = sizeof(pk11_dh_bn1536); ++ } ++ pubTemplate[5].pValue = isc_mem_get(key->mctx, ++ sizeof(pk11_dh_bn2)); ++ if (pubTemplate[5].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(pubTemplate[5].pValue, pk11_dh_bn2, sizeof(pk11_dh_bn2)); ++ pubTemplate[5].ulValueLen = sizeof(pk11_dh_bn2); ++ } else { ++ PK11_RET(pkcs_C_GenerateKey, ++ (pk11_ctx->session, &mech, ++ dTemplate, (CK_ULONG) 5, &domainparams), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, domainparams, ++ pTemplate, (CK_ULONG) 2), ++ DST_R_CRYPTOFAILURE); ++ pTemplate[0].pValue = isc_mem_get(key->mctx, ++ pTemplate[0].ulValueLen); ++ if (pTemplate[0].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(pTemplate[0].pValue, 0, pTemplate[0].ulValueLen); ++ pTemplate[1].pValue = isc_mem_get(key->mctx, ++ pTemplate[1].ulValueLen); ++ if (pTemplate[1].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(pTemplate[1].pValue, 0, pTemplate[1].ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, domainparams, ++ pTemplate, (CK_ULONG) 2), ++ DST_R_CRYPTOFAILURE); ++ ++ pubTemplate[4].pValue = pTemplate[0].pValue; ++ pubTemplate[4].ulValueLen = pTemplate[0].ulValueLen; ++ pTemplate[0].pValue = NULL; ++ pubTemplate[5].pValue = pTemplate[1].pValue; ++ pubTemplate[5].ulValueLen = pTemplate[1].ulValueLen; ++ pTemplate[1].pValue = NULL; ++ } ++ ++ mech.mechanism = CKM_DH_PKCS_KEY_PAIR_GEN; ++ PK11_RET(pkcs_C_GenerateKeyPair, ++ (pk11_ctx->session, &mech, ++ pubTemplate, (CK_ULONG) 6, ++ privTemplate, (CK_ULONG) 7, ++ &pub, &priv), ++ DST_R_CRYPTOFAILURE); ++ ++ dh = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dh)); ++ if (dh == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dh, 0, sizeof(*dh)); ++ key->keydata.pkey = dh; ++ dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 4); ++ if (dh->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dh->repr, 0, sizeof(*attr) * 4); ++ dh->attrcnt = 4; ++ ++ attr = dh->repr; ++ attr[0].type = CKA_PRIME; ++ attr[0].pValue = pubTemplate[4].pValue; ++ attr[0].ulValueLen = pubTemplate[4].ulValueLen; ++ pubTemplate[4].pValue = NULL; ++ ++ attr[1].type = CKA_BASE; ++ attr[1].pValue = pubTemplate[5].pValue; ++ attr[1].ulValueLen = pubTemplate[5].ulValueLen; ++ pubTemplate[5].pValue =NULL; ++ ++ attr += 2; ++ attr->type = CKA_VALUE; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ ++ attr++; ++ attr->type = CKA_VALUE; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->type = CKA_VALUE2; ++ ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, domainparams); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11dh_destroy(key); ++ if (priv != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ if (pub != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ if (domainparams != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, domainparams); ++ ++ if (pubTemplate[4].pValue != NULL) { ++ memset(pubTemplate[4].pValue, 0, pubTemplate[4].ulValueLen); ++ isc_mem_put(key->mctx, ++ pubTemplate[4].pValue, ++ pubTemplate[4].ulValueLen); ++ } ++ if (pubTemplate[5].pValue != NULL) { ++ memset(pubTemplate[5].pValue, 0, pubTemplate[5].ulValueLen); ++ isc_mem_put(key->mctx, ++ pubTemplate[5].pValue, ++ pubTemplate[5].ulValueLen); ++ } ++ if (pTemplate[0].pValue != NULL) { ++ memset(pTemplate[0].pValue, 0, pTemplate[0].ulValueLen); ++ isc_mem_put(key->mctx, ++ pTemplate[0].pValue, ++ pTemplate[0].ulValueLen); ++ } ++ if (pTemplate[1].pValue != NULL) { ++ memset(pTemplate[1].pValue, 0, pTemplate[1].ulValueLen); ++ isc_mem_put(key->mctx, ++ pTemplate[1].pValue, ++ pTemplate[1].ulValueLen); ++ } ++ ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11dh_isprivate(const dst_key_t *key) { ++ pk11_object_t *dh = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (dh == NULL) ++ return (ISC_FALSE); ++ attr = pk11_attribute_bytype(dh, CKA_VALUE2); ++ return (ISC_TF((attr != NULL) || dh->ontoken)); ++} ++ ++static void ++pkcs11dh_destroy(dst_key_t *key) { ++ pk11_object_t *dh = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (dh == NULL) ++ return; ++ ++ INSIST((dh->object == CK_INVALID_HANDLE) || dh->ontoken); ++ ++ for (attr = pk11_attribute_first(dh); ++ attr != NULL; ++ attr = pk11_attribute_next(dh, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ case CKA_VALUE2: ++ case CKA_PRIME: ++ case CKA_BASE: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (dh->repr != NULL) { ++ memset(dh->repr, 0, dh->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, dh->repr, dh->attrcnt * sizeof(*attr)); ++ } ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ key->keydata.pkey = NULL; ++} ++ ++static void ++uint16_toregion(isc_uint16_t val, isc_region_t *region) { ++ *region->base++ = (val & 0xff00) >> 8; ++ *region->base++ = (val & 0x00ff); ++} ++ ++static isc_uint16_t ++uint16_fromregion(isc_region_t *region) { ++ isc_uint16_t val; ++ unsigned char *cp = region->base; ++ ++ val = ((unsigned int)(cp[0])) << 8; ++ val |= ((unsigned int)(cp[1])); ++ ++ region->base += 2; ++ return (val); ++} ++ ++static isc_result_t ++pkcs11dh_todns(const dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *dh; ++ CK_ATTRIBUTE *attr; ++ isc_region_t r; ++ isc_uint16_t dnslen, plen = 0, glen = 0, publen = 0; ++ CK_BYTE *prime = NULL, *base = NULL, *pub = NULL; ++ ++ REQUIRE(key->keydata.pkey != NULL); ++ ++ dh = key->keydata.pkey; ++ ++ for (attr = pk11_attribute_first(dh); ++ attr != NULL; ++ attr = pk11_attribute_next(dh, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ pub = (CK_BYTE *) attr->pValue; ++ publen = (isc_uint16_t) attr->ulValueLen; ++ break; ++ case CKA_PRIME: ++ prime = (CK_BYTE *) attr->pValue; ++ plen = (isc_uint16_t) attr->ulValueLen; ++ break; ++ case CKA_BASE: ++ base = (CK_BYTE *) attr->pValue; ++ glen = (isc_uint16_t) attr->ulValueLen; ++ break; ++ } ++ REQUIRE((prime != NULL) && (base != NULL) && (pub != NULL)); ++ ++ isc_buffer_availableregion(data, &r); ++ ++ if ((glen == 1) && (memcmp(pk11_dh_bn2, base, glen) == 0) && ++ (((plen == sizeof(pk11_dh_bn768)) && ++ (memcmp(pk11_dh_bn768, prime, plen) == 0)) || ++ ((plen == sizeof(pk11_dh_bn1024)) && ++ (memcmp(pk11_dh_bn1024, prime, plen) == 0)) || ++ ((plen == sizeof(pk11_dh_bn1536)) && ++ (memcmp(pk11_dh_bn1536, prime, plen) == 0)))) { ++ plen = 1; ++ glen = 0; ++ } ++ ++ dnslen = plen + glen + publen + 6; ++ if (r.length < (unsigned int) dnslen) ++ return (ISC_R_NOSPACE); ++ ++ uint16_toregion(plen, &r); ++ if (plen == 1) { ++ if (memcmp(pk11_dh_bn768, prime, sizeof(pk11_dh_bn768)) == 0) ++ *r.base = 1; ++ else if (memcmp(pk11_dh_bn1024, prime, ++ sizeof(pk11_dh_bn1024)) == 0) ++ *r.base = 2; ++ else ++ *r.base = 3; ++ } ++ else ++ memcpy(r.base, prime, plen); ++ r.base += plen; ++ ++ uint16_toregion(glen, &r); ++ if (glen > 0) ++ memcpy(r.base, base, glen); ++ r.base += glen; ++ ++ uint16_toregion(publen, &r); ++ memcpy(r.base, pub, publen); ++ r.base += publen; ++ ++ isc_buffer_add(data, dnslen); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++pkcs11dh_fromdns(dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *dh; ++ isc_region_t r; ++ isc_uint16_t plen, glen, plen_, glen_, publen; ++ CK_BYTE *prime = NULL, *base = NULL, *pub = NULL; ++ CK_ATTRIBUTE *attr; ++ int special = 0; ++ ++ isc_buffer_remainingregion(data, &r); ++ if (r.length == 0) ++ return (ISC_R_SUCCESS); ++ ++ dh = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dh)); ++ if (dh == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(dh, 0, sizeof(*dh)); ++ ++ /* ++ * Read the prime length. 1 & 2 are table entries, > 16 means a ++ * prime follows, otherwise an error. ++ */ ++ if (r.length < 2) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ plen = uint16_fromregion(&r); ++ if (plen < 16 && plen != 1 && plen != 2) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ if (r.length < plen) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ plen_ = plen; ++ if (plen == 1 || plen == 2) { ++ if (plen == 1) ++ special = *r.base++; ++ else ++ special = uint16_fromregion(&r); ++ switch (special) { ++ case 1: ++ prime = pk11_dh_bn768; ++ plen_ = sizeof(pk11_dh_bn768); ++ break; ++ case 2: ++ prime = pk11_dh_bn1024; ++ plen_ = sizeof(pk11_dh_bn1024); ++ break; ++ case 3: ++ prime = pk11_dh_bn1536; ++ plen_ = sizeof(pk11_dh_bn1536); ++ break; ++ default: ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ } ++ else { ++ prime = r.base; ++ r.base += plen; ++ } ++ ++ /* ++ * Read the generator length. This should be 0 if the prime was ++ * special, but it might not be. If it's 0 and the prime is not ++ * special, we have a problem. ++ */ ++ if (r.length < 2) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ glen = uint16_fromregion(&r); ++ if (r.length < glen) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ glen_ = glen; ++ if (special != 0) { ++ if (glen == 0) { ++ base = pk11_dh_bn2; ++ glen_ = sizeof(pk11_dh_bn2); ++ } ++ else { ++ base = r.base; ++ if (memcmp(base, pk11_dh_bn2, glen) == 0) { ++ base = pk11_dh_bn2; ++ glen_ = sizeof(pk11_dh_bn2); ++ } ++ else { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ } ++ } ++ else { ++ if (glen == 0) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ base = r.base; ++ } ++ r.base += glen; ++ ++ if (r.length < 2) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ publen = uint16_fromregion(&r); ++ if (r.length < publen) { ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ pub = r.base; ++ r.base += publen; ++ ++ key->key_size = pk11_numbits(prime, plen_); ++ ++ dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3); ++ if (dh->repr == NULL) ++ goto nomemory; ++ memset(dh->repr, 0, sizeof(*attr) * 3); ++ dh->attrcnt = 3; ++ ++ attr = dh->repr; ++ attr[0].type = CKA_PRIME; ++ attr[0].pValue = isc_mem_get(key->mctx, plen_); ++ if (attr[0].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[0].pValue, prime, plen_); ++ attr[0].ulValueLen = (CK_ULONG) plen_; ++ ++ attr[1].type = CKA_BASE; ++ attr[1].pValue = isc_mem_get(key->mctx, glen_); ++ if (attr[1].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[1].pValue, base, glen_); ++ attr[1].ulValueLen = (CK_ULONG) glen_; ++ ++ attr[2].type = CKA_VALUE; ++ attr[2].pValue = isc_mem_get(key->mctx, publen); ++ if (attr[2].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[2].pValue, pub, publen); ++ attr[2].ulValueLen = (CK_ULONG) publen; ++ ++ isc_buffer_forward(data, plen + glen + publen + 6); ++ ++ key->keydata.pkey = dh; ++ ++ return (ISC_R_SUCCESS); ++ ++ nomemory: ++ for (attr = pk11_attribute_first(dh); ++ attr != NULL; ++ attr = pk11_attribute_next(dh, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ case CKA_PRIME: ++ case CKA_BASE: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (dh->repr != NULL) { ++ memset(dh->repr, 0, dh->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, dh->repr, dh->attrcnt * sizeof(*attr)); ++ } ++ memset(dh, 0, sizeof(*dh)); ++ isc_mem_put(key->mctx, dh, sizeof(*dh)); ++ return (ISC_R_NOMEMORY); ++} ++ ++static isc_result_t ++pkcs11dh_tofile(const dst_key_t *key, const char *directory) { ++ int i; ++ pk11_object_t *dh; ++ CK_ATTRIBUTE *attr; ++ CK_ATTRIBUTE *prime = NULL, *base = NULL, *pub = NULL, *prv = NULL; ++ dst_private_t priv; ++ unsigned char *bufs[4]; ++ isc_result_t result; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) ++ return (DST_R_EXTERNALKEY); ++ ++ dh = key->keydata.pkey; ++ ++ for (attr = pk11_attribute_first(dh); ++ attr != NULL; ++ attr = pk11_attribute_next(dh, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ pub = attr; ++ break; ++ case CKA_VALUE2: ++ prv = attr; ++ break; ++ case CKA_PRIME: ++ prime = attr; ++ break; ++ case CKA_BASE: ++ base = attr; ++ break; ++ } ++ if ((prime == NULL) || (base == NULL) || ++ (pub == NULL) || (prv == NULL)) ++ return (DST_R_NULLKEY); ++ ++ memset(bufs, 0, sizeof(bufs)); ++ for (i = 0; i < 4; i++) { ++ bufs[i] = isc_mem_get(key->mctx, prime->ulValueLen); ++ if (bufs[i] == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto fail; ++ } ++ memset(bufs[i], 0, prime->ulValueLen); ++ } ++ ++ i = 0; ++ ++ priv.elements[i].tag = TAG_DH_PRIME; ++ priv.elements[i].length = (unsigned short) prime->ulValueLen; ++ memcpy(bufs[i], prime->pValue, prime->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ ++ priv.elements[i].tag = TAG_DH_GENERATOR; ++ priv.elements[i].length = (unsigned short) base->ulValueLen; ++ memcpy(bufs[i], base->pValue, base->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ ++ priv.elements[i].tag = TAG_DH_PRIVATE; ++ priv.elements[i].length = (unsigned short) prv->ulValueLen; ++ memcpy(bufs[i], prv->pValue, prv->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ ++ priv.elements[i].tag = TAG_DH_PUBLIC; ++ priv.elements[i].length = (unsigned short) pub->ulValueLen; ++ memcpy(bufs[i], pub->pValue, pub->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ ++ priv.nelements = i; ++ result = dst__privstruct_writefile(key, &priv, directory); ++ fail: ++ for (i = 0; i < 4; i++) { ++ if (bufs[i] == NULL) ++ break; ++ memset(bufs[i], 0, prime->ulValueLen); ++ isc_mem_put(key->mctx, bufs[i], prime->ulValueLen); ++ } ++ return (result); ++} ++ ++static isc_result_t ++pkcs11dh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ++ dst_private_t priv; ++ isc_result_t ret; ++ int i; ++ pk11_object_t *dh = NULL; ++ CK_ATTRIBUTE *attr; ++ isc_mem_t *mctx; ++ ++ UNUSED(pub); ++ mctx = key->mctx; ++ ++ /* read private key file */ ++ ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ if (key->external) ++ DST_RET(DST_R_EXTERNALKEY); ++ ++ dh = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dh)); ++ if (dh == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dh, 0, sizeof(*dh)); ++ key->keydata.pkey = dh; ++ dh->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 4); ++ if (dh->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dh->repr, 0, sizeof(*attr) * 4); ++ dh->attrcnt = 4; ++ attr = dh->repr; ++ attr[0].type = CKA_PRIME; ++ attr[1].type = CKA_BASE; ++ attr[2].type = CKA_VALUE; ++ attr[3].type = CKA_VALUE2; ++ ++ for (i = 0; i < priv.nelements; i++) { ++ CK_BYTE *bn; ++ ++ bn = isc_mem_get(key->mctx, priv.elements[i].length); ++ if (bn == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(bn, priv.elements[i].data, priv.elements[i].length); ++ ++ switch (priv.elements[i].tag) { ++ case TAG_DH_PRIME: ++ attr = pk11_attribute_bytype(dh, CKA_PRIME); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DH_GENERATOR: ++ attr = pk11_attribute_bytype(dh, CKA_BASE); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DH_PRIVATE: ++ attr = pk11_attribute_bytype(dh, CKA_VALUE2); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DH_PUBLIC: ++ attr = pk11_attribute_bytype(dh, CKA_VALUE); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ } ++ } ++ dst__privstruct_free(&priv, mctx); ++ ++ attr = pk11_attribute_bytype(dh, CKA_PRIME); ++ INSIST(attr != NULL); ++ key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11dh_destroy(key); ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++} ++ ++static dst_func_t pkcs11dh_functions = { ++ NULL, /*%< createctx */ ++ NULL, /*%< createctx2 */ ++ NULL, /*%< destroyctx */ ++ NULL, /*%< adddata */ ++ NULL, /*%< sign */ ++ NULL, /*%< verify */ ++ NULL, /*%< verify2 */ ++ pkcs11dh_computesecret, ++ pkcs11dh_compare, ++ pkcs11dh_paramcompare, ++ pkcs11dh_generate, ++ pkcs11dh_isprivate, ++ pkcs11dh_destroy, ++ pkcs11dh_todns, ++ pkcs11dh_fromdns, ++ pkcs11dh_tofile, ++ pkcs11dh_parse, ++ NULL, /*%< cleanup */ ++ NULL, /*%< fromlabel */ ++ NULL, /*%< dump */ ++ NULL, /*%< restore */ ++}; ++ ++isc_result_t ++dst__pkcs11dh_init(dst_func_t **funcp) { ++ REQUIRE(funcp != NULL); ++ if (*funcp == NULL) ++ *funcp = &pkcs11dh_functions; ++ return (ISC_R_SUCCESS); ++} ++ ++#else /* PKCS11CRYPTO */ ++ ++#include <isc/util.h> ++ ++EMPTY_TRANSLATION_UNIT ++ ++#endif /* PKCS11CRYPTO */ ++/*! \file */ +diff --git a/lib/dns/pkcs11dsa_link.c b/lib/dns/pkcs11dsa_link.c +new file mode 100644 +index 0000000..6c8e46c +--- /dev/null ++++ b/lib/dns/pkcs11dsa_link.c +@@ -0,0 +1,1130 @@ ++/* ++ * Portions Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ * ++ * Portions Copyright (C) 1995-2000 by Network Associates, Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#ifdef PKCS11CRYPTO ++ ++#include <config.h> ++ ++#include <string.h> ++ ++#include <isc/entropy.h> ++#include <isc/mem.h> ++#include <isc/sha1.h> ++#include <isc/util.h> ++ ++#include <dst/result.h> ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include <pk11/internal.h> ++ ++/* ++ * FIPS 186-2 DSA keys: ++ * mechanisms: ++ * CKM_DSA_SHA1, ++ * CKM_DSA_KEY_PAIR_GEN, ++ * CKM_DSA_PARAMETER_GEN ++ * domain parameters: ++ * object class CKO_DOMAIN_PARAMETERS ++ * key type CKK_DSA ++ * attribute CKA_PRIME (prime p) ++ * attribute CKA_SUBPRIME (subprime q) ++ * attribute CKA_BASE (base g) ++ * optional attribute CKA_PRIME_BITS (p length in bits) ++ * public keys: ++ * object class CKO_PUBLIC_KEY ++ * key type CKK_DSA ++ * attribute CKA_PRIME (prime p) ++ * attribute CKA_SUBPRIME (subprime q) ++ * attribute CKA_BASE (base g) ++ * attribute CKA_VALUE (public value y) ++ * private keys: ++ * object class CKO_PRIVATE_KEY ++ * key type CKK_DSA ++ * attribute CKA_PRIME (prime p) ++ * attribute CKA_SUBPRIME (subprime q) ++ * attribute CKA_BASE (base g) ++ * attribute CKA_VALUE (private value x) ++ * reuse CKA_PRIVATE_EXPONENT for key pair private value ++ */ ++ ++#define CKA_VALUE2 CKA_PRIVATE_EXPONENT ++ ++#define DST_RET(a) {ret = a; goto err;} ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++static isc_result_t pkcs11dsa_todns(const dst_key_t *key, isc_buffer_t *data); ++static void pkcs11dsa_destroy(dst_key_t *key); ++ ++static isc_result_t ++pkcs11dsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_DSA_SHA1, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_DSA; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_PRIME, NULL, 0 }, ++ { CKA_SUBPRIME, NULL, 0 }, ++ { CKA_BASE, NULL, 0 }, ++ { CKA_VALUE, NULL, 0 } ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *dsa; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_DSA, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_DSA)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ dsa = key->keydata.pkey; ++ if (dsa->ontoken && (dsa->object != CK_INVALID_HANDLE)) { ++ pk11_ctx->ontoken = dsa->ontoken; ++ pk11_ctx->object = dsa->object; ++ goto token_key; ++ } ++ ++ for (attr = pk11_attribute_first(dsa); ++ attr != NULL; ++ attr = pk11_attribute_next(dsa, attr)) ++ switch (attr->type) { ++ case CKA_PRIME: ++ INSIST(keyTemplate[6].type == attr->type); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_SUBPRIME: ++ INSIST(keyTemplate[7].type == attr->type); ++ keyTemplate[7].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[7].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[7].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[7].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_BASE: ++ INSIST(keyTemplate[8].type == attr->type); ++ keyTemplate[8].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[8].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[8].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[8].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_VALUE2: ++ INSIST(keyTemplate[9].type == CKA_VALUE); ++ keyTemplate[9].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[9].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[9].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[9].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 10, ++ &pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ token_key: ++ ++ PK11_RET(pkcs_C_SignInit, ++ (pk11_ctx->session, &mech, pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ ++ for (i = 6; i <= 9; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object); ++ for (i = 6; i <= 9; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11dsa_createctx_verify(dst_key_t *key, dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_DSA_SHA1, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_DSA; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_PRIME, NULL, 0 }, ++ { CKA_SUBPRIME, NULL, 0 }, ++ { CKA_BASE, NULL, 0 }, ++ { CKA_VALUE, NULL, 0 } ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *dsa; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_DSA, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_DSA)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ dsa = key->keydata.pkey; ++ if (dsa->ontoken && (dsa->object != CK_INVALID_HANDLE)) { ++ pk11_ctx->ontoken = dsa->ontoken; ++ pk11_ctx->object = dsa->object; ++ goto token_key; ++ } ++ ++ for (attr = pk11_attribute_first(dsa); ++ attr != NULL; ++ attr = pk11_attribute_next(dsa, attr)) ++ switch (attr->type) { ++ case CKA_PRIME: ++ INSIST(keyTemplate[5].type == attr->type); ++ keyTemplate[5].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[5].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[5].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[5].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_SUBPRIME: ++ INSIST(keyTemplate[6].type == attr->type); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_BASE: ++ INSIST(keyTemplate[7].type == attr->type); ++ keyTemplate[7].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[7].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[7].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[7].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_VALUE: ++ INSIST(keyTemplate[8].type == attr->type); ++ keyTemplate[8].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[8].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[8].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[8].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 9, ++ &pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ token_key: ++ ++ PK11_RET(pkcs_C_VerifyInit, ++ (pk11_ctx->session, &mech, pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ ++ for (i = 5; i <= 8; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object); ++ for (i = 5; i <= 8; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11dsa_createctx(dst_key_t *key, dst_context_t *dctx) { ++ if (dctx->use == DO_SIGN) ++ return (pkcs11dsa_createctx_sign(key, dctx)); ++ else ++ return (pkcs11dsa_createctx_verify(key, dctx)); ++} ++ ++static void ++pkcs11dsa_destroyctx(dst_context_t *dctx) { ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ ++ if (pk11_ctx != NULL) { ++ if (!pk11_ctx->ontoken && ++ (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, ++ pk11_ctx->object); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ dctx->ctxdata.pk11_ctx = NULL; ++ } ++} ++ ++static isc_result_t ++pkcs11dsa_adddata(dst_context_t *dctx, const isc_region_t *data) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ if (dctx->use == DO_SIGN) ++ PK11_CALL(pkcs_C_SignUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ else ++ PK11_CALL(pkcs_C_VerifyUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11dsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { ++ CK_RV rv; ++ CK_ULONG siglen = ISC_SHA1_DIGESTLENGTH * 2; ++ isc_region_t r; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ isc_buffer_availableregion(sig, &r); ++ if (r.length < ISC_SHA1_DIGESTLENGTH * 2 + 1) ++ return (ISC_R_NOSPACE); ++ ++ PK11_RET(pkcs_C_SignFinal, ++ (pk11_ctx->session, (CK_BYTE_PTR) r.base + 1, &siglen), ++ DST_R_SIGNFAILURE); ++ if (siglen != ISC_SHA1_DIGESTLENGTH * 2) ++ return (DST_R_SIGNFAILURE); ++ ++ *r.base = (dctx->key->key_size - 512)/64; ++ isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1); ++ ++ err: ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11dsa_verify(dst_context_t *dctx, const isc_region_t *sig) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ PK11_CALL(pkcs_C_VerifyFinal, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) sig->base + 1, ++ (CK_ULONG) sig->length - 1), ++ DST_R_VERIFYFAILURE); ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11dsa_compare(const dst_key_t *key1, const dst_key_t *key2) { ++ pk11_object_t *dsa1, *dsa2; ++ CK_ATTRIBUTE *attr1, *attr2; ++ ++ dsa1 = key1->keydata.pkey; ++ dsa2 = key2->keydata.pkey; ++ ++ if ((dsa1 == NULL) && (dsa2 == NULL)) ++ return (ISC_TRUE); ++ else if ((dsa1 == NULL) || (dsa2 == NULL)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dsa1, CKA_PRIME); ++ attr2 = pk11_attribute_bytype(dsa2, CKA_PRIME); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dsa1, CKA_SUBPRIME); ++ attr2 = pk11_attribute_bytype(dsa2, CKA_SUBPRIME); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dsa1, CKA_BASE); ++ attr2 = pk11_attribute_bytype(dsa2, CKA_BASE); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dsa1, CKA_VALUE); ++ attr2 = pk11_attribute_bytype(dsa2, CKA_VALUE); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(dsa1, CKA_VALUE2); ++ attr2 = pk11_attribute_bytype(dsa2, CKA_VALUE2); ++ if (((attr1 != NULL) || (attr2 != NULL)) && ++ ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) ++ return (ISC_FALSE); ++ ++ if (!dsa1->ontoken && !dsa2->ontoken) ++ return (ISC_TRUE); ++ else if (dsa1->ontoken || dsa2->ontoken || ++ (dsa1->object != dsa2->object)) ++ return (ISC_FALSE); ++ ++ return (ISC_TRUE); ++} ++ ++static isc_result_t ++pkcs11dsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_DSA_PARAMETER_GEN, NULL, 0 }; ++ CK_OBJECT_HANDLE dp = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS dpClass = CKO_DOMAIN_PARAMETERS; ++ CK_KEY_TYPE keyType = CKK_DSA; ++ CK_ULONG bits = 0; ++ CK_ATTRIBUTE dpTemplate[] = ++ { ++ { CKA_CLASS, &dpClass, (CK_ULONG) sizeof(dpClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIME_BITS, &bits, (CK_ULONG) sizeof(bits) }, ++ }; ++ CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; ++ CK_ATTRIBUTE pubTemplate[] = ++ { ++ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_PRIME, NULL, 0 }, ++ { CKA_SUBPRIME, NULL, 0 }, ++ { CKA_BASE, NULL, 0 } ++ }; ++ CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY; ++ CK_ATTRIBUTE privTemplate[] = ++ { ++ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *dsa; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ UNUSED(unused); ++ UNUSED(callback); ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_DSA, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_DSA)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ bits = key->key_size; ++ PK11_RET(pkcs_C_GenerateKey, ++ (pk11_ctx->session, &mech, dpTemplate, (CK_ULONG) 5, &dp), ++ DST_R_CRYPTOFAILURE); ++ ++ dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa)); ++ if (dsa == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dsa, 0, sizeof(*dsa)); ++ key->keydata.pkey = dsa; ++ dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 5); ++ if (dsa->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dsa->repr, 0, sizeof(*attr) * 5); ++ dsa->attrcnt = 5; ++ ++ attr = dsa->repr; ++ attr[0].type = CKA_PRIME; ++ attr[1].type = CKA_SUBPRIME; ++ attr[2].type = CKA_BASE; ++ attr[3].type = CKA_VALUE; ++ attr[4].type = CKA_VALUE2; ++ ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, dp, attr, 3), ++ DST_R_CRYPTOFAILURE); ++ ++ for (i = 0; i <= 2; i++) { ++ attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); ++ if (attr[i].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr[i].pValue, 0, attr[i].ulValueLen); ++ } ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, dp, attr, 3), ++ DST_R_CRYPTOFAILURE); ++ pubTemplate[5].pValue = attr[0].pValue; ++ pubTemplate[5].ulValueLen = attr[0].ulValueLen; ++ pubTemplate[6].pValue = attr[1].pValue; ++ pubTemplate[6].ulValueLen = attr[1].ulValueLen; ++ pubTemplate[7].pValue = attr[2].pValue; ++ pubTemplate[7].ulValueLen = attr[2].ulValueLen; ++ ++ mech.mechanism = CKM_DSA_KEY_PAIR_GEN; ++ PK11_RET(pkcs_C_GenerateKeyPair, ++ (pk11_ctx->session, &mech, ++ pubTemplate, (CK_ULONG) 8, ++ privTemplate, (CK_ULONG) 7, ++ &pub, &priv), ++ DST_R_CRYPTOFAILURE); ++ ++ attr = dsa->repr; ++ attr += 3; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ ++ attr++; ++ attr->type = CKA_VALUE; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->type = CKA_VALUE2; ++ ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, dp); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11dsa_destroy(key); ++ if (priv != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ if (pub != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ if (dp != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, dp); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11dsa_isprivate(const dst_key_t *key) { ++ pk11_object_t *dsa = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (dsa == NULL) ++ return (ISC_FALSE); ++ attr = pk11_attribute_bytype(dsa, CKA_VALUE2); ++ return (ISC_TF((attr != NULL) || dsa->ontoken)); ++} ++ ++static void ++pkcs11dsa_destroy(dst_key_t *key) { ++ pk11_object_t *dsa = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (dsa == NULL) ++ return; ++ ++ INSIST((dsa->object == CK_INVALID_HANDLE) || dsa->ontoken); ++ ++ for (attr = pk11_attribute_first(dsa); ++ attr != NULL; ++ attr = pk11_attribute_next(dsa, attr)) ++ switch (attr->type) { ++ case CKA_PRIME: ++ case CKA_SUBPRIME: ++ case CKA_BASE: ++ case CKA_VALUE: ++ case CKA_VALUE2: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (dsa->repr != NULL) { ++ memset(dsa->repr, 0, dsa->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ dsa->repr, ++ dsa->attrcnt * sizeof(*attr)); ++ } ++ memset(dsa, 0, sizeof(*dsa)); ++ isc_mem_put(key->mctx, dsa, sizeof(*dsa)); ++ key->keydata.pkey = NULL; ++} ++ ++ ++static isc_result_t ++pkcs11dsa_todns(const dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *dsa; ++ CK_ATTRIBUTE *attr; ++ isc_region_t r; ++ int dnslen; ++ unsigned int t, p_bytes; ++ CK_ATTRIBUTE *prime = NULL, *subprime = NULL; ++ CK_ATTRIBUTE *base = NULL, *pub_key = NULL; ++ CK_BYTE *cp; ++ ++ REQUIRE(key->keydata.pkey != NULL); ++ ++ dsa = key->keydata.pkey; ++ ++ for (attr = pk11_attribute_first(dsa); ++ attr != NULL; ++ attr = pk11_attribute_next(dsa, attr)) ++ switch (attr->type) { ++ case CKA_PRIME: ++ prime = attr; ++ break; ++ case CKA_SUBPRIME: ++ subprime = attr; ++ break; ++ case CKA_BASE: ++ base = attr; ++ break; ++ case CKA_VALUE: ++ pub_key = attr; ++ break; ++ } ++ REQUIRE((prime != NULL) && (subprime != NULL) && ++ (base != NULL) && (pub_key != NULL)); ++ ++ isc_buffer_availableregion(data, &r); ++ ++ t = (prime->ulValueLen - 64) / 8; ++ if (t > 8) ++ return (DST_R_INVALIDPUBLICKEY); ++ p_bytes = 64 + 8 * t; ++ ++ dnslen = 1 + (key->key_size * 3)/8 + ISC_SHA1_DIGESTLENGTH; ++ if (r.length < (unsigned int) dnslen) ++ return (ISC_R_NOSPACE); ++ ++ memset(r.base, 0, dnslen); ++ *r.base++ = t; ++ cp = (CK_BYTE *) subprime->pValue; ++ memcpy(r.base + ISC_SHA1_DIGESTLENGTH - subprime->ulValueLen, ++ cp, subprime->ulValueLen); ++ r.base += ISC_SHA1_DIGESTLENGTH; ++ cp = (CK_BYTE *) prime->pValue; ++ memcpy(r.base + key->key_size/8 - prime->ulValueLen, ++ cp, prime->ulValueLen); ++ r.base += p_bytes; ++ cp = (CK_BYTE *) base->pValue; ++ memcpy(r.base + key->key_size/8 - base->ulValueLen, ++ cp, base->ulValueLen); ++ r.base += p_bytes; ++ cp = (CK_BYTE *) pub_key->pValue; ++ memcpy(r.base + key->key_size/8 - pub_key->ulValueLen, ++ cp, pub_key->ulValueLen); ++ r.base += p_bytes; ++ ++ isc_buffer_add(data, dnslen); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++pkcs11dsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *dsa; ++ isc_region_t r; ++ unsigned int t, p_bytes; ++ CK_BYTE *prime, *subprime, *base, *pub_key; ++ CK_ATTRIBUTE *attr; ++ ++ isc_buffer_remainingregion(data, &r); ++ if (r.length == 0) ++ return (ISC_R_SUCCESS); ++ ++ dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa)); ++ if (dsa == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(dsa, 0, sizeof(*dsa)); ++ ++ t = (unsigned int) *r.base++; ++ if (t > 8) { ++ memset(dsa, 0, sizeof(*dsa)); ++ isc_mem_put(key->mctx, dsa, sizeof(*dsa)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ p_bytes = 64 + 8 * t; ++ ++ if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) { ++ memset(dsa, 0, sizeof(*dsa)); ++ isc_mem_put(key->mctx, dsa, sizeof(*dsa)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ ++ subprime = r.base; ++ r.base += ISC_SHA1_DIGESTLENGTH; ++ ++ prime = r.base; ++ r.base += p_bytes; ++ ++ base = r.base; ++ r.base += p_bytes; ++ ++ pub_key = r.base; ++ r.base += p_bytes; ++ ++ key->key_size = p_bytes * 8; ++ ++ isc_buffer_forward(data, 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes); ++ ++ dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 4); ++ if (dsa->repr == NULL) ++ goto nomemory; ++ memset(dsa->repr, 0, sizeof(*attr) * 4); ++ dsa->attrcnt = 4; ++ ++ attr = dsa->repr; ++ attr[0].type = CKA_PRIME; ++ attr[0].pValue = isc_mem_get(key->mctx, p_bytes); ++ if (attr[0].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[0].pValue, prime, p_bytes); ++ attr[0].ulValueLen = p_bytes; ++ ++ attr[1].type = CKA_SUBPRIME; ++ attr[1].pValue = isc_mem_get(key->mctx, ISC_SHA1_DIGESTLENGTH); ++ if (attr[1].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[1].pValue, subprime, ISC_SHA1_DIGESTLENGTH); ++ attr[1].ulValueLen = ISC_SHA1_DIGESTLENGTH; ++ ++ attr[2].type = CKA_BASE; ++ attr[2].pValue = isc_mem_get(key->mctx, p_bytes); ++ if (attr[2].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[2].pValue, base, p_bytes); ++ attr[2].ulValueLen = p_bytes; ++ ++ attr[3].type = CKA_VALUE; ++ attr[3].pValue = isc_mem_get(key->mctx, p_bytes); ++ if (attr[3].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[3].pValue, pub_key, p_bytes); ++ attr[3].ulValueLen = p_bytes; ++ ++ key->keydata.pkey = dsa; ++ ++ return (ISC_R_SUCCESS); ++ ++ nomemory: ++ for (attr = pk11_attribute_first(dsa); ++ attr != NULL; ++ attr = pk11_attribute_next(dsa, attr)) ++ switch (attr->type) { ++ case CKA_PRIME: ++ case CKA_SUBPRIME: ++ case CKA_BASE: ++ case CKA_VALUE: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (dsa->repr != NULL) { ++ memset(dsa->repr, 0, dsa->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ dsa->repr, ++ dsa->attrcnt * sizeof(*attr)); ++ } ++ memset(dsa, 0, sizeof(*dsa)); ++ isc_mem_put(key->mctx, dsa, sizeof(*dsa)); ++ return (ISC_R_NOMEMORY); ++} ++ ++static isc_result_t ++pkcs11dsa_tofile(const dst_key_t *key, const char *directory) { ++ int cnt = 0; ++ pk11_object_t *dsa; ++ CK_ATTRIBUTE *attr; ++ CK_ATTRIBUTE *prime = NULL, *subprime = NULL, *base = NULL; ++ CK_ATTRIBUTE *pub_key = NULL, *priv_key = NULL; ++ dst_private_t priv; ++ unsigned char bufs[5][128]; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ ++ dsa = key->keydata.pkey; ++ ++ for (attr = pk11_attribute_first(dsa); ++ attr != NULL; ++ attr = pk11_attribute_next(dsa, attr)) ++ switch (attr->type) { ++ case CKA_PRIME: ++ prime = attr; ++ break; ++ case CKA_SUBPRIME: ++ subprime = attr; ++ break; ++ case CKA_BASE: ++ base = attr; ++ break; ++ case CKA_VALUE: ++ pub_key = attr; ++ break; ++ case CKA_VALUE2: ++ priv_key = attr; ++ break; ++ } ++ if ((prime == NULL) || (subprime == NULL) || (base == NULL) || ++ (pub_key == NULL) || (priv_key ==NULL)) ++ return (DST_R_NULLKEY); ++ ++ priv.elements[cnt].tag = TAG_DSA_PRIME; ++ priv.elements[cnt].length = (unsigned short) prime->ulValueLen; ++ memcpy(bufs[cnt], prime->pValue, prime->ulValueLen); ++ priv.elements[cnt].data = bufs[cnt]; ++ cnt++; ++ ++ priv.elements[cnt].tag = TAG_DSA_SUBPRIME; ++ priv.elements[cnt].length = (unsigned short) subprime->ulValueLen; ++ memcpy(bufs[cnt], subprime->pValue, subprime->ulValueLen); ++ priv.elements[cnt].data = bufs[cnt]; ++ cnt++; ++ ++ priv.elements[cnt].tag = TAG_DSA_BASE; ++ priv.elements[cnt].length = (unsigned short) base->ulValueLen; ++ memcpy(bufs[cnt], base->pValue, base->ulValueLen); ++ priv.elements[cnt].data = bufs[cnt]; ++ cnt++; ++ ++ priv.elements[cnt].tag = TAG_DSA_PRIVATE; ++ priv.elements[cnt].length = (unsigned short) priv_key->ulValueLen; ++ memcpy(bufs[cnt], priv_key->pValue, priv_key->ulValueLen); ++ priv.elements[cnt].data = bufs[cnt]; ++ cnt++; ++ ++ priv.elements[cnt].tag = TAG_DSA_PUBLIC; ++ priv.elements[cnt].length = (unsigned short) pub_key->ulValueLen; ++ memcpy(bufs[cnt], pub_key->pValue, pub_key->ulValueLen); ++ priv.elements[cnt].data = bufs[cnt]; ++ cnt++; ++ ++ priv.nelements = cnt; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++} ++ ++static isc_result_t ++pkcs11dsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ++ dst_private_t priv; ++ isc_result_t ret; ++ int i; ++ pk11_object_t *dsa = NULL; ++ CK_ATTRIBUTE *attr; ++ isc_mem_t *mctx = key->mctx; ++ ++ /* read private key file */ ++ ret = dst__privstruct_parse(key, DST_ALG_DSA, lexer, mctx, &priv); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ if (key->external) { ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ key->key_size = pub->key_size; ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ } ++ ++ dsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*dsa)); ++ if (dsa == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dsa, 0, sizeof(*dsa)); ++ key->keydata.pkey = dsa; ++ ++ dsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 5); ++ if (dsa->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(dsa->repr, 0, sizeof(*attr) * 5); ++ dsa->attrcnt = 5; ++ attr = dsa->repr; ++ attr[0].type = CKA_PRIME; ++ attr[1].type = CKA_SUBPRIME; ++ attr[2].type = CKA_BASE; ++ attr[3].type = CKA_VALUE; ++ attr[4].type = CKA_VALUE2; ++ ++ for (i = 0; i < priv.nelements; i++) { ++ CK_BYTE *bn; ++ ++ bn = isc_mem_get(key->mctx, priv.elements[i].length); ++ if (bn == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(bn, ++ priv.elements[i].data, ++ priv.elements[i].length); ++ ++ switch (priv.elements[i].tag) { ++ case TAG_DSA_PRIME: ++ attr = pk11_attribute_bytype(dsa, CKA_PRIME); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DSA_SUBPRIME: ++ attr = pk11_attribute_bytype(dsa, ++ CKA_SUBPRIME); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DSA_BASE: ++ attr = pk11_attribute_bytype(dsa, CKA_BASE); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DSA_PRIVATE: ++ attr = pk11_attribute_bytype(dsa, CKA_VALUE2); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_DSA_PUBLIC: ++ attr = pk11_attribute_bytype(dsa, CKA_VALUE); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ } ++ } ++ dst__privstruct_free(&priv, mctx); ++ ++ attr = pk11_attribute_bytype(dsa, CKA_PRIME); ++ INSIST(attr != NULL); ++ key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11dsa_destroy(key); ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++} ++ ++static dst_func_t pkcs11dsa_functions = { ++ pkcs11dsa_createctx, ++ NULL, /*%< createctx2 */ ++ pkcs11dsa_destroyctx, ++ pkcs11dsa_adddata, ++ pkcs11dsa_sign, ++ pkcs11dsa_verify, ++ NULL, /*%< verify2 */ ++ NULL, /*%< computesecret */ ++ pkcs11dsa_compare, ++ NULL, /*%< paramcompare */ ++ pkcs11dsa_generate, ++ pkcs11dsa_isprivate, ++ pkcs11dsa_destroy, ++ pkcs11dsa_todns, ++ pkcs11dsa_fromdns, ++ pkcs11dsa_tofile, ++ pkcs11dsa_parse, ++ NULL, /*%< cleanup */ ++ NULL, /*%< fromlabel */ ++ NULL, /*%< dump */ ++ NULL, /*%< restore */ ++}; ++ ++isc_result_t ++dst__pkcs11dsa_init(dst_func_t **funcp) { ++ REQUIRE(funcp != NULL); ++ if (*funcp == NULL) ++ *funcp = &pkcs11dsa_functions; ++ return (ISC_R_SUCCESS); ++} ++ ++#else /* PKCS11CRYPTO */ ++ ++#include <isc/util.h> ++ ++EMPTY_TRANSLATION_UNIT ++ ++#endif /* PKCS11CRYPTO */ ++/*! \file */ +diff --git a/lib/dns/pkcs11ecdsa_link.c b/lib/dns/pkcs11ecdsa_link.c +new file mode 100644 +index 0000000..4f56050 +--- /dev/null ++++ b/lib/dns/pkcs11ecdsa_link.c +@@ -0,0 +1,1189 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#include <config.h> ++ ++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_ECDSA) ++ ++#include <isc/entropy.h> ++#include <isc/mem.h> ++#include <isc/sha2.h> ++#include <isc/string.h> ++#include <isc/util.h> ++ ++#include <dns/keyvalues.h> ++#include <dst/result.h> ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++#define WANT_ECC_CURVES ++#include <pk11/constants.h> ++ ++#include <pkcs11/pkcs11.h> ++ ++/* ++ * FIPS 186-3 ECDSA keys: ++ * mechanisms: ++ * CKM_ECDSA, ++ * CKM_EC_KEY_PAIR_GEN ++ * domain parameters: ++ * CKA_EC_PARAMS (choice with OID namedCurve) ++ * public keys: ++ * object class CKO_PUBLIC_KEY ++ * key type CKK_EC ++ * attribute CKA_EC_PARAMS (choice with OID namedCurve) ++ * attribute CKA_EC_POINT (point Q) ++ * private keys: ++ * object class CKO_PRIVATE_KEY ++ * key type CKK_EC ++ * attribute CKA_EC_PARAMS (choice with OID namedCurve) ++ * attribute CKA_VALUE (big int d) ++ * point format: 0x04 (octet-string) <2*size+1> 0x4 (uncompressed) <x> <y> ++ */ ++ ++#define TAG_OCTECT_STRING 0x04 ++#define UNCOMPRESSED 0x04 ++ ++#define DST_RET(a) {ret = a; goto err;} ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++static isc_result_t pkcs11ecdsa_todns(const dst_key_t *key, ++ isc_buffer_t *data); ++static void pkcs11ecdsa_destroy(dst_key_t *key); ++static isc_result_t pkcs11ecdsa_fetch(dst_key_t *key, const char *engine, ++ const char *label, dst_key_t *pub); ++ ++static isc_result_t ++pkcs11ecdsa_createctx(dst_key_t *key, dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = {0, NULL, 0 }; ++ CK_SLOT_ID slotid; ++ pk11_context_t *pk11_ctx; ++ pk11_object_t *ec = key->keydata.pkey; ++ isc_result_t ret; ++ ++ UNUSED(key); ++ REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || ++ dctx->key->key_alg == DST_ALG_ECDSA384); ++ ++ if (dctx->key->key_alg == DST_ALG_ECDSA256) ++ mech.mechanism = CKM_SHA256; ++ else ++ mech.mechanism = CKM_SHA384; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ if (ec->ontoken && (dctx->use == DO_SIGN)) ++ slotid = ec->slot; ++ else ++ slotid = pk11_get_best_token(OP_EC); ++ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE, ISC_FALSE, ++ NULL, slotid); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ PK11_RET(pkcs_C_DigestInit, (pk11_ctx->session, &mech), ISC_R_FAILURE); ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static void ++pkcs11ecdsa_destroyctx(dst_context_t *dctx) { ++ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA384_DIGESTLENGTH; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ ++ REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || ++ dctx->key->key_alg == DST_ALG_ECDSA384); ++ ++ if (pk11_ctx != NULL) { ++ (void) pkcs_C_DigestFinal(pk11_ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ dctx->ctxdata.pk11_ctx = NULL; ++ } ++} ++ ++static isc_result_t ++pkcs11ecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 || ++ dctx->key->key_alg == DST_ALG_ECDSA384); ++ ++ PK11_CALL(pkcs_C_DigestUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11ecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_EC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_EC_PARAMS, NULL, 0 }, ++ { CKA_VALUE, NULL, 0 } ++ }; ++ CK_ATTRIBUTE *attr; ++ CK_BYTE digest[ISC_SHA384_DIGESTLENGTH]; ++ CK_ULONG dgstlen; ++ CK_ULONG siglen; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ dst_key_t *key = dctx->key; ++ pk11_object_t *ec = key->keydata.pkey; ++ isc_region_t r; ++ isc_result_t ret = ISC_R_SUCCESS; ++ unsigned int i; ++ ++ REQUIRE(key->key_alg == DST_ALG_ECDSA256 || ++ key->key_alg == DST_ALG_ECDSA384); ++ REQUIRE(ec != NULL); ++ ++ if (key->key_alg == DST_ALG_ECDSA256) { ++ dgstlen = ISC_SHA256_DIGESTLENGTH; ++ siglen = DNS_SIG_ECDSA256SIZE; ++ } else { ++ siglen = DNS_SIG_ECDSA384SIZE; ++ dgstlen = ISC_SHA384_DIGESTLENGTH; ++ } ++ ++ PK11_RET(pkcs_C_DigestFinal, ++ (pk11_ctx->session, digest, &dgstlen), ++ ISC_R_FAILURE); ++ ++ isc_buffer_availableregion(sig, &r); ++ if (r.length < siglen) ++ DST_RET(ISC_R_NOSPACE); ++ ++ if (ec->ontoken && (ec->object != CK_INVALID_HANDLE)) { ++ pk11_ctx->ontoken = ec->ontoken; ++ pk11_ctx->object = ec->object; ++ goto token_key; ++ } ++ ++ for (attr = pk11_attribute_first(ec); ++ attr != NULL; ++ attr = pk11_attribute_next(ec, attr)) ++ switch (attr->type) { ++ case CKA_EC_PARAMS: ++ INSIST(keyTemplate[5].type == attr->type); ++ keyTemplate[5].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[5].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[5].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[5].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_VALUE: ++ INSIST(keyTemplate[6].type == attr->type); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 7, ++ &hKey), ++ ISC_R_FAILURE); ++ ++ token_key: ++ ++ PK11_RET(pkcs_C_SignInit, ++ (pk11_ctx->session, &mech, ++ pk11_ctx->ontoken ? pk11_ctx->object : hKey), ++ ISC_R_FAILURE); ++ ++ PK11_RET(pkcs_C_Sign, ++ (pk11_ctx->session, ++ digest, dgstlen, ++ (CK_BYTE_PTR) r.base, &siglen), ++ DST_R_SIGNFAILURE); ++ ++ isc_buffer_add(sig, (unsigned int) siglen); ++ ++ err: ++ ++ if (hKey != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, hKey); ++ for (i = 5; i <= 6; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ dctx->ctxdata.pk11_ctx = NULL; ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11ecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_ECDSA, NULL, 0 }; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_EC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_EC_PARAMS, NULL, 0 }, ++ { CKA_EC_POINT, NULL, 0 } ++ }; ++ CK_ATTRIBUTE *attr; ++ CK_BYTE digest[ISC_SHA384_DIGESTLENGTH]; ++ CK_ULONG dgstlen; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ dst_key_t *key = dctx->key; ++ pk11_object_t *ec = key->keydata.pkey; ++ isc_result_t ret = ISC_R_SUCCESS; ++ unsigned int i; ++ ++ REQUIRE(key->key_alg == DST_ALG_ECDSA256 || ++ key->key_alg == DST_ALG_ECDSA384); ++ REQUIRE(ec != NULL); ++ ++ if (key->key_alg == DST_ALG_ECDSA256) ++ dgstlen = ISC_SHA256_DIGESTLENGTH; ++ else ++ dgstlen = ISC_SHA384_DIGESTLENGTH; ++ ++ PK11_RET(pkcs_C_DigestFinal, ++ (pk11_ctx->session, digest, &dgstlen), ++ ISC_R_FAILURE); ++ ++ for (attr = pk11_attribute_first(ec); ++ attr != NULL; ++ attr = pk11_attribute_next(ec, attr)) ++ switch (attr->type) { ++ case CKA_EC_PARAMS: ++ INSIST(keyTemplate[5].type == attr->type); ++ keyTemplate[5].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[5].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[5].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[5].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_EC_POINT: ++ INSIST(keyTemplate[6].type == attr->type); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 7, ++ &hKey), ++ ISC_R_FAILURE); ++ ++ PK11_RET(pkcs_C_VerifyInit, ++ (pk11_ctx->session, &mech, hKey), ++ ISC_R_FAILURE); ++ ++ PK11_RET(pkcs_C_Verify, ++ (pk11_ctx->session, ++ digest, dgstlen, ++ (CK_BYTE_PTR) sig->base, (CK_ULONG) sig->length), ++ DST_R_SIGNFAILURE); ++ ++ err: ++ ++ if (hKey != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, hKey); ++ for (i = 5; i <= 6; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ dctx->ctxdata.pk11_ctx = NULL; ++ ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11ecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) { ++ pk11_object_t *ec1, *ec2; ++ CK_ATTRIBUTE *attr1, *attr2; ++ ++ ec1 = key1->keydata.pkey; ++ ec2 = key2->keydata.pkey; ++ ++ if ((ec1 == NULL) && (ec2 == NULL)) ++ return (ISC_TRUE); ++ else if ((ec1 == NULL) || (ec2 == NULL)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(ec1, CKA_EC_PARAMS); ++ attr2 = pk11_attribute_bytype(ec2, CKA_EC_PARAMS); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(ec1, CKA_EC_POINT); ++ attr2 = pk11_attribute_bytype(ec2, CKA_EC_POINT); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(ec1, CKA_VALUE); ++ attr2 = pk11_attribute_bytype(ec2, CKA_VALUE); ++ if (((attr1 != NULL) || (attr2 != NULL)) && ++ ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) ++ return (ISC_FALSE); ++ ++ if (!ec1->ontoken && !ec2->ontoken) ++ return (ISC_TRUE); ++ else if (ec1->ontoken || ec2->ontoken || ++ (ec1->object != ec2->object)) ++ return (ISC_FALSE); ++ ++ return (ISC_TRUE); ++} ++ ++#define SETCURVE() \ ++ if (key->key_alg == DST_ALG_ECDSA256) { \ ++ attr->pValue = isc_mem_get(key->mctx, \ ++ sizeof(pk11_ecc_prime256v1)); \ ++ if (attr->pValue == NULL) \ ++ DST_RET(ISC_R_NOMEMORY); \ ++ memcpy(attr->pValue, \ ++ pk11_ecc_prime256v1, sizeof(pk11_ecc_prime256v1)); \ ++ attr->ulValueLen = sizeof(pk11_ecc_prime256v1); \ ++ } else { \ ++ attr->pValue = isc_mem_get(key->mctx, \ ++ sizeof(pk11_ecc_secp384r1)); \ ++ if (attr->pValue == NULL) \ ++ DST_RET(ISC_R_NOMEMORY); \ ++ memcpy(attr->pValue, \ ++ pk11_ecc_secp384r1, sizeof(pk11_ecc_secp384r1)); \ ++ attr->ulValueLen = sizeof(pk11_ecc_secp384r1); \ ++ } ++ ++#define FREECURVE() \ ++ if (attr->pValue != NULL) { \ ++ memset(attr->pValue, 0, attr->ulValueLen); \ ++ isc_mem_put(key->mctx, attr->pValue, attr->ulValueLen); \ ++ attr->pValue = NULL; \ ++ } ++ ++static isc_result_t ++pkcs11ecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_EC_KEY_PAIR_GEN, NULL, 0 }; ++ CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_EC; ++ CK_ATTRIBUTE pubTemplate[] = ++ { ++ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_EC_PARAMS, NULL, 0 } ++ }; ++ CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY; ++ CK_ATTRIBUTE privTemplate[] = ++ { ++ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) } ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *ec; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ ++ REQUIRE(key->key_alg == DST_ALG_ECDSA256 || ++ key->key_alg == DST_ALG_ECDSA384); ++ UNUSED(unused); ++ UNUSED(callback); ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_EC)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec)); ++ if (ec == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(ec, 0, sizeof(*ec)); ++ key->keydata.pkey = ec; ++ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3); ++ if (ec->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(ec->repr, 0, sizeof(*attr) * 3); ++ ec->attrcnt = 3; ++ ++ attr = ec->repr; ++ attr[0].type = CKA_EC_PARAMS; ++ attr[1].type = CKA_EC_POINT; ++ attr[2].type = CKA_VALUE; ++ ++ attr = &pubTemplate[5]; ++ SETCURVE(); ++ ++ PK11_RET(pkcs_C_GenerateKeyPair, ++ (pk11_ctx->session, &mech, ++ pubTemplate, (CK_ULONG) 6, ++ privTemplate, (CK_ULONG) 7, ++ &pub, &priv), ++ DST_R_CRYPTOFAILURE); ++ ++ attr = &pubTemplate[5]; ++ FREECURVE(); ++ ++ attr = ec->repr; ++ SETCURVE(); ++ ++ attr++; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ ++ attr++; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11ecdsa_destroy(key); ++ if (priv != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ if (pub != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11ecdsa_isprivate(const dst_key_t *key) { ++ pk11_object_t *ec = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (ec == NULL) ++ return (ISC_FALSE); ++ attr = pk11_attribute_bytype(ec, CKA_VALUE); ++ return (ISC_TF((attr != NULL) || ec->ontoken)); ++} ++ ++static void ++pkcs11ecdsa_destroy(dst_key_t *key) { ++ pk11_object_t *ec = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (ec == NULL) ++ return; ++ ++ INSIST((ec->object == CK_INVALID_HANDLE) || ec->ontoken); ++ ++ for (attr = pk11_attribute_first(ec); ++ attr != NULL; ++ attr = pk11_attribute_next(ec, attr)) ++ switch (attr->type) { ++ case CKA_LABEL: ++ case CKA_ID: ++ case CKA_EC_PARAMS: ++ case CKA_EC_POINT: ++ case CKA_VALUE: ++ FREECURVE(); ++ break; ++ } ++ if (ec->repr != NULL) { ++ memset(ec->repr, 0, ec->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ ec->repr, ++ ec->attrcnt * sizeof(*attr)); ++ } ++ memset(ec, 0, sizeof(*ec)); ++ isc_mem_put(key->mctx, ec, sizeof(*ec)); ++ key->keydata.pkey = NULL; ++} ++ ++static isc_result_t ++pkcs11ecdsa_todns(const dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *ec; ++ isc_region_t r; ++ unsigned int len; ++ CK_ATTRIBUTE *attr; ++ ++ REQUIRE(key->keydata.pkey != NULL); ++ ++ if (key->key_alg == DST_ALG_ECDSA256) ++ len = DNS_KEY_ECDSA256SIZE; ++ else ++ len = DNS_KEY_ECDSA384SIZE; ++ ++ ec = key->keydata.pkey; ++ attr = pk11_attribute_bytype(ec, CKA_EC_POINT); ++ if ((attr == NULL) || ++ (attr->ulValueLen != len + 3) || ++ (((CK_BYTE_PTR) attr->pValue)[0] != TAG_OCTECT_STRING) || ++ (((CK_BYTE_PTR) attr->pValue)[1] != len + 1) || ++ (((CK_BYTE_PTR) attr->pValue)[2] != UNCOMPRESSED)) ++ return (ISC_R_FAILURE); ++ ++ isc_buffer_availableregion(data, &r); ++ if (r.length < len) ++ return (ISC_R_NOSPACE); ++ memcpy(r.base, (CK_BYTE_PTR) attr->pValue + 3, len); ++ isc_buffer_add(data, len); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++pkcs11ecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *ec; ++ isc_region_t r; ++ unsigned int len; ++ CK_ATTRIBUTE *attr; ++ ++ REQUIRE(key->key_alg == DST_ALG_ECDSA256 || ++ key->key_alg == DST_ALG_ECDSA384); ++ ++ if (key->key_alg == DST_ALG_ECDSA256) ++ len = DNS_KEY_ECDSA256SIZE; ++ else ++ len = DNS_KEY_ECDSA384SIZE; ++ ++ isc_buffer_remainingregion(data, &r); ++ if (r.length == 0) ++ return (ISC_R_SUCCESS); ++ if (r.length != len) ++ return (DST_R_INVALIDPUBLICKEY); ++ ++ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec)); ++ if (ec == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(ec, 0, sizeof(*ec)); ++ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); ++ if (ec->repr == NULL) ++ goto nomemory; ++ ec->attrcnt = 2; ++ ++ attr = ec->repr; ++ attr->type = CKA_EC_PARAMS; ++ if (key->key_alg == DST_ALG_ECDSA256) { ++ attr->pValue = ++ isc_mem_get(key->mctx, sizeof(pk11_ecc_prime256v1)); ++ if (attr->pValue == NULL) ++ goto nomemory; ++ memcpy(attr->pValue, ++ pk11_ecc_prime256v1, sizeof(pk11_ecc_prime256v1)); ++ attr->ulValueLen = sizeof(pk11_ecc_prime256v1); ++ } else { ++ attr->pValue = ++ isc_mem_get(key->mctx, sizeof(pk11_ecc_secp384r1)); ++ if (attr->pValue == NULL) ++ goto nomemory; ++ memcpy(attr->pValue, ++ pk11_ecc_secp384r1, sizeof(pk11_ecc_secp384r1)); ++ attr->ulValueLen = sizeof(pk11_ecc_secp384r1); ++ } ++ ++ attr++; ++ attr->type = CKA_EC_POINT; ++ attr->pValue = isc_mem_get(key->mctx, len + 3); ++ if (attr->pValue == NULL) ++ goto nomemory; ++ ((CK_BYTE_PTR) attr->pValue)[0] = TAG_OCTECT_STRING; ++ ((CK_BYTE_PTR) attr->pValue)[1] = len + 1; ++ ((CK_BYTE_PTR) attr->pValue)[2] = UNCOMPRESSED; ++ memcpy((CK_BYTE_PTR) attr->pValue + 3, r.base, len); ++ attr->ulValueLen = len + 3; ++ ++ isc_buffer_forward(data, len); ++ key->keydata.pkey = ec; ++ return (ISC_R_SUCCESS); ++ ++ nomemory: ++ for (attr = pk11_attribute_first(ec); ++ attr != NULL; ++ attr = pk11_attribute_next(ec, attr)) ++ switch (attr->type) { ++ case CKA_EC_PARAMS: ++ case CKA_EC_POINT: ++ FREECURVE(); ++ break; ++ } ++ if (ec->repr != NULL) { ++ memset(ec->repr, 0, ec->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ ec->repr, ++ ec->attrcnt * sizeof(*attr)); ++ } ++ memset(ec, 0, sizeof(*ec)); ++ isc_mem_put(key->mctx, ec, sizeof(*ec)); ++ return (ISC_R_NOMEMORY); ++} ++ ++static isc_result_t ++pkcs11ecdsa_tofile(const dst_key_t *key, const char *directory) { ++ isc_result_t ret; ++ pk11_object_t *ec; ++ dst_private_t priv; ++ unsigned char *buf = NULL; ++ unsigned int i = 0; ++ CK_ATTRIBUTE *attr; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ ++ ec = key->keydata.pkey; ++ attr = pk11_attribute_bytype(ec, CKA_VALUE); ++ if (attr != NULL) { ++ buf = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (buf == NULL) ++ return (ISC_R_NOMEMORY); ++ priv.elements[i].tag = TAG_ECDSA_PRIVATEKEY; ++ priv.elements[i].length = (unsigned short) attr->ulValueLen; ++ memcpy(buf, attr->pValue, attr->ulValueLen); ++ priv.elements[i].data = buf; ++ i++; ++ } ++ ++ if (key->engine != NULL) { ++ priv.elements[i].tag = TAG_ECDSA_ENGINE; ++ priv.elements[i].length = strlen(key->engine) + 1; ++ priv.elements[i].data = (unsigned char *)key->engine; ++ i++; ++ } ++ ++ if (key->label != NULL) { ++ priv.elements[i].tag = TAG_ECDSA_LABEL; ++ priv.elements[i].length = strlen(key->label) + 1; ++ priv.elements[i].data = (unsigned char *)key->label; ++ i++; ++ } ++ ++ priv.nelements = i; ++ ret = dst__privstruct_writefile(key, &priv, directory); ++ ++ if (buf != NULL) { ++ memset(buf, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, buf, attr->ulValueLen); ++ } ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11ecdsa_fetch(dst_key_t *key, const char *engine, const char *label, ++ dst_key_t *pub) ++{ ++ CK_RV rv; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_EC; ++ CK_ATTRIBUTE searchTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_LABEL, NULL, 0 } ++ }; ++ CK_ULONG cnt; ++ CK_ATTRIBUTE *attr; ++ CK_ATTRIBUTE *pubattr; ++ pk11_object_t *ec; ++ pk11_object_t *pubec; ++ pk11_context_t *pk11_ctx = NULL; ++ isc_result_t ret; ++ ++ if (label == NULL) ++ return (DST_R_NOENGINE); ++ ++ ec = key->keydata.pkey; ++ pubec = pub->keydata.pkey; ++ ++ ec->object = CK_INVALID_HANDLE; ++ ec->ontoken = ISC_TRUE; ++ ec->reqlogon = ISC_TRUE; ++ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); ++ if (ec->repr == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(ec->repr, 0, sizeof(*attr) * 2); ++ ec->attrcnt = 2; ++ attr = ec->repr; ++ ++ attr->type = CKA_EC_PARAMS; ++ pubattr = pk11_attribute_bytype(pubec, CKA_EC_PARAMS); ++ attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen); ++ attr->ulValueLen = pubattr->ulValueLen; ++ attr++; ++ ++ attr->type = CKA_EC_POINT; ++ pubattr = pk11_attribute_bytype(pubec, CKA_EC_POINT); ++ attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen); ++ attr->ulValueLen = pubattr->ulValueLen; ++ ++ ret = pk11_parse_uri(ec, label, key->mctx, OP_EC); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE, ++ ec->reqlogon, NULL, ec->slot); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ attr = pk11_attribute_bytype(ec, CKA_LABEL); ++ if (attr == NULL) { ++ attr = pk11_attribute_bytype(ec, CKA_ID); ++ INSIST(attr != NULL); ++ searchTemplate[3].type = CKA_ID; ++ } ++ searchTemplate[3].pValue = attr->pValue; ++ searchTemplate[3].ulValueLen = attr->ulValueLen; ++ ++ PK11_RET(pkcs_C_FindObjectsInit, ++ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_FindObjects, ++ (pk11_ctx->session, &ec->object, (CK_ULONG) 1, &cnt), ++ DST_R_CRYPTOFAILURE); ++ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); ++ if (cnt == 0) ++ DST_RET(ISC_R_NOTFOUND); ++ if (cnt > 1) ++ DST_RET(ISC_R_EXISTS); ++ ++ if (engine != NULL) { ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ if (key->engine == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ } ++ ++ key->label = isc_mem_strdup(key->mctx, label); ++ if (key->label == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (pk11_ctx != NULL) { ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ } ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11ecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ++ dst_private_t priv; ++ isc_result_t ret; ++ pk11_object_t *ec = NULL; ++ CK_ATTRIBUTE *attr, *pattr; ++ isc_mem_t *mctx = key->mctx; ++ unsigned int i; ++ const char *engine = NULL, *label = NULL; ++ ++ REQUIRE(key->key_alg == DST_ALG_ECDSA256 || ++ key->key_alg == DST_ALG_ECDSA384); ++ ++ if ((pub == NULL) || (pub->keydata.pkey == NULL)) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ /* read private key file */ ++ ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ if (key->external) { ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ key->key_size = pub->key_size; ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ } ++ ++ for (i = 0; i < priv.nelements; i++) { ++ switch (priv.elements[i].tag) { ++ case TAG_ECDSA_ENGINE: ++ engine = (char *)priv.elements[i].data; ++ break; ++ case TAG_ECDSA_LABEL: ++ label = (char *)priv.elements[i].data; ++ break; ++ default: ++ break; ++ } ++ } ++ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec)); ++ if (ec == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(ec, 0, sizeof(*ec)); ++ key->keydata.pkey = ec; ++ ++ /* Is this key is stored in a HSM? See if we can fetch it. */ ++ if ((label != NULL) || (engine != NULL)) { ++ ret = pkcs11ecdsa_fetch(key, engine, label, pub); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++ } ++ ++ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 3); ++ if (ec->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(ec->repr, 0, sizeof(*attr) * 3); ++ ec->attrcnt = 3; ++ ++ attr = ec->repr; ++ attr->type = CKA_EC_PARAMS; ++ pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_PARAMS); ++ INSIST(pattr != NULL); ++ attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pattr->pValue, pattr->ulValueLen); ++ attr->ulValueLen = pattr->ulValueLen; ++ ++ attr++; ++ attr->type = CKA_EC_POINT; ++ pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_EC_POINT); ++ INSIST(pattr != NULL); ++ attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pattr->pValue, pattr->ulValueLen); ++ attr->ulValueLen = pattr->ulValueLen; ++ ++ attr++; ++ attr->type = CKA_VALUE; ++ attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, priv.elements[0].data, priv.elements[0].length); ++ attr->ulValueLen = priv.elements[0].length; ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11ecdsa_destroy(key); ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11ecdsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ++ const char *pin) ++{ ++ CK_RV rv; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_EC; ++ CK_ATTRIBUTE searchTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_LABEL, NULL, 0 } ++ }; ++ CK_ULONG cnt; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *ec; ++ pk11_context_t *pk11_ctx = NULL; ++ isc_result_t ret; ++ unsigned int i; ++ ++ UNUSED(pin); ++ ++ ec = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*ec)); ++ if (ec == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(ec, 0, sizeof(*ec)); ++ ec->object = CK_INVALID_HANDLE; ++ ec->ontoken = ISC_TRUE; ++ ec->reqlogon = ISC_TRUE; ++ key->keydata.pkey = ec; ++ ++ ec->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); ++ if (ec->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(ec->repr, 0, sizeof(*attr) * 2); ++ ec->attrcnt = 2; ++ attr = ec->repr; ++ attr[0].type = CKA_EC_PARAMS; ++ attr[1].type = CKA_EC_POINT; ++ ++ ret = pk11_parse_uri(ec, label, key->mctx, OP_EC); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_EC, ISC_TRUE, ISC_FALSE, ++ ec->reqlogon, NULL, ec->slot); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ attr = pk11_attribute_bytype(ec, CKA_LABEL); ++ if (attr == NULL) { ++ attr = pk11_attribute_bytype(ec, CKA_ID); ++ INSIST(attr != NULL); ++ searchTemplate[3].type = CKA_ID; ++ } ++ searchTemplate[3].pValue = attr->pValue; ++ searchTemplate[3].ulValueLen = attr->ulValueLen; ++ ++ PK11_RET(pkcs_C_FindObjectsInit, ++ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_FindObjects, ++ (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt), ++ DST_R_CRYPTOFAILURE); ++ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); ++ if (cnt == 0) ++ DST_RET(ISC_R_NOTFOUND); ++ if (cnt > 1) ++ DST_RET(ISC_R_EXISTS); ++ ++ attr = ec->repr; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, hKey, attr, 2), ++ DST_R_CRYPTOFAILURE); ++ for (i = 0; i <= 1; i++) { ++ attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); ++ if (attr[i].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr[i].pValue, 0, attr[i].ulValueLen); ++ } ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, hKey, attr, 2), ++ DST_R_CRYPTOFAILURE); ++ ++ keyClass = CKO_PRIVATE_KEY; ++ PK11_RET(pkcs_C_FindObjectsInit, ++ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_FindObjects, ++ (pk11_ctx->session, &ec->object, (CK_ULONG) 1, &cnt), ++ DST_R_CRYPTOFAILURE); ++ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); ++ if (cnt == 0) ++ DST_RET(ISC_R_NOTFOUND); ++ if (cnt > 1) ++ DST_RET(ISC_R_EXISTS); ++ ++ if (engine != NULL) { ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ if (key->engine == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ } ++ ++ key->label = isc_mem_strdup(key->mctx, label); ++ if (key->label == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11ecdsa_destroy(key); ++ if (pk11_ctx != NULL) { ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ } ++ return (ret); ++} ++ ++static dst_func_t pkcs11ecdsa_functions = { ++ pkcs11ecdsa_createctx, ++ NULL, /*%< createctx2 */ ++ pkcs11ecdsa_destroyctx, ++ pkcs11ecdsa_adddata, ++ pkcs11ecdsa_sign, ++ pkcs11ecdsa_verify, ++ NULL, /*%< verify2 */ ++ NULL, /*%< computesecret */ ++ pkcs11ecdsa_compare, ++ NULL, /*%< paramcompare */ ++ pkcs11ecdsa_generate, ++ pkcs11ecdsa_isprivate, ++ pkcs11ecdsa_destroy, ++ pkcs11ecdsa_todns, ++ pkcs11ecdsa_fromdns, ++ pkcs11ecdsa_tofile, ++ pkcs11ecdsa_parse, ++ NULL, /*%< cleanup */ ++ pkcs11ecdsa_fromlabel, ++ NULL, /*%< dump */ ++ NULL, /*%< restore */ ++}; ++ ++isc_result_t ++dst__pkcs11ecdsa_init(dst_func_t **funcp) { ++ REQUIRE(funcp != NULL); ++ if (*funcp == NULL) ++ *funcp = &pkcs11ecdsa_functions; ++ return (ISC_R_SUCCESS); ++} ++ ++#else /* PKCS11CRYPTO && HAVE_PKCS11_ECDSA */ ++ ++#include <isc/util.h> ++ ++EMPTY_TRANSLATION_UNIT ++ ++#endif /* PKCS11CRYPTO && HAVE_PKCS11_ECDSA */ ++/*! \file */ +diff --git a/lib/dns/pkcs11gost_link.c b/lib/dns/pkcs11gost_link.c +new file mode 100644 +index 0000000..c03b285 +--- /dev/null ++++ b/lib/dns/pkcs11gost_link.c +@@ -0,0 +1,949 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#include <config.h> ++ ++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_GOST) ++ ++#include <isc/entropy.h> ++#include <isc/mem.h> ++#include <isc/sha2.h> ++#include <isc/string.h> ++#include <isc/util.h> ++ ++#include <dns/keyvalues.h> ++#include <dns/log.h> ++#include <dst/result.h> ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++#include "dst_gost.h" ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++#define WANT_GOST_PARAMS ++#include <pk11/constants.h> ++ ++#include <pkcs11/pkcs11.h> ++ ++/* ++ * RU CryptoPro GOST keys: ++ * mechanisms: ++ * CKM_GOSTR3411 ++ * CKM_GOSTR3410_WITH_GOSTR3411 ++ * CKM_GOSTR3410_KEY_PAIR_GEN ++ * domain parameters: ++ * CKA_GOSTR3410_PARAMS (fixed BER OID 1.2.643.2.2.35.1) ++ * CKA_GOSTR3411_PARAMS (fixed BER OID 1.2.643.2.2.30.1) ++ * CKA_GOST28147_PARAMS (optional, don't use) ++ * public keys: ++ * object class CKO_PUBLIC_KEY ++ * key type CKK_GOSTR3410 ++ * attribute CKA_VALUE (point Q) ++ * attribute CKA_GOSTR3410_PARAMS ++ * attribute CKA_GOSTR3411_PARAMS ++ * attribute CKA_GOST28147_PARAMS ++ * private keys: ++ * object class CKO_PRIVATE_KEY ++ * key type CKK_GOSTR3410 ++ * attribute CKA_VALUE (big int d) ++ * attribute CKA_GOSTR3410_PARAMS ++ * attribute CKA_GOSTR3411_PARAMS ++ * attribute CKA_GOST28147_PARAMS ++ * point format: <x> <y> (little endian) ++ */ ++ ++#define CKA_VALUE2 CKA_PRIVATE_EXPONENT ++ ++#define ISC_GOST_SIGNATURELENGTH 64 ++#define ISC_GOST_PUBKEYLENGTH 64 ++ ++/* HASH methods */ ++ ++isc_result_t ++isc_gost_init(isc_gost_t *ctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_GOSTR3411, NULL, 0 }; ++ int ret = ISC_R_SUCCESS; ++ ++ ret = pk11_get_session(ctx, OP_GOST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ PK11_CALL(pkcs_C_DigestInit, (ctx->session, &mech), ISC_R_FAILURE); ++ return (ret); ++} ++ ++void ++isc_gost_invalidate(isc_gost_t *ctx) { ++ CK_BYTE garbage[ISC_GOST_DIGESTLENGTH]; ++ CK_ULONG len = ISC_GOST_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(ctx); ++} ++ ++isc_result_t ++isc_gost_update(isc_gost_t *ctx, const unsigned char *buf, unsigned int len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ int ret = ISC_R_SUCCESS; ++ ++ DE_CONST(buf, pPart); ++ PK11_CALL(pkcs_C_DigestUpdate, ++ (ctx->session, pPart, (CK_ULONG) len), ++ ISC_R_FAILURE); ++ return (ret); ++} ++ ++isc_result_t ++isc_gost_final(isc_gost_t *ctx, unsigned char *digest) { ++ CK_RV rv; ++ CK_ULONG len = ISC_GOST_DIGESTLENGTH; ++ int ret = ISC_R_SUCCESS; ++ ++ PK11_CALL(pkcs_C_DigestFinal, ++ (ctx->session, (CK_BYTE_PTR) digest, &len), ++ ISC_R_FAILURE); ++ pk11_return_session(ctx); ++ return (ret); ++} ++ ++/* DST methods */ ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++#define DST_RET(a) {ret = a; goto err;} ++ ++static isc_result_t pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data); ++static void pkcs11gost_destroy(dst_key_t *key); ++ ++static isc_result_t ++pkcs11gost_createctx_sign(dst_key_t *key, dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_GOSTR3410; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, 0 }, ++ { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, ++ (CK_ULONG) sizeof(pk11_gost_a_paramset) }, ++ { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, ++ (CK_ULONG) sizeof(pk11_gost_paramset) } ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *gost; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_GOST)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ gost = key->keydata.pkey; ++ if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) { ++ pk11_ctx->ontoken = gost->ontoken; ++ pk11_ctx->object = gost->object; ++ goto token_key; ++ } ++ ++ for (attr = pk11_attribute_first(gost); ++ attr != NULL; ++ attr = pk11_attribute_next(gost, attr)) ++ switch (attr->type) { ++ case CKA_VALUE2: ++ INSIST(keyTemplate[6].type == CKA_VALUE); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 9, ++ &pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ token_key: ++ ++ PK11_RET(pkcs_C_SignInit, ++ (pk11_ctx->session, &mech, pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ ++ for (i = 6; i <= 6; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object); ++ for (i = 6; i <= 6; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11gost_createctx_verify(dst_key_t *key, dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_GOSTR3410_WITH_GOSTR3411, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_GOSTR3410; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, 0 }, ++ { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, ++ (CK_ULONG) sizeof(pk11_gost_a_paramset) }, ++ { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, ++ (CK_ULONG) sizeof(pk11_gost_paramset) } ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *gost; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_GOST)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ gost = key->keydata.pkey; ++ if (gost->ontoken && (gost->object != CK_INVALID_HANDLE)) { ++ pk11_ctx->ontoken = gost->ontoken; ++ pk11_ctx->object = gost->object; ++ goto token_key; ++ } ++ ++ for (attr = pk11_attribute_first(gost); ++ attr != NULL; ++ attr = pk11_attribute_next(gost, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ INSIST(keyTemplate[5].type == attr->type); ++ keyTemplate[5].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[5].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[5].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[5].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 8, ++ &pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ token_key: ++ ++ PK11_RET(pkcs_C_VerifyInit, ++ (pk11_ctx->session, &mech, pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ ++ for (i = 5; i <= 5; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pk11_ctx->object); ++ for (i = 5; i <= 5; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11gost_createctx(dst_key_t *key, dst_context_t *dctx) { ++ if (dctx->use == DO_SIGN) ++ return (pkcs11gost_createctx_sign(key, dctx)); ++ else ++ return (pkcs11gost_createctx_verify(key, dctx)); ++} ++ ++static void ++pkcs11gost_destroyctx(dst_context_t *dctx) { ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ ++ if (pk11_ctx != NULL) { ++ if (!pk11_ctx->ontoken && ++ (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, ++ pk11_ctx->object); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ dctx->ctxdata.pk11_ctx = NULL; ++ } ++} ++ ++static isc_result_t ++pkcs11gost_adddata(dst_context_t *dctx, const isc_region_t *data) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ if (dctx->use == DO_SIGN) ++ PK11_CALL(pkcs_C_SignUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ else ++ PK11_CALL(pkcs_C_VerifyUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11gost_sign(dst_context_t *dctx, isc_buffer_t *sig) { ++ CK_RV rv; ++ CK_ULONG siglen = ISC_GOST_SIGNATURELENGTH; ++ isc_region_t r; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ isc_buffer_availableregion(sig, &r); ++ if (r.length < ISC_GOST_SIGNATURELENGTH) ++ return (ISC_R_NOSPACE); ++ ++ PK11_RET(pkcs_C_SignFinal, ++ (pk11_ctx->session, (CK_BYTE_PTR) r.base, &siglen), ++ DST_R_SIGNFAILURE); ++ if (siglen != ISC_GOST_SIGNATURELENGTH) ++ return (DST_R_SIGNFAILURE); ++ ++ isc_buffer_add(sig, ISC_GOST_SIGNATURELENGTH); ++ ++ err: ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11gost_verify(dst_context_t *dctx, const isc_region_t *sig) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ PK11_CALL(pkcs_C_VerifyFinal, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) sig->base, ++ (CK_ULONG) sig->length), ++ DST_R_VERIFYFAILURE); ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11gost_compare(const dst_key_t *key1, const dst_key_t *key2) { ++ pk11_object_t *gost1, *gost2; ++ CK_ATTRIBUTE *attr1, *attr2; ++ ++ gost1 = key1->keydata.pkey; ++ gost2 = key2->keydata.pkey; ++ ++ if ((gost1 == NULL) && (gost2 == NULL)) ++ return (ISC_TRUE); ++ else if ((gost1 == NULL) || (gost2 == NULL)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(gost1, CKA_VALUE); ++ attr2 = pk11_attribute_bytype(gost2, CKA_VALUE); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(gost1, CKA_VALUE2); ++ attr2 = pk11_attribute_bytype(gost2, CKA_VALUE2); ++ if (((attr1 != NULL) || (attr2 != NULL)) && ++ ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) ++ return (ISC_FALSE); ++ ++ if (!gost1->ontoken && !gost2->ontoken) ++ return (ISC_TRUE); ++ else if (gost1->ontoken || gost2->ontoken || ++ (gost1->object != gost2->object)) ++ return (ISC_FALSE); ++ ++ return (ISC_TRUE); ++} ++ ++static isc_result_t ++pkcs11gost_generate(dst_key_t *key, int unused, void (*callback)(int)) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_GOSTR3410_KEY_PAIR_GEN, NULL, 0 }; ++ CK_KEY_TYPE keyType = CKK_GOSTR3410; ++ CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; ++ CK_ATTRIBUTE pubTemplate[] = ++ { ++ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_GOSTR3410_PARAMS, pk11_gost_a_paramset, ++ (CK_ULONG) sizeof(pk11_gost_a_paramset) }, ++ { CKA_GOSTR3411_PARAMS, pk11_gost_paramset, ++ (CK_ULONG) sizeof(pk11_gost_paramset) } ++ }; ++ CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; ++ CK_OBJECT_HANDLE privClass = CKO_PRIVATE_KEY; ++ CK_ATTRIBUTE privTemplate[] = ++ { ++ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *gost; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ ++ UNUSED(unused); ++ UNUSED(callback); ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_GOST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_GOST)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ PK11_RET(pkcs_C_GenerateKeyPair, ++ (pk11_ctx->session, &mech, ++ pubTemplate, (CK_ULONG) 7, ++ privTemplate, (CK_ULONG) 7, ++ &pub, &priv), ++ DST_R_CRYPTOFAILURE); ++ ++ gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); ++ if (gost == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(gost, 0, sizeof(*gost)); ++ key->keydata.pkey = gost; ++ gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, ++ sizeof(*attr) * 2); ++ if (gost->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(gost->repr, 0, sizeof(*attr) * 2); ++ gost->attrcnt = 2; ++ ++ attr = gost->repr; ++ attr[0].type = CKA_VALUE; ++ attr[1].type = CKA_VALUE2; ++ ++ attr = gost->repr; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ ++ attr++; ++ attr->type = CKA_VALUE; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->pValue = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr->pValue, 0, attr->ulValueLen); ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 1), ++ DST_R_CRYPTOFAILURE); ++ attr->type = CKA_VALUE2; ++ ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11gost_destroy(key); ++ if (priv != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ if (pub != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11gost_isprivate(const dst_key_t *key) { ++ pk11_object_t *gost = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (gost == NULL) ++ return (ISC_FALSE); ++ attr = pk11_attribute_bytype(gost, CKA_VALUE2); ++ return (ISC_TF((attr != NULL) || gost->ontoken)); ++} ++ ++static void ++pkcs11gost_destroy(dst_key_t *key) { ++ pk11_object_t *gost = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (gost == NULL) ++ return; ++ ++ INSIST((gost->object == CK_INVALID_HANDLE) || gost->ontoken); ++ ++ for (attr = pk11_attribute_first(gost); ++ attr != NULL; ++ attr = pk11_attribute_next(gost, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ case CKA_VALUE2: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (gost->repr != NULL) { ++ memset(gost->repr, 0, gost->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ gost->repr, ++ gost->attrcnt * sizeof(*attr)); ++ } ++ memset(gost, 0, sizeof(*gost)); ++ isc_mem_put(key->mctx, gost, sizeof(*gost)); ++ key->keydata.pkey = NULL; ++} ++ ++static isc_result_t ++pkcs11gost_todns(const dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *gost; ++ isc_region_t r; ++ CK_ATTRIBUTE *attr; ++ ++ REQUIRE(key->keydata.pkey != NULL); ++ ++ gost = key->keydata.pkey; ++ attr = pk11_attribute_bytype(gost, CKA_VALUE); ++ if ((attr == NULL) || (attr->ulValueLen != ISC_GOST_PUBKEYLENGTH)) ++ return (ISC_R_FAILURE); ++ ++ isc_buffer_availableregion(data, &r); ++ if (r.length < ISC_GOST_PUBKEYLENGTH) ++ return (ISC_R_NOSPACE); ++ memcpy(r.base, (CK_BYTE_PTR) attr->pValue, ISC_GOST_PUBKEYLENGTH); ++ isc_buffer_add(data, ISC_GOST_PUBKEYLENGTH); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++pkcs11gost_fromdns(dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *gost; ++ isc_region_t r; ++ CK_ATTRIBUTE *attr; ++ ++ isc_buffer_remainingregion(data, &r); ++ if (r.length == 0) ++ return (ISC_R_SUCCESS); ++ if (r.length != ISC_GOST_PUBKEYLENGTH) ++ return (DST_R_INVALIDPUBLICKEY); ++ ++ gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); ++ if (gost == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(gost, 0, sizeof(*gost)); ++ gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr)); ++ if (gost->repr == NULL) ++ goto nomemory; ++ gost->attrcnt = 1; ++ ++ attr = gost->repr; ++ attr->type = CKA_VALUE; ++ attr->pValue = isc_mem_get(key->mctx, ISC_GOST_PUBKEYLENGTH); ++ if (attr->pValue == NULL) ++ goto nomemory; ++ memcpy((CK_BYTE_PTR) attr->pValue, r.base, ISC_GOST_PUBKEYLENGTH); ++ attr->ulValueLen = ISC_GOST_PUBKEYLENGTH; ++ ++ isc_buffer_forward(data, ISC_GOST_PUBKEYLENGTH); ++ key->keydata.pkey = gost; ++ return (ISC_R_SUCCESS); ++ ++ nomemory: ++ for (attr = pk11_attribute_first(gost); ++ attr != NULL; ++ attr = pk11_attribute_next(gost, attr)) ++ switch (attr->type) { ++ case CKA_VALUE: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (gost->repr != NULL) { ++ memset(gost->repr, 0, gost->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ gost->repr, ++ gost->attrcnt * sizeof(*attr)); ++ } ++ memset(gost, 0, sizeof(*gost)); ++ isc_mem_put(key->mctx, gost, sizeof(*gost)); ++ return (ISC_R_NOMEMORY); ++} ++ ++static unsigned char gost_private_der[39] = { ++ 0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, ++ 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x13, 0x30, ++ 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, ++ 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, ++ 0x02, 0x1e, 0x01, 0x04, 0x22, 0x02, 0x20 ++}; ++ ++#ifdef PREFER_GOSTASN1 ++ ++static isc_result_t ++pkcs11gost_tofile(const dst_key_t *key, const char *directory) { ++ isc_result_t ret; ++ pk11_object_t *gost; ++ dst_private_t priv; ++ unsigned char *buf = NULL; ++ unsigned int i = 0; ++ CK_ATTRIBUTE *attr; ++ int adj; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ ++ gost = key->keydata.pkey; ++ attr = pk11_attribute_bytype(gost, CKA_VALUE2); ++ if (attr != NULL) { ++ buf = isc_mem_get(key->mctx, attr->ulValueLen + 39); ++ if (buf == NULL) ++ return (ISC_R_NOMEMORY); ++ priv.elements[i].tag = TAG_GOST_PRIVASN1; ++ priv.elements[i].length = ++ (unsigned short) attr->ulValueLen + 39; ++ memcpy(buf, gost_private_der, 39); ++ memcpy(buf +39, attr->pValue, attr->ulValueLen); ++ adj = (int) attr->ulValueLen - 32; ++ if (adj != 0) { ++ buf[1] += adj; ++ buf[36] += adj; ++ buf[38] += adj; ++ } ++ priv.elements[i].data = buf; ++ i++; ++ } else ++ return (DST_R_CRYPTOFAILURE); ++ ++ priv.nelements = i; ++ ret = dst__privstruct_writefile(key, &priv, directory); ++ ++ if (buf != NULL) { ++ memset(buf, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, buf, attr->ulValueLen); ++ } ++ return (ret); ++} ++ ++#else ++ ++static isc_result_t ++pkcs11gost_tofile(const dst_key_t *key, const char *directory) { ++ isc_result_t ret; ++ pk11_object_t *gost; ++ dst_private_t priv; ++ unsigned char *buf = NULL; ++ unsigned int i = 0; ++ CK_ATTRIBUTE *attr; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ ++ gost = key->keydata.pkey; ++ attr = pk11_attribute_bytype(gost, CKA_VALUE2); ++ if (attr != NULL) { ++ buf = isc_mem_get(key->mctx, attr->ulValueLen); ++ if (buf == NULL) ++ return (ISC_R_NOMEMORY); ++ priv.elements[i].tag = TAG_GOST_PRIVRAW; ++ priv.elements[i].length = (unsigned short) attr->ulValueLen; ++ memcpy(buf, attr->pValue, attr->ulValueLen); ++ priv.elements[i].data = buf; ++ i++; ++ } else ++ return (DST_R_CRYPTOFAILURE); ++ ++ priv.nelements = i; ++ ret = dst__privstruct_writefile(key, &priv, directory); ++ ++ if (buf != NULL) { ++ memset(buf, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, buf, attr->ulValueLen); ++ } ++ return (ret); ++} ++#endif ++ ++static isc_result_t ++pkcs11gost_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ++ dst_private_t priv; ++ isc_result_t ret; ++ pk11_object_t *gost = NULL; ++ CK_ATTRIBUTE *attr, *pattr; ++ isc_mem_t *mctx = key->mctx; ++ ++ if ((pub == NULL) || (pub->keydata.pkey == NULL)) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ /* read private key file */ ++ ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ if (key->external) { ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ key->key_size = pub->key_size; ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ } ++ ++ if (priv.elements[0].tag == TAG_GOST_PRIVASN1) { ++ int adj = (int) priv.elements[0].length - (39 + 32); ++ unsigned char buf[39]; ++ ++ if ((adj > 0) || (adj < -31)) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ memcpy(buf, gost_private_der, 39); ++ if (adj != 0) { ++ buf[1] += adj; ++ buf[36] += adj; ++ buf[38] += adj; ++ } ++ if (memcmp(priv.elements[0].data, buf, 39) != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ priv.elements[0].tag = TAG_GOST_PRIVRAW; ++ priv.elements[0].length -= 39; ++ memmove(priv.elements[0].data, ++ priv.elements[0].data + 39, ++ 32 + adj); ++ } ++ ++ gost = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*gost)); ++ if (gost == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(gost, 0, sizeof(*gost)); ++ key->keydata.pkey = gost; ++ ++ gost->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, ++ sizeof(*attr) * 2); ++ if (gost->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(gost->repr, 0, sizeof(*attr) * 2); ++ gost->attrcnt = 2; ++ ++ attr = gost->repr; ++ attr->type = CKA_VALUE; ++ pattr = pk11_attribute_bytype(pub->keydata.pkey, CKA_VALUE); ++ INSIST(pattr != NULL); ++ attr->pValue = isc_mem_get(key->mctx, pattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pattr->pValue, pattr->ulValueLen); ++ attr->ulValueLen = pattr->ulValueLen; ++ ++ attr++; ++ attr->type = CKA_VALUE2; ++ attr->pValue = isc_mem_get(key->mctx, priv.elements[0].length); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, priv.elements[0].data, priv.elements[0].length); ++ attr->ulValueLen = priv.elements[0].length; ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11gost_destroy(key); ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++} ++ ++static dst_func_t pkcs11gost_functions = { ++ pkcs11gost_createctx, ++ NULL, /*%< createctx2 */ ++ pkcs11gost_destroyctx, ++ pkcs11gost_adddata, ++ pkcs11gost_sign, ++ pkcs11gost_verify, ++ NULL, /*%< verify2 */ ++ NULL, /*%< computesecret */ ++ pkcs11gost_compare, ++ NULL, /*%< paramcompare */ ++ pkcs11gost_generate, ++ pkcs11gost_isprivate, ++ pkcs11gost_destroy, ++ pkcs11gost_todns, ++ pkcs11gost_fromdns, ++ pkcs11gost_tofile, ++ pkcs11gost_parse, ++ NULL, /*%< cleanup */ ++ NULL, /*%< fromlabel */ ++ NULL, /*%< dump */ ++ NULL, /*%< restore */ ++}; ++ ++isc_result_t ++dst__pkcs11gost_init(dst_func_t **funcp) { ++ REQUIRE(funcp != NULL); ++ if (*funcp == NULL) ++ *funcp = &pkcs11gost_functions; ++ return (ISC_R_SUCCESS); ++} ++ ++#else /* PKCS11CRYPTO && HAVE_PKCS11_GOST */ ++ ++#include <isc/util.h> ++ ++EMPTY_TRANSLATION_UNIT ++ ++#endif /* PKCS11CRYPTO && HAVE_PKCS11_GOST */ ++/*! \file */ +diff --git a/lib/dns/pkcs11rsa_link.c b/lib/dns/pkcs11rsa_link.c +new file mode 100644 +index 0000000..010d4b6 +--- /dev/null ++++ b/lib/dns/pkcs11rsa_link.c +@@ -0,0 +1,1583 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#ifdef PKCS11CRYPTO ++ ++#include <config.h> ++ ++#include <isc/entropy.h> ++#include <isc/md5.h> ++#include <isc/sha1.h> ++#include <isc/sha2.h> ++#include <isc/mem.h> ++#include <isc/string.h> ++#include <isc/util.h> ++ ++#include <dst/result.h> ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include <pk11/internal.h> ++ ++/* ++ * Limit the size of public exponents. ++ */ ++#ifndef RSA_MAX_PUBEXP_BITS ++#define RSA_MAX_PUBEXP_BITS 35 ++#endif ++ ++#define DST_RET(a) {ret = a; goto err;} ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++static isc_result_t pkcs11rsa_todns(const dst_key_t *key, isc_buffer_t *data); ++static void pkcs11rsa_destroy(dst_key_t *key); ++static isc_result_t pkcs11rsa_fetch(dst_key_t *key, const char *engine, ++ const char *label, dst_key_t *pub); ++ ++static isc_result_t ++pkcs11rsa_createctx_sign(dst_key_t *key, dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { 0, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_RSA; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS, NULL, 0 }, ++ { CKA_PUBLIC_EXPONENT, NULL, 0 }, ++ { CKA_PRIVATE_EXPONENT, NULL, 0 }, ++ { CKA_PRIME_1, NULL, 0 }, ++ { CKA_PRIME_2, NULL, 0 }, ++ { CKA_EXPONENT_1, NULL, 0 }, ++ { CKA_EXPONENT_2, NULL, 0 }, ++ { CKA_COEFFICIENT, NULL, 0 } ++ }; ++ CK_ATTRIBUTE *attr; ++ CK_SLOT_ID slotid; ++ pk11_object_t *rsa; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ REQUIRE(key->key_alg == DST_ALG_RSAMD5 || ++ key->key_alg == DST_ALG_RSASHA1 || ++ key->key_alg == DST_ALG_NSEC3RSASHA1 || ++ key->key_alg == DST_ALG_RSASHA256 || ++ key->key_alg == DST_ALG_RSASHA512); ++ ++ rsa = key->keydata.pkey; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ if (rsa->ontoken) ++ slotid = rsa->slot; ++ else ++ slotid = pk11_get_best_token(OP_RSA); ++ ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, ++ rsa->reqlogon, NULL, slotid); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ if (rsa->ontoken && (rsa->object != CK_INVALID_HANDLE)) { ++ pk11_ctx->ontoken = rsa->ontoken; ++ pk11_ctx->object = rsa->object; ++ goto token_key; ++ } ++ ++ for (attr = pk11_attribute_first(rsa); ++ attr != NULL; ++ attr = pk11_attribute_next(rsa, attr)) ++ switch (attr->type) { ++ case CKA_MODULUS: ++ INSIST(keyTemplate[6].type == attr->type); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_PUBLIC_EXPONENT: ++ INSIST(keyTemplate[7].type == attr->type); ++ keyTemplate[7].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[7].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[7].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[7].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_PRIVATE_EXPONENT: ++ INSIST(keyTemplate[8].type == attr->type); ++ keyTemplate[8].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[8].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[8].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[8].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_PRIME_1: ++ INSIST(keyTemplate[9].type == attr->type); ++ keyTemplate[9].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[9].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[9].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[9].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_PRIME_2: ++ INSIST(keyTemplate[10].type == attr->type); ++ keyTemplate[10].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[10].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[10].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[10].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_EXPONENT_1: ++ INSIST(keyTemplate[11].type == attr->type); ++ keyTemplate[11].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[11].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[11].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[11].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_EXPONENT_2: ++ INSIST(keyTemplate[12].type == attr->type); ++ keyTemplate[12].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[12].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[12].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[12].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_COEFFICIENT: ++ INSIST(keyTemplate[13].type == attr->type); ++ keyTemplate[13].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[13].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[13].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[13].ulValueLen = attr->ulValueLen; ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 14, ++ &pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ token_key: ++ ++ switch (dctx->key->key_alg) { ++ case DST_ALG_RSAMD5: ++ mech.mechanism = CKM_MD5_RSA_PKCS; ++ break; ++ case DST_ALG_RSASHA1: ++ case DST_ALG_NSEC3RSASHA1: ++ mech.mechanism = CKM_SHA1_RSA_PKCS; ++ break; ++ case DST_ALG_RSASHA256: ++ mech.mechanism = CKM_SHA256_RSA_PKCS; ++ break; ++ case DST_ALG_RSASHA512: ++ mech.mechanism = CKM_SHA512_RSA_PKCS; ++ break; ++ default: ++ INSIST(0); ++ } ++ ++ PK11_RET(pkcs_C_SignInit, ++ (pk11_ctx->session, &mech, pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ ++ for (i = 6; i <= 13; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, ++ pk11_ctx->object); ++ for (i = 6; i <= 13; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11rsa_createctx_verify(dst_key_t *key, unsigned int maxbits, ++ dst_context_t *dctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { 0, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_RSA; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS, NULL, 0 }, ++ { CKA_PUBLIC_EXPONENT, NULL, 0 }, ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *rsa; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ REQUIRE(key->key_alg == DST_ALG_RSAMD5 || ++ key->key_alg == DST_ALG_RSASHA1 || ++ key->key_alg == DST_ALG_NSEC3RSASHA1 || ++ key->key_alg == DST_ALG_RSASHA256 || ++ key->key_alg == DST_ALG_RSASHA512); ++ ++ rsa = key->keydata.pkey; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(dctx->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, ++ rsa->reqlogon, NULL, ++ pk11_get_best_token(OP_RSA)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ for (attr = pk11_attribute_first(rsa); ++ attr != NULL; ++ attr = pk11_attribute_next(rsa, attr)) ++ switch (attr->type) { ++ case CKA_MODULUS: ++ INSIST(keyTemplate[5].type == attr->type); ++ keyTemplate[5].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[5].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[5].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[5].ulValueLen = attr->ulValueLen; ++ break; ++ case CKA_PUBLIC_EXPONENT: ++ INSIST(keyTemplate[6].type == attr->type); ++ keyTemplate[6].pValue = isc_mem_get(dctx->mctx, ++ attr->ulValueLen); ++ if (keyTemplate[6].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(keyTemplate[6].pValue, ++ attr->pValue, ++ attr->ulValueLen); ++ keyTemplate[6].ulValueLen = attr->ulValueLen; ++ if (pk11_numbits(attr->pValue, ++ attr->ulValueLen) > maxbits && ++ maxbits != 0) ++ DST_RET(DST_R_VERIFYFAILURE); ++ break; ++ } ++ pk11_ctx->object = CK_INVALID_HANDLE; ++ pk11_ctx->ontoken = ISC_FALSE; ++ PK11_RET(pkcs_C_CreateObject, ++ (pk11_ctx->session, ++ keyTemplate, (CK_ULONG) 7, ++ &pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ switch (dctx->key->key_alg) { ++ case DST_ALG_RSAMD5: ++ mech.mechanism = CKM_MD5_RSA_PKCS; ++ break; ++ case DST_ALG_RSASHA1: ++ case DST_ALG_NSEC3RSASHA1: ++ mech.mechanism = CKM_SHA1_RSA_PKCS; ++ break; ++ case DST_ALG_RSASHA256: ++ mech.mechanism = CKM_SHA256_RSA_PKCS; ++ break; ++ case DST_ALG_RSASHA512: ++ mech.mechanism = CKM_SHA512_RSA_PKCS; ++ break; ++ default: ++ INSIST(0); ++ } ++ ++ PK11_RET(pkcs_C_VerifyInit, ++ (pk11_ctx->session, &mech, pk11_ctx->object), ++ ISC_R_FAILURE); ++ ++ dctx->ctxdata.pk11_ctx = pk11_ctx; ++ ++ for (i = 5; i <= 6; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (!pk11_ctx->ontoken && (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, ++ pk11_ctx->object); ++ for (i = 5; i <= 6; i++) ++ if (keyTemplate[i].pValue != NULL) { ++ memset(keyTemplate[i].pValue, 0, ++ keyTemplate[i].ulValueLen); ++ isc_mem_put(dctx->mctx, ++ keyTemplate[i].pValue, ++ keyTemplate[i].ulValueLen); ++ } ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11rsa_createctx(dst_key_t *key, dst_context_t *dctx) { ++ if (dctx->use == DO_SIGN) ++ return (pkcs11rsa_createctx_sign(key, dctx)); ++ else ++ return (pkcs11rsa_createctx_verify(key, 0U, dctx)); ++} ++ ++static isc_result_t ++pkcs11rsa_createctx2(dst_key_t *key, int maxbits, dst_context_t *dctx) { ++ if (dctx->use == DO_SIGN) ++ return (pkcs11rsa_createctx_sign(key, dctx)); ++ else ++ return (pkcs11rsa_createctx_verify(key, ++ (unsigned) maxbits, dctx)); ++} ++ ++static void ++pkcs11rsa_destroyctx(dst_context_t *dctx) { ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ ++ if (pk11_ctx != NULL) { ++ if (!pk11_ctx->ontoken && ++ (pk11_ctx->object != CK_INVALID_HANDLE)) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, ++ pk11_ctx->object); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(dctx->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ dctx->ctxdata.pk11_ctx = NULL; ++ } ++} ++ ++static isc_result_t ++pkcs11rsa_adddata(dst_context_t *dctx, const isc_region_t *data) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ if (dctx->use == DO_SIGN) ++ PK11_CALL(pkcs_C_SignUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ else ++ PK11_CALL(pkcs_C_VerifyUpdate, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) data->base, ++ (CK_ULONG) data->length), ++ ISC_R_FAILURE); ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11rsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { ++ CK_RV rv; ++ CK_ULONG siglen = 0; ++ isc_region_t r; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ PK11_RET(pkcs_C_SignFinal, ++ (pk11_ctx->session, NULL, &siglen), ++ DST_R_SIGNFAILURE); ++ ++ isc_buffer_availableregion(sig, &r); ++ ++ if (r.length < (unsigned int) siglen) ++ return (ISC_R_NOSPACE); ++ ++ PK11_RET(pkcs_C_SignFinal, ++ (pk11_ctx->session, (CK_BYTE_PTR) r.base, &siglen), ++ DST_R_SIGNFAILURE); ++ ++ isc_buffer_add(sig, (unsigned int) siglen); ++ ++ err: ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11rsa_verify(dst_context_t *dctx, const isc_region_t *sig) { ++ CK_RV rv; ++ pk11_context_t *pk11_ctx = dctx->ctxdata.pk11_ctx; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ PK11_CALL(pkcs_C_VerifyFinal, ++ (pk11_ctx->session, ++ (CK_BYTE_PTR) sig->base, ++ (CK_ULONG) sig->length), ++ DST_R_VERIFYFAILURE); ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11rsa_compare(const dst_key_t *key1, const dst_key_t *key2) { ++ pk11_object_t *rsa1, *rsa2; ++ CK_ATTRIBUTE *attr1, *attr2; ++ ++ rsa1 = key1->keydata.pkey; ++ rsa2 = key2->keydata.pkey; ++ ++ if ((rsa1 == NULL) && (rsa2 == NULL)) ++ return (ISC_TRUE); ++ else if ((rsa1 == NULL) || (rsa2 == NULL)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(rsa1, CKA_MODULUS); ++ attr2 = pk11_attribute_bytype(rsa2, CKA_MODULUS); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(rsa1, CKA_PUBLIC_EXPONENT); ++ attr2 = pk11_attribute_bytype(rsa2, CKA_PUBLIC_EXPONENT); ++ if ((attr1 == NULL) && (attr2 == NULL)) ++ return (ISC_TRUE); ++ else if ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen)) ++ return (ISC_FALSE); ++ ++ attr1 = pk11_attribute_bytype(rsa1, CKA_PRIVATE_EXPONENT); ++ attr2 = pk11_attribute_bytype(rsa2, CKA_PRIVATE_EXPONENT); ++ if (((attr1 != NULL) || (attr2 != NULL)) && ++ ((attr1 == NULL) || (attr2 == NULL) || ++ (attr1->ulValueLen != attr2->ulValueLen) || ++ memcmp(attr1->pValue, attr2->pValue, attr1->ulValueLen))) ++ return (ISC_FALSE); ++ ++ if (!rsa1->ontoken && !rsa2->ontoken) ++ return (ISC_TRUE); ++ else if (rsa1->ontoken || rsa2->ontoken || ++ (rsa1->object != rsa2->object)) ++ return (ISC_FALSE); ++ ++ return (ISC_TRUE); ++} ++ ++static isc_result_t ++pkcs11rsa_generate(dst_key_t *key, int exp, void (*callback)(int)) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_RSA_PKCS_KEY_PAIR_GEN, NULL, 0 }; ++ CK_OBJECT_HANDLE pub = CK_INVALID_HANDLE; ++ CK_ULONG bits = 0; ++ CK_BYTE pubexp[5]; ++ CK_OBJECT_CLASS pubClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_RSA; ++ CK_ATTRIBUTE pubTemplate[] = ++ { ++ { CKA_CLASS, &pubClass, (CK_ULONG) sizeof(pubClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_VERIFY, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_MODULUS_BITS, &bits, (CK_ULONG) sizeof(bits) }, ++ { CKA_PUBLIC_EXPONENT, &pubexp, (CK_ULONG) sizeof(pubexp) } ++ }; ++ CK_OBJECT_HANDLE priv = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS privClass = CKO_PRIVATE_KEY; ++ CK_ATTRIBUTE privTemplate[] = ++ { ++ { CKA_CLASS, &privClass, (CK_ULONG) sizeof(privClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SENSITIVE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_EXTRACTABLE, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ }; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *rsa; ++ pk11_context_t *pk11_ctx; ++ isc_result_t ret; ++ unsigned int i; ++ ++ UNUSED(callback); ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, pk11_get_best_token(OP_RSA)); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ bits = key->key_size; ++ if (exp == 0) { ++ /* RSA_F4 0x10001 */ ++ pubexp[0] = 1; ++ pubexp[1] = 0; ++ pubexp[2] = 1; ++ pubTemplate[6].ulValueLen = 3; ++ } else { ++ /* F5 0x100000001 */ ++ pubexp[0] = 1; ++ pubexp[1] = 0; ++ pubexp[2] = 0; ++ pubexp[3] = 0; ++ pubexp[4] = 1; ++ pubTemplate[6].ulValueLen = 5; ++ } ++ ++ PK11_RET(pkcs_C_GenerateKeyPair, ++ (pk11_ctx->session, &mech, ++ pubTemplate, (CK_ULONG) 7, ++ privTemplate, (CK_ULONG) 7, ++ &pub, &priv), ++ DST_R_CRYPTOFAILURE); ++ ++ rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa)); ++ if (rsa == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(rsa, 0, sizeof(*rsa)); ++ key->keydata.pkey = rsa; ++ rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 8); ++ if (rsa->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(rsa->repr, 0, sizeof(*attr) * 8); ++ rsa->attrcnt = 8; ++ ++ attr = rsa->repr; ++ attr[0].type = CKA_MODULUS; ++ attr[1].type = CKA_PUBLIC_EXPONENT; ++ attr[2].type = CKA_PRIVATE_EXPONENT; ++ attr[3].type = CKA_PRIME_1; ++ attr[4].type = CKA_PRIME_2; ++ attr[5].type = CKA_EXPONENT_1; ++ attr[6].type = CKA_EXPONENT_2; ++ attr[7].type = CKA_COEFFICIENT; ++ ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 2), ++ DST_R_CRYPTOFAILURE); ++ for (i = 0; i <= 1; i++) { ++ attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); ++ if (attr[i].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr[i].pValue, 0, attr[i].ulValueLen); ++ } ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, pub, attr, 2), ++ DST_R_CRYPTOFAILURE); ++ ++ attr += 2; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 6), ++ DST_R_CRYPTOFAILURE); ++ for (i = 0; i <= 5; i++) { ++ attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); ++ if (attr[i].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr[i].pValue, 0, attr[i].ulValueLen); ++ } ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, priv, attr, 6), ++ DST_R_CRYPTOFAILURE); ++ ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11rsa_destroy(key); ++ if (priv != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, priv); ++ if (pub != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(pk11_ctx->session, pub); ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ret); ++} ++ ++static isc_boolean_t ++pkcs11rsa_isprivate(const dst_key_t *key) { ++ pk11_object_t *rsa = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (rsa == NULL) ++ return (ISC_FALSE); ++ attr = pk11_attribute_bytype(rsa, CKA_PRIVATE_EXPONENT); ++ return (ISC_TF((attr != NULL) || rsa->ontoken)); ++} ++ ++static void ++pkcs11rsa_destroy(dst_key_t *key) { ++ pk11_object_t *rsa = key->keydata.pkey; ++ CK_ATTRIBUTE *attr; ++ ++ if (rsa == NULL) ++ return; ++ ++ INSIST((rsa->object == CK_INVALID_HANDLE) || rsa->ontoken); ++ ++ for (attr = pk11_attribute_first(rsa); ++ attr != NULL; ++ attr = pk11_attribute_next(rsa, attr)) ++ switch (attr->type) { ++ case CKA_LABEL: ++ case CKA_ID: ++ case CKA_MODULUS: ++ case CKA_PUBLIC_EXPONENT: ++ case CKA_PRIVATE_EXPONENT: ++ case CKA_PRIME_1: ++ case CKA_PRIME_2: ++ case CKA_EXPONENT_1: ++ case CKA_EXPONENT_2: ++ case CKA_COEFFICIENT: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (rsa->repr != NULL) { ++ memset(rsa->repr, 0, rsa->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ rsa->repr, ++ rsa->attrcnt * sizeof(*attr)); ++ } ++ memset(rsa, 0, sizeof(*rsa)); ++ isc_mem_put(key->mctx, rsa, sizeof(*rsa)); ++ key->keydata.pkey = NULL; ++} ++ ++static isc_result_t ++pkcs11rsa_todns(const dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *rsa; ++ CK_ATTRIBUTE *attr; ++ isc_region_t r; ++ unsigned int e_bytes = 0, mod_bytes = 0; ++ CK_BYTE *exponent = NULL, *modulus = NULL; ++ ++ REQUIRE(key->keydata.pkey != NULL); ++ ++ rsa = key->keydata.pkey; ++ ++ for (attr = pk11_attribute_first(rsa); ++ attr != NULL; ++ attr = pk11_attribute_next(rsa, attr)) ++ switch (attr->type) { ++ case CKA_PUBLIC_EXPONENT: ++ exponent = (CK_BYTE *) attr->pValue; ++ e_bytes = (unsigned int) attr->ulValueLen; ++ break; ++ case CKA_MODULUS: ++ modulus = (CK_BYTE *) attr->pValue; ++ mod_bytes = (unsigned int) attr->ulValueLen; ++ break; ++ } ++ REQUIRE((exponent != NULL) && (modulus != NULL)); ++ ++ isc_buffer_availableregion(data, &r); ++ ++ if (e_bytes < 256) { /*%< key exponent is <= 2040 bits */ ++ if (r.length < 1) ++ return (ISC_R_NOSPACE); ++ isc_buffer_putuint8(data, (isc_uint8_t) e_bytes); ++ isc_region_consume(&r, 1); ++ } else { ++ if (r.length < 3) ++ return (ISC_R_NOSPACE); ++ isc_buffer_putuint8(data, 0); ++ isc_buffer_putuint16(data, (isc_uint16_t) e_bytes); ++ isc_region_consume(&r, 3); ++ } ++ ++ if (r.length < e_bytes + mod_bytes) ++ return (ISC_R_NOSPACE); ++ ++ memcpy(r.base, exponent, e_bytes); ++ isc_region_consume(&r, e_bytes); ++ memcpy(r.base, modulus, mod_bytes); ++ ++ isc_buffer_add(data, e_bytes + mod_bytes); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++pkcs11rsa_fromdns(dst_key_t *key, isc_buffer_t *data) { ++ pk11_object_t *rsa; ++ isc_region_t r; ++ unsigned int e_bytes, mod_bytes; ++ CK_BYTE *exponent = NULL, *modulus = NULL; ++ CK_ATTRIBUTE *attr; ++ ++ isc_buffer_remainingregion(data, &r); ++ if (r.length == 0) ++ return (ISC_R_SUCCESS); ++ ++ rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa)); ++ if (rsa == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(rsa, 0, sizeof(*rsa)); ++ ++ if (r.length < 1) { ++ memset(rsa, 0, sizeof(*rsa)); ++ isc_mem_put(key->mctx, rsa, sizeof(*rsa)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ e_bytes = *r.base++; ++ r.length--; ++ ++ if (e_bytes == 0) { ++ if (r.length < 2) { ++ memset(rsa, 0, sizeof(*rsa)); ++ isc_mem_put(key->mctx, rsa, sizeof(*rsa)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ e_bytes = ((*r.base++) << 8); ++ e_bytes += *r.base++; ++ r.length -= 2; ++ } ++ ++ if (r.length < e_bytes) { ++ memset(rsa, 0, sizeof(*rsa)); ++ isc_mem_put(key->mctx, rsa, sizeof(*rsa)); ++ return (DST_R_INVALIDPUBLICKEY); ++ } ++ exponent = r.base; ++ r.base += e_bytes; ++ r.length -= e_bytes; ++ modulus = r.base; ++ mod_bytes = r.length; ++ ++ key->key_size = pk11_numbits(modulus, mod_bytes); ++ ++ isc_buffer_forward(data, r.length); ++ ++ rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); ++ if (rsa->repr == NULL) ++ goto nomemory; ++ memset(rsa->repr, 0, sizeof(*attr) * 2); ++ rsa->attrcnt = 2; ++ attr = rsa->repr; ++ attr[0].type = CKA_MODULUS; ++ attr[0].pValue = isc_mem_get(key->mctx, mod_bytes); ++ if (attr[0].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[0].pValue, modulus, mod_bytes); ++ attr[0].ulValueLen = (CK_ULONG) mod_bytes; ++ attr[1].type = CKA_PUBLIC_EXPONENT; ++ attr[1].pValue = isc_mem_get(key->mctx, e_bytes); ++ if (attr[1].pValue == NULL) ++ goto nomemory; ++ memcpy(attr[1].pValue, exponent, e_bytes); ++ attr[1].ulValueLen = (CK_ULONG) e_bytes; ++ ++ key->keydata.pkey = rsa; ++ ++ return (ISC_R_SUCCESS); ++ ++ nomemory: ++ for (attr = pk11_attribute_first(rsa); ++ attr != NULL; ++ attr = pk11_attribute_next(rsa, attr)) ++ switch (attr->type) { ++ case CKA_MODULUS: ++ case CKA_PUBLIC_EXPONENT: ++ if (attr->pValue != NULL) { ++ memset(attr->pValue, 0, attr->ulValueLen); ++ isc_mem_put(key->mctx, ++ attr->pValue, ++ attr->ulValueLen); ++ } ++ break; ++ } ++ if (rsa->repr != NULL) { ++ memset(rsa->repr, 0, rsa->attrcnt * sizeof(*attr)); ++ isc_mem_put(key->mctx, ++ rsa->repr, ++ rsa->attrcnt * sizeof(*attr)); ++ } ++ memset(rsa, 0, sizeof(*rsa)); ++ isc_mem_put(key->mctx, rsa, sizeof(*rsa)); ++ return (ISC_R_NOMEMORY); ++} ++ ++static isc_result_t ++pkcs11rsa_tofile(const dst_key_t *key, const char *directory) { ++ int i; ++ pk11_object_t *rsa; ++ CK_ATTRIBUTE *attr; ++ CK_ATTRIBUTE *modulus = NULL, *exponent = NULL; ++ CK_ATTRIBUTE *d = NULL, *p = NULL, *q = NULL; ++ CK_ATTRIBUTE *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; ++ dst_private_t priv; ++ unsigned char *bufs[10]; ++ isc_result_t result; ++ ++ if (key->keydata.pkey == NULL) ++ return (DST_R_NULLKEY); ++ ++ if (key->external) { ++ priv.nelements = 0; ++ return (dst__privstruct_writefile(key, &priv, directory)); ++ } ++ ++ rsa = key->keydata.pkey; ++ ++ for (attr = pk11_attribute_first(rsa); ++ attr != NULL; ++ attr = pk11_attribute_next(rsa, attr)) ++ switch (attr->type) { ++ case CKA_MODULUS: ++ modulus = attr; ++ break; ++ case CKA_PUBLIC_EXPONENT: ++ exponent = attr; ++ break; ++ case CKA_PRIVATE_EXPONENT: ++ d = attr; ++ break; ++ case CKA_PRIME_1: ++ p = attr; ++ break; ++ case CKA_PRIME_2: ++ q = attr; ++ break; ++ case CKA_EXPONENT_1: ++ dmp1 = attr; ++ break; ++ case CKA_EXPONENT_2: ++ dmq1 = attr; ++ break; ++ case CKA_COEFFICIENT: ++ iqmp = attr; ++ break; ++ } ++ if ((modulus == NULL) || (exponent == NULL)) ++ return (DST_R_NULLKEY); ++ ++ memset(bufs, 0, sizeof(bufs)); ++ ++ for (i = 0; i < 10; i++) { ++ bufs[i] = isc_mem_get(key->mctx, modulus->ulValueLen); ++ if (bufs[i] == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto fail; ++ } ++ memset(bufs[i], 0, modulus->ulValueLen); ++ } ++ ++ i = 0; ++ ++ priv.elements[i].tag = TAG_RSA_MODULUS; ++ priv.elements[i].length = (unsigned short) modulus->ulValueLen; ++ memcpy(bufs[i], modulus->pValue, modulus->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ ++ priv.elements[i].tag = TAG_RSA_PUBLICEXPONENT; ++ priv.elements[i].length = (unsigned short) exponent->ulValueLen; ++ memcpy(bufs[i], exponent->pValue, exponent->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ ++ if (d != NULL) { ++ priv.elements[i].tag = TAG_RSA_PRIVATEEXPONENT; ++ priv.elements[i].length = (unsigned short) d->ulValueLen; ++ memcpy(bufs[i], d->pValue, d->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ } ++ ++ if (p != NULL) { ++ priv.elements[i].tag = TAG_RSA_PRIME1; ++ priv.elements[i].length = (unsigned short) p->ulValueLen; ++ memcpy(bufs[i], p->pValue, p->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ } ++ ++ if (q != NULL) { ++ priv.elements[i].tag = TAG_RSA_PRIME2; ++ priv.elements[i].length = (unsigned short) q->ulValueLen; ++ memcpy(bufs[i], q->pValue, q->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ } ++ ++ if (dmp1 != NULL) { ++ priv.elements[i].tag = TAG_RSA_EXPONENT1; ++ priv.elements[i].length = (unsigned short) dmp1->ulValueLen; ++ memcpy(bufs[i], dmp1->pValue, dmp1->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ } ++ ++ if (dmq1 != NULL) { ++ priv.elements[i].tag = TAG_RSA_EXPONENT2; ++ priv.elements[i].length = (unsigned short) dmq1->ulValueLen; ++ memcpy(bufs[i], dmq1->pValue, dmq1->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ } ++ ++ if (iqmp != NULL) { ++ priv.elements[i].tag = TAG_RSA_COEFFICIENT; ++ priv.elements[i].length = (unsigned short) iqmp->ulValueLen; ++ memcpy(bufs[i], iqmp->pValue, iqmp->ulValueLen); ++ priv.elements[i].data = bufs[i]; ++ i++; ++ } ++ ++ if (key->engine != NULL) { ++ priv.elements[i].tag = TAG_RSA_ENGINE; ++ priv.elements[i].length = strlen(key->engine) + 1; ++ priv.elements[i].data = (unsigned char *)key->engine; ++ i++; ++ } ++ ++ if (key->label != NULL) { ++ priv.elements[i].tag = TAG_RSA_LABEL; ++ priv.elements[i].length = strlen(key->label) + 1; ++ priv.elements[i].data = (unsigned char *)key->label; ++ i++; ++ } ++ ++ priv.nelements = i; ++ result = dst__privstruct_writefile(key, &priv, directory); ++ fail: ++ for (i = 0; i < 10; i++) { ++ if (bufs[i] == NULL) ++ break; ++ memset(bufs[i], 0, modulus->ulValueLen); ++ isc_mem_put(key->mctx, bufs[i], modulus->ulValueLen); ++ } ++ return (result); ++} ++ ++static isc_result_t ++pkcs11rsa_fetch(dst_key_t *key, const char *engine, const char *label, ++ dst_key_t *pub) ++{ ++ CK_RV rv; ++ CK_OBJECT_CLASS keyClass = CKO_PRIVATE_KEY; ++ CK_KEY_TYPE keyType = CKK_RSA; ++ CK_ATTRIBUTE searchTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_LABEL, NULL, 0 } ++ }; ++ CK_ULONG cnt; ++ CK_ATTRIBUTE *attr; ++ CK_ATTRIBUTE *pubattr; ++ pk11_object_t *rsa; ++ pk11_object_t *pubrsa; ++ pk11_context_t *pk11_ctx = NULL; ++ isc_result_t ret; ++ ++ if (label == NULL) ++ return (DST_R_NOENGINE); ++ ++ rsa = key->keydata.pkey; ++ pubrsa = pub->keydata.pkey; ++ ++ rsa->object = CK_INVALID_HANDLE; ++ rsa->ontoken = ISC_TRUE; ++ rsa->reqlogon = ISC_TRUE; ++ rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); ++ if (rsa->repr == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(rsa->repr, 0, sizeof(*attr) * 2); ++ rsa->attrcnt = 2; ++ attr = rsa->repr; ++ ++ attr->type = CKA_MODULUS; ++ pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS); ++ attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen); ++ attr->ulValueLen = pubattr->ulValueLen; ++ attr++; ++ ++ attr->type = CKA_PUBLIC_EXPONENT; ++ pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT); ++ attr->pValue = isc_mem_get(key->mctx, pubattr->ulValueLen); ++ if (attr->pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(attr->pValue, pubattr->pValue, pubattr->ulValueLen); ++ attr->ulValueLen = pubattr->ulValueLen; ++ ++ ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, ++ rsa->reqlogon, NULL, rsa->slot); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ attr = pk11_attribute_bytype(rsa, CKA_LABEL); ++ if (attr == NULL) { ++ attr = pk11_attribute_bytype(rsa, CKA_ID); ++ INSIST(attr != NULL); ++ searchTemplate[3].type = CKA_ID; ++ } ++ searchTemplate[3].pValue = attr->pValue; ++ searchTemplate[3].ulValueLen = attr->ulValueLen; ++ ++ PK11_RET(pkcs_C_FindObjectsInit, ++ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_FindObjects, ++ (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt), ++ DST_R_CRYPTOFAILURE); ++ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); ++ if (cnt == 0) ++ DST_RET(ISC_R_NOTFOUND); ++ if (cnt > 1) ++ DST_RET(ISC_R_EXISTS); ++ ++ if (engine != NULL) { ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ if (key->engine == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ } ++ ++ key->label = isc_mem_strdup(key->mctx, label); ++ if (key->label == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ attr = pk11_attribute_bytype(rsa, CKA_MODULUS); ++ INSIST(attr != NULL); ++ key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ if (pk11_ctx != NULL) { ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ } ++ ++ return (ret); ++} ++ ++static isc_result_t ++rsa_check(pk11_object_t *rsa, pk11_object_t *pubrsa) { ++ CK_ATTRIBUTE *pubattr, *privattr; ++ CK_BYTE *priv_exp = NULL, *priv_mod = NULL; ++ CK_BYTE *pub_exp = NULL, *pub_mod = NULL; ++ unsigned int priv_explen = 0, priv_modlen = 0; ++ unsigned int pub_explen = 0, pub_modlen = 0; ++ ++ REQUIRE(rsa != NULL && pubrsa != NULL); ++ ++ privattr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); ++ INSIST(privattr != NULL); ++ priv_exp = privattr->pValue; ++ priv_explen = privattr->ulValueLen; ++ ++ pubattr = pk11_attribute_bytype(pubrsa, CKA_PUBLIC_EXPONENT); ++ INSIST(pubattr != NULL); ++ pub_exp = pubattr->pValue; ++ pub_explen = pubattr->ulValueLen; ++ ++ if (priv_exp != NULL) { ++ if (priv_explen != pub_explen) ++ return (DST_R_INVALIDPRIVATEKEY); ++ if (memcmp(priv_exp, pub_exp, pub_explen) != 0) ++ return (DST_R_INVALIDPRIVATEKEY); ++ } else { ++ privattr->pValue = pub_exp; ++ privattr->ulValueLen = pub_explen; ++ pubattr->pValue = NULL; ++ pubattr->ulValueLen = 0; ++ } ++ ++ if (privattr->pValue == NULL) ++ return (DST_R_INVALIDPRIVATEKEY); ++ ++ privattr = pk11_attribute_bytype(rsa, CKA_MODULUS); ++ INSIST(privattr != NULL); ++ priv_mod = privattr->pValue; ++ priv_modlen = privattr->ulValueLen; ++ ++ pubattr = pk11_attribute_bytype(pubrsa, CKA_MODULUS); ++ INSIST(pubattr != NULL); ++ pub_mod = pubattr->pValue; ++ pub_modlen = pubattr->ulValueLen; ++ ++ if (priv_mod != NULL) { ++ if (priv_modlen != pub_modlen) ++ return (DST_R_INVALIDPRIVATEKEY); ++ if (memcmp(priv_mod, pub_mod, pub_modlen) != 0) ++ return (DST_R_INVALIDPRIVATEKEY); ++ } else { ++ privattr->pValue = pub_mod; ++ privattr->ulValueLen = pub_modlen; ++ pubattr->pValue = NULL; ++ pubattr->ulValueLen = 0; ++ } ++ ++ if (privattr->pValue == NULL) ++ return (DST_R_INVALIDPRIVATEKEY); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++pkcs11rsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { ++ dst_private_t priv; ++ isc_result_t ret; ++ int i; ++ pk11_object_t *rsa; ++ CK_ATTRIBUTE *attr; ++ isc_mem_t *mctx = key->mctx; ++ const char *engine = NULL, *label = NULL; ++ ++ /* read private key file */ ++ ret = dst__privstruct_parse(key, DST_ALG_RSA, lexer, mctx, &priv); ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ if (key->external) { ++ if (priv.nelements != 0) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ if (pub == NULL) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ key->keydata.pkey = pub->keydata.pkey; ++ pub->keydata.pkey = NULL; ++ key->key_size = pub->key_size; ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ } ++ ++ for (i = 0; i < priv.nelements; i++) { ++ switch (priv.elements[i].tag) { ++ case TAG_RSA_ENGINE: ++ engine = (char *)priv.elements[i].data; ++ break; ++ case TAG_RSA_LABEL: ++ label = (char *)priv.elements[i].data; ++ break; ++ default: ++ break; ++ } ++ } ++ rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa)); ++ if (rsa == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(rsa, 0, sizeof(*rsa)); ++ key->keydata.pkey = rsa; ++ ++ /* Is this key is stored in a HSM? See if we can fetch it. */ ++ if ((label != NULL) || (engine != NULL)) { ++ ret = pkcs11rsa_fetch(key, engine, label, pub); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++ } ++ ++ rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 8); ++ if (rsa->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(rsa->repr, 0, sizeof(*attr) * 8); ++ rsa->attrcnt = 8; ++ attr = rsa->repr; ++ attr[0].type = CKA_MODULUS; ++ attr[1].type = CKA_PUBLIC_EXPONENT; ++ attr[2].type = CKA_PRIVATE_EXPONENT; ++ attr[3].type = CKA_PRIME_1; ++ attr[4].type = CKA_PRIME_2; ++ attr[5].type = CKA_EXPONENT_1; ++ attr[6].type = CKA_EXPONENT_2; ++ attr[7].type = CKA_COEFFICIENT; ++ ++ for (i = 0; i < priv.nelements; i++) { ++ CK_BYTE *bn; ++ ++ switch (priv.elements[i].tag) { ++ case TAG_RSA_ENGINE: ++ continue; ++ case TAG_RSA_LABEL: ++ continue; ++ default: ++ bn = isc_mem_get(key->mctx, priv.elements[i].length); ++ if (bn == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memcpy(bn, ++ priv.elements[i].data, ++ priv.elements[i].length); ++ } ++ ++ switch (priv.elements[i].tag) { ++ case TAG_RSA_MODULUS: ++ attr = pk11_attribute_bytype(rsa, CKA_MODULUS); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_PUBLICEXPONENT: ++ attr = pk11_attribute_bytype(rsa, ++ CKA_PUBLIC_EXPONENT); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_PRIVATEEXPONENT: ++ attr = pk11_attribute_bytype(rsa, ++ CKA_PRIVATE_EXPONENT); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_PRIME1: ++ attr = pk11_attribute_bytype(rsa, CKA_PRIME_1); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_PRIME2: ++ attr = pk11_attribute_bytype(rsa, CKA_PRIME_2); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_EXPONENT1: ++ attr = pk11_attribute_bytype(rsa, ++ CKA_EXPONENT_1); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_EXPONENT2: ++ attr = pk11_attribute_bytype(rsa, ++ CKA_EXPONENT_2); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ case TAG_RSA_COEFFICIENT: ++ attr = pk11_attribute_bytype(rsa, ++ CKA_COEFFICIENT); ++ INSIST(attr != NULL); ++ attr->pValue = bn; ++ attr->ulValueLen = priv.elements[i].length; ++ break; ++ } ++ } ++ ++ if (rsa_check(rsa, pub->keydata.pkey) != ISC_R_SUCCESS) ++ DST_RET(DST_R_INVALIDPRIVATEKEY); ++ ++ attr = pk11_attribute_bytype(rsa, CKA_MODULUS); ++ INSIST(attr != NULL); ++ key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); ++ INSIST(attr != NULL); ++ if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) ++ DST_RET(ISC_R_RANGE); ++ ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11rsa_destroy(key); ++ dst__privstruct_free(&priv, mctx); ++ memset(&priv, 0, sizeof(priv)); ++ return (ret); ++} ++ ++static isc_result_t ++pkcs11rsa_fromlabel(dst_key_t *key, const char *engine, const char *label, ++ const char *pin) ++{ ++ CK_RV rv; ++ CK_OBJECT_HANDLE hKey = CK_INVALID_HANDLE; ++ CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; ++ CK_KEY_TYPE keyType = CKK_RSA; ++ CK_ATTRIBUTE searchTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_LABEL, NULL, 0 } ++ }; ++ CK_ULONG cnt; ++ CK_ATTRIBUTE *attr; ++ pk11_object_t *rsa; ++ pk11_context_t *pk11_ctx = NULL; ++ isc_result_t ret; ++ unsigned int i; ++ ++ UNUSED(pin); ++ ++ rsa = (pk11_object_t *) isc_mem_get(key->mctx, sizeof(*rsa)); ++ if (rsa == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(rsa, 0, sizeof(*rsa)); ++ rsa->object = CK_INVALID_HANDLE; ++ rsa->ontoken = ISC_TRUE; ++ rsa->reqlogon = ISC_TRUE; ++ key->keydata.pkey = rsa; ++ ++ rsa->repr = (CK_ATTRIBUTE *) isc_mem_get(key->mctx, sizeof(*attr) * 2); ++ if (rsa->repr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(rsa->repr, 0, sizeof(*attr) * 2); ++ rsa->attrcnt = 2; ++ attr = rsa->repr; ++ attr[0].type = CKA_MODULUS; ++ attr[1].type = CKA_PUBLIC_EXPONENT; ++ ++ ret = pk11_parse_uri(rsa, label, key->mctx, OP_RSA); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ pk11_ctx = (pk11_context_t *) isc_mem_get(key->mctx, ++ sizeof(*pk11_ctx)); ++ if (pk11_ctx == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ret = pk11_get_session(pk11_ctx, OP_RSA, ISC_TRUE, ISC_FALSE, ++ rsa->reqlogon, NULL, rsa->slot); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ ++ attr = pk11_attribute_bytype(rsa, CKA_LABEL); ++ if (attr == NULL) { ++ attr = pk11_attribute_bytype(rsa, CKA_ID); ++ INSIST(attr != NULL); ++ searchTemplate[3].type = CKA_ID; ++ } ++ searchTemplate[3].pValue = attr->pValue; ++ searchTemplate[3].ulValueLen = attr->ulValueLen; ++ ++ PK11_RET(pkcs_C_FindObjectsInit, ++ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_FindObjects, ++ (pk11_ctx->session, &hKey, (CK_ULONG) 1, &cnt), ++ DST_R_CRYPTOFAILURE); ++ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); ++ if (cnt == 0) ++ DST_RET(ISC_R_NOTFOUND); ++ if (cnt > 1) ++ DST_RET(ISC_R_EXISTS); ++ ++ attr = rsa->repr; ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, hKey, attr, 2), ++ DST_R_CRYPTOFAILURE); ++ for (i = 0; i <= 1; i++) { ++ attr[i].pValue = isc_mem_get(key->mctx, attr[i].ulValueLen); ++ if (attr[i].pValue == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ memset(attr[i].pValue, 0, attr[i].ulValueLen); ++ } ++ PK11_RET(pkcs_C_GetAttributeValue, ++ (pk11_ctx->session, hKey, attr, 2), ++ DST_R_CRYPTOFAILURE); ++ ++ keyClass = CKO_PRIVATE_KEY; ++ PK11_RET(pkcs_C_FindObjectsInit, ++ (pk11_ctx->session, searchTemplate, (CK_ULONG) 4), ++ DST_R_CRYPTOFAILURE); ++ PK11_RET(pkcs_C_FindObjects, ++ (pk11_ctx->session, &rsa->object, (CK_ULONG) 1, &cnt), ++ DST_R_CRYPTOFAILURE); ++ (void) pkcs_C_FindObjectsFinal(pk11_ctx->session); ++ if (cnt == 0) ++ DST_RET(ISC_R_NOTFOUND); ++ if (cnt > 1) ++ DST_RET(ISC_R_EXISTS); ++ ++ if (engine != NULL) { ++ key->engine = isc_mem_strdup(key->mctx, engine); ++ if (key->engine == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ } ++ ++ key->label = isc_mem_strdup(key->mctx, label); ++ if (key->label == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ ++ attr = pk11_attribute_bytype(rsa, CKA_PUBLIC_EXPONENT); ++ INSIST(attr != NULL); ++ if (pk11_numbits(attr->pValue, attr->ulValueLen) > RSA_MAX_PUBEXP_BITS) ++ DST_RET(ISC_R_RANGE); ++ ++ attr = pk11_attribute_bytype(rsa, CKA_MODULUS); ++ INSIST(attr != NULL); ++ key->key_size = pk11_numbits(attr->pValue, attr->ulValueLen); ++ ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ ++ return (ISC_R_SUCCESS); ++ ++ err: ++ pkcs11rsa_destroy(key); ++ if (pk11_ctx != NULL) { ++ pk11_return_session(pk11_ctx); ++ memset(pk11_ctx, 0, sizeof(*pk11_ctx)); ++ isc_mem_put(key->mctx, pk11_ctx, sizeof(*pk11_ctx)); ++ } ++ ++ return (ret); ++} ++ ++static dst_func_t pkcs11rsa_functions = { ++ pkcs11rsa_createctx, ++ pkcs11rsa_createctx2, ++ pkcs11rsa_destroyctx, ++ pkcs11rsa_adddata, ++ pkcs11rsa_sign, ++ pkcs11rsa_verify, ++ NULL, /*%< verify2 */ ++ NULL, /*%< computesecret */ ++ pkcs11rsa_compare, ++ NULL, /*%< paramcompare */ ++ pkcs11rsa_generate, ++ pkcs11rsa_isprivate, ++ pkcs11rsa_destroy, ++ pkcs11rsa_todns, ++ pkcs11rsa_fromdns, ++ pkcs11rsa_tofile, ++ pkcs11rsa_parse, ++ NULL, /*%< cleanup */ ++ pkcs11rsa_fromlabel, ++ NULL, /*%< dump */ ++ NULL, /*%< restore */ ++}; ++ ++isc_result_t ++dst__pkcs11rsa_init(dst_func_t **funcp) { ++ REQUIRE(funcp != NULL); ++ ++ if (*funcp == NULL) ++ *funcp = &pkcs11rsa_functions; ++ return (ISC_R_SUCCESS); ++} ++ ++#else /* PKCS11CRYPTO */ ++ ++#include <isc/util.h> ++ ++EMPTY_TRANSLATION_UNIT ++ ++#endif /* PKCS11CRYPTO */ ++/*! \file */ +diff --git a/lib/dns/rdata/generic/dlv_32769.c b/lib/dns/rdata/generic/dlv_32769.c +index 5751ad8..732abdb 100644 +--- a/lib/dns/rdata/generic/dlv_32769.c ++++ b/lib/dns/rdata/generic/dlv_32769.c +@@ -28,6 +28,7 @@ + + #include <dns/ds.h> + ++#include "dst_gost.h" + + static inline isc_result_t + fromtext_dlv(ARGS_FROMTEXT) { +@@ -81,9 +82,11 @@ fromtext_dlv(ARGS_FROMTEXT) { + case DNS_DSDIGEST_SHA256: + length = ISC_SHA256_DIGESTLENGTH; + break; ++#ifdef ISC_GOST_DIGESTLENGTH + case DNS_DSDIGEST_GOST: + length = ISC_GOST_DIGESTLENGTH; + break; ++#endif + case DNS_DSDIGEST_SHA384: + length = ISC_SHA384_DIGESTLENGTH; + break; +@@ -168,8 +171,10 @@ fromwire_dlv(ARGS_FROMWIRE) { + sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || + (sr.base[3] == DNS_DSDIGEST_SHA256 && + sr.length < 4 + ISC_SHA256_DIGESTLENGTH) || ++#ifdef ISC_GOST_DIGESTLENGTH + (sr.base[3] == DNS_DSDIGEST_GOST && + sr.length < 4 + ISC_GOST_DIGESTLENGTH) || ++#endif + (sr.base[3] == DNS_DSDIGEST_SHA384 && + sr.length < 4 + ISC_SHA384_DIGESTLENGTH)) + return (ISC_R_UNEXPECTEDEND); +@@ -183,8 +188,10 @@ fromwire_dlv(ARGS_FROMWIRE) { + sr.length = 4 + ISC_SHA1_DIGESTLENGTH; + else if (sr.base[3] == DNS_DSDIGEST_SHA256) + sr.length = 4 + ISC_SHA256_DIGESTLENGTH; ++#ifdef ISC_GOST_DIGESTLENGTH + else if (sr.base[3] == DNS_DSDIGEST_GOST) + sr.length = 4 + ISC_GOST_DIGESTLENGTH; ++#endif + else if (sr.base[3] == DNS_DSDIGEST_SHA384) + sr.length = 4 + ISC_SHA384_DIGESTLENGTH; + +@@ -236,9 +243,11 @@ fromstruct_dlv(ARGS_FROMSTRUCT) { + case DNS_DSDIGEST_SHA256: + REQUIRE(dlv->length == ISC_SHA256_DIGESTLENGTH); + break; ++#ifdef ISC_GOST_DIGESTLENGTH + case DNS_DSDIGEST_GOST: + REQUIRE(dlv->length == ISC_GOST_DIGESTLENGTH); + break; ++#endif + case DNS_DSDIGEST_SHA384: + REQUIRE(dlv->length == ISC_SHA384_DIGESTLENGTH); + break; +diff --git a/lib/dns/rdata/generic/ds_43.c b/lib/dns/rdata/generic/ds_43.c +index dd47c8d..fc7f126 100644 +--- a/lib/dns/rdata/generic/ds_43.c ++++ b/lib/dns/rdata/generic/ds_43.c +@@ -30,6 +30,8 @@ + + #include <dns/ds.h> + ++#include "dst_gost.h" ++ + static inline isc_result_t + fromtext_ds(ARGS_FROMTEXT) { + isc_token_t token; +@@ -81,9 +83,11 @@ fromtext_ds(ARGS_FROMTEXT) { + case DNS_DSDIGEST_SHA256: + length = ISC_SHA256_DIGESTLENGTH; + break; ++#ifdef ISC_GOST_DIGESTLENGTH + case DNS_DSDIGEST_GOST: + length = ISC_GOST_DIGESTLENGTH; + break; ++#endif + case DNS_DSDIGEST_SHA384: + length = ISC_SHA384_DIGESTLENGTH; + break; +@@ -168,8 +172,10 @@ fromwire_ds(ARGS_FROMWIRE) { + sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || + (sr.base[3] == DNS_DSDIGEST_SHA256 && + sr.length < 4 + ISC_SHA256_DIGESTLENGTH) || ++#ifdef ISC_GOST_DIGESTLENGTH + (sr.base[3] == DNS_DSDIGEST_GOST && + sr.length < 4 + ISC_GOST_DIGESTLENGTH) || ++#endif + (sr.base[3] == DNS_DSDIGEST_SHA384 && + sr.length < 4 + ISC_SHA384_DIGESTLENGTH)) + return (ISC_R_UNEXPECTEDEND); +@@ -183,8 +189,10 @@ fromwire_ds(ARGS_FROMWIRE) { + sr.length = 4 + ISC_SHA1_DIGESTLENGTH; + else if (sr.base[3] == DNS_DSDIGEST_SHA256) + sr.length = 4 + ISC_SHA256_DIGESTLENGTH; ++#ifdef ISC_GOST_DIGESTLENGTH + else if (sr.base[3] == DNS_DSDIGEST_GOST) + sr.length = 4 + ISC_GOST_DIGESTLENGTH; ++#endif + else if (sr.base[3] == DNS_DSDIGEST_SHA384) + sr.length = 4 + ISC_SHA384_DIGESTLENGTH; + +@@ -236,9 +244,11 @@ fromstruct_ds(ARGS_FROMSTRUCT) { + case DNS_DSDIGEST_SHA256: + REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH); + break; ++#ifdef ISC_GOST_DIGESTLENGTH + case DNS_DSDIGEST_GOST: + REQUIRE(ds->length == ISC_GOST_DIGESTLENGTH); + break; ++#endif + case DNS_DSDIGEST_SHA384: + REQUIRE(ds->length == ISC_SHA384_DIGESTLENGTH); + break; +diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in +index db47476..3b19784 100644 +--- a/lib/dns/tests/Makefile.in ++++ b/lib/dns/tests/Makefile.in +@@ -26,8 +26,9 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} @DST_OPENSSL_INC@ +-CDEFINES = @USE_OPENSSL@ -DTESTS="\"${top_builddir}/lib/dns/tests/\"" ++CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} ${ISC_INCLUDES} \ ++ @DST_OPENSSL_INC@ ++CDEFINES = @CRYPTO@ -DTESTS="\"${top_builddir}/lib/dns/tests/\"" + + ISCLIBS = ../../isc/libisc.@A@ + ISCDEPLIBS = ../../isc/libisc.@A@ +@@ -37,13 +38,13 @@ DNSDEPLIBS = ../libdns.@A@ + LIBS = @LIBS@ @ATFLIBS@ + + OBJS = dnstest.@O@ +-SRCS = dnstest.c master_test.c dbiterator_test.c time_test.c \ ++SRCS = dnstest.c gost_test.c master_test.c dbiterator_test.c time_test.c \ + private_test.c update_test.c zonemgr_test.c zt_test.c \ + dbdiff_test.c dispatch_test.c nsec3_test.c \ + rdataset_test.c rdata_test.c + + SUBDIRS = +-TARGETS = master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \ ++TARGETS = gost_test@EXEEXT@ master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \ + private_test@EXEEXT@ update_test@EXEEXT@ zonemgr_test@EXEEXT@ \ + zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ \ + dispatch_test@EXEEXT@ nsec3_test@EXEEXT@ \ +@@ -123,6 +124,11 @@ dispatch_test@EXEEXT@: dispatch_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + dispatch_test.@O@ dnstest.@O@ ${DNSLIBS} \ + ${ISCLIBS} ${LIBS} + ++gost_test@EXEEXT@: gost_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ ++ gost_test.@O@ dnstest.@O@ ${DNSLIBS} \ ++ ${ISCLIBS} ${LIBS} ++ + unit:: + sh ${top_srcdir}/unit/unittest.sh + +diff --git a/lib/dns/tests/gost_test.c b/lib/dns/tests/gost_test.c +new file mode 100644 +index 0000000..0dd9e55 +--- /dev/null ++++ b/lib/dns/tests/gost_test.c +@@ -0,0 +1,232 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++/* ! \file */ ++ ++#include <config.h> ++ ++#include <atf-c.h> ++ ++#include <stdio.h> ++#include <string.h> ++ ++#include <isc/util.h> ++#include <isc/string.h> ++ ++#include "dnstest.h" ++ ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) ++ ++#include "../dst_gost.h" ++ ++/* ++ * Test data from Wikipedia GOST (hash function) ++ */ ++ ++unsigned char digest[ISC_GOST_DIGESTLENGTH]; ++unsigned char buffer[1024]; ++const char *s; ++char str[ISC_GOST_DIGESTLENGTH]; ++int i = 0; ++ ++isc_result_t ++tohexstr(unsigned char *d, unsigned int len, char *out); ++/* ++ * Precondition: a hexadecimal number in *d, the length of that number in len, ++ * and a pointer to a character array to put the output (*out). ++ * Postcondition: A String representation of the given hexadecimal number is ++ * placed into the array *out ++ * ++ * 'out' MUST point to an array of at least len / 2 + 1 ++ * ++ * Return values: ISC_R_SUCCESS if the operation is sucessful ++ */ ++ ++isc_result_t ++tohexstr(unsigned char *d, unsigned int len, char *out) { ++ ++ out[0]='\0'; ++ char c_ret[] = "AA"; ++ unsigned int i; ++ strcat(out, "0x"); ++ for (i = 0; i < len; i++) { ++ sprintf(c_ret, "%02X", d[i]); ++ strcat(out, c_ret); ++ } ++ strcat(out, "\0"); ++ return (ISC_R_SUCCESS); ++} ++ ++ ++#define TEST_INPUT(x) (x), sizeof(x)-1 ++ ++typedef struct hash_testcase { ++ const char *input; ++ size_t input_len; ++ const char *result; ++ int repeats; ++} hash_testcase_t; ++ ++ATF_TC(isc_gost); ++ATF_TC_HEAD(isc_gost, tc) { ++ atf_tc_set_md_var(tc, "descr", ++ "GOST R 34.11-94 examples from Wikipedia"); ++} ++ATF_TC_BODY(isc_gost, tc) { ++ isc_gost_t gost; ++ isc_result_t result; ++ ++ UNUSED(tc); ++ ++ /* ++ * These are the various test vectors. All of these are passed ++ * through the hash function and the results are compared to the ++ * result specified here. ++ */ ++ hash_testcase_t testcases[] = { ++ /* Test 1 */ ++ { ++ TEST_INPUT(""), ++ "0x981E5F3CA30C841487830F84FB433E1" ++ "3AC1101569B9C13584AC483234CD656C0", ++ 1 ++ }, ++ /* Test 2 */ ++ { ++ TEST_INPUT("a"), ++ "0xE74C52DD282183BF37AF0079C9F7805" ++ "5715A103F17E3133CEFF1AACF2F403011", ++ 1 ++ }, ++ /* Test 3 */ ++ { ++ TEST_INPUT("abc"), ++ "0xB285056DBF18D7392D7677369524DD1" ++ "4747459ED8143997E163B2986F92FD42C", ++ 1 ++ }, ++ /* Test 4 */ ++ { ++ TEST_INPUT("message digest"), ++ "0xBC6041DD2AA401EBFA6E9886734174F" ++ "EBDB4729AA972D60F549AC39B29721BA0", ++ 1 ++ }, ++ /* Test 5 */ ++ { ++ TEST_INPUT("The quick brown fox jumps " ++ "over the lazy dog"), ++ "0x9004294A361A508C586FE53D1F1B027" ++ "46765E71B765472786E4770D565830A76", ++ 1 ++ }, ++ /* Test 6 */ ++ { ++ TEST_INPUT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde" ++ "fghijklmnopqrstuvwxyz0123456789"), ++ "0x73B70A39497DE53A6E08C67B6D4DB85" ++ "3540F03E9389299D9B0156EF7E85D0F61", ++ 1 ++ }, ++ /* Test 7 */ ++ { ++ TEST_INPUT("1234567890123456789012345678901" ++ "2345678901234567890123456789012" ++ "345678901234567890"), ++ "0x6BC7B38989B28CF93AE8842BF9D7529" ++ "05910A7528A61E5BCE0782DE43E610C90", ++ 1 ++ }, ++ /* Test 8 */ ++ { ++ TEST_INPUT("This is message, length=32 bytes"), ++ "0x2CEFC2F7B7BDC514E18EA57FA74FF35" ++ "7E7FA17D652C75F69CB1BE7893EDE48EB", ++ 1 ++ }, ++ /* Test 9 */ ++ { ++ TEST_INPUT("Suppose the original message " ++ "has length = 50 bytes"), ++ "0xC3730C5CBCCACF915AC292676F21E8B" ++ "D4EF75331D9405E5F1A61DC3130A65011", ++ 1 ++ }, ++ /* Test 10 */ ++ { ++ TEST_INPUT("U") /* times 128 */, ++ "0x1C4AC7614691BBF427FA2316216BE8F" ++ "10D92EDFD37CD1027514C1008F649C4E8", ++ 128 ++ }, ++ /* Test 11 */ ++ { ++ TEST_INPUT("a") /* times 1000000 */, ++ "0x8693287AA62F9478F7CB312EC0866B6" ++ "C4E4A0F11160441E8F4FFCD2715DD554F", ++ 1000000 ++ }, ++ { NULL, 0, NULL, 1 } ++ }; ++ ++ result = dns_test_begin(NULL, ISC_FALSE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ hash_testcase_t *testcase = testcases; ++ ++ while (testcase->input != NULL && testcase->result != NULL) { ++ result = isc_gost_init(&gost); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ for(i = 0; i < testcase->repeats; i++) { ++ result = isc_gost_update(&gost, ++ (const isc_uint8_t *) testcase->input, ++ testcase->input_len); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ } ++ result = isc_gost_final(&gost, digest); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ tohexstr(digest, ISC_GOST_DIGESTLENGTH, str); ++ ATF_CHECK_STREQ(str, testcase->result); ++ ++ testcase++; ++ } ++ ++ dns_test_end(); ++} ++#else ++ATF_TC(untested); ++ATF_TC_HEAD(untested, tc) { ++ atf_tc_set_md_var(tc, "descr", "skipping gost test"); ++} ++ATF_TC_BODY(untested, tc) { ++ UNUSED(tc); ++ atf_tc_skip("GOST hash not available"); ++} ++#endif ++/* ++ * Main ++ */ ++ATF_TP_ADD_TCS(tp) { ++#if defined(HAVE_OPENSSL_GOST) || defined(HAVE_PKCS11_GOST) ++ ATF_TP_ADD_TC(tp, isc_gost); ++#else ++ ATF_TP_ADD_TC(tp, untested); ++#endif ++ return (atf_no_error()); ++} ++ +diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c +index 161c188..20c98e5 100644 +--- a/lib/dns/tkey.c ++++ b/lib/dns/tkey.c +@@ -45,8 +45,14 @@ + #include <dst/dst.h> + #include <dst/gssapi.h> + ++#include "dst_internal.h" ++ + #define TKEY_RANDOM_AMOUNT 16 + ++#ifdef PKCS11CRYPTO ++#include <pk11/pk11.h> ++#endif ++ + #define RETERR(x) do { \ + result = (x); \ + if (result != ISC_R_SUCCESS) \ +@@ -382,8 +388,8 @@ process_dhtkey(dns_message_t *msg, dns_name_t *signer, dns_name_t *name, + if (randomdata == NULL) + goto failure; + +- result = isc_entropy_getdata(tctx->ectx, randomdata, +- TKEY_RANDOM_AMOUNT, NULL, 0); ++ result = dst__entropy_getdata(randomdata, TKEY_RANDOM_AMOUNT, ++ ISC_FALSE); + if (result != ISC_R_SUCCESS) { + tkey_log("process_dhtkey: failed to obtain entropy: %s", + isc_result_totext(result)); +diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c +index c7768f4..3239bff 100644 +--- a/lib/dns/tsig.c ++++ b/lib/dns/tsig.c +@@ -946,8 +946,9 @@ dns_tsig_sign(dns_message_t *msg) { + isc_buffer_t headerbuf; + isc_uint16_t digestbits; + +- ret = dst_context_create2(key->key, mctx, +- DNS_LOGCATEGORY_DNSSEC, &ctx); ++ ret = dst_context_create3(key->key, mctx, ++ DNS_LOGCATEGORY_DNSSEC, ++ ISC_TRUE, &ctx); + if (ret != ISC_R_SUCCESS) + return (ret); + +@@ -1345,8 +1346,9 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + sig_r.base = tsig.signature; + sig_r.length = tsig.siglen; + +- ret = dst_context_create2(key, mctx, +- DNS_LOGCATEGORY_DNSSEC, &ctx); ++ ret = dst_context_create3(key, mctx, ++ DNS_LOGCATEGORY_DNSSEC, ++ ISC_FALSE, &ctx); + if (ret != ISC_R_SUCCESS) + return (ret); + +@@ -1577,9 +1579,9 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + key = tsigkey->key; + + if (msg->tsigctx == NULL) { +- ret = dst_context_create2(key, mctx, ++ ret = dst_context_create3(key, mctx, + DNS_LOGCATEGORY_DNSSEC, +- &msg->tsigctx); ++ ISC_FALSE, &msg->tsigctx); + if (ret != ISC_R_SUCCESS) + goto cleanup_querystruct; + +diff --git a/lib/export/dns/Makefile.in b/lib/export/dns/Makefile.in +index 1e4540f..e10bf59 100644 +--- a/lib/export/dns/Makefile.in ++++ b/lib/export/dns/Makefile.in +@@ -28,10 +28,10 @@ export_srcdir = @top_srcdir@/lib/export + + @BIND9_MAKE_INCLUDES@ + +-CINCLUDES = -I. -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \ ++CINCLUDES = -I. -I${top_srcdir}/lib/dns -Iinclude ${DNS_INCLUDES} -I${export_srcdir}/isc/include \ + ${ISC_INCLUDES} @DST_OPENSSL_INC@ @DST_GSSAPI_INC@ + +-CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_GSSAPI@ ++CDEFINES = -DUSE_MD5 @CRYPTO@ @USE_GSSAPI@ + + CWARNINGS = + +diff --git a/lib/export/isc/Makefile.in b/lib/export/isc/Makefile.in +index 62e5acd..a5f8bd0 100644 +--- a/lib/export/isc/Makefile.in ++++ b/lib/export/isc/Makefile.in +@@ -27,7 +27,7 @@ CINCLUDES = -I${srcdir}/unix/include \ + -I${srcdir}/@ISC_ARCH_DIR@/include \ + -I${export_srcdir}/isc/include -I${srcdir}/include \ + @ISC_OPENSSL_INC@ +-CDEFINES = @USE_OPENSSL@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \ ++CDEFINES = @CRYPTO@ -DUSE_APPIMPREGISTER -DUSE_MEMIMPREGISTER \ + -DUSE_SOCKETIMPREGISTER -DUSE_TASKIMPREGISTER \ + -DUSE_TIMERIMPREGISTER + CWARNINGS = +@@ -48,7 +48,8 @@ UNIXOBJS = @ISC_ISCIPV6_O@ \ + unix/file.@O@ \ + unix/fsaccess.@O@ \ + unix/stdio.@O@ \ +- unix/stdtime.@O@ unix/strerror.@O@ unix/time.@O@ ++ unix/stdtime.@O@ unix/strerror.@O@ unix/time.@O@ unix/entropy.@O@ \ ++ unix/keyboard.@O@ + + NLSOBJS = nls/msgcat.@O@ + +diff --git a/lib/export/isc/unix/Makefile.in b/lib/export/isc/unix/Makefile.in +index 1873202..a904615 100644 +--- a/lib/export/isc/unix/Makefile.in ++++ b/lib/export/isc/unix/Makefile.in +@@ -40,6 +40,8 @@ OBJS = @ISC_IPV6_O@ \ + file.@O@ fsaccess.@O@ \ + stdio.@O@ stdtime.@O@ strerror.@O@ \ + time.@O@ \ ++ entropy.@O@ \ ++ keyboard.@O@ \ + ${ISCDRIVEROBJS} + + # Alphabetically +@@ -51,6 +53,8 @@ SRCS = @ISC_IPV6_C@ \ + file.c fsaccess.c \ + stdio.c stdtime.c strerror.c \ + time.c \ ++ entropy.c \ ++ keyboard.c \ + ${ISCDRIVERSRCS} + + SUBDIRS = include +diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in +index eb718fd..df62ec9 100644 +--- a/lib/isc/Makefile.in ++++ b/lib/isc/Makefile.in +@@ -23,16 +23,20 @@ top_srcdir = @top_srcdir@ + + @LIBISC_API@ + ++@BIND9_MAKE_INCLUDES@ ++ ++PROVIDER = @PKCS11_PROVIDER@ ++ + CINCLUDES = -I${srcdir}/unix/include \ + -I${srcdir}/@ISC_THREAD_DIR@/include \ + -I${srcdir}/@ISC_ARCH_DIR@/include \ + -I./include \ +- -I${srcdir}/include @ISC_OPENSSL_INC@ +-CDEFINES = @USE_OPENSSL@ ++ -I${srcdir}/include @ISC_OPENSSL_INC@ ${DNS_INCLUDES} ++CDEFINES = @CRYPTO@ -DPK11_LIB_LOCATION=\"${PROVIDER}\" + CWARNINGS = + + # Alphabetically +-UNIXOBJS = @ISC_ISCIPV6_O@ \ ++UNIXOBJS = @ISC_ISCIPV6_O@ @ISC_ISCPK11_API_O@ \ + unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ \ + unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \ + unix/interfaceiter.@O@ unix/keyboard.@O@ unix/net.@O@ \ +@@ -50,7 +54,7 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ + win32/thread.@O@ win32/time.@O@ + + # Alphabetically +-OBJS = @ISC_EXTRA_OBJS@ \ ++OBJS = @ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \ + assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \ + bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \ + counter.@O@ error.@O@ event.@O@ \ +@@ -68,7 +72,7 @@ OBJS = @ISC_EXTRA_OBJS@ \ + SYMTBLOBJS = backtrace-emptytbl.@O@ + + # Alphabetically +-SRCS = @ISC_EXTRA_SRCS@ \ ++SRCS = @ISC_EXTRA_SRCS@ @ISC_PK11_C@ @ISC_PK11_RESULT_C@ \ + assertions.c backtrace.c base32.c base64.c bitstring.c \ + buffer.c bufferlist.c commandline.c counter.c \ + error.c event.c heap.c hex.c hmacmd5.c hmacsha.c \ +diff --git a/lib/isc/entropy.c b/lib/isc/entropy.c +index da9e81f..ae882d8 100644 +--- a/lib/isc/entropy.c ++++ b/lib/isc/entropy.c +@@ -46,6 +46,9 @@ + #include <isc/time.h> + #include <isc/util.h> + ++#ifdef PKCS11CRYPTO ++#include <pk11/pk11.h> ++#endif + + #define ENTROPY_MAGIC ISC_MAGIC('E', 'n', 't', 'e') + #define SOURCE_MAGIC ISC_MAGIC('E', 'n', 't', 's') +@@ -1236,6 +1239,11 @@ isc_entropy_usebestsource(isc_entropy_t *ectx, isc_entropysource_t **source, + use_keyboard == ISC_ENTROPY_KEYBOARDNO || + use_keyboard == ISC_ENTROPY_KEYBOARDMAYBE); + ++#ifdef PKCS11CRYPTO ++ if (randomfile != NULL) ++ pk11_rand_seed_fromfile(randomfile); ++#endif ++ + #ifdef PATH_RANDOMDEV + if (randomfile == NULL) { + randomfile = PATH_RANDOMDEV; +diff --git a/lib/isc/hmacmd5.c b/lib/isc/hmacmd5.c +index 4c4046d..79ec24a 100644 +--- a/lib/isc/hmacmd5.c ++++ b/lib/isc/hmacmd5.c +@@ -33,6 +33,11 @@ + #include <isc/types.h> + #include <isc/util.h> + ++#if PKCS11CRYPTO || PKCS11CRYPTOWITHHMAC ++#include <pk11/internal.h> ++#include <pk11/pk11.h> ++#endif ++ + #ifdef ISC_PLATFORM_OPENSSLHASH + + void +@@ -60,6 +65,167 @@ isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { + HMAC_CTX_cleanup(ctx); + } + ++#elif PKCS11CRYPTOWITHHMAC ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++void ++isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_MD5_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, (CK_ULONG) len } ++ }; ++ ++ DE_CONST(key, keyTemplate[5].pValue); ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ ctx->object = CK_INVALID_HANDLE; ++ PK11_FATALCHECK(pkcs_C_CreateObject, ++ (ctx->session, keyTemplate, ++ (CK_ULONG) 6, &ctx->object)); ++ INSIST(ctx->object != CK_INVALID_HANDLE); ++ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object)); ++} ++ ++void ++isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) { ++ CK_BYTE garbage[ISC_MD5_DIGESTLENGTH]; ++ CK_ULONG len = ISC_MD5_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_SignFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++void ++isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_SignUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { ++ CK_RV rv; ++ CK_ULONG len = ISC_MD5_DIGESTLENGTH; ++ ++ PK11_FATALCHECK(pkcs_C_SignFinal, ++ (ctx->session, (CK_BYTE_PTR) digest, &len)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++#elif PKCS11CRYPTO ++ ++#define PADLEN 64 ++#define IPAD 0x36 ++#define OPAD 0x5C ++ ++void ++isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_MD5, NULL, 0 }; ++ unsigned char ipad[PADLEN]; ++ unsigned int i; ++ ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ RUNTIME_CHECK((ctx->key = pk11_mem_get(PADLEN)) != NULL); ++ if (len > PADLEN) { ++ CK_BYTE_PTR kPart; ++ CK_ULONG kl; ++ ++ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech)); ++ DE_CONST(key, kPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, kPart, (CK_ULONG) len)); ++ kl = ISC_MD5_DIGESTLENGTH; ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (ctx->session, (CK_BYTE_PTR) ctx->key, &kl)); ++ } else ++ memcpy(ctx->key, key, len); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech)); ++ memset(ipad, IPAD, PADLEN); ++ for (i = 0; i < PADLEN; i++) ++ ipad[i] ^= ctx->key[i]; ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, ipad, (CK_ULONG) PADLEN)); ++} ++ ++void ++isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) { ++ if (ctx->key != NULL) ++ pk11_mem_put(ctx->key, PADLEN); ++ ctx->key = NULL; ++ isc_md5_invalidate(ctx); ++} ++ ++void ++isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_MD5, NULL, 0 }; ++ CK_ULONG len = ISC_MD5_DIGESTLENGTH; ++ CK_BYTE opad[PADLEN]; ++ unsigned int i; ++ ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (ctx->session, (CK_BYTE_PTR) digest, ++ (CK_ULONG_PTR) &len)); ++ memset(opad, OPAD, PADLEN); ++ for (i = 0; i < PADLEN; i++) ++ opad[i] ^= ctx->key[i]; ++ pk11_mem_put(ctx->key, PADLEN); ++ ctx->key = NULL; ++ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech)); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, opad, (CK_ULONG) PADLEN)); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, (CK_BYTE_PTR) digest, len)); ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (ctx->session, ++ (CK_BYTE_PTR) digest, ++ (CK_ULONG_PTR) &len)); ++ pk11_return_session(ctx); ++} ++ + #else + + #define PADLEN 64 +diff --git a/lib/isc/hmacsha.c b/lib/isc/hmacsha.c +index 3870963..9b79bc7 100644 +--- a/lib/isc/hmacsha.c ++++ b/lib/isc/hmacsha.c +@@ -34,6 +34,11 @@ + #include <isc/types.h> + #include <isc/util.h> + ++#if PKCS11CRYPTO ++#include <pk11/internal.h> ++#include <pk11/pk11.h> ++#endif ++ + #ifdef ISC_PLATFORM_OPENSSLHASH + + void +@@ -191,6 +196,376 @@ isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { + memset(newdigest, 0, sizeof(newdigest)); + } + ++#elif PKCS11CRYPTO ++ ++static CK_BBOOL truevalue = TRUE; ++static CK_BBOOL falsevalue = FALSE; ++ ++void ++isc_hmacsha1_init(isc_hmacsha1_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA_1_HMAC, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_SHA_1_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, (CK_ULONG) len } ++ }; ++ ++ DE_CONST(key, keyTemplate[5].pValue); ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ ctx->object = CK_INVALID_HANDLE; ++ PK11_FATALCHECK(pkcs_C_CreateObject, ++ (ctx->session, keyTemplate, ++ (CK_ULONG) 6, &ctx->object)); ++ INSIST(ctx->object != CK_INVALID_HANDLE); ++ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object)); ++} ++ ++void ++isc_hmacsha1_invalidate(isc_hmacsha1_t *ctx) { ++ CK_BYTE garbage[ISC_SHA1_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA1_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_SignFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++void ++isc_hmacsha1_update(isc_hmacsha1_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_SignUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacsha1_sign(isc_hmacsha1_t *ctx, unsigned char *digest, size_t len) { ++ CK_RV rv; ++ CK_BYTE newdigest[ISC_SHA1_DIGESTLENGTH]; ++ CK_ULONG psl = ISC_SHA1_DIGESTLENGTH; ++ ++ REQUIRE(len <= ISC_SHA1_DIGESTLENGTH); ++ ++ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++ memcpy(digest, newdigest, len); ++ memset(newdigest, 0, sizeof(newdigest)); ++} ++ ++void ++isc_hmacsha224_init(isc_hmacsha224_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA224_HMAC, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_SHA224_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, (CK_ULONG) len } ++ }; ++ ++ DE_CONST(key, keyTemplate[5].pValue); ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ ctx->object = CK_INVALID_HANDLE; ++ PK11_FATALCHECK(pkcs_C_CreateObject, ++ (ctx->session, keyTemplate, ++ (CK_ULONG) 6, &ctx->object)); ++ INSIST(ctx->object != CK_INVALID_HANDLE); ++ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object)); ++} ++ ++void ++isc_hmacsha224_invalidate(isc_hmacsha224_t *ctx) { ++ CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA224_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_SignFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++void ++isc_hmacsha224_update(isc_hmacsha224_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_SignUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacsha224_sign(isc_hmacsha224_t *ctx, unsigned char *digest, size_t len) { ++ CK_RV rv; ++ CK_BYTE newdigest[ISC_SHA224_DIGESTLENGTH]; ++ CK_ULONG psl = ISC_SHA224_DIGESTLENGTH; ++ ++ REQUIRE(len <= ISC_SHA224_DIGESTLENGTH); ++ ++ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++ memcpy(digest, newdigest, len); ++ memset(newdigest, 0, sizeof(newdigest)); ++} ++ ++void ++isc_hmacsha256_init(isc_hmacsha256_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA256_HMAC, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_SHA256_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, (CK_ULONG) len } ++ }; ++ ++ DE_CONST(key, keyTemplate[5].pValue); ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ ctx->object = CK_INVALID_HANDLE; ++ PK11_FATALCHECK(pkcs_C_CreateObject, ++ (ctx->session, keyTemplate, ++ (CK_ULONG) 6, &ctx->object)); ++ INSIST(ctx->object != CK_INVALID_HANDLE); ++ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object)); ++} ++ ++void ++isc_hmacsha256_invalidate(isc_hmacsha256_t *ctx) { ++ CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA256_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_SignFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++void ++isc_hmacsha256_update(isc_hmacsha256_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_SignUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacsha256_sign(isc_hmacsha256_t *ctx, unsigned char *digest, size_t len) { ++ CK_RV rv; ++ CK_BYTE newdigest[ISC_SHA256_DIGESTLENGTH]; ++ CK_ULONG psl = ISC_SHA256_DIGESTLENGTH; ++ ++ REQUIRE(len <= ISC_SHA256_DIGESTLENGTH); ++ ++ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++ memcpy(digest, newdigest, len); ++ memset(newdigest, 0, sizeof(newdigest)); ++} ++ ++void ++isc_hmacsha384_init(isc_hmacsha384_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA384_HMAC, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_SHA384_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, (CK_ULONG) len } ++ }; ++ ++ DE_CONST(key, keyTemplate[5].pValue); ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ ctx->object = CK_INVALID_HANDLE; ++ PK11_FATALCHECK(pkcs_C_CreateObject, ++ (ctx->session, keyTemplate, ++ (CK_ULONG) 6, &ctx->object)); ++ INSIST(ctx->object != CK_INVALID_HANDLE); ++ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object)); ++} ++ ++void ++isc_hmacsha384_invalidate(isc_hmacsha384_t *ctx) { ++ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA384_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_SignFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++void ++isc_hmacsha384_update(isc_hmacsha384_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_SignUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacsha384_sign(isc_hmacsha384_t *ctx, unsigned char *digest, size_t len) { ++ CK_RV rv; ++ CK_BYTE newdigest[ISC_SHA384_DIGESTLENGTH]; ++ CK_ULONG psl = ISC_SHA384_DIGESTLENGTH; ++ ++ REQUIRE(len <= ISC_SHA384_DIGESTLENGTH); ++ ++ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++ memcpy(digest, newdigest, len); ++ memset(newdigest, 0, sizeof(newdigest)); ++} ++ ++void ++isc_hmacsha512_init(isc_hmacsha512_t *ctx, const unsigned char *key, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA512_HMAC, NULL, 0 }; ++ CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; ++ CK_KEY_TYPE keyType = CKK_SHA512_HMAC; ++ CK_ATTRIBUTE keyTemplate[] = ++ { ++ { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) }, ++ { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) }, ++ { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) }, ++ { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) }, ++ { CKA_VALUE, NULL, (CK_ULONG) len } ++ }; ++ ++ DE_CONST(key, keyTemplate[5].pValue); ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ ctx->object = CK_INVALID_HANDLE; ++ PK11_FATALCHECK(pkcs_C_CreateObject, ++ (ctx->session, keyTemplate, ++ (CK_ULONG) 6, &ctx->object)); ++ INSIST(ctx->object != CK_INVALID_HANDLE); ++ PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object)); ++} ++ ++void ++isc_hmacsha512_invalidate(isc_hmacsha512_t *ctx) { ++ CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA512_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_SignFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++} ++ ++void ++isc_hmacsha512_update(isc_hmacsha512_t *ctx, const unsigned char *buf, ++ unsigned int len) ++{ ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_SignUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_hmacsha512_sign(isc_hmacsha512_t *ctx, unsigned char *digest, size_t len) { ++ CK_RV rv; ++ CK_BYTE newdigest[ISC_SHA512_DIGESTLENGTH]; ++ CK_ULONG psl = ISC_SHA512_DIGESTLENGTH; ++ ++ REQUIRE(len <= ISC_SHA512_DIGESTLENGTH); ++ ++ PK11_FATALCHECK(pkcs_C_SignFinal, (ctx->session, newdigest, &psl)); ++ if (ctx->object != CK_INVALID_HANDLE) ++ (void) pkcs_C_DestroyObject(ctx->session, ctx->object); ++ ctx->object = CK_INVALID_HANDLE; ++ pk11_return_session(ctx); ++ memcpy(digest, newdigest, len); ++ memset(newdigest, 0, sizeof(newdigest)); ++} ++ + #else + + #define IPAD 0x36 +diff --git a/lib/isc/include/Makefile.in b/lib/isc/include/Makefile.in +index 70c165e..c92ad45 100644 +--- a/lib/isc/include/Makefile.in ++++ b/lib/isc/include/Makefile.in +@@ -19,7 +19,7 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + +-SUBDIRS = isc ++SUBDIRS = isc pk11 pkcs11 + TARGETS = + + @BIND9_MAKE_RULES@ +diff --git a/lib/isc/include/isc/hmacmd5.h b/lib/isc/include/isc/hmacmd5.h +index 9ecad45..e008328 100644 +--- a/lib/isc/include/isc/hmacmd5.h ++++ b/lib/isc/include/isc/hmacmd5.h +@@ -37,6 +37,11 @@ + + typedef HMAC_CTX isc_hmacmd5_t; + ++#elif PKCS11CRYPTO ++#include <pk11/pk11.h> ++ ++typedef pk11_context_t isc_hmacmd5_t; ++ + #else + + typedef struct { +diff --git a/lib/isc/include/isc/hmacsha.h b/lib/isc/include/isc/hmacsha.h +index 1d0e184..c223897 100644 +--- a/lib/isc/include/isc/hmacsha.h ++++ b/lib/isc/include/isc/hmacsha.h +@@ -45,6 +45,15 @@ typedef HMAC_CTX isc_hmacsha256_t; + typedef HMAC_CTX isc_hmacsha384_t; + typedef HMAC_CTX isc_hmacsha512_t; + ++#elif PKCS11CRYPTO ++#include <pk11/pk11.h> ++ ++typedef pk11_context_t isc_hmacsha1_t; ++typedef pk11_context_t isc_hmacsha224_t; ++typedef pk11_context_t isc_hmacsha256_t; ++typedef pk11_context_t isc_hmacsha384_t; ++typedef pk11_context_t isc_hmacsha512_t; ++ + #else + + typedef struct { +diff --git a/lib/isc/include/isc/md5.h b/lib/isc/include/isc/md5.h +index dfa586d..a2e00b3 100644 +--- a/lib/isc/include/isc/md5.h ++++ b/lib/isc/include/isc/md5.h +@@ -55,6 +55,11 @@ + + typedef EVP_MD_CTX isc_md5_t; + ++#elif PKCS11CRYPTO ++#include <pk11/pk11.h> ++ ++typedef pk11_context_t isc_md5_t; ++ + #else + + typedef struct { +diff --git a/lib/isc/include/isc/resultclass.h b/lib/isc/include/isc/resultclass.h +index d91e800..44b0eb4 100644 +--- a/lib/isc/include/isc/resultclass.h ++++ b/lib/isc/include/isc/resultclass.h +@@ -46,6 +46,6 @@ + #define ISC_RESULTCLASS_OMAPI ISC_RESULTCLASS_FROMNUM(4) + #define ISC_RESULTCLASS_ISCCC ISC_RESULTCLASS_FROMNUM(5) + #define ISC_RESULTCLASS_DHCP ISC_RESULTCLASS_FROMNUM(6) +- ++#define ISC_RESULTCLASS_PK11 ISC_RESULTCLASS_FROMNUM(7) + + #endif /* ISC_RESULTCLASS_H */ +diff --git a/lib/isc/include/isc/sha1.h b/lib/isc/include/isc/sha1.h +index 313ff96..f11a783 100644 +--- a/lib/isc/include/isc/sha1.h ++++ b/lib/isc/include/isc/sha1.h +@@ -40,6 +40,11 @@ + + typedef EVP_MD_CTX isc_sha1_t; + ++#elif PKCS11CRYPTO ++#include <pk11/pk11.h> ++ ++typedef pk11_context_t isc_sha1_t; ++ + #else + + typedef struct { +diff --git a/lib/isc/include/isc/sha2.h b/lib/isc/include/isc/sha2.h +index 439bbb9..14faa6e 100644 +--- a/lib/isc/include/isc/sha2.h ++++ b/lib/isc/include/isc/sha2.h +@@ -84,6 +84,12 @@ + typedef EVP_MD_CTX isc_sha256_t; + typedef EVP_MD_CTX isc_sha512_t; + ++#elif PKCS11CRYPTO ++#include <pk11/pk11.h> ++ ++typedef pk11_context_t isc_sha256_t; ++typedef pk11_context_t isc_sha512_t; ++ + #else + + /* +diff --git a/lib/isc/include/pk11/Makefile.in b/lib/isc/include/pk11/Makefile.in +new file mode 100644 +index 0000000..744c40e +--- /dev/null ++++ b/lib/isc/include/pk11/Makefile.in +@@ -0,0 +1,38 @@ ++# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_VERSION@ ++ ++# ++# Only list headers that are to be installed and are not ++# machine generated. The latter are handled specially in the ++# install target below. ++# ++HEADERS = constants.h internal.h pk11.h result.h ++SUBDIRS = ++TARGETS = ++ ++@BIND9_MAKE_RULES@ ++ ++installdirs: ++ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pk11 ++ ++install:: installdirs ++ for i in ${HEADERS}; do \ ++ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/pk11 ; \ ++ done +diff --git a/lib/isc/include/pk11/constants.h b/lib/isc/include/pk11/constants.h +new file mode 100644 +index 0000000..e1e0581 +--- /dev/null ++++ b/lib/isc/include/pk11/constants.h +@@ -0,0 +1,107 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#ifndef PK11_CONSTANTS_H ++#define PK11_CONSTANTS_H 1 ++ ++/*! \file pk11/constants.h */ ++ ++/*% ++ * Static arrays of data used for key template initalization ++ */ ++#ifdef WANT_ECC_CURVES ++static CK_BYTE pk11_ecc_prime256v1[] = { ++ 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07 ++}; ++static CK_BYTE pk11_ecc_secp384r1[] = { ++ 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22 ++}; ++#endif ++ ++#ifdef WANT_DH_PRIMES ++static CK_BYTE pk11_dh_bn2[] = { 2 }; ++static CK_BYTE pk11_dh_bn768[] = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, ++ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, ++ 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, ++ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, ++ 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, ++ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, ++ 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, ++ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, ++ 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, ++ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x3a, 0x36, 0x20, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static CK_BYTE pk11_dh_bn1024[] = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, ++ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, ++ 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, ++ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, ++ 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, ++ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, ++ 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, ++ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, ++ 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, ++ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, ++ 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, ++ 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, ++ 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6, ++ 0x49, 0x28, 0x66, 0x51, 0xec, 0xe6, 0x53, 0x81, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++static CK_BYTE pk11_dh_bn1536[] = { ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ++ 0xc9, 0x0f, 0xda, 0xa2, 0x21, 0x68, 0xc2, 0x34, ++ 0xc4, 0xc6, 0x62, 0x8b, 0x80, 0xdc, 0x1c, 0xd1, ++ 0x29, 0x02, 0x4e, 0x08, 0x8a, 0x67, 0xcc, 0x74, ++ 0x02, 0x0b, 0xbe, 0xa6, 0x3b, 0x13, 0x9b, 0x22, ++ 0x51, 0x4a, 0x08, 0x79, 0x8e, 0x34, 0x04, 0xdd, ++ 0xef, 0x95, 0x19, 0xb3, 0xcd, 0x3a, 0x43, 0x1b, ++ 0x30, 0x2b, 0x0a, 0x6d, 0xf2, 0x5f, 0x14, 0x37, ++ 0x4f, 0xe1, 0x35, 0x6d, 0x6d, 0x51, 0xc2, 0x45, ++ 0xe4, 0x85, 0xb5, 0x76, 0x62, 0x5e, 0x7e, 0xc6, ++ 0xf4, 0x4c, 0x42, 0xe9, 0xa6, 0x37, 0xed, 0x6b, ++ 0x0b, 0xff, 0x5c, 0xb6, 0xf4, 0x06, 0xb7, 0xed, ++ 0xee, 0x38, 0x6b, 0xfb, 0x5a, 0x89, 0x9f, 0xa5, ++ 0xae, 0x9f, 0x24, 0x11, 0x7c, 0x4b, 0x1f, 0xe6, ++ 0x49, 0x28, 0x66, 0x51, 0xec, 0xe4, 0x5b, 0x3d, ++ 0xc2, 0x00, 0x7c, 0xb8, 0xa1, 0x63, 0xbf, 0x05, ++ 0x98, 0xda, 0x48, 0x36, 0x1c, 0x55, 0xd3, 0x9a, ++ 0x69, 0x16, 0x3f, 0xa8, 0xfd, 0x24, 0xcf, 0x5f, ++ 0x83, 0x65, 0x5d, 0x23, 0xdc, 0xa3, 0xad, 0x96, ++ 0x1c, 0x62, 0xf3, 0x56, 0x20, 0x85, 0x52, 0xbb, ++ 0x9e, 0xd5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6d, ++ 0x67, 0x0c, 0x35, 0x4e, 0x4a, 0xbc, 0x98, 0x04, ++ 0xf1, 0x74, 0x6c, 0x08, 0xca, 0x23, 0x73, 0x27, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ++}; ++#endif ++ ++#ifdef WANT_GOST_PARAMS ++static CK_BYTE pk11_gost_a_paramset[] = { ++ 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01 ++}; ++static CK_BYTE pk11_gost_paramset[] = { ++ 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01 ++}; ++#endif ++ ++#endif /* PK11_CONSTANTS_H */ +diff --git a/lib/isc/include/pk11/internal.h b/lib/isc/include/pk11/internal.h +new file mode 100644 +index 0000000..14bef3c +--- /dev/null ++++ b/lib/isc/include/pk11/internal.h +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++#ifndef PK11_INTERNAL_H ++#define PK11_INTERNAL_H 1 ++ ++/*! \file pk11/internal.h */ ++ ++ISC_LANG_BEGINDECLS ++ ++const char *pk11_get_lib_name(void); ++ ++void *pk11_mem_get(size_t size); ++ ++void pk11_mem_put(void *ptr, size_t size); ++ ++CK_SLOT_ID pk11_get_best_token(pk11_optype_t optype); ++ ++unsigned int pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt); ++ ++CK_ATTRIBUTE *pk11_attribute_first(const pk11_object_t *obj); ++ ++CK_ATTRIBUTE *pk11_attribute_next(const pk11_object_t *obj, ++ CK_ATTRIBUTE *attr); ++ ++CK_ATTRIBUTE *pk11_attribute_bytype(const pk11_object_t *obj, ++ CK_ATTRIBUTE_TYPE type); ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* PK11_INTERNAL_H */ +diff --git a/lib/isc/include/pk11/pk11.h b/lib/isc/include/pk11/pk11.h +new file mode 100644 +index 0000000..964a2a7 +--- /dev/null ++++ b/lib/isc/include/pk11/pk11.h +@@ -0,0 +1,295 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef PK11_PK11_H ++#define PK11_PK11_H 1 ++ ++/*! \file pk11/pk11.h */ ++ ++#include <isc/lang.h> ++#include <isc/magic.h> ++#include <isc/types.h> ++ ++#define PK11_FATALCHECK(func, args) \ ++ ((void) (((rv = (func) args) == CKR_OK) || \ ++ ((pk11_error_fatalcheck)(__FILE__, __LINE__, #func, rv), 0))) ++ ++#include <pkcs11/cryptoki.h> ++ ++ISC_LANG_BEGINDECLS ++ ++#define SES_MAGIC ISC_MAGIC('P','K','S','S') ++#define TOK_MAGIC ISC_MAGIC('P','K','T','K') ++ ++#define VALID_SES(x) ISC_MAGIC_VALID(x, SES_MAGIC) ++#define VALID_TOK(x) ISC_MAGIC_VALID(x, TOK_MAGIC) ++ ++typedef struct pk11_context pk11_context_t; ++ ++struct pk11_object { ++ CK_OBJECT_HANDLE object; ++ CK_SLOT_ID slot; ++ CK_BBOOL ontoken; ++ CK_BBOOL reqlogon; ++ CK_BYTE attrcnt; ++ CK_ATTRIBUTE *repr; ++}; ++ ++struct pk11_context { ++ void *handle; ++ CK_SESSION_HANDLE session; ++ CK_BBOOL ontoken; ++ CK_OBJECT_HANDLE object; ++#ifndef PKCS11CRYPTOWITHHMAC ++ unsigned char *key; ++#endif ++}; ++ ++typedef struct pk11_object pk11_object_t; ++ ++typedef enum { ++ OP_ANY = 0, ++ OP_RAND = 1, ++ OP_RSA = 2, ++ OP_DSA = 3, ++ OP_DH = 4, ++ OP_DIGEST = 5, ++ OP_EC = 6, ++ OP_GOST = 7, ++ OP_AES = 8, ++ OP_MAX = 9 ++} pk11_optype_t; ++ ++/*% ++ * Function prototypes ++ */ ++ ++void pk11_set_lib_name(const char *lib_name); ++/*%< ++ * Set the PKCS#11 provider (aka library) path/name. ++ */ ++ ++isc_result_t pk11_initialize(isc_mem_t *mctx, const char *engine); ++/*%< ++ * Initialize PKCS#11 device ++ * ++ * mctx: memory context to attach to pk11_mctx. ++ * engine: PKCS#11 provider (aka library) path/name. ++ * ++ * returns: ++ * ISC_R_SUCCESS ++ * PK11_R_NOPROVIDER: can't load the provider ++ * PK11_R_INITFAILED: C_Initialize() failed ++ * PK11_R_NORANDOMSERVICE: can't find required random service ++ * PK11_R_NODIGESTSERVICE: can't find required digest service ++ * PK11_R_NOAESSERVICE: can't find required AES service ++ */ ++ ++isc_result_t pk11_get_session(pk11_context_t *ctx, ++ pk11_optype_t optype, ++ isc_boolean_t need_services, ++ isc_boolean_t rw, ++ isc_boolean_t logon, ++ const char *pin, ++ CK_SLOT_ID slot); ++/*%< ++ * Initialize PKCS#11 device and acquire a session. ++ * ++ * need_services: ++ * if ISC_TRUE, this session requires full PKCS#11 API ++ * support including random and digest services, and ++ * the lack of these services will cause the session not ++ * to be initialized. If ISC_FALSE, the function will return ++ * an error code indicating the missing service, but the ++ * session will be usable for other purposes. ++ * rw: if ISC_TRUE, session will be read/write (useful for ++ * generating or destroying keys); otherwise read-only. ++ * login: indicates whether to log in to the device ++ * pin: optional PIN, overriding any PIN currently associated ++ * with the ++ * slot: device slot ID ++ */ ++ ++void pk11_return_session(pk11_context_t *ctx); ++/*%< ++ * Release an active PKCS#11 session for reuse. ++ */ ++ ++isc_result_t pk11_finalize(void); ++/*%< ++ * Shut down PKCS#11 device and free all sessions. ++ */ ++ ++isc_result_t pk11_rand_bytes(unsigned char *buf, int num); ++ ++void pk11_rand_seed_fromfile(const char *randomfile); ++ ++isc_result_t pk11_parse_uri(pk11_object_t *obj, const char *label, ++ isc_mem_t *mctx, pk11_optype_t optype); ++ ++ISC_PLATFORM_NORETURN_PRE void ++pk11_error_fatalcheck(const char *file, int line, ++ const char *funcname, CK_RV rv) ++ISC_PLATFORM_NORETURN_POST; ++ ++void pk11_dump_tokens(void); ++ ++CK_RV ++pkcs_C_Initialize(CK_VOID_PTR pReserved); ++ ++CK_RV ++pkcs_C_Finalize(CK_VOID_PTR pReserved); ++ ++CK_RV ++pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, ++ CK_ULONG_PTR pulCount); ++ ++CK_RV ++pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo); ++ ++CK_RV ++pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, ++ CK_MECHANISM_INFO_PTR pInfo); ++ ++CK_RV ++pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, ++ CK_VOID_PTR pApplication, ++ CK_RV (*Notify) (CK_SESSION_HANDLE hSession, ++ CK_NOTIFICATION event, ++ CK_VOID_PTR pApplication), ++ CK_SESSION_HANDLE_PTR phSession); ++ ++CK_RV ++pkcs_C_CloseSession(CK_SESSION_HANDLE hSession); ++ ++CK_RV ++pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, ++ CK_CHAR_PTR pPin, CK_ULONG usPinLen); ++ ++CK_RV ++pkcs_C_Logout(CK_SESSION_HANDLE hSession); ++ ++CK_RV ++pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject); ++ ++CK_RV ++pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject); ++ ++CK_RV ++pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, ++ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount); ++ ++CK_RV ++pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, ++ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount); ++ ++CK_RV ++pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG usCount); ++ ++CK_RV ++pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, ++ CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount); ++ ++CK_RV ++pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession); ++ ++CK_RV ++pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey); ++ ++CK_RV ++pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, ++ CK_ULONG_PTR pulEncryptedDataLen); ++ ++CK_RV ++pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism); ++ ++CK_RV ++pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen); ++ ++CK_RV ++pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, ++ CK_ULONG_PTR pulDigestLen); ++ ++CK_RV ++pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey); ++ ++CK_RV ++pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, ++ CK_ULONG_PTR pulSignatureLen); ++ ++CK_RV ++pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen); ++ ++CK_RV ++pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, ++ CK_ULONG_PTR pulSignatureLen); ++ ++CK_RV ++pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey); ++ ++CK_RV ++pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, ++ CK_ULONG ulSignatureLen); ++ ++CK_RV ++pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen); ++ ++CK_RV ++pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, ++ CK_ULONG ulSignatureLen); ++ ++CK_RV ++pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, ++ CK_OBJECT_HANDLE_PTR phKey); ++ ++CK_RV ++pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism, ++ CK_ATTRIBUTE_PTR pPublicKeyTemplate, ++ CK_ULONG usPublicKeyAttributeCount, ++ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, ++ CK_ULONG usPrivateKeyAttributeCount, ++ CK_OBJECT_HANDLE_PTR phPrivateKey, ++ CK_OBJECT_HANDLE_PTR phPublicKey); ++ ++CK_RV ++pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); ++ ++CK_RV ++pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, ++ CK_ULONG ulSeedLen); ++ ++CK_RV ++pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, ++ CK_ULONG ulRandomLen); ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* PK11_PK11_H */ +diff --git a/lib/isc/include/pk11/result.h b/lib/isc/include/pk11/result.h +new file mode 100644 +index 0000000..f624140 +--- /dev/null ++++ b/lib/isc/include/pk11/result.h +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef PK11_RESULT_H ++#define PK11_RESULT_H 1 ++ ++/*! \file pk11/result.h */ ++ ++#include <isc/lang.h> ++#include <isc/resultclass.h> ++ ++/* ++ * Nothing in this file truly depends on <isc/result.h>, but the ++ * PK11 result codes are considered to be publicly derived from ++ * the ISC result codes, so including this file buys you the ISC_R_ ++ * namespace too. ++ */ ++#include <isc/result.h> /* Contractual promise. */ ++ ++#define PK11_R_INITFAILED (ISC_RESULTCLASS_PK11 + 0) ++#define PK11_R_NOPROVIDER (ISC_RESULTCLASS_PK11 + 1) ++#define PK11_R_NORANDOMSERVICE (ISC_RESULTCLASS_PK11 + 2) ++#define PK11_R_NODIGESTSERVICE (ISC_RESULTCLASS_PK11 + 3) ++#define PK11_R_NOAESSERVICE (ISC_RESULTCLASS_PK11 + 4) ++ ++#define PK11_R_NRESULTS 5 /* Number of results */ ++ ++ISC_LANG_BEGINDECLS ++ ++LIBISC_EXTERNAL_DATA extern isc_msgcat_t *pk11_msgcat; ++ ++void ++pk11_initmsgcat(void); ++ ++const char * ++pk11_result_totext(isc_result_t); ++ ++void ++pk11_result_register(void); ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* PK11_RESULT_H */ +diff --git a/lib/isc/include/pkcs11/Makefile.in b/lib/isc/include/pkcs11/Makefile.in +new file mode 100644 +index 0000000..6e98688 +--- /dev/null ++++ b/lib/isc/include/pkcs11/Makefile.in +@@ -0,0 +1,40 @@ ++# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# $Id: Makefile.in,v 1.7 2007/06/19 23:47:22 tbox Exp $ ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_VERSION@ ++ ++# ++# Only list headers that are to be installed and are not ++# machine generated. The latter are handled specially in the ++# install target below. ++# ++HEADERS = pkcs11f.h pkcs11.h pkcs11t.h ++SUBDIRS = ++TARGETS = ++ ++@BIND9_MAKE_RULES@ ++ ++installdirs: ++ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11 ++ ++install:: installdirs ++ for i in ${HEADERS}; do \ ++ ${INSTALL_DATA} ${srcdir}/$$i ${DESTDIR}${includedir}/pkcs11 ; \ ++ done +diff --git a/lib/isc/include/pkcs11/pkcs11.h b/lib/isc/include/pkcs11/pkcs11.h +new file mode 100644 +index 0000000..9261e1e +--- /dev/null ++++ b/lib/isc/include/pkcs11/pkcs11.h +@@ -0,0 +1,299 @@ ++/* pkcs11.h include file for PKCS #11. */ ++/* $Revision: 1.2 $ */ ++ ++/* License to copy and use this software is granted provided that it is ++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface ++ * (Cryptoki)" in all material mentioning or referencing this software. ++ ++ * License is also granted to make and use derivative works provided that ++ * such works are identified as "derived from the RSA Security Inc. PKCS #11 ++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or ++ * referencing the derived work. ++ ++ * RSA Security Inc. makes no representations concerning either the ++ * merchantability of this software or the suitability of this software for ++ * any particular purpose. It is provided "as is" without express or implied ++ * warranty of any kind. ++ */ ++ ++#ifndef _PKCS11_H_ ++#define _PKCS11_H_ 1 ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/* Before including this file (pkcs11.h) (or pkcs11t.h by ++ * itself), 6 platform-specific macros must be defined. These ++ * macros are described below, and typical definitions for them ++ * are also given. Be advised that these definitions can depend ++ * on both the platform and the compiler used (and possibly also ++ * on whether a Cryptoki library is linked statically or ++ * dynamically). ++ * ++ * In addition to defining these 6 macros, the packing convention ++ * for Cryptoki structures should be set. The Cryptoki ++ * convention on packing is that structures should be 1-byte ++ * aligned. ++ * ++ * If you're using Microsoft Developer Studio 5.0 to produce ++ * Win32 stuff, this might be done by using the following ++ * preprocessor directive before including pkcs11.h or pkcs11t.h: ++ * ++ * #pragma pack(push, cryptoki, 1) ++ * ++ * and using the following preprocessor directive after including ++ * pkcs11.h or pkcs11t.h: ++ * ++ * #pragma pack(pop, cryptoki) ++ * ++ * If you're using an earlier version of Microsoft Developer ++ * Studio to produce Win16 stuff, this might be done by using ++ * the following preprocessor directive before including ++ * pkcs11.h or pkcs11t.h: ++ * ++ * #pragma pack(1) ++ * ++ * In a UNIX environment, you're on your own for this. You might ++ * not need to do (or be able to do!) anything. ++ * ++ * ++ * Now for the macros: ++ * ++ * ++ * 1. CK_PTR: The indirection string for making a pointer to an ++ * object. It can be used like this: ++ * ++ * typedef CK_BYTE CK_PTR CK_BYTE_PTR; ++ * ++ * If you're using Microsoft Developer Studio 5.0 to produce ++ * Win32 stuff, it might be defined by: ++ * ++ * #define CK_PTR * ++ * ++ * If you're using an earlier version of Microsoft Developer ++ * Studio to produce Win16 stuff, it might be defined by: ++ * ++ * #define CK_PTR far * ++ * ++ * In a typical UNIX environment, it might be defined by: ++ * ++ * #define CK_PTR * ++ * ++ * ++ * 2. CK_DEFINE_FUNCTION(returnType, name): A macro which makes ++ * an exportable Cryptoki library function definition out of a ++ * return type and a function name. It should be used in the ++ * following fashion to define the exposed Cryptoki functions in ++ * a Cryptoki library: ++ * ++ * CK_DEFINE_FUNCTION(CK_RV, C_Initialize)( ++ * CK_VOID_PTR pReserved ++ * ) ++ * { ++ * ... ++ * } ++ * ++ * If you're using Microsoft Developer Studio 5.0 to define a ++ * function in a Win32 Cryptoki .dll, it might be defined by: ++ * ++ * #define CK_DEFINE_FUNCTION(returnType, name) \ ++ * returnType __declspec(dllexport) name ++ * ++ * If you're using an earlier version of Microsoft Developer ++ * Studio to define a function in a Win16 Cryptoki .dll, it ++ * might be defined by: ++ * ++ * #define CK_DEFINE_FUNCTION(returnType, name) \ ++ * returnType __export _far _pascal name ++ * ++ * In a UNIX environment, it might be defined by: ++ * ++ * #define CK_DEFINE_FUNCTION(returnType, name) \ ++ * returnType name ++ * ++ * ++ * 3. CK_DECLARE_FUNCTION(returnType, name): A macro which makes ++ * an importable Cryptoki library function declaration out of a ++ * return type and a function name. It should be used in the ++ * following fashion: ++ * ++ * extern CK_DECLARE_FUNCTION(CK_RV, C_Initialize)( ++ * CK_VOID_PTR pReserved ++ * ); ++ * ++ * If you're using Microsoft Developer Studio 5.0 to declare a ++ * function in a Win32 Cryptoki .dll, it might be defined by: ++ * ++ * #define CK_DECLARE_FUNCTION(returnType, name) \ ++ * returnType __declspec(dllimport) name ++ * ++ * If you're using an earlier version of Microsoft Developer ++ * Studio to declare a function in a Win16 Cryptoki .dll, it ++ * might be defined by: ++ * ++ * #define CK_DECLARE_FUNCTION(returnType, name) \ ++ * returnType __export _far _pascal name ++ * ++ * In a UNIX environment, it might be defined by: ++ * ++ * #define CK_DECLARE_FUNCTION(returnType, name) \ ++ * returnType name ++ * ++ * ++ * 4. CK_DECLARE_FUNCTION_POINTER(returnType, name): A macro ++ * which makes a Cryptoki API function pointer declaration or ++ * function pointer type declaration out of a return type and a ++ * function name. It should be used in the following fashion: ++ * ++ * // Define funcPtr to be a pointer to a Cryptoki API function ++ * // taking arguments args and returning CK_RV. ++ * CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtr)(args); ++ * ++ * or ++ * ++ * // Define funcPtrType to be the type of a pointer to a ++ * // Cryptoki API function taking arguments args and returning ++ * // CK_RV, and then define funcPtr to be a variable of type ++ * // funcPtrType. ++ * typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, funcPtrType)(args); ++ * funcPtrType funcPtr; ++ * ++ * If you're using Microsoft Developer Studio 5.0 to access ++ * functions in a Win32 Cryptoki .dll, in might be defined by: ++ * ++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ ++ * returnType __declspec(dllimport) (* name) ++ * ++ * If you're using an earlier version of Microsoft Developer ++ * Studio to access functions in a Win16 Cryptoki .dll, it might ++ * be defined by: ++ * ++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ ++ * returnType __export _far _pascal (* name) ++ * ++ * In a UNIX environment, it might be defined by: ++ * ++ * #define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ ++ * returnType (* name) ++ * ++ * ++ * 5. CK_CALLBACK_FUNCTION(returnType, name): A macro which makes ++ * a function pointer type for an application callback out of ++ * a return type for the callback and a name for the callback. ++ * It should be used in the following fashion: ++ * ++ * CK_CALLBACK_FUNCTION(CK_RV, myCallback)(args); ++ * ++ * to declare a function pointer, myCallback, to a callback ++ * which takes arguments args and returns a CK_RV. It can also ++ * be used like this: ++ * ++ * typedef CK_CALLBACK_FUNCTION(CK_RV, myCallbackType)(args); ++ * myCallbackType myCallback; ++ * ++ * If you're using Microsoft Developer Studio 5.0 to do Win32 ++ * Cryptoki development, it might be defined by: ++ * ++ * #define CK_CALLBACK_FUNCTION(returnType, name) \ ++ * returnType (* name) ++ * ++ * If you're using an earlier version of Microsoft Developer ++ * Studio to do Win16 development, it might be defined by: ++ * ++ * #define CK_CALLBACK_FUNCTION(returnType, name) \ ++ * returnType _far _pascal (* name) ++ * ++ * In a UNIX environment, it might be defined by: ++ * ++ * #define CK_CALLBACK_FUNCTION(returnType, name) \ ++ * returnType (* name) ++ * ++ * ++ * 6. NULL_PTR: This macro is the value of a NULL pointer. ++ * ++ * In any ANSI/ISO C environment (and in many others as well), ++ * this should best be defined by ++ * ++ * #ifndef NULL_PTR ++ * #define NULL_PTR 0 ++ * #endif ++ */ ++ ++ ++/* All the various Cryptoki types and #define'd values are in the ++ * file pkcs11t.h. */ ++#include "pkcs11t.h" ++ ++#define __PASTE(x,y) x##y ++ ++ ++/* ============================================================== ++ * Define the "extern" form of all the entry points. ++ * ============================================================== ++ */ ++ ++#define CK_NEED_ARG_LIST 1 ++#define CK_PKCS11_FUNCTION_INFO(name) \ ++ extern CK_DECLARE_FUNCTION(CK_RV, name) ++ ++/* pkcs11f.h has all the information about the Cryptoki ++ * function prototypes. */ ++#include "pkcs11f.h" ++ ++#undef CK_NEED_ARG_LIST ++#undef CK_PKCS11_FUNCTION_INFO ++ ++ ++/* ============================================================== ++ * Define the typedef form of all the entry points. That is, for ++ * each Cryptoki function C_XXX, define a type CK_C_XXX which is ++ * a pointer to that kind of function. ++ * ============================================================== ++ */ ++ ++#define CK_NEED_ARG_LIST 1 ++#define CK_PKCS11_FUNCTION_INFO(name) \ ++ typedef CK_DECLARE_FUNCTION_POINTER(CK_RV, __PASTE(CK_,name)) ++ ++/* pkcs11f.h has all the information about the Cryptoki ++ * function prototypes. */ ++#include "pkcs11f.h" ++ ++#undef CK_NEED_ARG_LIST ++#undef CK_PKCS11_FUNCTION_INFO ++ ++ ++/* ============================================================== ++ * Define structed vector of entry points. A CK_FUNCTION_LIST ++ * contains a CK_VERSION indicating a library's Cryptoki version ++ * and then a whole slew of function pointers to the routines in ++ * the library. This type was declared, but not defined, in ++ * pkcs11t.h. ++ * ============================================================== ++ */ ++ ++#define CK_PKCS11_FUNCTION_INFO(name) \ ++ __PASTE(CK_,name) name; ++ ++struct CK_FUNCTION_LIST { ++ ++ CK_VERSION version; /* Cryptoki version */ ++ ++/* Pile all the function pointers into the CK_FUNCTION_LIST. */ ++/* pkcs11f.h has all the information about the Cryptoki ++ * function prototypes. */ ++#include "pkcs11f.h" ++ ++}; ++ ++#undef CK_PKCS11_FUNCTION_INFO ++ ++ ++#undef __PASTE ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif +diff --git a/lib/isc/include/pkcs11/pkcs11f.h b/lib/isc/include/pkcs11/pkcs11f.h +new file mode 100644 +index 0000000..dec6315 +--- /dev/null ++++ b/lib/isc/include/pkcs11/pkcs11f.h +@@ -0,0 +1,912 @@ ++/* pkcs11f.h include file for PKCS #11. */ ++/* $Revision: 1.2 $ */ ++ ++/* License to copy and use this software is granted provided that it is ++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface ++ * (Cryptoki)" in all material mentioning or referencing this software. ++ ++ * License is also granted to make and use derivative works provided that ++ * such works are identified as "derived from the RSA Security Inc. PKCS #11 ++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or ++ * referencing the derived work. ++ ++ * RSA Security Inc. makes no representations concerning either the ++ * merchantability of this software or the suitability of this software for ++ * any particular purpose. It is provided "as is" without express or implied ++ * warranty of any kind. ++ */ ++ ++/* This header file contains pretty much everything about all the */ ++/* Cryptoki function prototypes. Because this information is */ ++/* used for more than just declaring function prototypes, the */ ++/* order of the functions appearing herein is important, and */ ++/* should not be altered. */ ++ ++/* General-purpose */ ++ ++/* C_Initialize initializes the Cryptoki library. */ ++CK_PKCS11_FUNCTION_INFO(C_Initialize) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_VOID_PTR pInitArgs /* if this is not NULL_PTR, it gets ++ * cast to CK_C_INITIALIZE_ARGS_PTR ++ * and dereferenced */ ++); ++#endif ++ ++ ++/* C_Finalize indicates that an application is done with the ++ * Cryptoki library. */ ++CK_PKCS11_FUNCTION_INFO(C_Finalize) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_VOID_PTR pReserved /* reserved. Should be NULL_PTR */ ++); ++#endif ++ ++ ++/* C_GetInfo returns general information about Cryptoki. */ ++CK_PKCS11_FUNCTION_INFO(C_GetInfo) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_INFO_PTR pInfo /* location that receives information */ ++); ++#endif ++ ++ ++/* C_GetFunctionList returns the function list. */ ++CK_PKCS11_FUNCTION_INFO(C_GetFunctionList) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_FUNCTION_LIST_PTR_PTR ppFunctionList /* receives pointer to ++ * function list */ ++); ++#endif ++ ++ ++ ++/* Slot and token management */ ++ ++/* C_GetSlotList obtains a list of slots in the system. */ ++CK_PKCS11_FUNCTION_INFO(C_GetSlotList) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_BBOOL tokenPresent, /* only slots with tokens? */ ++ CK_SLOT_ID_PTR pSlotList, /* receives array of slot IDs */ ++ CK_ULONG_PTR pulCount /* receives number of slots */ ++); ++#endif ++ ++ ++/* C_GetSlotInfo obtains information about a particular slot in ++ * the system. */ ++CK_PKCS11_FUNCTION_INFO(C_GetSlotInfo) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SLOT_ID slotID, /* the ID of the slot */ ++ CK_SLOT_INFO_PTR pInfo /* receives the slot information */ ++); ++#endif ++ ++ ++/* C_GetTokenInfo obtains information about a particular token ++ * in the system. */ ++CK_PKCS11_FUNCTION_INFO(C_GetTokenInfo) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SLOT_ID slotID, /* ID of the token's slot */ ++ CK_TOKEN_INFO_PTR pInfo /* receives the token information */ ++); ++#endif ++ ++ ++/* C_GetMechanismList obtains a list of mechanism types ++ * supported by a token. */ ++CK_PKCS11_FUNCTION_INFO(C_GetMechanismList) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SLOT_ID slotID, /* ID of token's slot */ ++ CK_MECHANISM_TYPE_PTR pMechanismList, /* gets mech. array */ ++ CK_ULONG_PTR pulCount /* gets # of mechs. */ ++); ++#endif ++ ++ ++/* C_GetMechanismInfo obtains information about a particular ++ * mechanism possibly supported by a token. */ ++CK_PKCS11_FUNCTION_INFO(C_GetMechanismInfo) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SLOT_ID slotID, /* ID of the token's slot */ ++ CK_MECHANISM_TYPE type, /* type of mechanism */ ++ CK_MECHANISM_INFO_PTR pInfo /* receives mechanism info */ ++); ++#endif ++ ++ ++/* C_InitToken initializes a token. */ ++CK_PKCS11_FUNCTION_INFO(C_InitToken) ++#ifdef CK_NEED_ARG_LIST ++/* pLabel changed from CK_CHAR_PTR to CK_UTF8CHAR_PTR for v2.10 */ ++( ++ CK_SLOT_ID slotID, /* ID of the token's slot */ ++ CK_UTF8CHAR_PTR pPin, /* the SO's initial PIN */ ++ CK_ULONG ulPinLen, /* length in bytes of the PIN */ ++ CK_UTF8CHAR_PTR pLabel /* 32-byte token label (blank padded) */ ++); ++#endif ++ ++ ++/* C_InitPIN initializes the normal user's PIN. */ ++CK_PKCS11_FUNCTION_INFO(C_InitPIN) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_UTF8CHAR_PTR pPin, /* the normal user's PIN */ ++ CK_ULONG ulPinLen /* length in bytes of the PIN */ ++); ++#endif ++ ++ ++/* C_SetPIN modifies the PIN of the user who is logged in. */ ++CK_PKCS11_FUNCTION_INFO(C_SetPIN) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_UTF8CHAR_PTR pOldPin, /* the old PIN */ ++ CK_ULONG ulOldLen, /* length of the old PIN */ ++ CK_UTF8CHAR_PTR pNewPin, /* the new PIN */ ++ CK_ULONG ulNewLen /* length of the new PIN */ ++); ++#endif ++ ++ ++ ++/* Session management */ ++ ++/* C_OpenSession opens a session between an application and a ++ * token. */ ++CK_PKCS11_FUNCTION_INFO(C_OpenSession) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SLOT_ID slotID, /* the slot's ID */ ++ CK_FLAGS flags, /* from CK_SESSION_INFO */ ++ CK_VOID_PTR pApplication, /* passed to callback */ ++ CK_NOTIFY Notify, /* callback function */ ++ CK_SESSION_HANDLE_PTR phSession /* gets session handle */ ++); ++#endif ++ ++ ++/* C_CloseSession closes a session between an application and a ++ * token. */ ++CK_PKCS11_FUNCTION_INFO(C_CloseSession) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession /* the session's handle */ ++); ++#endif ++ ++ ++/* C_CloseAllSessions closes all sessions with a token. */ ++CK_PKCS11_FUNCTION_INFO(C_CloseAllSessions) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SLOT_ID slotID /* the token's slot */ ++); ++#endif ++ ++ ++/* C_GetSessionInfo obtains information about the session. */ ++CK_PKCS11_FUNCTION_INFO(C_GetSessionInfo) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_SESSION_INFO_PTR pInfo /* receives session info */ ++); ++#endif ++ ++ ++/* C_GetOperationState obtains the state of the cryptographic operation ++ * in a session. */ ++CK_PKCS11_FUNCTION_INFO(C_GetOperationState) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pOperationState, /* gets state */ ++ CK_ULONG_PTR pulOperationStateLen /* gets state length */ ++); ++#endif ++ ++ ++/* C_SetOperationState restores the state of the cryptographic ++ * operation in a session. */ ++CK_PKCS11_FUNCTION_INFO(C_SetOperationState) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pOperationState, /* holds state */ ++ CK_ULONG ulOperationStateLen, /* holds state length */ ++ CK_OBJECT_HANDLE hEncryptionKey, /* en/decryption key */ ++ CK_OBJECT_HANDLE hAuthenticationKey /* sign/verify key */ ++); ++#endif ++ ++ ++/* C_Login logs a user into a token. */ ++CK_PKCS11_FUNCTION_INFO(C_Login) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_USER_TYPE userType, /* the user type */ ++ CK_UTF8CHAR_PTR pPin, /* the user's PIN */ ++ CK_ULONG ulPinLen /* the length of the PIN */ ++); ++#endif ++ ++ ++/* C_Logout logs a user out from a token. */ ++CK_PKCS11_FUNCTION_INFO(C_Logout) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession /* the session's handle */ ++); ++#endif ++ ++ ++ ++/* Object management */ ++ ++/* C_CreateObject creates a new object. */ ++CK_PKCS11_FUNCTION_INFO(C_CreateObject) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_ATTRIBUTE_PTR pTemplate, /* the object's template */ ++ CK_ULONG ulCount, /* attributes in template */ ++ CK_OBJECT_HANDLE_PTR phObject /* gets new object's handle. */ ++); ++#endif ++ ++ ++/* C_CopyObject copies an object, creating a new object for the ++ * copy. */ ++CK_PKCS11_FUNCTION_INFO(C_CopyObject) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_OBJECT_HANDLE hObject, /* the object's handle */ ++ CK_ATTRIBUTE_PTR pTemplate, /* template for new object */ ++ CK_ULONG ulCount, /* attributes in template */ ++ CK_OBJECT_HANDLE_PTR phNewObject /* receives handle of copy */ ++); ++#endif ++ ++ ++/* C_DestroyObject destroys an object. */ ++CK_PKCS11_FUNCTION_INFO(C_DestroyObject) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_OBJECT_HANDLE hObject /* the object's handle */ ++); ++#endif ++ ++ ++/* C_GetObjectSize gets the size of an object in bytes. */ ++CK_PKCS11_FUNCTION_INFO(C_GetObjectSize) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_OBJECT_HANDLE hObject, /* the object's handle */ ++ CK_ULONG_PTR pulSize /* receives size of object */ ++); ++#endif ++ ++ ++/* C_GetAttributeValue obtains the value of one or more object ++ * attributes. */ ++CK_PKCS11_FUNCTION_INFO(C_GetAttributeValue) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_OBJECT_HANDLE hObject, /* the object's handle */ ++ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs; gets vals */ ++ CK_ULONG ulCount /* attributes in template */ ++); ++#endif ++ ++ ++/* C_SetAttributeValue modifies the value of one or more object ++ * attributes */ ++CK_PKCS11_FUNCTION_INFO(C_SetAttributeValue) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_OBJECT_HANDLE hObject, /* the object's handle */ ++ CK_ATTRIBUTE_PTR pTemplate, /* specifies attrs and values */ ++ CK_ULONG ulCount /* attributes in template */ ++); ++#endif ++ ++ ++/* C_FindObjectsInit initializes a search for token and session ++ * objects that match a template. */ ++CK_PKCS11_FUNCTION_INFO(C_FindObjectsInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_ATTRIBUTE_PTR pTemplate, /* attribute values to match */ ++ CK_ULONG ulCount /* attrs in search template */ ++); ++#endif ++ ++ ++/* C_FindObjects continues a search for token and session ++ * objects that match a template, obtaining additional object ++ * handles. */ ++CK_PKCS11_FUNCTION_INFO(C_FindObjects) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_OBJECT_HANDLE_PTR phObject, /* gets obj. handles */ ++ CK_ULONG ulMaxObjectCount, /* max handles to get */ ++ CK_ULONG_PTR pulObjectCount /* actual # returned */ ++); ++#endif ++ ++ ++/* C_FindObjectsFinal finishes a search for token and session ++ * objects. */ ++CK_PKCS11_FUNCTION_INFO(C_FindObjectsFinal) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession /* the session's handle */ ++); ++#endif ++ ++ ++ ++/* Encryption and decryption */ ++ ++/* C_EncryptInit initializes an encryption operation. */ ++CK_PKCS11_FUNCTION_INFO(C_EncryptInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the encryption mechanism */ ++ CK_OBJECT_HANDLE hKey /* handle of encryption key */ ++); ++#endif ++ ++ ++/* C_Encrypt encrypts single-part data. */ ++CK_PKCS11_FUNCTION_INFO(C_Encrypt) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pData, /* the plaintext data */ ++ CK_ULONG ulDataLen, /* bytes of plaintext */ ++ CK_BYTE_PTR pEncryptedData, /* gets ciphertext */ ++ CK_ULONG_PTR pulEncryptedDataLen /* gets c-text size */ ++); ++#endif ++ ++ ++/* C_EncryptUpdate continues a multiple-part encryption ++ * operation. */ ++CK_PKCS11_FUNCTION_INFO(C_EncryptUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pPart, /* the plaintext data */ ++ CK_ULONG ulPartLen, /* plaintext data len */ ++ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ ++ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text size */ ++); ++#endif ++ ++ ++/* C_EncryptFinal finishes a multiple-part encryption ++ * operation. */ ++CK_PKCS11_FUNCTION_INFO(C_EncryptFinal) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session handle */ ++ CK_BYTE_PTR pLastEncryptedPart, /* last c-text */ ++ CK_ULONG_PTR pulLastEncryptedPartLen /* gets last size */ ++); ++#endif ++ ++ ++/* C_DecryptInit initializes a decryption operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DecryptInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the decryption mechanism */ ++ CK_OBJECT_HANDLE hKey /* handle of decryption key */ ++); ++#endif ++ ++ ++/* C_Decrypt decrypts encrypted data in a single part. */ ++CK_PKCS11_FUNCTION_INFO(C_Decrypt) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pEncryptedData, /* ciphertext */ ++ CK_ULONG ulEncryptedDataLen, /* ciphertext length */ ++ CK_BYTE_PTR pData, /* gets plaintext */ ++ CK_ULONG_PTR pulDataLen /* gets p-text size */ ++); ++#endif ++ ++ ++/* C_DecryptUpdate continues a multiple-part decryption ++ * operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DecryptUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pEncryptedPart, /* encrypted data */ ++ CK_ULONG ulEncryptedPartLen, /* input length */ ++ CK_BYTE_PTR pPart, /* gets plaintext */ ++ CK_ULONG_PTR pulPartLen /* p-text size */ ++); ++#endif ++ ++ ++/* C_DecryptFinal finishes a multiple-part decryption ++ * operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DecryptFinal) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pLastPart, /* gets plaintext */ ++ CK_ULONG_PTR pulLastPartLen /* p-text size */ ++); ++#endif ++ ++ ++ ++/* Message digesting */ ++ ++/* C_DigestInit initializes a message-digesting operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DigestInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism /* the digesting mechanism */ ++); ++#endif ++ ++ ++/* C_Digest digests data in a single part. */ ++CK_PKCS11_FUNCTION_INFO(C_Digest) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pData, /* data to be digested */ ++ CK_ULONG ulDataLen, /* bytes of data to digest */ ++ CK_BYTE_PTR pDigest, /* gets the message digest */ ++ CK_ULONG_PTR pulDigestLen /* gets digest length */ ++); ++#endif ++ ++ ++/* C_DigestUpdate continues a multiple-part message-digesting ++ * operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DigestUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pPart, /* data to be digested */ ++ CK_ULONG ulPartLen /* bytes of data to be digested */ ++); ++#endif ++ ++ ++/* C_DigestKey continues a multi-part message-digesting ++ * operation, by digesting the value of a secret key as part of ++ * the data already digested. */ ++CK_PKCS11_FUNCTION_INFO(C_DigestKey) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_OBJECT_HANDLE hKey /* secret key to digest */ ++); ++#endif ++ ++ ++/* C_DigestFinal finishes a multiple-part message-digesting ++ * operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DigestFinal) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pDigest, /* gets the message digest */ ++ CK_ULONG_PTR pulDigestLen /* gets byte count of digest */ ++); ++#endif ++ ++ ++ ++/* Signing and MACing */ ++ ++/* C_SignInit initializes a signature (private key encryption) ++ * operation, where the signature is (will be) an appendix to ++ * the data, and plaintext cannot be recovered from the ++ *signature. */ ++CK_PKCS11_FUNCTION_INFO(C_SignInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ ++ CK_OBJECT_HANDLE hKey /* handle of signature key */ ++); ++#endif ++ ++ ++/* C_Sign signs (encrypts with private key) data in a single ++ * part, where the signature is (will be) an appendix to the ++ * data, and plaintext cannot be recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_Sign) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pData, /* the data to sign */ ++ CK_ULONG ulDataLen, /* count of bytes to sign */ ++ CK_BYTE_PTR pSignature, /* gets the signature */ ++ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ++); ++#endif ++ ++ ++/* C_SignUpdate continues a multiple-part signature operation, ++ * where the signature is (will be) an appendix to the data, ++ * and plaintext cannot be recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_SignUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pPart, /* the data to sign */ ++ CK_ULONG ulPartLen /* count of bytes to sign */ ++); ++#endif ++ ++ ++/* C_SignFinal finishes a multiple-part signature operation, ++ * returning the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_SignFinal) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pSignature, /* gets the signature */ ++ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ++); ++#endif ++ ++ ++/* C_SignRecoverInit initializes a signature operation, where ++ * the data can be recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_SignRecoverInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the signature mechanism */ ++ CK_OBJECT_HANDLE hKey /* handle of the signature key */ ++); ++#endif ++ ++ ++/* C_SignRecover signs data in a single operation, where the ++ * data can be recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_SignRecover) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pData, /* the data to sign */ ++ CK_ULONG ulDataLen, /* count of bytes to sign */ ++ CK_BYTE_PTR pSignature, /* gets the signature */ ++ CK_ULONG_PTR pulSignatureLen /* gets signature length */ ++); ++#endif ++ ++ ++ ++/* Verifying signatures and MACs */ ++ ++/* C_VerifyInit initializes a verification operation, where the ++ * signature is an appendix to the data, and plaintext cannot ++ * cannot be recovered from the signature (e.g. DSA). */ ++CK_PKCS11_FUNCTION_INFO(C_VerifyInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ ++ CK_OBJECT_HANDLE hKey /* verification key */ ++); ++#endif ++ ++ ++/* C_Verify verifies a signature in a single-part operation, ++ * where the signature is an appendix to the data, and plaintext ++ * cannot be recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_Verify) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pData, /* signed data */ ++ CK_ULONG ulDataLen, /* length of signed data */ ++ CK_BYTE_PTR pSignature, /* signature */ ++ CK_ULONG ulSignatureLen /* signature length*/ ++); ++#endif ++ ++ ++/* C_VerifyUpdate continues a multiple-part verification ++ * operation, where the signature is an appendix to the data, ++ * and plaintext cannot be recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_VerifyUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pPart, /* signed data */ ++ CK_ULONG ulPartLen /* length of signed data */ ++); ++#endif ++ ++ ++/* C_VerifyFinal finishes a multiple-part verification ++ * operation, checking the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_VerifyFinal) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pSignature, /* signature to verify */ ++ CK_ULONG ulSignatureLen /* signature length */ ++); ++#endif ++ ++ ++/* C_VerifyRecoverInit initializes a signature verification ++ * operation, where the data is recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_VerifyRecoverInit) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the verification mechanism */ ++ CK_OBJECT_HANDLE hKey /* verification key */ ++); ++#endif ++ ++ ++/* C_VerifyRecover verifies a signature in a single-part ++ * operation, where the data is recovered from the signature. */ ++CK_PKCS11_FUNCTION_INFO(C_VerifyRecover) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pSignature, /* signature to verify */ ++ CK_ULONG ulSignatureLen, /* signature length */ ++ CK_BYTE_PTR pData, /* gets signed data */ ++ CK_ULONG_PTR pulDataLen /* gets signed data len */ ++); ++#endif ++ ++ ++ ++/* Dual-function cryptographic operations */ ++ ++/* C_DigestEncryptUpdate continues a multiple-part digesting ++ * and encryption operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DigestEncryptUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pPart, /* the plaintext data */ ++ CK_ULONG ulPartLen, /* plaintext length */ ++ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ ++ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ ++); ++#endif ++ ++ ++/* C_DecryptDigestUpdate continues a multiple-part decryption and ++ * digesting operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DecryptDigestUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pEncryptedPart, /* ciphertext */ ++ CK_ULONG ulEncryptedPartLen, /* ciphertext length */ ++ CK_BYTE_PTR pPart, /* gets plaintext */ ++ CK_ULONG_PTR pulPartLen /* gets plaintext len */ ++); ++#endif ++ ++ ++/* C_SignEncryptUpdate continues a multiple-part signing and ++ * encryption operation. */ ++CK_PKCS11_FUNCTION_INFO(C_SignEncryptUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pPart, /* the plaintext data */ ++ CK_ULONG ulPartLen, /* plaintext length */ ++ CK_BYTE_PTR pEncryptedPart, /* gets ciphertext */ ++ CK_ULONG_PTR pulEncryptedPartLen /* gets c-text length */ ++); ++#endif ++ ++ ++/* C_DecryptVerifyUpdate continues a multiple-part decryption and ++ * verify operation. */ ++CK_PKCS11_FUNCTION_INFO(C_DecryptVerifyUpdate) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_BYTE_PTR pEncryptedPart, /* ciphertext */ ++ CK_ULONG ulEncryptedPartLen, /* ciphertext length */ ++ CK_BYTE_PTR pPart, /* gets plaintext */ ++ CK_ULONG_PTR pulPartLen /* gets p-text length */ ++); ++#endif ++ ++ ++ ++/* Key management */ ++ ++/* C_GenerateKey generates a secret key, creating a new key ++ * object. */ ++CK_PKCS11_FUNCTION_INFO(C_GenerateKey) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* key generation mech. */ ++ CK_ATTRIBUTE_PTR pTemplate, /* template for new key */ ++ CK_ULONG ulCount, /* # of attrs in template */ ++ CK_OBJECT_HANDLE_PTR phKey /* gets handle of new key */ ++); ++#endif ++ ++ ++/* C_GenerateKeyPair generates a public-key/private-key pair, ++ * creating new key objects. */ ++CK_PKCS11_FUNCTION_INFO(C_GenerateKeyPair) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session ++ * handle */ ++ CK_MECHANISM_PTR pMechanism, /* key-gen ++ * mech. */ ++ CK_ATTRIBUTE_PTR pPublicKeyTemplate, /* template ++ * for pub. ++ * key */ ++ CK_ULONG ulPublicKeyAttributeCount, /* # pub. ++ * attrs. */ ++ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, /* template ++ * for priv. ++ * key */ ++ CK_ULONG ulPrivateKeyAttributeCount, /* # priv. ++ * attrs. */ ++ CK_OBJECT_HANDLE_PTR phPublicKey, /* gets pub. ++ * key ++ * handle */ ++ CK_OBJECT_HANDLE_PTR phPrivateKey /* gets ++ * priv. key ++ * handle */ ++); ++#endif ++ ++ ++/* C_WrapKey wraps (i.e., encrypts) a key. */ ++CK_PKCS11_FUNCTION_INFO(C_WrapKey) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* the wrapping mechanism */ ++ CK_OBJECT_HANDLE hWrappingKey, /* wrapping key */ ++ CK_OBJECT_HANDLE hKey, /* key to be wrapped */ ++ CK_BYTE_PTR pWrappedKey, /* gets wrapped key */ ++ CK_ULONG_PTR pulWrappedKeyLen /* gets wrapped key size */ ++); ++#endif ++ ++ ++/* C_UnwrapKey unwraps (decrypts) a wrapped key, creating a new ++ * key object. */ ++CK_PKCS11_FUNCTION_INFO(C_UnwrapKey) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* unwrapping mech. */ ++ CK_OBJECT_HANDLE hUnwrappingKey, /* unwrapping key */ ++ CK_BYTE_PTR pWrappedKey, /* the wrapped key */ ++ CK_ULONG ulWrappedKeyLen, /* wrapped key len */ ++ CK_ATTRIBUTE_PTR pTemplate, /* new key template */ ++ CK_ULONG ulAttributeCount, /* template length */ ++ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ ++); ++#endif ++ ++ ++/* C_DeriveKey derives a key from a base key, creating a new key ++ * object. */ ++CK_PKCS11_FUNCTION_INFO(C_DeriveKey) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* session's handle */ ++ CK_MECHANISM_PTR pMechanism, /* key deriv. mech. */ ++ CK_OBJECT_HANDLE hBaseKey, /* base key */ ++ CK_ATTRIBUTE_PTR pTemplate, /* new key template */ ++ CK_ULONG ulAttributeCount, /* template length */ ++ CK_OBJECT_HANDLE_PTR phKey /* gets new handle */ ++); ++#endif ++ ++ ++ ++/* Random number generation */ ++ ++/* C_SeedRandom mixes additional seed material into the token's ++ * random number generator. */ ++CK_PKCS11_FUNCTION_INFO(C_SeedRandom) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR pSeed, /* the seed material */ ++ CK_ULONG ulSeedLen /* length of seed material */ ++); ++#endif ++ ++ ++/* C_GenerateRandom generates random data. */ ++CK_PKCS11_FUNCTION_INFO(C_GenerateRandom) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_BYTE_PTR RandomData, /* receives the random data */ ++ CK_ULONG ulRandomLen /* # of bytes to generate */ ++); ++#endif ++ ++ ++ ++/* Parallel function management */ ++ ++/* C_GetFunctionStatus is a legacy function; it obtains an ++ * updated status of a function running in parallel with an ++ * application. */ ++CK_PKCS11_FUNCTION_INFO(C_GetFunctionStatus) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession /* the session's handle */ ++); ++#endif ++ ++ ++/* C_CancelFunction is a legacy function; it cancels a function ++ * running in parallel. */ ++CK_PKCS11_FUNCTION_INFO(C_CancelFunction) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_SESSION_HANDLE hSession /* the session's handle */ ++); ++#endif ++ ++ ++ ++/* Functions added in for Cryptoki Version 2.01 or later */ ++ ++/* C_WaitForSlotEvent waits for a slot event (token insertion, ++ * removal, etc.) to occur. */ ++CK_PKCS11_FUNCTION_INFO(C_WaitForSlotEvent) ++#ifdef CK_NEED_ARG_LIST ++( ++ CK_FLAGS flags, /* blocking/nonblocking flag */ ++ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ ++ CK_VOID_PTR pRserved /* reserved. Should be NULL_PTR */ ++); ++#endif +diff --git a/lib/isc/include/pkcs11/pkcs11t.h b/lib/isc/include/pkcs11/pkcs11t.h +new file mode 100644 +index 0000000..92a80bb +--- /dev/null ++++ b/lib/isc/include/pkcs11/pkcs11t.h +@@ -0,0 +1,1977 @@ ++/* pkcs11t.h include file for PKCS #11. */ ++/* $Revision: 1.2 $ */ ++ ++/* License to copy and use this software is granted provided that it is ++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface ++ * (Cryptoki)" in all material mentioning or referencing this software. ++ ++ * License is also granted to make and use derivative works provided that ++ * such works are identified as "derived from the RSA Security Inc. PKCS #11 ++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or ++ * referencing the derived work. ++ ++ * RSA Security Inc. makes no representations concerning either the ++ * merchantability of this software or the suitability of this software for ++ * any particular purpose. It is provided "as is" without express or implied ++ * warranty of any kind. ++ */ ++ ++/* See top of pkcs11.h for information about the macros that ++ * must be defined and the structure-packing conventions that ++ * must be set before including this file. */ ++ ++#ifndef _PKCS11T_H_ ++#define _PKCS11T_H_ 1 ++ ++#define CRYPTOKI_VERSION_MAJOR 2 ++#define CRYPTOKI_VERSION_MINOR 30 ++#define CRYPTOKI_VERSION_REVISION 0 ++#define CRYPTOKI_VERSION_AMENDMENT 0 ++ ++#define CK_TRUE 1 ++#define CK_FALSE 0 ++ ++#ifndef CK_DISABLE_TRUE_FALSE ++#ifndef FALSE ++#define FALSE CK_FALSE ++#endif ++ ++#ifndef TRUE ++#define TRUE CK_TRUE ++#endif ++#endif ++ ++/* an unsigned 8-bit value */ ++typedef unsigned char CK_BYTE; ++ ++/* an unsigned 8-bit character */ ++typedef CK_BYTE CK_CHAR; ++ ++/* an 8-bit UTF-8 character */ ++typedef CK_BYTE CK_UTF8CHAR; ++ ++/* a BYTE-sized Boolean flag */ ++typedef CK_BYTE CK_BBOOL; ++ ++/* an unsigned value, at least 32 bits long */ ++typedef unsigned long int CK_ULONG; ++ ++/* a signed value, the same size as a CK_ULONG */ ++/* CK_LONG is new for v2.0 */ ++typedef long int CK_LONG; ++ ++/* at least 32 bits; each bit is a Boolean flag */ ++typedef CK_ULONG CK_FLAGS; ++ ++ ++/* some special values for certain CK_ULONG variables */ ++#define CK_UNAVAILABLE_INFORMATION (~0UL) ++#define CK_EFFECTIVELY_INFINITE 0 ++ ++ ++typedef CK_BYTE CK_PTR CK_BYTE_PTR; ++typedef CK_CHAR CK_PTR CK_CHAR_PTR; ++typedef CK_UTF8CHAR CK_PTR CK_UTF8CHAR_PTR; ++typedef CK_ULONG CK_PTR CK_ULONG_PTR; ++typedef void CK_PTR CK_VOID_PTR; ++ ++/* Pointer to a CK_VOID_PTR-- i.e., pointer to pointer to void */ ++typedef CK_VOID_PTR CK_PTR CK_VOID_PTR_PTR; ++ ++ ++/* The following value is always invalid if used as a session */ ++/* handle or object handle */ ++#define CK_INVALID_HANDLE 0 ++ ++ ++typedef struct CK_VERSION { ++ CK_BYTE major; /* integer portion of version number */ ++ CK_BYTE minor; /* 1/100ths portion of version number */ ++} CK_VERSION; ++ ++typedef CK_VERSION CK_PTR CK_VERSION_PTR; ++ ++ ++typedef struct CK_INFO { ++ /* manufacturerID and libraryDecription have been changed from ++ * CK_CHAR to CK_UTF8CHAR for v2.10 */ ++ CK_VERSION cryptokiVersion; /* Cryptoki interface ver */ ++ CK_UTF8CHAR manufacturerID[32]; /* blank padded */ ++ CK_FLAGS flags; /* must be zero */ ++ ++ /* libraryDescription and libraryVersion are new for v2.0 */ ++ CK_UTF8CHAR libraryDescription[32]; /* blank padded */ ++ CK_VERSION libraryVersion; /* version of library */ ++} CK_INFO; ++ ++typedef CK_INFO CK_PTR CK_INFO_PTR; ++ ++ ++/* CK_NOTIFICATION enumerates the types of notifications that ++ * Cryptoki provides to an application */ ++/* CK_NOTIFICATION has been changed from an enum to a CK_ULONG ++ * for v2.0 */ ++typedef CK_ULONG CK_NOTIFICATION; ++#define CKN_SURRENDER 0 ++ ++/* The following notification is new for PKCS #11 v2.20 amendment 3 */ ++#define CKN_OTP_CHANGED 1 ++ ++ ++typedef CK_ULONG CK_SLOT_ID; ++ ++typedef CK_SLOT_ID CK_PTR CK_SLOT_ID_PTR; ++ ++ ++/* CK_SLOT_INFO provides information about a slot */ ++typedef struct CK_SLOT_INFO { ++ /* slotDescription and manufacturerID have been changed from ++ * CK_CHAR to CK_UTF8CHAR for v2.10 */ ++ CK_UTF8CHAR slotDescription[64]; /* blank padded */ ++ CK_UTF8CHAR manufacturerID[32]; /* blank padded */ ++ CK_FLAGS flags; ++ ++ /* hardwareVersion and firmwareVersion are new for v2.0 */ ++ CK_VERSION hardwareVersion; /* version of hardware */ ++ CK_VERSION firmwareVersion; /* version of firmware */ ++} CK_SLOT_INFO; ++ ++/* flags: bit flags that provide capabilities of the slot ++ * Bit Flag Mask Meaning ++ */ ++#define CKF_TOKEN_PRESENT 0x00000001 /* a token is there */ ++#define CKF_REMOVABLE_DEVICE 0x00000002 /* removable devices*/ ++#define CKF_HW_SLOT 0x00000004 /* hardware slot */ ++ ++typedef CK_SLOT_INFO CK_PTR CK_SLOT_INFO_PTR; ++ ++ ++/* CK_TOKEN_INFO provides information about a token */ ++typedef struct CK_TOKEN_INFO { ++ /* label, manufacturerID, and model have been changed from ++ * CK_CHAR to CK_UTF8CHAR for v2.10 */ ++ CK_UTF8CHAR label[32]; /* blank padded */ ++ CK_UTF8CHAR manufacturerID[32]; /* blank padded */ ++ CK_UTF8CHAR model[16]; /* blank padded */ ++ CK_CHAR serialNumber[16]; /* blank padded */ ++ CK_FLAGS flags; /* see below */ ++ ++ /* ulMaxSessionCount, ulSessionCount, ulMaxRwSessionCount, ++ * ulRwSessionCount, ulMaxPinLen, and ulMinPinLen have all been ++ * changed from CK_USHORT to CK_ULONG for v2.0 */ ++ CK_ULONG ulMaxSessionCount; /* max open sessions */ ++ CK_ULONG ulSessionCount; /* sess. now open */ ++ CK_ULONG ulMaxRwSessionCount; /* max R/W sessions */ ++ CK_ULONG ulRwSessionCount; /* R/W sess. now open */ ++ CK_ULONG ulMaxPinLen; /* in bytes */ ++ CK_ULONG ulMinPinLen; /* in bytes */ ++ CK_ULONG ulTotalPublicMemory; /* in bytes */ ++ CK_ULONG ulFreePublicMemory; /* in bytes */ ++ CK_ULONG ulTotalPrivateMemory; /* in bytes */ ++ CK_ULONG ulFreePrivateMemory; /* in bytes */ ++ ++ /* hardwareVersion, firmwareVersion, and time are new for ++ * v2.0 */ ++ CK_VERSION hardwareVersion; /* version of hardware */ ++ CK_VERSION firmwareVersion; /* version of firmware */ ++ CK_CHAR utcTime[16]; /* time */ ++} CK_TOKEN_INFO; ++ ++/* The flags parameter is defined as follows: ++ * Bit Flag Mask Meaning ++ */ ++#define CKF_RNG 0x00000001 /* has random # ++ * generator */ ++#define CKF_WRITE_PROTECTED 0x00000002 /* token is ++ * write- ++ * protected */ ++#define CKF_LOGIN_REQUIRED 0x00000004 /* user must ++ * login */ ++#define CKF_USER_PIN_INITIALIZED 0x00000008 /* normal user's ++ * PIN is set */ ++ ++/* CKF_RESTORE_KEY_NOT_NEEDED is new for v2.0. If it is set, ++ * that means that *every* time the state of cryptographic ++ * operations of a session is successfully saved, all keys ++ * needed to continue those operations are stored in the state */ ++#define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020 ++ ++/* CKF_CLOCK_ON_TOKEN is new for v2.0. If it is set, that means ++ * that the token has some sort of clock. The time on that ++ * clock is returned in the token info structure */ ++#define CKF_CLOCK_ON_TOKEN 0x00000040 ++ ++/* CKF_PROTECTED_AUTHENTICATION_PATH is new for v2.0. If it is ++ * set, that means that there is some way for the user to login ++ * without sending a PIN through the Cryptoki library itself */ ++#define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100 ++ ++/* CKF_DUAL_CRYPTO_OPERATIONS is new for v2.0. If it is true, ++ * that means that a single session with the token can perform ++ * dual simultaneous cryptographic operations (digest and ++ * encrypt; decrypt and digest; sign and encrypt; and decrypt ++ * and sign) */ ++#define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200 ++ ++/* CKF_TOKEN_INITIALIZED if new for v2.10. If it is true, the ++ * token has been initialized using C_InitializeToken or an ++ * equivalent mechanism outside the scope of PKCS #11. ++ * Calling C_InitializeToken when this flag is set will cause ++ * the token to be reinitialized. */ ++#define CKF_TOKEN_INITIALIZED 0x00000400 ++ ++/* CKF_SECONDARY_AUTHENTICATION if new for v2.10. If it is ++ * true, the token supports secondary authentication for ++ * private key objects. This flag is deprecated in v2.11 and ++ onwards. */ ++#define CKF_SECONDARY_AUTHENTICATION 0x00000800 ++ ++/* CKF_USER_PIN_COUNT_LOW if new for v2.10. If it is true, an ++ * incorrect user login PIN has been entered at least once ++ * since the last successful authentication. */ ++#define CKF_USER_PIN_COUNT_LOW 0x00010000 ++ ++/* CKF_USER_PIN_FINAL_TRY if new for v2.10. If it is true, ++ * supplying an incorrect user PIN will it to become locked. */ ++#define CKF_USER_PIN_FINAL_TRY 0x00020000 ++ ++/* CKF_USER_PIN_LOCKED if new for v2.10. If it is true, the ++ * user PIN has been locked. User login to the token is not ++ * possible. */ ++#define CKF_USER_PIN_LOCKED 0x00040000 ++ ++/* CKF_USER_PIN_TO_BE_CHANGED if new for v2.10. If it is true, ++ * the user PIN value is the default value set by token ++ * initialization or manufacturing, or the PIN has been ++ * expired by the card. */ ++#define CKF_USER_PIN_TO_BE_CHANGED 0x00080000 ++ ++/* CKF_SO_PIN_COUNT_LOW if new for v2.10. If it is true, an ++ * incorrect SO login PIN has been entered at least once since ++ * the last successful authentication. */ ++#define CKF_SO_PIN_COUNT_LOW 0x00100000 ++ ++/* CKF_SO_PIN_FINAL_TRY if new for v2.10. If it is true, ++ * supplying an incorrect SO PIN will it to become locked. */ ++#define CKF_SO_PIN_FINAL_TRY 0x00200000 ++ ++/* CKF_SO_PIN_LOCKED if new for v2.10. If it is true, the SO ++ * PIN has been locked. SO login to the token is not possible. ++ */ ++#define CKF_SO_PIN_LOCKED 0x00400000 ++ ++/* CKF_SO_PIN_TO_BE_CHANGED if new for v2.10. If it is true, ++ * the SO PIN value is the default value set by token ++ * initialization or manufacturing, or the PIN has been ++ * expired by the card. */ ++#define CKF_SO_PIN_TO_BE_CHANGED 0x00800000 ++ ++/* CKF_ERROR_STATE if new for v2.30. If it is true, ++ * the token failed a FIPS 140-2 self-test and ++ * entered an error state. */ ++#define CKF_ERROR_STATE 0x01000000 ++ ++typedef CK_TOKEN_INFO CK_PTR CK_TOKEN_INFO_PTR; ++ ++ ++/* CK_SESSION_HANDLE is a Cryptoki-assigned value that ++ * identifies a session */ ++typedef CK_ULONG CK_SESSION_HANDLE; ++ ++typedef CK_SESSION_HANDLE CK_PTR CK_SESSION_HANDLE_PTR; ++ ++ ++/* CK_USER_TYPE enumerates the types of Cryptoki users */ ++/* CK_USER_TYPE has been changed from an enum to a CK_ULONG for ++ * v2.0 */ ++typedef CK_ULONG CK_USER_TYPE; ++/* Security Officer */ ++#define CKU_SO 0 ++/* Normal user */ ++#define CKU_USER 1 ++/* Context specific (added in v2.20) */ ++#define CKU_CONTEXT_SPECIFIC 2 ++ ++/* CK_STATE enumerates the session states */ ++/* CK_STATE has been changed from an enum to a CK_ULONG for ++ * v2.0 */ ++typedef CK_ULONG CK_STATE; ++#define CKS_RO_PUBLIC_SESSION 0 ++#define CKS_RO_USER_FUNCTIONS 1 ++#define CKS_RW_PUBLIC_SESSION 2 ++#define CKS_RW_USER_FUNCTIONS 3 ++#define CKS_RW_SO_FUNCTIONS 4 ++ ++ ++/* CK_SESSION_INFO provides information about a session */ ++typedef struct CK_SESSION_INFO { ++ CK_SLOT_ID slotID; ++ CK_STATE state; ++ CK_FLAGS flags; /* see below */ ++ ++ /* ulDeviceError was changed from CK_USHORT to CK_ULONG for ++ * v2.0 */ ++ CK_ULONG ulDeviceError; /* device-dependent error code */ ++} CK_SESSION_INFO; ++ ++/* The flags are defined in the following table: ++ * Bit Flag Mask Meaning ++ */ ++#define CKF_RW_SESSION 0x00000002 /* session is r/w */ ++#define CKF_SERIAL_SESSION 0x00000004 /* no parallel */ ++ ++typedef CK_SESSION_INFO CK_PTR CK_SESSION_INFO_PTR; ++ ++ ++/* CK_OBJECT_HANDLE is a token-specific identifier for an ++ * object */ ++typedef CK_ULONG CK_OBJECT_HANDLE; ++ ++typedef CK_OBJECT_HANDLE CK_PTR CK_OBJECT_HANDLE_PTR; ++ ++ ++/* CK_OBJECT_CLASS is a value that identifies the classes (or ++ * types) of objects that Cryptoki recognizes. It is defined ++ * as follows: */ ++/* CK_OBJECT_CLASS was changed from CK_USHORT to CK_ULONG for ++ * v2.0 */ ++typedef CK_ULONG CK_OBJECT_CLASS; ++ ++/* The following classes of objects are defined: */ ++/* CKO_HW_FEATURE is new for v2.10 */ ++/* CKO_DOMAIN_PARAMETERS is new for v2.11 */ ++/* CKO_MECHANISM is new for v2.20 */ ++#define CKO_DATA 0x00000000 ++#define CKO_CERTIFICATE 0x00000001 ++#define CKO_PUBLIC_KEY 0x00000002 ++#define CKO_PRIVATE_KEY 0x00000003 ++#define CKO_SECRET_KEY 0x00000004 ++#define CKO_HW_FEATURE 0x00000005 ++#define CKO_DOMAIN_PARAMETERS 0x00000006 ++#define CKO_MECHANISM 0x00000007 ++ ++/* CKO_OTP_KEY is new for PKCS #11 v2.20 amendment 1 */ ++#define CKO_OTP_KEY 0x00000008 ++ ++#define CKO_VENDOR_DEFINED 0x80000000 ++ ++typedef CK_OBJECT_CLASS CK_PTR CK_OBJECT_CLASS_PTR; ++ ++/* CK_HW_FEATURE_TYPE is new for v2.10. CK_HW_FEATURE_TYPE is a ++ * value that identifies the hardware feature type of an object ++ * with CK_OBJECT_CLASS equal to CKO_HW_FEATURE. */ ++typedef CK_ULONG CK_HW_FEATURE_TYPE; ++ ++/* The following hardware feature types are defined */ ++/* CKH_USER_INTERFACE is new for v2.20 */ ++#define CKH_MONOTONIC_COUNTER 0x00000001 ++#define CKH_CLOCK 0x00000002 ++#define CKH_USER_INTERFACE 0x00000003 ++#define CKH_VENDOR_DEFINED 0x80000000 ++ ++/* CK_KEY_TYPE is a value that identifies a key type */ ++/* CK_KEY_TYPE was changed from CK_USHORT to CK_ULONG for v2.0 */ ++typedef CK_ULONG CK_KEY_TYPE; ++ ++/* the following key types are defined: */ ++#define CKK_RSA 0x00000000 ++#define CKK_DSA 0x00000001 ++#define CKK_DH 0x00000002 ++ ++/* CKK_ECDSA and CKK_KEA are new for v2.0 */ ++/* CKK_ECDSA is deprecated in v2.11, CKK_EC is preferred. */ ++#define CKK_ECDSA 0x00000003 ++#define CKK_EC 0x00000003 ++#define CKK_X9_42_DH 0x00000004 ++#define CKK_KEA 0x00000005 ++ ++#define CKK_GENERIC_SECRET 0x00000010 ++#define CKK_RC2 0x00000011 ++#define CKK_RC4 0x00000012 ++#define CKK_DES 0x00000013 ++#define CKK_DES2 0x00000014 ++#define CKK_DES3 0x00000015 ++ ++/* all these key types are new for v2.0 */ ++#define CKK_CAST 0x00000016 ++#define CKK_CAST3 0x00000017 ++/* CKK_CAST5 is deprecated in v2.11, CKK_CAST128 is preferred. */ ++#define CKK_CAST5 0x00000018 ++#define CKK_CAST128 0x00000018 ++#define CKK_RC5 0x00000019 ++#define CKK_IDEA 0x0000001A ++#define CKK_SKIPJACK 0x0000001B ++#define CKK_BATON 0x0000001C ++#define CKK_JUNIPER 0x0000001D ++#define CKK_CDMF 0x0000001E ++#define CKK_AES 0x0000001F ++ ++/* BlowFish and TwoFish are new for v2.20 */ ++#define CKK_BLOWFISH 0x00000020 ++#define CKK_TWOFISH 0x00000021 ++ ++/* SecurID, HOTP, and ACTI are new for PKCS #11 v2.20 amendment 1 */ ++#define CKK_SECURID 0x00000022 ++#define CKK_HOTP 0x00000023 ++#define CKK_ACTI 0x00000024 ++ ++/* Camellia is new for PKCS #11 v2.20 amendment 3 */ ++#define CKK_CAMELLIA 0x00000025 ++/* ARIA is new for PKCS #11 v2.20 amendment 3 */ ++#define CKK_ARIA 0x00000026 ++ ++/* From PKCS #11 v2.20 amendment 4 draft 2 */ ++#define CKK_MD5_HMAC 0x00000027 ++#define CKK_SHA_1_HMAC 0x00000028 ++#define CKK_RIPEMD128_HMAC 0x00000029 ++#define CKK_RIPEMD160_HMAC 0x0000002A ++#define CKK_SHA256_HMAC 0x0000002B ++#define CKK_SHA384_HMAC 0x0000002C ++#define CKK_SHA512_HMAC 0x0000002D ++#define CKK_SHA224_HMAC 0x0000002E ++ ++/* From PKCS #11 v2.30 */ ++#define CKK_SEED 0x0000002F ++#define CKK_GOSTR3410 0x00000030 ++#define CKK_GOSTR3411 0x00000031 ++#define CKK_GOST28147 0x00000032 ++ ++#define CKK_VENDOR_DEFINED 0x80000000 ++ ++ ++/* CK_CERTIFICATE_TYPE is a value that identifies a certificate ++ * type */ ++/* CK_CERTIFICATE_TYPE was changed from CK_USHORT to CK_ULONG ++ * for v2.0 */ ++typedef CK_ULONG CK_CERTIFICATE_TYPE; ++ ++/* The following certificate types are defined: */ ++/* CKC_X_509_ATTR_CERT is new for v2.10 */ ++/* CKC_WTLS is new for v2.20 */ ++#define CKC_X_509 0x00000000 ++#define CKC_X_509_ATTR_CERT 0x00000001 ++#define CKC_WTLS 0x00000002 ++#define CKC_VENDOR_DEFINED 0x80000000 ++ ++ ++/* CK_ATTRIBUTE_TYPE is a value that identifies an attribute ++ * type */ ++/* CK_ATTRIBUTE_TYPE was changed from CK_USHORT to CK_ULONG for ++ * v2.0 */ ++typedef CK_ULONG CK_ATTRIBUTE_TYPE; ++ ++/* The CKF_ARRAY_ATTRIBUTE flag identifies an attribute which ++ consists of an array of values. */ ++#define CKF_ARRAY_ATTRIBUTE 0x40000000 ++ ++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1 ++ and relates to the CKA_OTP_FORMAT attribute */ ++#define CK_OTP_FORMAT_DECIMAL 0 ++#define CK_OTP_FORMAT_HEXADECIMAL 1 ++#define CK_OTP_FORMAT_ALPHANUMERIC 2 ++#define CK_OTP_FORMAT_BINARY 3 ++ ++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1 ++ and relates to the CKA_OTP_..._REQUIREMENT attributes */ ++#define CK_OTP_PARAM_IGNORED 0 ++#define CK_OTP_PARAM_OPTIONAL 1 ++#define CK_OTP_PARAM_MANDATORY 2 ++ ++/* The following attribute types are defined: */ ++#define CKA_CLASS 0x00000000 ++#define CKA_TOKEN 0x00000001 ++#define CKA_PRIVATE 0x00000002 ++#define CKA_LABEL 0x00000003 ++#define CKA_APPLICATION 0x00000010 ++#define CKA_VALUE 0x00000011 ++ ++/* CKA_OBJECT_ID is new for v2.10 */ ++#define CKA_OBJECT_ID 0x00000012 ++ ++#define CKA_CERTIFICATE_TYPE 0x00000080 ++#define CKA_ISSUER 0x00000081 ++#define CKA_SERIAL_NUMBER 0x00000082 ++ ++/* CKA_AC_ISSUER, CKA_OWNER, and CKA_ATTR_TYPES are new ++ * for v2.10 */ ++#define CKA_AC_ISSUER 0x00000083 ++#define CKA_OWNER 0x00000084 ++#define CKA_ATTR_TYPES 0x00000085 ++ ++/* CKA_TRUSTED is new for v2.11 */ ++#define CKA_TRUSTED 0x00000086 ++ ++/* CKA_CERTIFICATE_CATEGORY ... ++ * CKA_CHECK_VALUE are new for v2.20 */ ++#define CKA_CERTIFICATE_CATEGORY 0x00000087 ++#define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088 ++#define CKA_URL 0x00000089 ++#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008A ++#define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008B ++/* One from v2.30? */ ++#define CKA_NAME_HASH_ALGORITH 0x0000008C ++#define CKA_CHECK_VALUE 0x00000090 ++ ++#define CKA_KEY_TYPE 0x00000100 ++#define CKA_SUBJECT 0x00000101 ++#define CKA_ID 0x00000102 ++#define CKA_SENSITIVE 0x00000103 ++#define CKA_ENCRYPT 0x00000104 ++#define CKA_DECRYPT 0x00000105 ++#define CKA_WRAP 0x00000106 ++#define CKA_UNWRAP 0x00000107 ++#define CKA_SIGN 0x00000108 ++#define CKA_SIGN_RECOVER 0x00000109 ++#define CKA_VERIFY 0x0000010A ++#define CKA_VERIFY_RECOVER 0x0000010B ++#define CKA_DERIVE 0x0000010C ++#define CKA_START_DATE 0x00000110 ++#define CKA_END_DATE 0x00000111 ++#define CKA_MODULUS 0x00000120 ++#define CKA_MODULUS_BITS 0x00000121 ++#define CKA_PUBLIC_EXPONENT 0x00000122 ++#define CKA_PRIVATE_EXPONENT 0x00000123 ++#define CKA_PRIME_1 0x00000124 ++#define CKA_PRIME_2 0x00000125 ++#define CKA_EXPONENT_1 0x00000126 ++#define CKA_EXPONENT_2 0x00000127 ++#define CKA_COEFFICIENT 0x00000128 ++#define CKA_PRIME 0x00000130 ++#define CKA_SUBPRIME 0x00000131 ++#define CKA_BASE 0x00000132 ++ ++/* CKA_PRIME_BITS and CKA_SUB_PRIME_BITS are new for v2.11 */ ++#define CKA_PRIME_BITS 0x00000133 ++#define CKA_SUBPRIME_BITS 0x00000134 ++#define CKA_SUB_PRIME_BITS CKA_SUBPRIME_BITS ++/* (To retain backwards-compatibility) */ ++ ++#define CKA_VALUE_BITS 0x00000160 ++#define CKA_VALUE_LEN 0x00000161 ++ ++/* CKA_EXTRACTABLE, CKA_LOCAL, CKA_NEVER_EXTRACTABLE, ++ * CKA_ALWAYS_SENSITIVE, CKA_MODIFIABLE, CKA_ECDSA_PARAMS, ++ * and CKA_EC_POINT are new for v2.0 */ ++#define CKA_EXTRACTABLE 0x00000162 ++#define CKA_LOCAL 0x00000163 ++#define CKA_NEVER_EXTRACTABLE 0x00000164 ++#define CKA_ALWAYS_SENSITIVE 0x00000165 ++ ++/* CKA_KEY_GEN_MECHANISM is new for v2.11 */ ++#define CKA_KEY_GEN_MECHANISM 0x00000166 ++ ++#define CKA_MODIFIABLE 0x00000170 ++ ++/* From v2.30? */ ++#define CKA_COPYABLE 0x00000171 ++ ++/* CKA_ECDSA_PARAMS is deprecated in v2.11, ++ * CKA_EC_PARAMS is preferred. */ ++#define CKA_ECDSA_PARAMS 0x00000180 ++#define CKA_EC_PARAMS 0x00000180 ++ ++#define CKA_EC_POINT 0x00000181 ++ ++/* CKA_SECONDARY_AUTH, CKA_AUTH_PIN_FLAGS, ++ * are new for v2.10. Deprecated in v2.11 and onwards. */ ++#define CKA_SECONDARY_AUTH 0x00000200 ++#define CKA_AUTH_PIN_FLAGS 0x00000201 ++ ++/* CKA_ALWAYS_AUTHENTICATE ... ++ * CKA_UNWRAP_TEMPLATE are new for v2.20 */ ++#define CKA_ALWAYS_AUTHENTICATE 0x00000202 ++ ++#define CKA_WRAP_WITH_TRUSTED 0x00000210 ++#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211) ++#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212) ++ ++/* CKA_OTP... atttributes are new for PKCS #11 v2.20 amendment 3. */ ++#define CKA_OTP_FORMAT 0x00000220 ++#define CKA_OTP_LENGTH 0x00000221 ++#define CKA_OTP_TIME_INTERVAL 0x00000222 ++#define CKA_OTP_USER_FRIENDLY_MODE 0x00000223 ++#define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224 ++#define CKA_OTP_TIME_REQUIREMENT 0x00000225 ++#define CKA_OTP_COUNTER_REQUIREMENT 0x00000226 ++#define CKA_OTP_PIN_REQUIREMENT 0x00000227 ++#define CKA_OTP_COUNTER 0x0000022E ++#define CKA_OTP_TIME 0x0000022F ++#define CKA_OTP_USER_IDENTIFIER 0x0000022A ++#define CKA_OTP_SERVICE_IDENTIFIER 0x0000022B ++#define CKA_OTP_SERVICE_LOGO 0x0000022C ++#define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022D ++ ++/* CKA_GOST... */ ++#define CKA_GOSTR3410_PARAMS 0x00000250 ++#define CKA_GOSTR3411_PARAMS 0x00000251 ++#define CKA_GOST28147_PARAMS 0x00000252 ++ ++/* CKA_HW_FEATURE_TYPE, CKA_RESET_ON_INIT, and CKA_HAS_RESET ++ * are new for v2.10 */ ++#define CKA_HW_FEATURE_TYPE 0x00000300 ++#define CKA_RESET_ON_INIT 0x00000301 ++#define CKA_HAS_RESET 0x00000302 ++ ++/* The following attributes are new for v2.20 */ ++#define CKA_PIXEL_X 0x00000400 ++#define CKA_PIXEL_Y 0x00000401 ++#define CKA_RESOLUTION 0x00000402 ++#define CKA_CHAR_ROWS 0x00000403 ++#define CKA_CHAR_COLUMNS 0x00000404 ++#define CKA_COLOR 0x00000405 ++#define CKA_BITS_PER_PIXEL 0x00000406 ++#define CKA_CHAR_SETS 0x00000480 ++#define CKA_ENCODING_METHODS 0x00000481 ++#define CKA_MIME_TYPES 0x00000482 ++#define CKA_MECHANISM_TYPE 0x00000500 ++#define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501 ++#define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502 ++#define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503 ++#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE|0x00000600) ++/* From v2.30? */ ++#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000211) ++#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000212) ++#define CKA_DERIVE_TEMPLATE (CKF_ARRAY_ATTRIBUTE|0x00000213) ++ ++#define CKA_VENDOR_DEFINED 0x80000000 ++ ++/* CK_ATTRIBUTE is a structure that includes the type, length ++ * and value of an attribute */ ++typedef struct CK_ATTRIBUTE { ++ CK_ATTRIBUTE_TYPE type; ++ CK_VOID_PTR pValue; ++ ++ /* ulValueLen went from CK_USHORT to CK_ULONG for v2.0 */ ++ CK_ULONG ulValueLen; /* in bytes */ ++} CK_ATTRIBUTE; ++ ++typedef CK_ATTRIBUTE CK_PTR CK_ATTRIBUTE_PTR; ++ ++ ++/* CK_DATE is a structure that defines a date */ ++typedef struct CK_DATE{ ++ CK_CHAR year[4]; /* the year ("1900" - "9999") */ ++ CK_CHAR month[2]; /* the month ("01" - "12") */ ++ CK_CHAR day[2]; /* the day ("01" - "31") */ ++} CK_DATE; ++ ++ ++/* CK_MECHANISM_TYPE is a value that identifies a mechanism ++ * type */ ++/* CK_MECHANISM_TYPE was changed from CK_USHORT to CK_ULONG for ++ * v2.0 */ ++typedef CK_ULONG CK_MECHANISM_TYPE; ++ ++/* the following mechanism types are defined: */ ++#define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000 ++#define CKM_RSA_PKCS 0x00000001 ++#define CKM_RSA_9796 0x00000002 ++#define CKM_RSA_X_509 0x00000003 ++ ++/* CKM_MD2_RSA_PKCS, CKM_MD5_RSA_PKCS, and CKM_SHA1_RSA_PKCS ++ * are new for v2.0. They are mechanisms which hash and sign */ ++#define CKM_MD2_RSA_PKCS 0x00000004 ++#define CKM_MD5_RSA_PKCS 0x00000005 ++#define CKM_SHA1_RSA_PKCS 0x00000006 ++ ++/* CKM_RIPEMD128_RSA_PKCS, CKM_RIPEMD160_RSA_PKCS, and ++ * CKM_RSA_PKCS_OAEP are new for v2.10 */ ++#define CKM_RIPEMD128_RSA_PKCS 0x00000007 ++#define CKM_RIPEMD160_RSA_PKCS 0x00000008 ++#define CKM_RSA_PKCS_OAEP 0x00000009 ++ ++/* CKM_RSA_X9_31_KEY_PAIR_GEN, CKM_RSA_X9_31, CKM_SHA1_RSA_X9_31, ++ * CKM_RSA_PKCS_PSS, and CKM_SHA1_RSA_PKCS_PSS are new for v2.11 */ ++#define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000A ++#define CKM_RSA_X9_31 0x0000000B ++#define CKM_SHA1_RSA_X9_31 0x0000000C ++#define CKM_RSA_PKCS_PSS 0x0000000D ++#define CKM_SHA1_RSA_PKCS_PSS 0x0000000E ++ ++#define CKM_DSA_KEY_PAIR_GEN 0x00000010 ++#define CKM_DSA 0x00000011 ++#define CKM_DSA_SHA1 0x00000012 ++/* Other DSAs */ ++#define CKM_DSA_SHA224 0x00000013 ++#define CKM_DSA_SHA256 0x00000014 ++#define CKM_DSA_SHA384 0x00000015 ++#define CKM_DSA_SHA512 0x00000016 ++ ++#define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020 ++#define CKM_DH_PKCS_DERIVE 0x00000021 ++ ++/* CKM_X9_42_DH_KEY_PAIR_GEN, CKM_X9_42_DH_DERIVE, ++ * CKM_X9_42_DH_HYBRID_DERIVE, and CKM_X9_42_MQV_DERIVE are new for ++ * v2.11 */ ++#define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030 ++#define CKM_X9_42_DH_DERIVE 0x00000031 ++#define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032 ++#define CKM_X9_42_MQV_DERIVE 0x00000033 ++ ++/* CKM_SHA256/384/512 are new for v2.20 */ ++#define CKM_SHA256_RSA_PKCS 0x00000040 ++#define CKM_SHA384_RSA_PKCS 0x00000041 ++#define CKM_SHA512_RSA_PKCS 0x00000042 ++#define CKM_SHA256_RSA_PKCS_PSS 0x00000043 ++#define CKM_SHA384_RSA_PKCS_PSS 0x00000044 ++#define CKM_SHA512_RSA_PKCS_PSS 0x00000045 ++ ++/* SHA-224 RSA mechanisms are new for PKCS #11 v2.20 amendment 3 */ ++#define CKM_SHA224_RSA_PKCS 0x00000046 ++#define CKM_SHA224_RSA_PKCS_PSS 0x00000047 ++ ++#define CKM_RC2_KEY_GEN 0x00000100 ++#define CKM_RC2_ECB 0x00000101 ++#define CKM_RC2_CBC 0x00000102 ++#define CKM_RC2_MAC 0x00000103 ++ ++/* CKM_RC2_MAC_GENERAL and CKM_RC2_CBC_PAD are new for v2.0 */ ++#define CKM_RC2_MAC_GENERAL 0x00000104 ++#define CKM_RC2_CBC_PAD 0x00000105 ++ ++#define CKM_RC4_KEY_GEN 0x00000110 ++#define CKM_RC4 0x00000111 ++#define CKM_DES_KEY_GEN 0x00000120 ++#define CKM_DES_ECB 0x00000121 ++#define CKM_DES_CBC 0x00000122 ++#define CKM_DES_MAC 0x00000123 ++ ++/* CKM_DES_MAC_GENERAL and CKM_DES_CBC_PAD are new for v2.0 */ ++#define CKM_DES_MAC_GENERAL 0x00000124 ++#define CKM_DES_CBC_PAD 0x00000125 ++ ++#define CKM_DES2_KEY_GEN 0x00000130 ++#define CKM_DES3_KEY_GEN 0x00000131 ++#define CKM_DES3_ECB 0x00000132 ++#define CKM_DES3_CBC 0x00000133 ++#define CKM_DES3_MAC 0x00000134 ++ ++/* CKM_DES3_MAC_GENERAL, CKM_DES3_CBC_PAD, CKM_CDMF_KEY_GEN, ++ * CKM_CDMF_ECB, CKM_CDMF_CBC, CKM_CDMF_MAC, ++ * CKM_CDMF_MAC_GENERAL, and CKM_CDMF_CBC_PAD are new for v2.0, ++ * CKM_DES3_CMAC_GENERAL and CKM_DES3_CMAC are from v2.30? */ ++#define CKM_DES3_MAC_GENERAL 0x00000135 ++#define CKM_DES3_CBC_PAD 0x00000136 ++#define CKM_DES3_CMAC_GENERAL 0x00000137 ++#define CKM_DES3_CMAC 0x00000138 ++#define CKM_CDMF_KEY_GEN 0x00000140 ++#define CKM_CDMF_ECB 0x00000141 ++#define CKM_CDMF_CBC 0x00000142 ++#define CKM_CDMF_MAC 0x00000143 ++#define CKM_CDMF_MAC_GENERAL 0x00000144 ++#define CKM_CDMF_CBC_PAD 0x00000145 ++ ++/* the following four DES mechanisms are new for v2.20 */ ++#define CKM_DES_OFB64 0x00000150 ++#define CKM_DES_OFB8 0x00000151 ++#define CKM_DES_CFB64 0x00000152 ++#define CKM_DES_CFB8 0x00000153 ++ ++#define CKM_MD2 0x00000200 ++ ++/* CKM_MD2_HMAC and CKM_MD2_HMAC_GENERAL are new for v2.0 */ ++#define CKM_MD2_HMAC 0x00000201 ++#define CKM_MD2_HMAC_GENERAL 0x00000202 ++ ++#define CKM_MD5 0x00000210 ++ ++/* CKM_MD5_HMAC and CKM_MD5_HMAC_GENERAL are new for v2.0 */ ++#define CKM_MD5_HMAC 0x00000211 ++#define CKM_MD5_HMAC_GENERAL 0x00000212 ++ ++#define CKM_SHA_1 0x00000220 ++ ++/* CKM_SHA_1_HMAC and CKM_SHA_1_HMAC_GENERAL are new for v2.0 */ ++#define CKM_SHA_1_HMAC 0x00000221 ++#define CKM_SHA_1_HMAC_GENERAL 0x00000222 ++ ++/* CKM_RIPEMD128, CKM_RIPEMD128_HMAC, ++ * CKM_RIPEMD128_HMAC_GENERAL, CKM_RIPEMD160, CKM_RIPEMD160_HMAC, ++ * and CKM_RIPEMD160_HMAC_GENERAL are new for v2.10 */ ++#define CKM_RIPEMD128 0x00000230 ++#define CKM_RIPEMD128_HMAC 0x00000231 ++#define CKM_RIPEMD128_HMAC_GENERAL 0x00000232 ++#define CKM_RIPEMD160 0x00000240 ++#define CKM_RIPEMD160_HMAC 0x00000241 ++#define CKM_RIPEMD160_HMAC_GENERAL 0x00000242 ++ ++/* CKM_SHA256/384/512 are new for v2.20 */ ++#define CKM_SHA256 0x00000250 ++#define CKM_SHA256_HMAC 0x00000251 ++#define CKM_SHA256_HMAC_GENERAL 0x00000252 ++ ++/* SHA-224 is new for PKCS #11 v2.20 amendment 3 */ ++#define CKM_SHA224 0x00000255 ++#define CKM_SHA224_HMAC 0x00000256 ++#define CKM_SHA224_HMAC_GENERAL 0x00000257 ++ ++#define CKM_SHA384 0x00000260 ++#define CKM_SHA384_HMAC 0x00000261 ++#define CKM_SHA384_HMAC_GENERAL 0x00000262 ++#define CKM_SHA512 0x00000270 ++#define CKM_SHA512_HMAC 0x00000271 ++#define CKM_SHA512_HMAC_GENERAL 0x00000272 ++ ++/* SecurID is new for PKCS #11 v2.20 amendment 1 */ ++#define CKM_SECURID_KEY_GEN 0x00000280 ++#define CKM_SECURID 0x00000282 ++ ++/* HOTP is new for PKCS #11 v2.20 amendment 1 */ ++#define CKM_HOTP_KEY_GEN 0x00000290 ++#define CKM_HOTP 0x00000291 ++ ++/* ACTI is new for PKCS #11 v2.20 amendment 1 */ ++#define CKM_ACTI 0x000002A0 ++#define CKM_ACTI_KEY_GEN 0x000002A1 ++ ++/* All of the following mechanisms are new for v2.0 */ ++/* Note that CAST128 and CAST5 are the same algorithm */ ++#define CKM_CAST_KEY_GEN 0x00000300 ++#define CKM_CAST_ECB 0x00000301 ++#define CKM_CAST_CBC 0x00000302 ++#define CKM_CAST_MAC 0x00000303 ++#define CKM_CAST_MAC_GENERAL 0x00000304 ++#define CKM_CAST_CBC_PAD 0x00000305 ++#define CKM_CAST3_KEY_GEN 0x00000310 ++#define CKM_CAST3_ECB 0x00000311 ++#define CKM_CAST3_CBC 0x00000312 ++#define CKM_CAST3_MAC 0x00000313 ++#define CKM_CAST3_MAC_GENERAL 0x00000314 ++#define CKM_CAST3_CBC_PAD 0x00000315 ++#define CKM_CAST5_KEY_GEN 0x00000320 ++#define CKM_CAST128_KEY_GEN 0x00000320 ++#define CKM_CAST5_ECB 0x00000321 ++#define CKM_CAST128_ECB 0x00000321 ++#define CKM_CAST5_CBC 0x00000322 ++#define CKM_CAST128_CBC 0x00000322 ++#define CKM_CAST5_MAC 0x00000323 ++#define CKM_CAST128_MAC 0x00000323 ++#define CKM_CAST5_MAC_GENERAL 0x00000324 ++#define CKM_CAST128_MAC_GENERAL 0x00000324 ++#define CKM_CAST5_CBC_PAD 0x00000325 ++#define CKM_CAST128_CBC_PAD 0x00000325 ++#define CKM_RC5_KEY_GEN 0x00000330 ++#define CKM_RC5_ECB 0x00000331 ++#define CKM_RC5_CBC 0x00000332 ++#define CKM_RC5_MAC 0x00000333 ++#define CKM_RC5_MAC_GENERAL 0x00000334 ++#define CKM_RC5_CBC_PAD 0x00000335 ++#define CKM_IDEA_KEY_GEN 0x00000340 ++#define CKM_IDEA_ECB 0x00000341 ++#define CKM_IDEA_CBC 0x00000342 ++#define CKM_IDEA_MAC 0x00000343 ++#define CKM_IDEA_MAC_GENERAL 0x00000344 ++#define CKM_IDEA_CBC_PAD 0x00000345 ++#define CKM_GENERIC_SECRET_KEY_GEN 0x00000350 ++#define CKM_CONCATENATE_BASE_AND_KEY 0x00000360 ++#define CKM_CONCATENATE_BASE_AND_DATA 0x00000362 ++#define CKM_CONCATENATE_DATA_AND_BASE 0x00000363 ++#define CKM_XOR_BASE_AND_DATA 0x00000364 ++#define CKM_EXTRACT_KEY_FROM_KEY 0x00000365 ++#define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370 ++#define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371 ++#define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372 ++ ++/* CKM_SSL3_MASTER_KEY_DERIVE_DH, CKM_TLS_PRE_MASTER_KEY_GEN, ++ * CKM_TLS_MASTER_KEY_DERIVE, CKM_TLS_KEY_AND_MAC_DERIVE, and ++ * CKM_TLS_MASTER_KEY_DERIVE_DH are new for v2.11 */ ++#define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373 ++#define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374 ++#define CKM_TLS_MASTER_KEY_DERIVE 0x00000375 ++#define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376 ++#define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377 ++ ++/* CKM_TLS_PRF is new for v2.20 */ ++#define CKM_TLS_PRF 0x00000378 ++ ++#define CKM_SSL3_MD5_MAC 0x00000380 ++#define CKM_SSL3_SHA1_MAC 0x00000381 ++#define CKM_MD5_KEY_DERIVATION 0x00000390 ++#define CKM_MD2_KEY_DERIVATION 0x00000391 ++#define CKM_SHA1_KEY_DERIVATION 0x00000392 ++ ++/* CKM_SHA256/384/512 are new for v2.20 */ ++#define CKM_SHA256_KEY_DERIVATION 0x00000393 ++#define CKM_SHA384_KEY_DERIVATION 0x00000394 ++#define CKM_SHA512_KEY_DERIVATION 0x00000395 ++ ++/* SHA-224 key derivation is new for PKCS #11 v2.20 amendment 3 */ ++#define CKM_SHA224_KEY_DERIVATION 0x00000396 ++ ++#define CKM_PBE_MD2_DES_CBC 0x000003A0 ++#define CKM_PBE_MD5_DES_CBC 0x000003A1 ++#define CKM_PBE_MD5_CAST_CBC 0x000003A2 ++#define CKM_PBE_MD5_CAST3_CBC 0x000003A3 ++#define CKM_PBE_MD5_CAST5_CBC 0x000003A4 ++#define CKM_PBE_MD5_CAST128_CBC 0x000003A4 ++#define CKM_PBE_SHA1_CAST5_CBC 0x000003A5 ++#define CKM_PBE_SHA1_CAST128_CBC 0x000003A5 ++#define CKM_PBE_SHA1_RC4_128 0x000003A6 ++#define CKM_PBE_SHA1_RC4_40 0x000003A7 ++#define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8 ++#define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9 ++#define CKM_PBE_SHA1_RC2_128_CBC 0x000003AA ++#define CKM_PBE_SHA1_RC2_40_CBC 0x000003AB ++ ++/* CKM_PKCS5_PBKD2 is new for v2.10 */ ++#define CKM_PKCS5_PBKD2 0x000003B0 ++ ++#define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0 ++ ++/* WTLS mechanisms are new for v2.20 */ ++#define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0 ++#define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1 ++#define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2 ++#define CKM_WTLS_PRF 0x000003D3 ++#define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4 ++#define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5 ++ ++#define CKM_KEY_WRAP_LYNKS 0x00000400 ++#define CKM_KEY_WRAP_SET_OAEP 0x00000401 ++ ++/* CKM_CMS_SIG is new for v2.20 */ ++#define CKM_CMS_SIG 0x00000500 ++ ++/* CKM_KIP mechanisms are new for PKCS #11 v2.20 amendment 2 */ ++#define CKM_KIP_DERIVE 0x00000510 ++#define CKM_KIP_WRAP 0x00000511 ++#define CKM_KIP_MAC 0x00000512 ++ ++/* Camellia is new for PKCS #11 v2.20 amendment 3 */ ++#define CKM_CAMELLIA_KEY_GEN 0x00000550 ++#define CKM_CAMELLIA_ECB 0x00000551 ++#define CKM_CAMELLIA_CBC 0x00000552 ++#define CKM_CAMELLIA_MAC 0x00000553 ++#define CKM_CAMELLIA_MAC_GENERAL 0x00000554 ++#define CKM_CAMELLIA_CBC_PAD 0x00000555 ++#define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556 ++#define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557 ++#define CKM_CAMELLIA_CTR 0x00000558 ++ ++/* ARIA is new for PKCS #11 v2.20 amendment 3 */ ++#define CKM_ARIA_KEY_GEN 0x00000560 ++#define CKM_ARIA_ECB 0x00000561 ++#define CKM_ARIA_CBC 0x00000562 ++#define CKM_ARIA_MAC 0x00000563 ++#define CKM_ARIA_MAC_GENERAL 0x00000564 ++#define CKM_ARIA_CBC_PAD 0x00000565 ++#define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566 ++#define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567 ++ ++/* SEED is new from PKCS #11 v2.30? */ ++#define CKM_SEED_KEY_GEN 0x00000650 ++#define CKM_SEED_ECB 0x00000651 ++#define CKM_SEED_CBC 0x00000652 ++#define CKM_SEED_MAC 0x00000653 ++#define CKM_SEED_MAC_GENERAL 0x00000654 ++#define CKM_SEED_CBC_PAD 0x00000655 ++#define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656 ++#define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657 ++ ++/* Fortezza mechanisms */ ++#define CKM_SKIPJACK_KEY_GEN 0x00001000 ++#define CKM_SKIPJACK_ECB64 0x00001001 ++#define CKM_SKIPJACK_CBC64 0x00001002 ++#define CKM_SKIPJACK_OFB64 0x00001003 ++#define CKM_SKIPJACK_CFB64 0x00001004 ++#define CKM_SKIPJACK_CFB32 0x00001005 ++#define CKM_SKIPJACK_CFB16 0x00001006 ++#define CKM_SKIPJACK_CFB8 0x00001007 ++#define CKM_SKIPJACK_WRAP 0x00001008 ++#define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009 ++#define CKM_SKIPJACK_RELAYX 0x0000100a ++#define CKM_KEA_KEY_PAIR_GEN 0x00001010 ++#define CKM_KEA_KEY_DERIVE 0x00001011 ++#define CKM_FORTEZZA_TIMESTAMP 0x00001020 ++#define CKM_BATON_KEY_GEN 0x00001030 ++#define CKM_BATON_ECB128 0x00001031 ++#define CKM_BATON_ECB96 0x00001032 ++#define CKM_BATON_CBC128 0x00001033 ++#define CKM_BATON_COUNTER 0x00001034 ++#define CKM_BATON_SHUFFLE 0x00001035 ++#define CKM_BATON_WRAP 0x00001036 ++ ++/* CKM_ECDSA_KEY_PAIR_GEN is deprecated in v2.11, ++ * CKM_EC_KEY_PAIR_GEN is preferred */ ++#define CKM_ECDSA_KEY_PAIR_GEN 0x00001040 ++#define CKM_EC_KEY_PAIR_GEN 0x00001040 ++ ++#define CKM_ECDSA 0x00001041 ++#define CKM_ECDSA_SHA1 0x00001042 ++ ++/* From v2.30? */ ++#define CKM_ECDSA_SHA224 0x00001043 ++#define CKM_ECDSA_SHA256 0x00001044 ++#define CKM_ECDSA_SHA384 0x00001045 ++#define CKM_ECDSA_SHA512 0x00001046 ++ ++/* CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, and CKM_ECMQV_DERIVE ++ * are new for v2.11 */ ++#define CKM_ECDH1_DERIVE 0x00001050 ++#define CKM_ECDH1_COFACTOR_DERIVE 0x00001051 ++#define CKM_ECMQV_DERIVE 0x00001052 ++ ++#define CKM_JUNIPER_KEY_GEN 0x00001060 ++#define CKM_JUNIPER_ECB128 0x00001061 ++#define CKM_JUNIPER_CBC128 0x00001062 ++#define CKM_JUNIPER_COUNTER 0x00001063 ++#define CKM_JUNIPER_SHUFFLE 0x00001064 ++#define CKM_JUNIPER_WRAP 0x00001065 ++#define CKM_FASTHASH 0x00001070 ++ ++/* CKM_AES_KEY_GEN, CKM_AES_ECB, CKM_AES_CBC, CKM_AES_MAC, ++ * CKM_AES_MAC_GENERAL, CKM_AES_CBC_PAD, CKM_DSA_PARAMETER_GEN, ++ * CKM_DH_PKCS_PARAMETER_GEN, and CKM_X9_42_DH_PARAMETER_GEN are ++ * new for v2.11 */ ++#define CKM_AES_KEY_GEN 0x00001080 ++#define CKM_AES_ECB 0x00001081 ++#define CKM_AES_CBC 0x00001082 ++#define CKM_AES_MAC 0x00001083 ++#define CKM_AES_MAC_GENERAL 0x00001084 ++#define CKM_AES_CBC_PAD 0x00001085 ++ ++/* AES counter mode is new for PKCS #11 v2.20 amendment 3 */ ++#define CKM_AES_CTR 0x00001086 ++ ++/* Missing CKM_AES_GCM and co! */ ++ ++/* BlowFish and TwoFish are new for v2.20 */ ++#define CKM_BLOWFISH_KEY_GEN 0x00001090 ++#define CKM_BLOWFISH_CBC 0x00001091 ++#define CKM_TWOFISH_KEY_GEN 0x00001092 ++#define CKM_TWOFISH_CBC 0x00001093 ++ ++ ++/* CKM_xxx_ENCRYPT_DATA mechanisms are new for v2.20 */ ++#define CKM_DES_ECB_ENCRYPT_DATA 0x00001100 ++#define CKM_DES_CBC_ENCRYPT_DATA 0x00001101 ++#define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102 ++#define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103 ++#define CKM_AES_ECB_ENCRYPT_DATA 0x00001104 ++#define CKM_AES_CBC_ENCRYPT_DATA 0x00001105 ++ ++/* GOST mechanism from v2.30? */ ++#define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200 ++#define CKM_GOSTR3410 0x00001201 ++#define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202 ++#define CKM_GOSTR3410_KEY_WRAP 0x00001203 ++#define CKM_GOSTR3410_DERIVE 0x00001204 ++#define CKM_GOSTR3411 0x00001210 ++#define CKM_GOSTR3411_HMAC 0x00001211 ++#define CKM_GOST28147_KEY_GEN 0x00001220 ++#define CKM_GOST28147_ECB 0x00001221 ++#define CKM_GOST28147 0x00001222 ++#define CKM_GOST28147_MAC 0x00001223 ++#define CKM_GOST28147_KEY_WRAP 0x00001224 ++ ++#define CKM_DSA_PARAMETER_GEN 0x00002000 ++#define CKM_DH_PKCS_PARAMETER_GEN 0x00002001 ++#define CKM_X9_42_DH_PARAMETER_GEN 0x00002002 ++ ++/* Missing AES_OFB and co, and RSA_PKCS 1_1 */ ++ ++#define CKM_VENDOR_DEFINED 0x80000000 ++ ++typedef CK_MECHANISM_TYPE CK_PTR CK_MECHANISM_TYPE_PTR; ++ ++ ++/* CK_MECHANISM is a structure that specifies a particular ++ * mechanism */ ++typedef struct CK_MECHANISM { ++ CK_MECHANISM_TYPE mechanism; ++ CK_VOID_PTR pParameter; ++ ++ /* ulParameterLen was changed from CK_USHORT to CK_ULONG for ++ * v2.0 */ ++ CK_ULONG ulParameterLen; /* in bytes */ ++} CK_MECHANISM; ++ ++typedef CK_MECHANISM CK_PTR CK_MECHANISM_PTR; ++ ++ ++/* CK_MECHANISM_INFO provides information about a particular ++ * mechanism */ ++typedef struct CK_MECHANISM_INFO { ++ CK_ULONG ulMinKeySize; ++ CK_ULONG ulMaxKeySize; ++ CK_FLAGS flags; ++} CK_MECHANISM_INFO; ++ ++/* The flags are defined as follows: ++ * Bit Flag Mask Meaning */ ++#define CKF_HW 0x00000001 /* performed by HW */ ++ ++/* The flags CKF_ENCRYPT, CKF_DECRYPT, CKF_DIGEST, CKF_SIGN, ++ * CKG_SIGN_RECOVER, CKF_VERIFY, CKF_VERIFY_RECOVER, ++ * CKF_GENERATE, CKF_GENERATE_KEY_PAIR, CKF_WRAP, CKF_UNWRAP, ++ * and CKF_DERIVE are new for v2.0. They specify whether or not ++ * a mechanism can be used for a particular task */ ++#define CKF_ENCRYPT 0x00000100 ++#define CKF_DECRYPT 0x00000200 ++#define CKF_DIGEST 0x00000400 ++#define CKF_SIGN 0x00000800 ++#define CKF_SIGN_RECOVER 0x00001000 ++#define CKF_VERIFY 0x00002000 ++#define CKF_VERIFY_RECOVER 0x00004000 ++#define CKF_GENERATE 0x00008000 ++#define CKF_GENERATE_KEY_PAIR 0x00010000 ++#define CKF_WRAP 0x00020000 ++#define CKF_UNWRAP 0x00040000 ++#define CKF_DERIVE 0x00080000 ++ ++/* CKF_EC_F_P, CKF_EC_F_2M, CKF_EC_ECPARAMETERS, CKF_EC_NAMEDCURVE, ++ * CKF_EC_UNCOMPRESS, and CKF_EC_COMPRESS are new for v2.11. They ++ * describe a token's EC capabilities not available in mechanism ++ * information. */ ++#define CKF_EC_F_P 0x00100000 ++#define CKF_EC_F_2M 0x00200000 ++#define CKF_EC_ECPARAMETERS 0x00400000 ++#define CKF_EC_NAMEDCURVE 0x00800000 ++#define CKF_EC_UNCOMPRESS 0x01000000 ++#define CKF_EC_COMPRESS 0x02000000 ++ ++#define CKF_EXTENSION 0x80000000 /* FALSE for this version */ ++ ++typedef CK_MECHANISM_INFO CK_PTR CK_MECHANISM_INFO_PTR; ++ ++ ++/* CK_RV is a value that identifies the return value of a ++ * Cryptoki function */ ++/* CK_RV was changed from CK_USHORT to CK_ULONG for v2.0 */ ++typedef CK_ULONG CK_RV; ++ ++#define CKR_OK 0x00000000 ++#define CKR_CANCEL 0x00000001 ++#define CKR_HOST_MEMORY 0x00000002 ++#define CKR_SLOT_ID_INVALID 0x00000003 ++ ++/* CKR_FLAGS_INVALID was removed for v2.0 */ ++ ++/* CKR_GENERAL_ERROR and CKR_FUNCTION_FAILED are new for v2.0 */ ++#define CKR_GENERAL_ERROR 0x00000005 ++#define CKR_FUNCTION_FAILED 0x00000006 ++ ++/* CKR_ARGUMENTS_BAD, CKR_NO_EVENT, CKR_NEED_TO_CREATE_THREADS, ++ * and CKR_CANT_LOCK are new for v2.01 */ ++#define CKR_ARGUMENTS_BAD 0x00000007 ++#define CKR_NO_EVENT 0x00000008 ++#define CKR_NEED_TO_CREATE_THREADS 0x00000009 ++#define CKR_CANT_LOCK 0x0000000A ++ ++#define CKR_ATTRIBUTE_READ_ONLY 0x00000010 ++#define CKR_ATTRIBUTE_SENSITIVE 0x00000011 ++#define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012 ++#define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013 ++/* New CKR_COPY_PROHIBITED in v2.30? */ ++#define CKR_COPY_PROHIBITED 0x0000001A ++#define CKR_DATA_INVALID 0x00000020 ++#define CKR_DATA_LEN_RANGE 0x00000021 ++#define CKR_DEVICE_ERROR 0x00000030 ++#define CKR_DEVICE_MEMORY 0x00000031 ++#define CKR_DEVICE_REMOVED 0x00000032 ++#define CKR_ENCRYPTED_DATA_INVALID 0x00000040 ++#define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041 ++#define CKR_FUNCTION_CANCELED 0x00000050 ++#define CKR_FUNCTION_NOT_PARALLEL 0x00000051 ++ ++/* CKR_FUNCTION_NOT_SUPPORTED is new for v2.0 */ ++#define CKR_FUNCTION_NOT_SUPPORTED 0x00000054 ++ ++#define CKR_KEY_HANDLE_INVALID 0x00000060 ++ ++/* CKR_KEY_SENSITIVE was removed for v2.0 */ ++ ++#define CKR_KEY_SIZE_RANGE 0x00000062 ++#define CKR_KEY_TYPE_INCONSISTENT 0x00000063 ++ ++/* CKR_KEY_NOT_NEEDED, CKR_KEY_CHANGED, CKR_KEY_NEEDED, ++ * CKR_KEY_INDIGESTIBLE, CKR_KEY_FUNCTION_NOT_PERMITTED, ++ * CKR_KEY_NOT_WRAPPABLE, and CKR_KEY_UNEXTRACTABLE are new for ++ * v2.0 */ ++#define CKR_KEY_NOT_NEEDED 0x00000064 ++#define CKR_KEY_CHANGED 0x00000065 ++#define CKR_KEY_NEEDED 0x00000066 ++#define CKR_KEY_INDIGESTIBLE 0x00000067 ++#define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068 ++#define CKR_KEY_NOT_WRAPPABLE 0x00000069 ++#define CKR_KEY_UNEXTRACTABLE 0x0000006A ++ ++#define CKR_MECHANISM_INVALID 0x00000070 ++#define CKR_MECHANISM_PARAM_INVALID 0x00000071 ++ ++/* CKR_OBJECT_CLASS_INCONSISTENT and CKR_OBJECT_CLASS_INVALID ++ * were removed for v2.0 */ ++#define CKR_OBJECT_HANDLE_INVALID 0x00000082 ++#define CKR_OPERATION_ACTIVE 0x00000090 ++#define CKR_OPERATION_NOT_INITIALIZED 0x00000091 ++#define CKR_PIN_INCORRECT 0x000000A0 ++#define CKR_PIN_INVALID 0x000000A1 ++#define CKR_PIN_LEN_RANGE 0x000000A2 ++ ++/* CKR_PIN_EXPIRED and CKR_PIN_LOCKED are new for v2.0 */ ++#define CKR_PIN_EXPIRED 0x000000A3 ++#define CKR_PIN_LOCKED 0x000000A4 ++ ++#define CKR_SESSION_CLOSED 0x000000B0 ++#define CKR_SESSION_COUNT 0x000000B1 ++#define CKR_SESSION_HANDLE_INVALID 0x000000B3 ++#define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4 ++#define CKR_SESSION_READ_ONLY 0x000000B5 ++#define CKR_SESSION_EXISTS 0x000000B6 ++ ++/* CKR_SESSION_READ_ONLY_EXISTS and ++ * CKR_SESSION_READ_WRITE_SO_EXISTS are new for v2.0 */ ++#define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7 ++#define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8 ++ ++#define CKR_SIGNATURE_INVALID 0x000000C0 ++#define CKR_SIGNATURE_LEN_RANGE 0x000000C1 ++#define CKR_TEMPLATE_INCOMPLETE 0x000000D0 ++#define CKR_TEMPLATE_INCONSISTENT 0x000000D1 ++#define CKR_TOKEN_NOT_PRESENT 0x000000E0 ++#define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1 ++#define CKR_TOKEN_WRITE_PROTECTED 0x000000E2 ++#define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0 ++#define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1 ++#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2 ++ ++/* private extra values */ ++#define CKR_LIBRARY_ALREADY_INITIALIZED 0x000000FD ++#define CKR_LIBRARY_FAILED_TO_LOAD 0x000000FE ++#define CKR_SYMBOL_RESOLUTION_FAILED 0x000000FF ++ ++#define CKR_USER_ALREADY_LOGGED_IN 0x00000100 ++#define CKR_USER_NOT_LOGGED_IN 0x00000101 ++#define CKR_USER_PIN_NOT_INITIALIZED 0x00000102 ++#define CKR_USER_TYPE_INVALID 0x00000103 ++ ++/* CKR_USER_ANOTHER_ALREADY_LOGGED_IN and CKR_USER_TOO_MANY_TYPES ++ * are new to v2.01 */ ++#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104 ++#define CKR_USER_TOO_MANY_TYPES 0x00000105 ++ ++#define CKR_WRAPPED_KEY_INVALID 0x00000110 ++#define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112 ++#define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113 ++#define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114 ++#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115 ++#define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120 ++ ++/* These are new to v2.0 */ ++#define CKR_RANDOM_NO_RNG 0x00000121 ++ ++/* These are new to v2.11 */ ++#define CKR_DOMAIN_PARAMS_INVALID 0x00000130 ++ ++/* These are new to v2.0 */ ++#define CKR_BUFFER_TOO_SMALL 0x00000150 ++#define CKR_SAVED_STATE_INVALID 0x00000160 ++#define CKR_INFORMATION_SENSITIVE 0x00000170 ++#define CKR_STATE_UNSAVEABLE 0x00000180 ++ ++/* These are new to v2.01 */ ++#define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190 ++#define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191 ++#define CKR_MUTEX_BAD 0x000001A0 ++#define CKR_MUTEX_NOT_LOCKED 0x000001A1 ++ ++/* The following return values are new for PKCS #11 v2.20 amendment 3 */ ++#define CKR_NEW_PIN_MODE 0x000001B0 ++#define CKR_NEXT_OTP 0x000001B1 ++ ++/* New from v2.30? */ ++#define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5 ++#define CKR_FIPS_SELF_TEST_FAILED 0x000001B6 ++#define CKR_LIBRARY_LOAD_FAILED 0x000001B7 ++#define CKR_PIN_TOO_WEAK 0x000001B8 ++#define CKR_PUBLIC_KEY_INVALID 0x000001B9 ++ ++/* This is new to v2.20 */ ++#define CKR_FUNCTION_REJECTED 0x00000200 ++ ++#define CKR_VENDOR_DEFINED 0x80000000 ++ ++ ++/* CK_NOTIFY is an application callback that processes events */ ++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_NOTIFY)( ++ CK_SESSION_HANDLE hSession, /* the session's handle */ ++ CK_NOTIFICATION event, ++ CK_VOID_PTR pApplication /* passed to C_OpenSession */ ++); ++ ++ ++/* CK_FUNCTION_LIST is a structure holding a Cryptoki spec ++ * version and pointers of appropriate types to all the ++ * Cryptoki functions */ ++/* CK_FUNCTION_LIST is new for v2.0 */ ++typedef struct CK_FUNCTION_LIST CK_FUNCTION_LIST; ++ ++typedef CK_FUNCTION_LIST CK_PTR CK_FUNCTION_LIST_PTR; ++ ++typedef CK_FUNCTION_LIST_PTR CK_PTR CK_FUNCTION_LIST_PTR_PTR; ++ ++ ++/* CK_CREATEMUTEX is an application callback for creating a ++ * mutex object */ ++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_CREATEMUTEX)( ++ CK_VOID_PTR_PTR ppMutex /* location to receive ptr to mutex */ ++); ++ ++ ++/* CK_DESTROYMUTEX is an application callback for destroying a ++ * mutex object */ ++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_DESTROYMUTEX)( ++ CK_VOID_PTR pMutex /* pointer to mutex */ ++); ++ ++ ++/* CK_LOCKMUTEX is an application callback for locking a mutex */ ++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_LOCKMUTEX)( ++ CK_VOID_PTR pMutex /* pointer to mutex */ ++); ++ ++ ++/* CK_UNLOCKMUTEX is an application callback for unlocking a ++ * mutex */ ++typedef CK_CALLBACK_FUNCTION(CK_RV, CK_UNLOCKMUTEX)( ++ CK_VOID_PTR pMutex /* pointer to mutex */ ++); ++ ++ ++/* CK_C_INITIALIZE_ARGS provides the optional arguments to ++ * C_Initialize */ ++typedef struct CK_C_INITIALIZE_ARGS { ++ CK_CREATEMUTEX CreateMutex; ++ CK_DESTROYMUTEX DestroyMutex; ++ CK_LOCKMUTEX LockMutex; ++ CK_UNLOCKMUTEX UnlockMutex; ++ CK_FLAGS flags; ++ CK_VOID_PTR pReserved; ++} CK_C_INITIALIZE_ARGS; ++ ++/* flags: bit flags that provide capabilities of the slot ++ * Bit Flag Mask Meaning ++ */ ++#define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001 ++#define CKF_OS_LOCKING_OK 0x00000002 ++ ++typedef CK_C_INITIALIZE_ARGS CK_PTR CK_C_INITIALIZE_ARGS_PTR; ++ ++ ++/* additional flags for parameters to functions */ ++ ++/* CKF_DONT_BLOCK is for the function C_WaitForSlotEvent */ ++#define CKF_DONT_BLOCK 1 ++ ++/* CK_RSA_PKCS_OAEP_MGF_TYPE is new for v2.10. ++ * CK_RSA_PKCS_OAEP_MGF_TYPE is used to indicate the Message ++ * Generation Function (MGF) applied to a message block when ++ * formatting a message block for the PKCS #1 OAEP encryption ++ * scheme. */ ++typedef CK_ULONG CK_RSA_PKCS_MGF_TYPE; ++ ++typedef CK_RSA_PKCS_MGF_TYPE CK_PTR CK_RSA_PKCS_MGF_TYPE_PTR; ++ ++/* The following MGFs are defined */ ++/* CKG_MGF1_SHA256, CKG_MGF1_SHA384, and CKG_MGF1_SHA512 ++ * are new for v2.20 */ ++#define CKG_MGF1_SHA1 0x00000001 ++#define CKG_MGF1_SHA256 0x00000002 ++#define CKG_MGF1_SHA384 0x00000003 ++#define CKG_MGF1_SHA512 0x00000004 ++/* SHA-224 is new for PKCS #11 v2.20 amendment 3 */ ++#define CKG_MGF1_SHA224 0x00000005 ++ ++/* CK_RSA_PKCS_OAEP_SOURCE_TYPE is new for v2.10. ++ * CK_RSA_PKCS_OAEP_SOURCE_TYPE is used to indicate the source ++ * of the encoding parameter when formatting a message block ++ * for the PKCS #1 OAEP encryption scheme. */ ++typedef CK_ULONG CK_RSA_PKCS_OAEP_SOURCE_TYPE; ++ ++typedef CK_RSA_PKCS_OAEP_SOURCE_TYPE CK_PTR CK_RSA_PKCS_OAEP_SOURCE_TYPE_PTR; ++ ++/* The following encoding parameter sources are defined */ ++#define CKZ_DATA_SPECIFIED 0x00000001 ++ ++/* CK_RSA_PKCS_OAEP_PARAMS is new for v2.10. ++ * CK_RSA_PKCS_OAEP_PARAMS provides the parameters to the ++ * CKM_RSA_PKCS_OAEP mechanism. */ ++typedef struct CK_RSA_PKCS_OAEP_PARAMS { ++ CK_MECHANISM_TYPE hashAlg; ++ CK_RSA_PKCS_MGF_TYPE mgf; ++ CK_RSA_PKCS_OAEP_SOURCE_TYPE source; ++ CK_VOID_PTR pSourceData; ++ CK_ULONG ulSourceDataLen; ++} CK_RSA_PKCS_OAEP_PARAMS; ++ ++typedef CK_RSA_PKCS_OAEP_PARAMS CK_PTR CK_RSA_PKCS_OAEP_PARAMS_PTR; ++ ++/* CK_RSA_PKCS_PSS_PARAMS is new for v2.11. ++ * CK_RSA_PKCS_PSS_PARAMS provides the parameters to the ++ * CKM_RSA_PKCS_PSS mechanism(s). */ ++typedef struct CK_RSA_PKCS_PSS_PARAMS { ++ CK_MECHANISM_TYPE hashAlg; ++ CK_RSA_PKCS_MGF_TYPE mgf; ++ CK_ULONG sLen; ++} CK_RSA_PKCS_PSS_PARAMS; ++ ++typedef CK_RSA_PKCS_PSS_PARAMS CK_PTR CK_RSA_PKCS_PSS_PARAMS_PTR; ++ ++/* CK_EC_KDF_TYPE is new for v2.11. */ ++typedef CK_ULONG CK_EC_KDF_TYPE; ++ ++/* The following EC Key Derivation Functions are defined */ ++#define CKD_NULL 0x00000001 ++#define CKD_SHA1_KDF 0x00000002 ++ ++/* CK_ECDH1_DERIVE_PARAMS is new for v2.11. ++ * CK_ECDH1_DERIVE_PARAMS provides the parameters to the ++ * CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE mechanisms, ++ * where each party contributes one key pair. ++ */ ++typedef struct CK_ECDH1_DERIVE_PARAMS { ++ CK_EC_KDF_TYPE kdf; ++ CK_ULONG ulSharedDataLen; ++ CK_BYTE_PTR pSharedData; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++} CK_ECDH1_DERIVE_PARAMS; ++ ++typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR; ++ ++ ++/* CK_ECDH2_DERIVE_PARAMS is new for v2.11. ++ * CK_ECDH2_DERIVE_PARAMS provides the parameters to the ++ * CKM_ECMQV_DERIVE mechanism, where each party contributes two key pairs. */ ++typedef struct CK_ECDH2_DERIVE_PARAMS { ++ CK_EC_KDF_TYPE kdf; ++ CK_ULONG ulSharedDataLen; ++ CK_BYTE_PTR pSharedData; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++ CK_ULONG ulPrivateDataLen; ++ CK_OBJECT_HANDLE hPrivateData; ++ CK_ULONG ulPublicDataLen2; ++ CK_BYTE_PTR pPublicData2; ++} CK_ECDH2_DERIVE_PARAMS; ++ ++typedef CK_ECDH2_DERIVE_PARAMS CK_PTR CK_ECDH2_DERIVE_PARAMS_PTR; ++ ++typedef struct CK_ECMQV_DERIVE_PARAMS { ++ CK_EC_KDF_TYPE kdf; ++ CK_ULONG ulSharedDataLen; ++ CK_BYTE_PTR pSharedData; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++ CK_ULONG ulPrivateDataLen; ++ CK_OBJECT_HANDLE hPrivateData; ++ CK_ULONG ulPublicDataLen2; ++ CK_BYTE_PTR pPublicData2; ++ CK_OBJECT_HANDLE publicKey; ++} CK_ECMQV_DERIVE_PARAMS; ++ ++typedef CK_ECMQV_DERIVE_PARAMS CK_PTR CK_ECMQV_DERIVE_PARAMS_PTR; ++ ++/* Typedefs and defines for the CKM_X9_42_DH_KEY_PAIR_GEN and the ++ * CKM_X9_42_DH_PARAMETER_GEN mechanisms (new for PKCS #11 v2.11) */ ++typedef CK_ULONG CK_X9_42_DH_KDF_TYPE; ++typedef CK_X9_42_DH_KDF_TYPE CK_PTR CK_X9_42_DH_KDF_TYPE_PTR; ++ ++/* The following X9.42 DH key derivation functions are defined ++ (besides CKD_NULL already defined : */ ++#define CKD_SHA1_KDF_ASN1 0x00000003 ++#define CKD_SHA1_KDF_CONCATENATE 0x00000004 ++ ++/* CK_X9_42_DH1_DERIVE_PARAMS is new for v2.11. ++ * CK_X9_42_DH1_DERIVE_PARAMS provides the parameters to the ++ * CKM_X9_42_DH_DERIVE key derivation mechanism, where each party ++ * contributes one key pair */ ++typedef struct CK_X9_42_DH1_DERIVE_PARAMS { ++ CK_X9_42_DH_KDF_TYPE kdf; ++ CK_ULONG ulOtherInfoLen; ++ CK_BYTE_PTR pOtherInfo; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++} CK_X9_42_DH1_DERIVE_PARAMS; ++ ++typedef struct CK_X9_42_DH1_DERIVE_PARAMS CK_PTR CK_X9_42_DH1_DERIVE_PARAMS_PTR; ++ ++/* CK_X9_42_DH2_DERIVE_PARAMS is new for v2.11. ++ * CK_X9_42_DH2_DERIVE_PARAMS provides the parameters to the ++ * CKM_X9_42_DH_HYBRID_DERIVE and CKM_X9_42_MQV_DERIVE key derivation ++ * mechanisms, where each party contributes two key pairs */ ++typedef struct CK_X9_42_DH2_DERIVE_PARAMS { ++ CK_X9_42_DH_KDF_TYPE kdf; ++ CK_ULONG ulOtherInfoLen; ++ CK_BYTE_PTR pOtherInfo; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++ CK_ULONG ulPrivateDataLen; ++ CK_OBJECT_HANDLE hPrivateData; ++ CK_ULONG ulPublicDataLen2; ++ CK_BYTE_PTR pPublicData2; ++} CK_X9_42_DH2_DERIVE_PARAMS; ++ ++typedef CK_X9_42_DH2_DERIVE_PARAMS CK_PTR CK_X9_42_DH2_DERIVE_PARAMS_PTR; ++ ++typedef struct CK_X9_42_MQV_DERIVE_PARAMS { ++ CK_X9_42_DH_KDF_TYPE kdf; ++ CK_ULONG ulOtherInfoLen; ++ CK_BYTE_PTR pOtherInfo; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++ CK_ULONG ulPrivateDataLen; ++ CK_OBJECT_HANDLE hPrivateData; ++ CK_ULONG ulPublicDataLen2; ++ CK_BYTE_PTR pPublicData2; ++ CK_OBJECT_HANDLE publicKey; ++} CK_X9_42_MQV_DERIVE_PARAMS; ++ ++typedef CK_X9_42_MQV_DERIVE_PARAMS CK_PTR CK_X9_42_MQV_DERIVE_PARAMS_PTR; ++ ++/* CK_KEA_DERIVE_PARAMS provides the parameters to the ++ * CKM_KEA_DERIVE mechanism */ ++/* CK_KEA_DERIVE_PARAMS is new for v2.0 */ ++typedef struct CK_KEA_DERIVE_PARAMS { ++ CK_BBOOL isSender; ++ CK_ULONG ulRandomLen; ++ CK_BYTE_PTR pRandomA; ++ CK_BYTE_PTR pRandomB; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++} CK_KEA_DERIVE_PARAMS; ++ ++typedef CK_KEA_DERIVE_PARAMS CK_PTR CK_KEA_DERIVE_PARAMS_PTR; ++ ++ ++/* CK_RC2_PARAMS provides the parameters to the CKM_RC2_ECB and ++ * CKM_RC2_MAC mechanisms. An instance of CK_RC2_PARAMS just ++ * holds the effective keysize */ ++typedef CK_ULONG CK_RC2_PARAMS; ++ ++typedef CK_RC2_PARAMS CK_PTR CK_RC2_PARAMS_PTR; ++ ++ ++/* CK_RC2_CBC_PARAMS provides the parameters to the CKM_RC2_CBC ++ * mechanism */ ++typedef struct CK_RC2_CBC_PARAMS { ++ /* ulEffectiveBits was changed from CK_USHORT to CK_ULONG for ++ * v2.0 */ ++ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ ++ ++ CK_BYTE iv[8]; /* IV for CBC mode */ ++} CK_RC2_CBC_PARAMS; ++ ++typedef CK_RC2_CBC_PARAMS CK_PTR CK_RC2_CBC_PARAMS_PTR; ++ ++ ++/* CK_RC2_MAC_GENERAL_PARAMS provides the parameters for the ++ * CKM_RC2_MAC_GENERAL mechanism */ ++/* CK_RC2_MAC_GENERAL_PARAMS is new for v2.0 */ ++typedef struct CK_RC2_MAC_GENERAL_PARAMS { ++ CK_ULONG ulEffectiveBits; /* effective bits (1-1024) */ ++ CK_ULONG ulMacLength; /* Length of MAC in bytes */ ++} CK_RC2_MAC_GENERAL_PARAMS; ++ ++typedef CK_RC2_MAC_GENERAL_PARAMS CK_PTR \ ++ CK_RC2_MAC_GENERAL_PARAMS_PTR; ++ ++ ++/* CK_RC5_PARAMS provides the parameters to the CKM_RC5_ECB and ++ * CKM_RC5_MAC mechanisms */ ++/* CK_RC5_PARAMS is new for v2.0 */ ++typedef struct CK_RC5_PARAMS { ++ CK_ULONG ulWordsize; /* wordsize in bits */ ++ CK_ULONG ulRounds; /* number of rounds */ ++} CK_RC5_PARAMS; ++ ++typedef CK_RC5_PARAMS CK_PTR CK_RC5_PARAMS_PTR; ++ ++ ++/* CK_RC5_CBC_PARAMS provides the parameters to the CKM_RC5_CBC ++ * mechanism */ ++/* CK_RC5_CBC_PARAMS is new for v2.0 */ ++typedef struct CK_RC5_CBC_PARAMS { ++ CK_ULONG ulWordsize; /* wordsize in bits */ ++ CK_ULONG ulRounds; /* number of rounds */ ++ CK_BYTE_PTR pIv; /* pointer to IV */ ++ CK_ULONG ulIvLen; /* length of IV in bytes */ ++} CK_RC5_CBC_PARAMS; ++ ++typedef CK_RC5_CBC_PARAMS CK_PTR CK_RC5_CBC_PARAMS_PTR; ++ ++ ++/* CK_RC5_MAC_GENERAL_PARAMS provides the parameters for the ++ * CKM_RC5_MAC_GENERAL mechanism */ ++/* CK_RC5_MAC_GENERAL_PARAMS is new for v2.0 */ ++typedef struct CK_RC5_MAC_GENERAL_PARAMS { ++ CK_ULONG ulWordsize; /* wordsize in bits */ ++ CK_ULONG ulRounds; /* number of rounds */ ++ CK_ULONG ulMacLength; /* Length of MAC in bytes */ ++} CK_RC5_MAC_GENERAL_PARAMS; ++ ++typedef CK_RC5_MAC_GENERAL_PARAMS CK_PTR \ ++ CK_RC5_MAC_GENERAL_PARAMS_PTR; ++ ++ ++/* CK_MAC_GENERAL_PARAMS provides the parameters to most block ++ * ciphers' MAC_GENERAL mechanisms. Its value is the length of ++ * the MAC */ ++/* CK_MAC_GENERAL_PARAMS is new for v2.0 */ ++typedef CK_ULONG CK_MAC_GENERAL_PARAMS; ++ ++typedef CK_MAC_GENERAL_PARAMS CK_PTR CK_MAC_GENERAL_PARAMS_PTR; ++ ++/* CK_DES/AES_ECB/CBC_ENCRYPT_DATA_PARAMS are new for v2.20 */ ++typedef struct CK_DES_CBC_ENCRYPT_DATA_PARAMS { ++ CK_BYTE iv[8]; ++ CK_BYTE_PTR pData; ++ CK_ULONG length; ++} CK_DES_CBC_ENCRYPT_DATA_PARAMS; ++ ++typedef CK_DES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_DES_CBC_ENCRYPT_DATA_PARAMS_PTR; ++ ++typedef struct CK_AES_CBC_ENCRYPT_DATA_PARAMS { ++ CK_BYTE iv[16]; ++ CK_BYTE_PTR pData; ++ CK_ULONG length; ++} CK_AES_CBC_ENCRYPT_DATA_PARAMS; ++ ++typedef CK_AES_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_AES_CBC_ENCRYPT_DATA_PARAMS_PTR; ++ ++/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS provides the parameters to the ++ * CKM_SKIPJACK_PRIVATE_WRAP mechanism */ ++/* CK_SKIPJACK_PRIVATE_WRAP_PARAMS is new for v2.0 */ ++typedef struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { ++ CK_ULONG ulPasswordLen; ++ CK_BYTE_PTR pPassword; ++ CK_ULONG ulPublicDataLen; ++ CK_BYTE_PTR pPublicData; ++ CK_ULONG ulPAndGLen; ++ CK_ULONG ulQLen; ++ CK_ULONG ulRandomLen; ++ CK_BYTE_PTR pRandomA; ++ CK_BYTE_PTR pPrimeP; ++ CK_BYTE_PTR pBaseG; ++ CK_BYTE_PTR pSubprimeQ; ++} CK_SKIPJACK_PRIVATE_WRAP_PARAMS; ++ ++typedef CK_SKIPJACK_PRIVATE_WRAP_PARAMS CK_PTR \ ++ CK_SKIPJACK_PRIVATE_WRAP_PTR; ++ ++ ++/* CK_SKIPJACK_RELAYX_PARAMS provides the parameters to the ++ * CKM_SKIPJACK_RELAYX mechanism */ ++/* CK_SKIPJACK_RELAYX_PARAMS is new for v2.0 */ ++typedef struct CK_SKIPJACK_RELAYX_PARAMS { ++ CK_ULONG ulOldWrappedXLen; ++ CK_BYTE_PTR pOldWrappedX; ++ CK_ULONG ulOldPasswordLen; ++ CK_BYTE_PTR pOldPassword; ++ CK_ULONG ulOldPublicDataLen; ++ CK_BYTE_PTR pOldPublicData; ++ CK_ULONG ulOldRandomLen; ++ CK_BYTE_PTR pOldRandomA; ++ CK_ULONG ulNewPasswordLen; ++ CK_BYTE_PTR pNewPassword; ++ CK_ULONG ulNewPublicDataLen; ++ CK_BYTE_PTR pNewPublicData; ++ CK_ULONG ulNewRandomLen; ++ CK_BYTE_PTR pNewRandomA; ++} CK_SKIPJACK_RELAYX_PARAMS; ++ ++typedef CK_SKIPJACK_RELAYX_PARAMS CK_PTR \ ++ CK_SKIPJACK_RELAYX_PARAMS_PTR; ++ ++ ++typedef struct CK_PBE_PARAMS { ++ CK_BYTE_PTR pInitVector; ++ CK_UTF8CHAR_PTR pPassword; ++ CK_ULONG ulPasswordLen; ++ CK_BYTE_PTR pSalt; ++ CK_ULONG ulSaltLen; ++ CK_ULONG ulIteration; ++} CK_PBE_PARAMS; ++ ++typedef CK_PBE_PARAMS CK_PTR CK_PBE_PARAMS_PTR; ++ ++ ++/* CK_KEY_WRAP_SET_OAEP_PARAMS provides the parameters to the ++ * CKM_KEY_WRAP_SET_OAEP mechanism */ ++/* CK_KEY_WRAP_SET_OAEP_PARAMS is new for v2.0 */ ++typedef struct CK_KEY_WRAP_SET_OAEP_PARAMS { ++ CK_BYTE bBC; /* block contents byte */ ++ CK_BYTE_PTR pX; /* extra data */ ++ CK_ULONG ulXLen; /* length of extra data in bytes */ ++} CK_KEY_WRAP_SET_OAEP_PARAMS; ++ ++typedef CK_KEY_WRAP_SET_OAEP_PARAMS CK_PTR \ ++ CK_KEY_WRAP_SET_OAEP_PARAMS_PTR; ++ ++ ++typedef struct CK_SSL3_RANDOM_DATA { ++ CK_BYTE_PTR pClientRandom; ++ CK_ULONG ulClientRandomLen; ++ CK_BYTE_PTR pServerRandom; ++ CK_ULONG ulServerRandomLen; ++} CK_SSL3_RANDOM_DATA; ++ ++ ++typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { ++ CK_SSL3_RANDOM_DATA RandomInfo; ++ CK_VERSION_PTR pVersion; ++} CK_SSL3_MASTER_KEY_DERIVE_PARAMS; ++ ++typedef struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS CK_PTR \ ++ CK_SSL3_MASTER_KEY_DERIVE_PARAMS_PTR; ++ ++ ++typedef struct CK_SSL3_KEY_MAT_OUT { ++ CK_OBJECT_HANDLE hClientMacSecret; ++ CK_OBJECT_HANDLE hServerMacSecret; ++ CK_OBJECT_HANDLE hClientKey; ++ CK_OBJECT_HANDLE hServerKey; ++ CK_BYTE_PTR pIVClient; ++ CK_BYTE_PTR pIVServer; ++} CK_SSL3_KEY_MAT_OUT; ++ ++typedef CK_SSL3_KEY_MAT_OUT CK_PTR CK_SSL3_KEY_MAT_OUT_PTR; ++ ++ ++typedef struct CK_SSL3_KEY_MAT_PARAMS { ++ CK_ULONG ulMacSizeInBits; ++ CK_ULONG ulKeySizeInBits; ++ CK_ULONG ulIVSizeInBits; ++ CK_BBOOL bIsExport; ++ CK_SSL3_RANDOM_DATA RandomInfo; ++ CK_SSL3_KEY_MAT_OUT_PTR pReturnedKeyMaterial; ++} CK_SSL3_KEY_MAT_PARAMS; ++ ++typedef CK_SSL3_KEY_MAT_PARAMS CK_PTR CK_SSL3_KEY_MAT_PARAMS_PTR; ++ ++/* CK_TLS_PRF_PARAMS is new for version 2.20 */ ++typedef struct CK_TLS_PRF_PARAMS { ++ CK_BYTE_PTR pSeed; ++ CK_ULONG ulSeedLen; ++ CK_BYTE_PTR pLabel; ++ CK_ULONG ulLabelLen; ++ CK_BYTE_PTR pOutput; ++ CK_ULONG_PTR pulOutputLen; ++} CK_TLS_PRF_PARAMS; ++ ++typedef CK_TLS_PRF_PARAMS CK_PTR CK_TLS_PRF_PARAMS_PTR; ++ ++/* WTLS is new for version 2.20 */ ++typedef struct CK_WTLS_RANDOM_DATA { ++ CK_BYTE_PTR pClientRandom; ++ CK_ULONG ulClientRandomLen; ++ CK_BYTE_PTR pServerRandom; ++ CK_ULONG ulServerRandomLen; ++} CK_WTLS_RANDOM_DATA; ++ ++typedef CK_WTLS_RANDOM_DATA CK_PTR CK_WTLS_RANDOM_DATA_PTR; ++ ++typedef struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS { ++ CK_MECHANISM_TYPE DigestMechanism; ++ CK_WTLS_RANDOM_DATA RandomInfo; ++ CK_BYTE_PTR pVersion; ++} CK_WTLS_MASTER_KEY_DERIVE_PARAMS; ++ ++typedef CK_WTLS_MASTER_KEY_DERIVE_PARAMS CK_PTR \ ++ CK_WTLS_MASTER_KEY_DERIVE_PARAMS_PTR; ++ ++typedef struct CK_WTLS_PRF_PARAMS { ++ CK_MECHANISM_TYPE DigestMechanism; ++ CK_BYTE_PTR pSeed; ++ CK_ULONG ulSeedLen; ++ CK_BYTE_PTR pLabel; ++ CK_ULONG ulLabelLen; ++ CK_BYTE_PTR pOutput; ++ CK_ULONG_PTR pulOutputLen; ++} CK_WTLS_PRF_PARAMS; ++ ++typedef CK_WTLS_PRF_PARAMS CK_PTR CK_WTLS_PRF_PARAMS_PTR; ++ ++typedef struct CK_WTLS_KEY_MAT_OUT { ++ CK_OBJECT_HANDLE hMacSecret; ++ CK_OBJECT_HANDLE hKey; ++ CK_BYTE_PTR pIV; ++} CK_WTLS_KEY_MAT_OUT; ++ ++typedef CK_WTLS_KEY_MAT_OUT CK_PTR CK_WTLS_KEY_MAT_OUT_PTR; ++ ++typedef struct CK_WTLS_KEY_MAT_PARAMS { ++ CK_MECHANISM_TYPE DigestMechanism; ++ CK_ULONG ulMacSizeInBits; ++ CK_ULONG ulKeySizeInBits; ++ CK_ULONG ulIVSizeInBits; ++ CK_ULONG ulSequenceNumber; ++ CK_BBOOL bIsExport; ++ CK_WTLS_RANDOM_DATA RandomInfo; ++ CK_WTLS_KEY_MAT_OUT_PTR pReturnedKeyMaterial; ++} CK_WTLS_KEY_MAT_PARAMS; ++ ++typedef CK_WTLS_KEY_MAT_PARAMS CK_PTR CK_WTLS_KEY_MAT_PARAMS_PTR; ++ ++/* CMS is new for version 2.20 */ ++typedef struct CK_CMS_SIG_PARAMS { ++ CK_OBJECT_HANDLE certificateHandle; ++ CK_MECHANISM_PTR pSigningMechanism; ++ CK_MECHANISM_PTR pDigestMechanism; ++ CK_UTF8CHAR_PTR pContentType; ++ CK_BYTE_PTR pRequestedAttributes; ++ CK_ULONG ulRequestedAttributesLen; ++ CK_BYTE_PTR pRequiredAttributes; ++ CK_ULONG ulRequiredAttributesLen; ++} CK_CMS_SIG_PARAMS; ++ ++typedef CK_CMS_SIG_PARAMS CK_PTR CK_CMS_SIG_PARAMS_PTR; ++ ++typedef struct CK_KEY_DERIVATION_STRING_DATA { ++ CK_BYTE_PTR pData; ++ CK_ULONG ulLen; ++} CK_KEY_DERIVATION_STRING_DATA; ++ ++typedef CK_KEY_DERIVATION_STRING_DATA CK_PTR \ ++ CK_KEY_DERIVATION_STRING_DATA_PTR; ++ ++ ++/* The CK_EXTRACT_PARAMS is used for the ++ * CKM_EXTRACT_KEY_FROM_KEY mechanism. It specifies which bit ++ * of the base key should be used as the first bit of the ++ * derived key */ ++/* CK_EXTRACT_PARAMS is new for v2.0 */ ++typedef CK_ULONG CK_EXTRACT_PARAMS; ++ ++typedef CK_EXTRACT_PARAMS CK_PTR CK_EXTRACT_PARAMS_PTR; ++ ++/* CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is new for v2.10. ++ * CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE is used to ++ * indicate the Pseudo-Random Function (PRF) used to generate ++ * key bits using PKCS #5 PBKDF2. */ ++typedef CK_ULONG CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE; ++ ++typedef CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE CK_PTR CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE_PTR; ++ ++/* The following PRFs are defined in PKCS #5 v2.0. */ ++#define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001 ++ ++ ++/* CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is new for v2.10. ++ * CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE is used to indicate the ++ * source of the salt value when deriving a key using PKCS #5 ++ * PBKDF2. */ ++typedef CK_ULONG CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE; ++ ++typedef CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE CK_PTR CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE_PTR; ++ ++/* The following salt value sources are defined in PKCS #5 v2.0. */ ++#define CKZ_SALT_SPECIFIED 0x00000001 ++ ++/* CK_PKCS5_PBKD2_PARAMS is new for v2.10. ++ * CK_PKCS5_PBKD2_PARAMS is a structure that provides the ++ * parameters to the CKM_PKCS5_PBKD2 mechanism. */ ++typedef struct CK_PKCS5_PBKD2_PARAMS { ++ CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; ++ CK_VOID_PTR pSaltSourceData; ++ CK_ULONG ulSaltSourceDataLen; ++ CK_ULONG iterations; ++ CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; ++ CK_VOID_PTR pPrfData; ++ CK_ULONG ulPrfDataLen; ++ CK_UTF8CHAR_PTR pPassword; ++ CK_ULONG_PTR ulPasswordLen; ++} CK_PKCS5_PBKD2_PARAMS; ++ ++typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR; ++ ++/* All CK_OTP structs are new for PKCS #11 v2.20 amendment 3 */ ++ ++typedef CK_ULONG CK_OTP_PARAM_TYPE; ++typedef CK_OTP_PARAM_TYPE CK_PARAM_TYPE; /* B/w compatibility */ ++ ++typedef struct CK_OTP_PARAM { ++ CK_OTP_PARAM_TYPE type; ++ CK_VOID_PTR pValue; ++ CK_ULONG ulValueLen; ++} CK_OTP_PARAM; ++ ++typedef CK_OTP_PARAM CK_PTR CK_OTP_PARAM_PTR; ++ ++typedef struct CK_OTP_PARAMS { ++ CK_OTP_PARAM_PTR pParams; ++ CK_ULONG ulCount; ++} CK_OTP_PARAMS; ++ ++typedef CK_OTP_PARAMS CK_PTR CK_OTP_PARAMS_PTR; ++ ++typedef struct CK_OTP_SIGNATURE_INFO { ++ CK_OTP_PARAM_PTR pParams; ++ CK_ULONG ulCount; ++} CK_OTP_SIGNATURE_INFO; ++ ++typedef CK_OTP_SIGNATURE_INFO CK_PTR CK_OTP_SIGNATURE_INFO_PTR; ++ ++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1 */ ++#define CK_OTP_VALUE 0 ++#define CK_OTP_PIN 1 ++#define CK_OTP_CHALLENGE 2 ++#define CK_OTP_TIME 3 ++#define CK_OTP_COUNTER 4 ++#define CK_OTP_FLAGS 5 ++#define CK_OTP_OUTPUT_LENGTH 6 ++#define CK_OTP_OUTPUT_FORMAT 7 ++ ++/* The following OTP-related defines are new for PKCS #11 v2.20 amendment 1 */ ++#define CKF_NEXT_OTP 0x00000001 ++#define CKF_EXCLUDE_TIME 0x00000002 ++#define CKF_EXCLUDE_COUNTER 0x00000004 ++#define CKF_EXCLUDE_CHALLENGE 0x00000008 ++#define CKF_EXCLUDE_PIN 0x00000010 ++#define CKF_USER_FRIENDLY_OTP 0x00000020 ++ ++/* CK_KIP_PARAMS is new for PKCS #11 v2.20 amendment 2 */ ++typedef struct CK_KIP_PARAMS { ++ CK_MECHANISM_PTR pMechanism; ++ CK_OBJECT_HANDLE hKey; ++ CK_BYTE_PTR pSeed; ++ CK_ULONG ulSeedLen; ++} CK_KIP_PARAMS; ++ ++typedef CK_KIP_PARAMS CK_PTR CK_KIP_PARAMS_PTR; ++ ++/* CK_AES_CTR_PARAMS is new for PKCS #11 v2.20 amendment 3 */ ++typedef struct CK_AES_CTR_PARAMS { ++ CK_ULONG ulCounterBits; ++ CK_BYTE cb[16]; ++} CK_AES_CTR_PARAMS; ++ ++typedef CK_AES_CTR_PARAMS CK_PTR CK_AES_CTR_PARAMS_PTR; ++ ++/* CK_CAMELLIA_CTR_PARAMS is new for PKCS #11 v2.20 amendment 3 */ ++typedef struct CK_CAMELLIA_CTR_PARAMS { ++ CK_ULONG ulCounterBits; ++ CK_BYTE cb[16]; ++} CK_CAMELLIA_CTR_PARAMS; ++ ++typedef CK_CAMELLIA_CTR_PARAMS CK_PTR CK_CAMELLIA_CTR_PARAMS_PTR; ++ ++/* CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS is new for PKCS #11 v2.20 amendment 3 */ ++typedef struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS { ++ CK_BYTE iv[16]; ++ CK_BYTE_PTR pData; ++ CK_ULONG length; ++} CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS; ++ ++typedef CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS_PTR; ++ ++/* CK_ARIA_CBC_ENCRYPT_DATA_PARAMS is new for PKCS #11 v2.20 amendment 3 */ ++typedef struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS { ++ CK_BYTE iv[16]; ++ CK_BYTE_PTR pData; ++ CK_ULONG length; ++} CK_ARIA_CBC_ENCRYPT_DATA_PARAMS; ++ ++typedef CK_ARIA_CBC_ENCRYPT_DATA_PARAMS CK_PTR CK_ARIA_CBC_ENCRYPT_DATA_PARAMS_PTR; ++ ++#endif +diff --git a/lib/isc/md5.c b/lib/isc/md5.c +index 7c6419b..2e3cf9a 100644 +--- a/lib/isc/md5.c ++++ b/lib/isc/md5.c +@@ -41,6 +41,12 @@ + #include <isc/platform.h> + #include <isc/string.h> + #include <isc/types.h> ++ ++#if PKCS11CRYPTO ++#include <pk11/internal.h> ++#include <pk11/pk11.h> ++#endif ++ + #include <isc/util.h> + + #ifdef ISC_PLATFORM_OPENSSLHASH +@@ -65,6 +71,50 @@ isc_md5_final(isc_md5_t *ctx, unsigned char *digest) { + EVP_DigestFinal(ctx, digest, NULL); + } + ++#elif PKCS11CRYPTO ++ ++void ++isc_md5_init(isc_md5_t *ctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_MD5, NULL, 0 }; ++ ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech)); ++} ++ ++void ++isc_md5_invalidate(isc_md5_t *ctx) { ++ CK_BYTE garbage[ISC_MD5_DIGESTLENGTH]; ++ CK_ULONG len = ISC_MD5_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(ctx); ++} ++ ++void ++isc_md5_update(isc_md5_t *ctx, const unsigned char *buf, unsigned int len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_md5_final(isc_md5_t *ctx, unsigned char *digest) { ++ CK_RV rv; ++ CK_ULONG len = ISC_MD5_DIGESTLENGTH; ++ ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (ctx->session, (CK_BYTE_PTR) digest, &len)); ++ pk11_return_session(ctx); ++} ++ + #else + + static void +diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c +new file mode 100644 +index 0000000..015bff2 +--- /dev/null ++++ b/lib/isc/pk11.c +@@ -0,0 +1,1327 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* ++ * Portions copyright (c) 2008 Nominet UK. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in the ++ * documentation and/or other materials provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR ++ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES ++ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ++ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++ ++/* ++ * Copyright 2009 Sun Microsystems, Inc. All rights reserved. ++ * Use is subject to license terms. ++ */ ++ ++/* ++ * This product includes software developed by the OpenSSL Project for ++ * use in the OpenSSL Toolkit (http://www.openssl.org/). ++ * ++ * This project also referenced hw_pkcs11-0.9.7b.patch written by ++ * Afchine Madjlessi. ++ */ ++/* ++ * ==================================================================== ++ * Copyright (c) 2000-2001 The OpenSSL Project. All rights reserved. ++ * ++ * Redistribution and use in source and binary forms, with or without ++ * modification, are permitted provided that the following conditions ++ * are met: ++ * ++ * 1. Redistributions of source code must retain the above copyright ++ * notice, this list of conditions and the following disclaimer. ++ * ++ * 2. Redistributions in binary form must reproduce the above copyright ++ * notice, this list of conditions and the following disclaimer in ++ * the documentation and/or other materials provided with the ++ * distribution. ++ * ++ * 3. All advertising materials mentioning features or use of this ++ * software must display the following acknowledgment: ++ * "This product includes software developed by the OpenSSL Project ++ * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" ++ * ++ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to ++ * endorse or promote products derived from this software without ++ * prior written permission. For written permission, please contact ++ * licensing@OpenSSL.org. ++ * ++ * 5. Products derived from this software may not be called "OpenSSL" ++ * nor may "OpenSSL" appear in their names without prior written ++ * permission of the OpenSSL Project. ++ * ++ * 6. Redistributions of any form whatsoever must retain the following ++ * acknowledgment: ++ * "This product includes software developed by the OpenSSL Project ++ * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY ++ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR ++ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, ++ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED ++ * OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ==================================================================== ++ * ++ * This product includes cryptographic software written by Eric Young ++ * (eay@cryptsoft.com). This product includes software written by Tim ++ * Hudson (tjh@cryptsoft.com). ++ * ++ */ ++ ++/* $Id$ */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++#include <isc/log.h> ++#include <isc/mem.h> ++#include <isc/once.h> ++#include <isc/platform.h> ++#include <isc/stdio.h> ++#include <isc/thread.h> ++#include <isc/util.h> ++ ++#include <dst/result.h> ++ ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++#include <pk11/result.h> ++ ++#include <pkcs11/cryptoki.h> ++#include <pkcs11/pkcs11.h> ++ ++#define PINLEN 32 ++ ++#ifndef PK11_NO_LOGERR ++#define PK11_NO_LOGERR 1 ++#endif ++ ++static isc_once_t once = ISC_ONCE_INIT; ++static isc_mem_t *pk11_mctx = NULL; ++static isc_int32_t allocsize = 0; ++static isc_boolean_t initialized = ISC_FALSE; ++ ++typedef struct pk11_session pk11_session_t; ++typedef struct pk11_token pk11_token_t; ++typedef ISC_LIST(pk11_session_t) pk11_sessionlist_t; ++ ++struct pk11_session { ++ unsigned int magic; ++ CK_SESSION_HANDLE session; ++ ISC_LINK(pk11_session_t) link; ++ pk11_token_t *token; ++}; ++ ++struct pk11_token { ++ unsigned int magic; ++ unsigned int operations; ++ ISC_LINK(pk11_token_t) link; ++ CK_SLOT_ID slotid; ++ pk11_sessionlist_t sessions; ++ isc_boolean_t logged; ++ char name[32]; ++ char manuf[32]; ++ char model[16]; ++ char serial[16]; ++ char pin[PINLEN]; ++}; ++static ISC_LIST(pk11_token_t) tokens; ++ ++static pk11_token_t *rand_token; ++static pk11_token_t *best_rsa_token; ++static pk11_token_t *best_dsa_token; ++static pk11_token_t *best_dh_token; ++static pk11_token_t *digest_token; ++static pk11_token_t *best_ec_token; ++static pk11_token_t *best_gost_token; ++static pk11_token_t *aes_token; ++ ++static isc_result_t free_all_sessions(void); ++static isc_result_t free_session_list(pk11_sessionlist_t *slist); ++static isc_result_t setup_session(pk11_session_t *sp, ++ pk11_token_t *token, ++ isc_boolean_t rw); ++static void choose_slots(void); ++static isc_result_t token_login(pk11_session_t *sp); ++static char *percent_decode(char *x, size_t *len); ++static isc_boolean_t pk11strcmp(const char *x, size_t lenx, ++ const char *y, size_t leny); ++static CK_ATTRIBUTE *push_attribute(pk11_object_t *obj, ++ isc_mem_t *mctx, ++ size_t len); ++ ++static isc_mutex_t alloclock; ++static isc_mutex_t sessionlock; ++ ++static pk11_sessionlist_t actives; ++ ++static CK_C_INITIALIZE_ARGS pk11_init_args = { ++ NULL_PTR, /* CreateMutex */ ++ NULL_PTR, /* DestroyMutex */ ++ NULL_PTR, /* LockMutex */ ++ NULL_PTR, /* UnlockMutex */ ++ CKF_OS_LOCKING_OK, /* flags */ ++ NULL_PTR, /* pReserved */ ++}; ++ ++#ifndef PK11_LIB_LOCATION ++#define PK11_LIB_LOCATION "unknown_provider" ++#endif ++ ++#ifndef WIN32 ++static const char *lib_name = PK11_LIB_LOCATION; ++#else ++static const char *lib_name = PK11_LIB_LOCATION ".dll"; ++#endif ++ ++void ++pk11_set_lib_name(const char *name) { ++ lib_name = name; ++} ++ ++const char * ++pk11_get_lib_name(void) { ++ return (lib_name); ++} ++ ++static void ++initialize(void) { ++ char *pk11_provider; ++ ++ RUNTIME_CHECK(isc_mutex_init(&alloclock) == ISC_R_SUCCESS); ++ RUNTIME_CHECK(isc_mutex_init(&sessionlock) == ISC_R_SUCCESS); ++ ++ pk11_provider = getenv("PKCS11_PROVIDER"); ++ if (pk11_provider != NULL) ++ lib_name = pk11_provider; ++} ++ ++void * ++pk11_mem_get(size_t size) { ++ void *ptr; ++ ++ LOCK(&alloclock); ++ if (pk11_mctx != NULL) ++ ptr = isc_mem_get(pk11_mctx, size); ++ else { ++ ptr = malloc(size); ++ if (ptr != NULL) ++ allocsize += (int)size; ++ } ++ UNLOCK(&alloclock); ++ ++ if (ptr != NULL) ++ memset(ptr, 0, size); ++ return (ptr); ++} ++ ++void ++pk11_mem_put(void *ptr, size_t size) { ++ if (ptr != NULL) ++ memset(ptr, 0, size); ++ LOCK(&alloclock); ++ if (pk11_mctx != NULL) ++ isc_mem_put(pk11_mctx, ptr, size); ++ else { ++ if (ptr != NULL) ++ allocsize -= (int)size; ++ free(ptr); ++ } ++ UNLOCK(&alloclock); ++} ++ ++isc_result_t ++pk11_initialize(isc_mem_t *mctx, const char *engine) { ++ isc_result_t result; ++ CK_RV rv; ++ ++ RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS); ++ ++ LOCK(&alloclock); ++ if ((mctx != NULL) && (pk11_mctx == NULL) && (allocsize == 0)) ++ isc_mem_attach(mctx, &pk11_mctx); ++ if (initialized) { ++ UNLOCK(&alloclock); ++ return (ISC_R_SUCCESS); ++ } else { ++ LOCK(&sessionlock); ++ initialized = ISC_TRUE; ++ UNLOCK(&alloclock); ++ } ++ ++ ISC_LIST_INIT(tokens); ++ ISC_LIST_INIT(actives); ++ ++ if (engine != NULL) ++ lib_name = engine; ++ ++ /* Initialize the CRYPTOKI library */ ++ rv = pkcs_C_Initialize((CK_VOID_PTR) &pk11_init_args); ++ ++ if (rv == 0xfe) { ++ result = PK11_R_NOPROVIDER; ++ goto unlock; ++ } ++ if (rv != CKR_OK) { ++ result = PK11_R_INITFAILED; ++ goto unlock; ++ } ++ ++ choose_slots(); ++#ifdef PKCS11CRYPTO ++ if (rand_token == NULL) { ++ result = PK11_R_NORANDOMSERVICE; ++ goto unlock; ++ } ++ if (digest_token == NULL) { ++ result = PK11_R_NODIGESTSERVICE; ++ goto unlock; ++ } ++#if defined(ISC_PLATFORM_USESIT) && defined(AES_SIT) ++ if (aes_token == NULL) { ++ result = PK11_R_NOAESSERVICE; ++ goto unlock; ++ } ++#endif ++#endif /* PKCS11CRYPTO */ ++ result = ISC_R_SUCCESS; ++ unlock: ++ UNLOCK(&sessionlock); ++ return (result); ++} ++ ++isc_result_t ++pk11_finalize(void) { ++ pk11_token_t *token, *next; ++ isc_result_t ret; ++ ++ ret = free_all_sessions(); ++ (void) pkcs_C_Finalize(NULL_PTR); ++ token = ISC_LIST_HEAD(tokens); ++ while (token != NULL) { ++ next = ISC_LIST_NEXT(token, link); ++ ISC_LIST_UNLINK(tokens, token, link); ++ if (token == rand_token) ++ rand_token = NULL; ++ if (token == best_rsa_token) ++ best_rsa_token = NULL; ++ if (token == best_dsa_token) ++ best_dsa_token = NULL; ++ if (token == best_dh_token) ++ best_dh_token = NULL; ++ if (token == digest_token) ++ digest_token = NULL; ++ if (token == best_ec_token) ++ best_ec_token = NULL; ++ if (token == best_gost_token) ++ best_gost_token = NULL; ++ if (token == aes_token) ++ aes_token = NULL; ++ pk11_mem_put(token, sizeof(*token)); ++ token = next; ++ } ++ if (pk11_mctx != NULL) ++ isc_mem_detach(&pk11_mctx); ++ initialized = ISC_FALSE; ++ return (ret); ++} ++ ++isc_result_t ++pk11_rand_bytes(unsigned char *buf, int num) { ++ isc_result_t ret; ++ CK_RV rv; ++ pk11_context_t ctx; ++ ++ ret = pk11_get_session(&ctx, OP_RAND, ISC_FALSE, ISC_FALSE, ++ ISC_FALSE, NULL, 0); ++ if ((ret != ISC_R_SUCCESS) && ++ (ret != PK11_R_NODIGESTSERVICE) && ++ (ret != PK11_R_NOAESSERVICE)) ++ return (ret); ++ RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE); ++ rv = pkcs_C_GenerateRandom(ctx.session, ++ (CK_BYTE_PTR) buf, (CK_ULONG) num); ++ pk11_return_session(&ctx); ++ if (rv == CKR_OK) ++ return (ISC_R_SUCCESS); ++ else ++ return (DST_R_CRYPTOFAILURE); ++} ++ ++#define SEEDSIZE 1024 ++ ++static CK_BYTE seed[SEEDSIZE]; ++ ++void ++pk11_rand_seed_fromfile(const char *randomfile) { ++ pk11_context_t ctx; ++ FILE *stream = NULL; ++ size_t cc = 0; ++ isc_result_t ret; ++ ++ ret = pk11_get_session(&ctx, OP_RAND, ISC_FALSE, ISC_FALSE, ++ ISC_FALSE, NULL, 0); ++ if ((ret != ISC_R_SUCCESS) && ++ (ret != PK11_R_NODIGESTSERVICE) && ++ (ret != PK11_R_NOAESSERVICE)) ++ return; ++ RUNTIME_CHECK(ctx.session != CK_INVALID_HANDLE); ++ ret = isc_stdio_open(randomfile, "r", &stream); ++ if (ret != ISC_R_SUCCESS) ++ goto cleanup; ++ ret = isc_stdio_read(seed, 1, SEEDSIZE, stream, &cc); ++ if (ret!= ISC_R_SUCCESS) ++ goto cleanup; ++ ret = isc_stdio_close(stream); ++ stream = NULL; ++ if (ret!= ISC_R_SUCCESS) ++ goto cleanup; ++ (void) pkcs_C_SeedRandom(ctx.session, seed, (CK_ULONG) cc); ++ ++ cleanup: ++ if (stream != NULL) ++ (void) isc_stdio_close(stream); ++ pk11_return_session(&ctx); ++} ++ ++isc_result_t ++pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype, ++ isc_boolean_t need_services, isc_boolean_t rw, ++ isc_boolean_t logon, const char *pin, CK_SLOT_ID slot) ++{ ++ pk11_token_t *token = NULL; ++ pk11_sessionlist_t *freelist; ++ pk11_session_t *sp; ++ isc_result_t ret; ++#ifdef PKCS11CRYPTO ++ isc_result_t service_ret = ISC_R_SUCCESS; ++#else ++ UNUSED(need_services); ++#endif ++ ++ memset(ctx, 0, sizeof(pk11_context_t)); ++ ctx->handle = NULL; ++ ctx->session = CK_INVALID_HANDLE; ++ ++ ret = pk11_initialize(NULL, NULL); ++#ifdef PKCS11CRYPTO ++ if (ret == PK11_R_NORANDOMSERVICE || ++ ret == PK11_R_NODIGESTSERVICE || ++ ret == PK11_R_NOAESSERVICE) { ++ if (need_services) ++ return (ret); ++ service_ret = ret; ++ } ++ else ++#endif /* PKCS11CRYPTO */ ++ if (ret != ISC_R_SUCCESS) ++ return (ret); ++ ++ LOCK(&sessionlock); ++ /* wait for initialization to finish */ ++ UNLOCK(&sessionlock); ++ ++ switch(optype) { ++#ifdef PKCS11CRYPTO ++ case OP_RAND: ++ token = rand_token; ++ break; ++ case OP_DIGEST: ++ token = digest_token; ++ break; ++ case OP_AES: ++ token = aes_token; ++ break; ++ case OP_ANY: ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) ++ if (token->slotid == slot) ++ break; ++ break; ++#endif ++ default: ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) ++ if (token->slotid == slot) ++ break; ++#ifdef PKCS11CRYPTO ++ if ((token == NULL) || ++ ((token->operations & (1 << optype)) == 0)) ++ return (ISC_R_NOTFOUND); ++#endif ++ break; ++ } ++ if (token == NULL) ++ return (ISC_R_NOTFOUND); ++ ++ /* Override the token's PIN */ ++ if (logon && pin != NULL && *pin != '\0') { ++ memset(token->pin, 0, PINLEN); ++ strncpy(token->pin, pin, PINLEN); ++ } ++ ++ freelist = &token->sessions; ++ ++ LOCK(&sessionlock); ++ sp = ISC_LIST_HEAD(*freelist); ++ if (sp != NULL) { ++ ISC_LIST_UNLINK(*freelist, sp, link); ++ ISC_LIST_APPEND(actives, sp, link); ++ UNLOCK(&sessionlock); ++ if (logon) ++ ret = token_login(sp); ++ ctx->handle = sp; ++ ctx->session = sp->session; ++ return (ret); ++ } ++ UNLOCK(&sessionlock); ++ ++ sp = pk11_mem_get(sizeof(*sp)); ++ if (sp == NULL) ++ return (ISC_R_NOMEMORY); ++ sp->magic = SES_MAGIC; ++ sp->token = token; ++ sp->session = CK_INVALID_HANDLE; ++ ISC_LINK_INIT(sp, link); ++ ret = setup_session(sp, token, rw); ++ if ((ret == ISC_R_SUCCESS) && logon) ++ ret = token_login(sp); ++ LOCK(&sessionlock); ++ ISC_LIST_APPEND(actives, sp, link); ++ UNLOCK(&sessionlock); ++ ctx->handle = sp; ++ ctx->session = sp->session; ++#ifdef PKCS11CRYPTO ++ if (ret == ISC_R_SUCCESS) ++ ret = service_ret; ++#endif ++ return (ret); ++} ++ ++void ++pk11_return_session(pk11_context_t *ctx) { ++ pk11_session_t *sp = (pk11_session_t *) ctx->handle; ++ ++ if (sp == NULL) ++ return; ++ ctx->handle = NULL; ++ ctx->session = CK_INVALID_HANDLE; ++ ++ LOCK(&sessionlock); ++ ISC_LIST_UNLINK(actives, sp, link); ++ UNLOCK(&sessionlock); ++ if (sp->session == CK_INVALID_HANDLE) { ++ pk11_mem_put(sp, sizeof(*sp)); ++ return; ++ } ++ ++ LOCK(&sessionlock); ++ ISC_LIST_APPEND(sp->token->sessions, sp, link); ++ UNLOCK(&sessionlock); ++} ++ ++static isc_result_t ++free_all_sessions(void) { ++ pk11_token_t *token; ++ isc_result_t ret = ISC_R_SUCCESS; ++ isc_result_t oret; ++ ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) { ++ oret = free_session_list(&token->sessions); ++ if (oret != ISC_R_SUCCESS) ++ ret = oret; ++ } ++ if (!ISC_LIST_EMPTY(actives)) { ++ ret = ISC_R_ADDRINUSE; ++ oret = free_session_list(&actives); ++ if (oret != ISC_R_SUCCESS) ++ ret = oret; ++ } ++ return (ret); ++} ++ ++static isc_result_t ++free_session_list(pk11_sessionlist_t *slist) { ++ pk11_session_t *sp; ++ CK_RV rv; ++ isc_result_t ret; ++ ++ ret = ISC_R_SUCCESS; ++ LOCK(&sessionlock); ++ while (!ISC_LIST_EMPTY(*slist)) { ++ sp = ISC_LIST_HEAD(*slist); ++ UNLOCK(&sessionlock); ++ if (sp->session != CK_INVALID_HANDLE) { ++ rv = pkcs_C_CloseSession(sp->session); ++ if (rv != CKR_OK) ++ ret = DST_R_CRYPTOFAILURE; ++ } ++ LOCK(&sessionlock); ++ ISC_LIST_UNLINK(*slist, sp, link); ++ pk11_mem_put(sp, sizeof(*sp)); ++ } ++ UNLOCK(&sessionlock); ++ ++ return (ret); ++} ++ ++static isc_result_t ++setup_session(pk11_session_t *sp, pk11_token_t *token, ++ isc_boolean_t rw) ++{ ++ CK_RV rv; ++ CK_FLAGS flags = CKF_SERIAL_SESSION; ++ ++ if (rw) ++ flags += CKF_RW_SESSION; ++ ++ rv = pkcs_C_OpenSession(token->slotid, flags, NULL_PTR, ++ NULL_PTR, &sp->session); ++ if (rv != CKR_OK) ++ return (DST_R_CRYPTOFAILURE); ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++token_login(pk11_session_t *sp) { ++ CK_RV rv; ++ pk11_token_t *token = sp->token; ++ isc_result_t ret = ISC_R_SUCCESS; ++ ++ LOCK(&sessionlock); ++ if (!token->logged) { ++ rv = pkcs_C_Login(sp->session, CKU_USER, ++ (CK_UTF8CHAR_PTR) token->pin, ++ (CK_ULONG) strlen(token->pin)); ++ if (rv != CKR_OK) { ++ ret = ISC_R_NOPERM; ++#if PK11_NO_LOGERR ++ pk11_error_fatalcheck(__FILE__, __LINE__, ++ "pkcs_C_Login", rv); ++#endif ++ } else ++ token->logged = ISC_TRUE; ++ } ++ UNLOCK(&sessionlock); ++ return (ret); ++} ++ ++static void ++choose_slots(void) { ++ CK_MECHANISM_INFO mechInfo; ++ CK_TOKEN_INFO tokenInfo; ++ CK_RV rv; ++ CK_SLOT_ID slot; ++ CK_SLOT_ID_PTR slotList; ++ CK_ULONG slotCount; ++ pk11_token_t *token; ++ unsigned int i; ++ ++ slotCount = 0; ++ PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, NULL_PTR, &slotCount)); ++ /* it's not an error if we didn't find any providers */ ++ if (slotCount == 0) ++ return; ++ slotList = pk11_mem_get(sizeof(CK_SLOT_ID_PTR) * slotCount); ++ RUNTIME_CHECK(slotList != NULL); ++ PK11_FATALCHECK(pkcs_C_GetSlotList, (CK_FALSE, slotList, &slotCount)); ++ ++ for (i = 0; i < slotCount; i++) { ++ slot = slotList[i]; ++ ++ rv = pkcs_C_GetTokenInfo(slot, &tokenInfo); ++ if (rv != CKR_OK) ++ continue; ++ token = pk11_mem_get(sizeof(*token)); ++ RUNTIME_CHECK(token != NULL); ++ token->magic = TOK_MAGIC; ++ token->slotid = slot; ++ ISC_LINK_INIT(token, link); ++ ISC_LIST_INIT(token->sessions); ++ memmove(token->name, tokenInfo.label, 32); ++ memmove(token->manuf, tokenInfo.manufacturerID, 32); ++ memmove(token->model, tokenInfo.model, 16); ++ memmove(token->serial, tokenInfo.serialNumber, 16); ++ ISC_LIST_APPEND(tokens, token, link); ++ if ((tokenInfo.flags & CKF_RNG) == 0) ++ goto try_rsa; ++ token->operations |= 1 << OP_RAND; ++ if (rand_token == NULL) ++ rand_token = token; ++ ++ try_rsa: ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) ++ goto try_dsa; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_RSA_PKCS, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_dsa; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA1_RSA_PKCS, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_dsa; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_RSA_PKCS, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_dsa; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_RSA_PKCS, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_dsa; ++ token->operations |= 1 << OP_RSA; ++ if (best_rsa_token == NULL) ++ best_rsa_token = token; ++ ++ try_dsa: ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_PARAMETER_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0)) ++ goto try_dh; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_KEY_PAIR_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) ++ goto try_dh; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_DSA_SHA1, &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_dh; ++ token->operations |= 1 << OP_DSA; ++ if (best_dsa_token == NULL) ++ best_dsa_token = token; ++ ++ try_dh: ++#ifdef notdef ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_PARAMETER_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_GENERATE) == 0)) ++ goto try_digest; ++#endif ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_KEY_PAIR_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) ++ goto try_digest; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_DH_PKCS_DERIVE, ++ &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DERIVE) == 0)) ++ goto try_digest; ++ token->operations |= 1 << OP_DH; ++ if (best_dh_token == NULL) ++ best_dh_token = token; ++ ++ try_digest: ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ continue; ++#ifdef PKCS11CRYPTOWITHHMAC ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_MD5_HMAC, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) ++ continue; ++#endif ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA_1_HMAC, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA224_HMAC, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA256_HMAC, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA384_HMAC, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) ++ continue; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_SHA512_HMAC, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_SIGN) == 0)) ++ continue; ++ token->operations |= 1 << OP_DIGEST; ++ if (digest_token == NULL) ++ digest_token = token; ++ ++ /* ECDSA requires digest */ ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_EC_KEY_PAIR_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) ++ goto try_gost; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_ECDSA, &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_gost; ++ token->operations |= 1 << OP_EC; ++ if (best_ec_token == NULL) ++ best_ec_token = token; ++ ++ try_gost: ++ /* does GOST require digest too? */ ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3411, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_DIGEST) == 0)) ++ goto try_aes; ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_GOSTR3410_KEY_PAIR_GEN, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_GENERATE_KEY_PAIR) == 0)) ++ goto try_aes; ++ rv = pkcs_C_GetMechanismInfo(slot, ++ CKM_GOSTR3410_WITH_GOSTR3411, ++ &mechInfo); ++ if ((rv != CKR_OK) || ++ ((mechInfo.flags & CKF_SIGN) == 0) || ++ ((mechInfo.flags & CKF_VERIFY) == 0)) ++ goto try_aes; ++ token->operations |= 1 << OP_GOST; ++ if (best_gost_token == NULL) ++ best_gost_token = token; ++ ++ try_aes: ++ rv = pkcs_C_GetMechanismInfo(slot, CKM_AES_ECB, &mechInfo); ++ if ((rv != CKR_OK) || ((mechInfo.flags & CKF_ENCRYPT) == 0)) ++ continue; ++ token->operations |= 1 << OP_AES; ++ if (aes_token == NULL) ++ aes_token = token; ++ } ++ ++ if (slotList != NULL) ++ pk11_mem_put(slotList, sizeof(CK_SLOT_ID_PTR) * slotCount); ++} ++ ++CK_SLOT_ID ++pk11_get_best_token(pk11_optype_t optype) { ++ pk11_token_t *token = NULL; ++ ++ switch (optype) { ++ case OP_RAND: ++ token = rand_token; ++ break; ++ case OP_RSA: ++ token = best_rsa_token; ++ break; ++ case OP_DSA: ++ token = best_dsa_token; ++ break; ++ case OP_DH: ++ token = best_dh_token; ++ break; ++ case OP_DIGEST: ++ token = digest_token; ++ break; ++ case OP_EC: ++ token = best_ec_token; ++ break; ++ case OP_GOST: ++ token = best_gost_token; ++ break; ++ case OP_AES: ++ token = aes_token; ++ break; ++ default: ++ break; ++ } ++ if (token == NULL) ++ return (0); ++ return (token->slotid); ++} ++ ++unsigned int ++pk11_numbits(CK_BYTE_PTR data, unsigned int bytecnt) { ++ unsigned int bitcnt, i; ++ CK_BYTE top; ++ ++ if (bytecnt == 0) ++ return (0); ++ bitcnt = bytecnt * 8; ++ for (i = 0; i < bytecnt; i++) { ++ top = data[i]; ++ if (top == 0) { ++ bitcnt -= 8; ++ continue; ++ } ++ if (top & 0x80) ++ return (bitcnt); ++ if (top & 0x40) ++ return (bitcnt - 1); ++ if (top & 0x20) ++ return (bitcnt - 2); ++ if (top & 0x10) ++ return (bitcnt - 3); ++ if (top & 0x08) ++ return (bitcnt - 4); ++ if (top & 0x04) ++ return (bitcnt - 5); ++ if (top & 0x02) ++ return (bitcnt - 6); ++ if (top & 0x01) ++ return (bitcnt - 7); ++ break; ++ } ++ INSIST(0); ++} ++ ++CK_ATTRIBUTE * ++pk11_attribute_first(const pk11_object_t *obj) { ++ return (obj->repr); ++} ++ ++CK_ATTRIBUTE * ++pk11_attribute_next(const pk11_object_t *obj, CK_ATTRIBUTE *attr) { ++ CK_ATTRIBUTE *next; ++ ++ next = attr + 1; ++ if ((next - obj->repr) >= obj->attrcnt) ++ return (NULL); ++ return (next); ++} ++ ++CK_ATTRIBUTE * ++pk11_attribute_bytype(const pk11_object_t *obj, CK_ATTRIBUTE_TYPE type) { ++ CK_ATTRIBUTE *attr; ++ ++ for(attr = pk11_attribute_first(obj); ++ attr != NULL; ++ attr = pk11_attribute_next(obj, attr)) ++ if (attr->type == type) ++ return (attr); ++ return (NULL); ++} ++ ++static char * ++percent_decode(char *x, size_t *len) { ++ char *p, *c; ++ unsigned char v; ++ ++ INSIST(len != NULL); ++ ++ for (p = c = x; p[0] != '\0'; p++, c++) { ++ switch (p[0]) { ++ case '%': ++ v = 0; ++ switch (p[1]) { ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ v = (p[1] - '0') << 4; ++ break; ++ case 'A': ++ case 'B': ++ case 'C': ++ case 'D': ++ case 'E': ++ case 'F': ++ v = (p[1] - 'A' + 10) << 4; ++ break; ++ case 'a': ++ case 'b': ++ case 'c': ++ case 'd': ++ case 'e': ++ case 'f': ++ v = (p[1] - 'a' + 10) << 4; ++ break; ++ default: ++ return (NULL); ++ } ++ switch (p[2]) { ++ case '0': ++ case '1': ++ case '2': ++ case '3': ++ case '4': ++ case '5': ++ case '6': ++ case '7': ++ case '8': ++ case '9': ++ v |= (p[2] - '0') & 0x0f; ++ break; ++ case 'A': ++ case 'B': ++ case 'C': ++ case 'D': ++ case 'E': ++ case 'F': ++ v = (p[2] - 'A' + 10) & 0x0f; ++ break; ++ case 'a': ++ case 'b': ++ case 'c': ++ case 'd': ++ case 'e': ++ case 'f': ++ v = (p[2] - 'a' + 10) & 0x0f; ++ break; ++ default: ++ return (NULL); ++ } ++ p += 2; ++ *c = (char) v; ++ (*len)++; ++ break; ++ default: ++ *c = *p; ++ (*len)++; ++ } ++ } ++ return (x); ++} ++ ++static isc_boolean_t ++pk11strcmp(const char *x, size_t lenx, const char *y, size_t leny) { ++ char buf[32]; ++ ++ INSIST((leny == 32) || (leny == 16)); ++ ++ memset(buf, ' ', 32); ++ if (lenx > leny) ++ lenx = leny; ++ memmove(buf, x, lenx); ++ return (ISC_TF(memcmp(buf, y, leny) == 0)); ++} ++ ++static CK_ATTRIBUTE * ++push_attribute(pk11_object_t *obj, isc_mem_t *mctx, size_t len) { ++ CK_ATTRIBUTE *old = obj->repr; ++ CK_ATTRIBUTE *attr; ++ CK_BYTE cnt = obj->attrcnt; ++ ++ obj->repr = isc_mem_get(mctx, (cnt + 1) * sizeof(*attr)); ++ if (obj->repr == NULL) { ++ obj->repr = old; ++ return (NULL); ++ } ++ memset(obj->repr, 0, (cnt + 1) * sizeof(*attr)); ++ memmove(obj->repr, old, cnt * sizeof(*attr)); ++ attr = obj->repr + cnt; ++ attr->ulValueLen = (CK_ULONG) len; ++ attr->pValue = isc_mem_get(mctx, len); ++ if (attr->pValue == NULL) { ++ memset(obj->repr, 0, (cnt + 1) * sizeof(*attr)); ++ isc_mem_put(mctx, obj->repr, (cnt + 1) * sizeof(*attr)); ++ obj->repr = old; ++ return (NULL); ++ } ++ memset(attr->pValue, 0, len); ++ if (old != NULL) { ++ memset(old, 0, cnt * sizeof(*attr)); ++ isc_mem_put(mctx, old, cnt * sizeof(*attr)); ++ } ++ obj->attrcnt++; ++ return (attr); ++} ++ ++#define DST_RET(a) { ret = a; goto err; } ++ ++isc_result_t ++pk11_parse_uri(pk11_object_t *obj, const char *label, ++ isc_mem_t *mctx, pk11_optype_t optype) ++{ ++ CK_ATTRIBUTE *attr; ++ pk11_token_t *token = NULL; ++ char *uri, *p, *a, *na, *v; ++ size_t len, l; ++ FILE *stream = NULL; ++ char pin[PINLEN]; ++ isc_boolean_t gotpin = ISC_FALSE; ++ isc_result_t ret; ++ ++ /* get values to work on */ ++ len = strlen(label) + 1; ++ uri = isc_mem_get(mctx, len); ++ if (uri == NULL) ++ return (ISC_R_NOMEMORY); ++ memmove(uri, label, len); ++ ++ /* get the URI scheme */ ++ p = strchr(uri, ':'); ++ if (p == NULL) ++ DST_RET(PK11_R_NOPROVIDER); ++ *p++ = '\0'; ++ if (strcmp(uri, "pkcs11") != 0) ++ DST_RET(PK11_R_NOPROVIDER); ++ ++ /* get attributes */ ++ for (na = p; na != NULL;) { ++ a = na; ++ p = strchr(a, ';'); ++ if (p == NULL) { ++ /* last attribute */ ++ na = NULL; ++ } else { ++ *p++ = '\0'; ++ na = p; ++ } ++ p = strchr(a, '='); ++ if (p != NULL) { ++ *p++ = '\0'; ++ v = p; ++ } else ++ v = a; ++ l = 0; ++ v = percent_decode(v, &l); ++ if (v == NULL) ++ DST_RET(PK11_R_NOPROVIDER); ++ if ((a == v) || (strcmp(a, "object") == 0)) { ++ /* object: CKA_LABEL */ ++ attr = pk11_attribute_bytype(obj, CKA_LABEL); ++ if (attr != NULL) ++ DST_RET(PK11_R_NOPROVIDER); ++ attr = push_attribute(obj, mctx, l); ++ if (attr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ attr->type = CKA_LABEL; ++ memmove(attr->pValue, v, l); ++ } else if (strcmp(a, "token") == 0) { ++ /* token: CK_TOKEN_INFO label */ ++ if (token == NULL) ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) ++ if (pk11strcmp(v, l, token->name, 32)) ++ break; ++ } else if (strcmp(a, "manufacturer") == 0) { ++ /* manufacturer: CK_TOKEN_INFO manufacturerID */ ++ if (token == NULL) ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) ++ if (pk11strcmp(v, l, token->manuf, 32)) ++ break; ++ } else if (strcmp(a, "serial") == 0) { ++ /* serial: CK_TOKEN_INFO serialNumber */ ++ if (token == NULL) ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) ++ if (pk11strcmp(v, l, token->serial, 16)) ++ break; ++ } else if (strcmp(a, "model") == 0) { ++ /* model: CK_TOKEN_INFO model */ ++ if (token == NULL) ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) ++ if (pk11strcmp(v, l, token->model, 16)) ++ break; ++ } else if (strcmp(a, "library-manufacturer") == 0) { ++ /* ignored */ ++ } else if (strcmp(a, "library-description") == 0) { ++ /* ignored */ ++ } else if (strcmp(a, "library-version") == 0) { ++ /* ignored */ ++ } else if (strcmp(a, "object-type") == 0) { ++ /* object-type: CKA_CLASS */ ++ /* only private makes sense */ ++ if (strcmp(v, "private") != 0) ++ DST_RET(PK11_R_NOPROVIDER); ++ } else if (strcmp(a, "id") == 0) { ++ /* id: CKA_ID */ ++ attr = pk11_attribute_bytype(obj, CKA_ID); ++ if (attr != NULL) ++ DST_RET(PK11_R_NOPROVIDER); ++ attr = push_attribute(obj, mctx, l); ++ if (attr == NULL) ++ DST_RET(ISC_R_NOMEMORY); ++ attr->type = CKA_ID; ++ memmove(attr->pValue, v, l); ++ } else if (strcmp(a, "pin-source") == 0) { ++ /* pin-source: PIN */ ++ ret = isc_stdio_open(v, "r", &stream); ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ memset(pin, 0, PINLEN); ++ ret = isc_stdio_read(pin, 1, PINLEN - 1, stream, NULL); ++ if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF)) ++ goto err; ++ ret = isc_stdio_close(stream); ++ stream = NULL; ++ if (ret != ISC_R_SUCCESS) ++ goto err; ++ gotpin = ISC_TRUE; ++ } else ++ DST_RET(PK11_R_NOPROVIDER); ++ } ++ ++ if ((pk11_attribute_bytype(obj, CKA_LABEL) == NULL) && ++ (pk11_attribute_bytype(obj, CKA_ID) == NULL)) ++ DST_RET(ISC_R_NOTFOUND); ++ ++ if (token == NULL) { ++ if (optype == OP_RSA) ++ token = best_rsa_token; ++ else if (optype == OP_DSA) ++ token = best_dsa_token; ++ else if (optype == OP_DH) ++ token = best_dh_token; ++ else if (optype == OP_EC) ++ token = best_ec_token; ++ } ++ if (token == NULL) ++ DST_RET(ISC_R_NOTFOUND); ++ obj->slot = token->slotid; ++ if (gotpin) { ++ memmove(token->pin, pin, PINLEN); ++ obj->reqlogon = ISC_TRUE; ++ } ++ ++ ret = ISC_R_SUCCESS; ++ ++ err: ++ if (stream != NULL) ++ (void) isc_stdio_close(stream); ++ isc_mem_put(mctx, uri, len); ++ return (ret); ++} ++ ++void ++pk11_error_fatalcheck(const char *file, int line, ++ const char *funcname, CK_RV rv) ++{ ++ isc_error_fatal(file, line, "%s: Error = 0x%.8lX\n", funcname, rv); ++} ++ ++void ++pk11_dump_tokens(void) ++{ ++ pk11_token_t *token; ++ isc_boolean_t first; ++ ++ printf("DEFAULTS\n"); ++ printf("\trand_token=%p\n", rand_token); ++ printf("\tbest_rsa_token=%p\n", best_rsa_token); ++ printf("\tbest_dsa_token=%p\n", best_dsa_token); ++ printf("\tbest_dh_token=%p\n", best_dh_token); ++ printf("\tdigest_token=%p\n", digest_token); ++ printf("\tbest_ec_token=%p\n", best_ec_token); ++ printf("\tbest_gost_token=%p\n", best_gost_token); ++ printf("\taes_token=%p\n", aes_token); ++ ++ for (token = ISC_LIST_HEAD(tokens); ++ token != NULL; ++ token = ISC_LIST_NEXT(token, link)) { ++ printf("\nTOKEN\n"); ++ printf("\taddress=%p\n", token); ++ printf("\tslotID=%lu\n", token->slotid); ++ printf("\tlabel=%.32s\n", token->name); ++ printf("\tmanufacturerID=%.32s\n", token->manuf); ++ printf("\tmodel=%.16s\n", token->model); ++ printf("\tserialNumber=%.16s\n", token->serial); ++ printf("\tsupported operations=0x%x (", token->operations); ++ first = ISC_TRUE; ++ if (token->operations & (1 << OP_RAND)) { ++ if (!first) ++ printf(","); ++ first = ISC_FALSE; ++ printf("RAND"); ++ } ++ if (token->operations & (1 << OP_RSA)) { ++ if (!first) ++ printf(","); ++ first = ISC_FALSE; ++ printf("RSA"); ++ } ++ if (token->operations & (1 << OP_DSA)) { ++ if (!first) ++ printf(","); ++ first = ISC_FALSE; ++ printf("DSA"); ++ } ++ if (token->operations & (1 << OP_DH)) { ++ if (!first) ++ printf(","); ++ first = ISC_FALSE; ++ printf("DH"); ++ } ++ if (token->operations & (1 << OP_DIGEST)) { ++ if (!first) ++ printf(","); ++ first = ISC_FALSE; ++ printf("DIGEST"); ++ } ++ if (token->operations & (1 << OP_EC)) { ++ if (!first) ++ printf(","); ++ first = ISC_FALSE; ++ printf("EC"); ++ } ++ printf(")\n"); ++ } ++} +diff --git a/lib/isc/pk11_result.c b/lib/isc/pk11_result.c +new file mode 100644 +index 0000000..0ada753 +--- /dev/null ++++ b/lib/isc/pk11_result.c +@@ -0,0 +1,85 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include <config.h> ++#include <stddef.h> ++ ++#include <isc/once.h> ++#include <isc/msgcat.h> ++#include <isc/util.h> ++ ++#include <pk11/result.h> ++ ++LIBISC_EXTERNAL_DATA isc_msgcat_t * pk11_msgcat = NULL; ++ ++static isc_once_t msgcat_once = ISC_ONCE_INIT; ++ ++static const char *text[PK11_R_NRESULTS] = { ++ "PKCS#11 initialization failed", /*%< 0 */ ++ "no PKCS#11 provider", /*%< 1 */ ++ "PKCS#11 provider has no random service", /*%< 2 */ ++ "PKCS#11 provider has no digest service", /*%< 3 */ ++ "PKCS#11 provider has no AES service", /*%< 4 */ ++}; ++ ++#define PK11_RESULT_RESULTSET 2 ++ ++static isc_once_t once = ISC_ONCE_INIT; ++ ++static void ++open_msgcat(void) { ++ isc_msgcat_open("libpk11.cat", &pk11_msgcat); ++} ++ ++void ++pk11_initmsgcat(void) { ++ ++ /* ++ * Initialize the PKCS#11 support's message catalog, ++ * pk11_msgcat, if it has not already been initialized. ++ */ ++ ++ RUNTIME_CHECK(isc_once_do(&msgcat_once, open_msgcat) == ISC_R_SUCCESS); ++} ++ ++static void ++initialize_action(void) { ++ isc_result_t result; ++ ++ result = isc_result_register(ISC_RESULTCLASS_PK11, PK11_R_NRESULTS, ++ text, pk11_msgcat, PK11_RESULT_RESULTSET); ++ if (result != ISC_R_SUCCESS) ++ UNEXPECTED_ERROR(__FILE__, __LINE__, ++ "isc_result_register() failed: %u", result); ++} ++ ++static void ++initialize(void) { ++ pk11_initmsgcat(); ++ RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); ++} ++ ++const char * ++pk11_result_totext(isc_result_t result) { ++ initialize(); ++ ++ return (isc_result_totext(result)); ++} ++ ++void ++pk11_result_register(void) { ++ initialize(); ++} +diff --git a/lib/isc/sha1.c b/lib/isc/sha1.c +index cce9603..caa721e 100644 +--- a/lib/isc/sha1.c ++++ b/lib/isc/sha1.c +@@ -44,8 +44,12 @@ + #include <isc/types.h> + #include <isc/util.h> + +-#ifdef ISC_PLATFORM_OPENSSLHASH ++#if PKCS11CRYPTO ++#include <pk11/internal.h> ++#include <pk11/pk11.h> ++#endif + ++#ifdef ISC_PLATFORM_OPENSSLHASH + void + isc_sha1_init(isc_sha1_t *context) + { +@@ -77,6 +81,50 @@ isc_sha1_final(isc_sha1_t *context, unsigned char *digest) { + EVP_DigestFinal(context, digest, NULL); + } + ++#elif PKCS11CRYPTO ++ ++void ++isc_sha1_init(isc_sha1_t *ctx) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA_1, NULL, 0 }; ++ ++ RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech)); ++} ++ ++void ++isc_sha1_invalidate(isc_sha1_t *ctx) { ++ CK_BYTE garbage[ISC_SHA1_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA1_DIGESTLENGTH; ++ ++ if (ctx->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(ctx->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(ctx); ++} ++ ++void ++isc_sha1_update(isc_sha1_t *ctx, const unsigned char *buf, unsigned int len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ DE_CONST(buf, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (ctx->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_sha1_final(isc_sha1_t *ctx, unsigned char *digest) { ++ CK_RV rv; ++ CK_ULONG len = ISC_SHA1_DIGESTLENGTH; ++ ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (ctx->session, (CK_BYTE_PTR) digest, &len)); ++ pk11_return_session(ctx); ++} ++ + #else + + #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) +diff --git a/lib/isc/sha2.c b/lib/isc/sha2.c +index db2e349..d7e0cf6 100644 +--- a/lib/isc/sha2.c ++++ b/lib/isc/sha2.c +@@ -63,6 +63,11 @@ + #include <isc/string.h> + #include <isc/util.h> + ++#if PKCS11CRYPTO ++#include <pk11/internal.h> ++#include <pk11/pk11.h> ++#endif ++ + #ifdef ISC_PLATFORM_OPENSSLHASH + + void +@@ -219,6 +224,272 @@ isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { + } + } + ++#elif PKCS11CRYPTO ++ ++void ++isc_sha224_init(isc_sha224_t *context) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA224, NULL, 0 }; ++ ++ if (context == (isc_sha224_t *)0) { ++ return; ++ } ++ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech)); ++} ++ ++void ++isc_sha224_invalidate(isc_sha224_t *context) { ++ CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA224_DIGESTLENGTH; ++ ++ if (context->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(context); ++} ++ ++void ++isc_sha224_update(isc_sha224_t *context, const isc_uint8_t* data, size_t len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ if (len == 0U) { ++ /* Calling with no data is valid - we do nothing */ ++ return; ++ } ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha224_t *)0 && data != (isc_uint8_t*)0); ++ ++ DE_CONST(data, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (context->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_sha224_final(isc_uint8_t digest[], isc_sha224_t *context) { ++ CK_RV rv; ++ CK_ULONG len = ISC_SHA224_DIGESTLENGTH; ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha224_t *)0); ++ ++ /* If no digest buffer is passed, we don't bother doing this: */ ++ if (digest != (isc_uint8_t*)0) { ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (context->session, ++ (CK_BYTE_PTR) digest, ++ &len)); ++ } else { ++ CK_BYTE garbage[ISC_SHA224_DIGESTLENGTH]; ++ ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ } ++ pk11_return_session(context); ++} ++ ++void ++isc_sha256_init(isc_sha256_t *context) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA256, NULL, 0 }; ++ ++ if (context == (isc_sha256_t *)0) { ++ return; ++ } ++ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech)); ++} ++ ++void ++isc_sha256_invalidate(isc_sha256_t *context) { ++ CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA256_DIGESTLENGTH; ++ ++ if (context->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(context); ++} ++ ++void ++isc_sha256_update(isc_sha256_t *context, const isc_uint8_t* data, size_t len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ if (len == 0U) { ++ /* Calling with no data is valid - we do nothing */ ++ return; ++ } ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha256_t *)0 && data != (isc_uint8_t*)0); ++ ++ DE_CONST(data, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (context->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_sha256_final(isc_uint8_t digest[], isc_sha256_t *context) { ++ CK_RV rv; ++ CK_ULONG len = ISC_SHA256_DIGESTLENGTH; ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha256_t *)0); ++ ++ /* If no digest buffer is passed, we don't bother doing this: */ ++ if (digest != (isc_uint8_t*)0) { ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (context->session, ++ (CK_BYTE_PTR) digest, ++ &len)); ++ } else { ++ CK_BYTE garbage[ISC_SHA256_DIGESTLENGTH]; ++ ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ } ++ pk11_return_session(context); ++} ++ ++void ++isc_sha512_init(isc_sha512_t *context) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA512, NULL, 0 }; ++ ++ if (context == (isc_sha512_t *)0) { ++ return; ++ } ++ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech)); ++} ++ ++void ++isc_sha512_invalidate(isc_sha512_t *context) { ++ CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA512_DIGESTLENGTH; ++ ++ if (context->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(context); ++} ++ ++void ++isc_sha512_update(isc_sha512_t *context, const isc_uint8_t* data, size_t len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ if (len == 0U) { ++ /* Calling with no data is valid - we do nothing */ ++ return; ++ } ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha512_t *)0 && data != (isc_uint8_t*)0); ++ ++ DE_CONST(data, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (context->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_sha512_final(isc_uint8_t digest[], isc_sha512_t *context) { ++ CK_RV rv; ++ CK_ULONG len = ISC_SHA512_DIGESTLENGTH; ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha512_t *)0); ++ ++ /* If no digest buffer is passed, we don't bother doing this: */ ++ if (digest != (isc_uint8_t*)0) { ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (context->session, ++ (CK_BYTE_PTR) digest, ++ &len)); ++ } else { ++ CK_BYTE garbage[ISC_SHA512_DIGESTLENGTH]; ++ ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ } ++ pk11_return_session(context); ++} ++ ++void ++isc_sha384_init(isc_sha384_t *context) { ++ CK_RV rv; ++ CK_MECHANISM mech = { CKM_SHA384, NULL, 0 }; ++ ++ if (context == (isc_sha384_t *)0) { ++ return; ++ } ++ RUNTIME_CHECK(pk11_get_session(context, OP_DIGEST, ISC_TRUE, ISC_FALSE, ++ ISC_FALSE, NULL, 0) == ISC_R_SUCCESS); ++ PK11_FATALCHECK(pkcs_C_DigestInit, (context->session, &mech)); ++} ++ ++void ++isc_sha384_invalidate(isc_sha384_t *context) { ++ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH]; ++ CK_ULONG len = ISC_SHA384_DIGESTLENGTH; ++ ++ if (context->handle == NULL) ++ return; ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ pk11_return_session(context); ++} ++ ++void ++isc_sha384_update(isc_sha384_t *context, const isc_uint8_t* data, size_t len) { ++ CK_RV rv; ++ CK_BYTE_PTR pPart; ++ ++ if (len == 0U) { ++ /* Calling with no data is valid - we do nothing */ ++ return; ++ } ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha384_t *)0 && data != (isc_uint8_t*)0); ++ ++ DE_CONST(data, pPart); ++ PK11_FATALCHECK(pkcs_C_DigestUpdate, ++ (context->session, pPart, (CK_ULONG) len)); ++} ++ ++void ++isc_sha384_final(isc_uint8_t digest[], isc_sha384_t *context) { ++ CK_RV rv; ++ CK_ULONG len = ISC_SHA384_DIGESTLENGTH; ++ ++ /* Sanity check: */ ++ REQUIRE(context != (isc_sha384_t *)0); ++ ++ /* If no digest buffer is passed, we don't bother doing this: */ ++ if (digest != (isc_uint8_t*)0) { ++ PK11_FATALCHECK(pkcs_C_DigestFinal, ++ (context->session, ++ (CK_BYTE_PTR) digest, ++ &len)); ++ } else { ++ CK_BYTE garbage[ISC_SHA384_DIGESTLENGTH]; ++ ++ (void) pkcs_C_DigestFinal(context->session, garbage, &len); ++ memset(garbage, 0, sizeof(garbage)); ++ } ++ pk11_return_session(context); ++} ++ + #else + + /* +@@ -1312,6 +1583,8 @@ isc_sha224_end(isc_sha224_t *context, char buffer[]) { + } else { + #ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); ++#elif PKCS11CRYPTO ++ pk11_return_session(context); + #else + memset(context, 0, sizeof(*context)); + #endif +@@ -1351,6 +1624,8 @@ isc_sha256_end(isc_sha256_t *context, char buffer[]) { + } else { + #ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); ++#elif PKCS11CRYPTO ++ pk11_return_session(context); + #else + memset(context, 0, sizeof(*context)); + #endif +@@ -1390,6 +1665,8 @@ isc_sha512_end(isc_sha512_t *context, char buffer[]) { + } else { + #ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); ++#elif PKCS11CRYPTO ++ pk11_return_session(context); + #else + memset(context, 0, sizeof(*context)); + #endif +@@ -1429,6 +1706,8 @@ isc_sha384_end(isc_sha384_t *context, char buffer[]) { + } else { + #ifdef ISC_PLATFORM_OPENSSLHASH + EVP_MD_CTX_cleanup(context); ++#elif PKCS11CRYPTO ++ pk11_return_session(context); + #else + memset(context, 0, sizeof(*context)); + #endif +diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in +index c1411cb..0595fa2 100644 +--- a/lib/isc/unix/Makefile.in ++++ b/lib/isc/unix/Makefile.in +@@ -29,14 +29,14 @@ CDEFINES = + CWARNINGS = + + # Alphabetically +-OBJS = @ISC_IPV6_O@ \ ++OBJS = @ISC_IPV6_O@ @ISC_PK11_API_O@ \ + app.@O@ dir.@O@ entropy.@O@ errno2result.@O@ file.@O@ \ + fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \ + os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \ + strerror.@O@ syslog.@O@ time.@O@ + + # Alphabetically +-SRCS = @ISC_IPV6_C@ \ ++SRCS = @ISC_IPV6_C@ @ISC_PK11_API_C@ \ + app.c dir.c entropy.c errno2result.c file.c \ + fsaccess.c interfaceiter.c keyboard.c net.c \ + os.c resource.c socket.c stdio.c stdtime.c \ +diff --git a/lib/isc/unix/include/Makefile.in b/lib/isc/unix/include/Makefile.in +index 46c243e..354e6c8 100644 +--- a/lib/isc/unix/include/Makefile.in ++++ b/lib/isc/unix/include/Makefile.in +@@ -19,7 +19,7 @@ srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ + +-SUBDIRS = isc ++SUBDIRS = isc pkcs11 + TARGETS = + + @BIND9_MAKE_RULES@ +diff --git a/lib/isc/unix/include/pkcs11/Makefile.in b/lib/isc/unix/include/pkcs11/Makefile.in +new file mode 100644 +index 0000000..8b175f4 +--- /dev/null ++++ b/lib/isc/unix/include/pkcs11/Makefile.in +@@ -0,0 +1,33 @@ ++# Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# $Id: Makefile.in,v 1.4 2007/06/19 23:47:23 tbox Exp $ ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++HEADERS = cryptoki.h ++SUBDIRS = ++TARGETS = ++ ++@BIND9_MAKE_RULES@ ++ ++installdirs: ++ $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${includedir}/pkcs11 ++ ++install:: installdirs ++ for i in ${HEADERS}; do \ ++ ${INSTALL_DATA} $(srcdir)/$$i ${DESTDIR}${includedir}/pkcs11 ; \ ++ done +diff --git a/lib/isc/unix/include/pkcs11/cryptoki.h b/lib/isc/unix/include/pkcs11/cryptoki.h +new file mode 100644 +index 0000000..7dc48b0 +--- /dev/null ++++ b/lib/isc/unix/include/pkcs11/cryptoki.h +@@ -0,0 +1,66 @@ ++/* cryptoki.h include file for PKCS #11. */ ++/* ++ * Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS ++ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED ++ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE ++ * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ++ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR ++ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ */ ++/* $Revision: 1.3 $ */ ++ ++/* ++ * Portions Copyright RSA Security Inc. ++ * ++ * License to copy and use this software is granted provided that it is ++ * identified as "RSA Security Inc. PKCS #11 Cryptographic Token Interface ++ * (Cryptoki)" in all material mentioning or referencing this software. ++ ++ * License is also granted to make and use derivative works provided that ++ * such works are identified as "derived from the RSA Security Inc. PKCS #11 ++ * Cryptographic Token Interface (Cryptoki)" in all material mentioning or ++ * referencing the derived work. ++ ++ * RSA Security Inc. makes no representations concerning either the ++ * merchantability of this software or the suitability of this software for ++ * any particular purpose. It is provided "as is" without express or implied ++ * warranty of any kind. ++ */ ++ ++/* This is a sample file containing the top level include directives ++ * for building Unix Cryptoki libraries and applications. ++ */ ++ ++#ifndef ___CRYPTOKI_H_INC___ ++#define ___CRYPTOKI_H_INC___ ++ ++#define CK_PTR * ++ ++#define CK_DEFINE_FUNCTION(returnType, name) \ ++ returnType name ++ ++#define CK_DECLARE_FUNCTION(returnType, name) \ ++ returnType name ++ ++#define CK_DECLARE_FUNCTION_POINTER(returnType, name) \ ++ returnType (* name) ++ ++#define CK_CALLBACK_FUNCTION(returnType, name) \ ++ returnType (* name) ++ ++/* NULL is in unistd.h */ ++#include <unistd.h> ++#define NULL_PTR NULL ++ ++#undef CK_PKCS11_FUNCTION_INFO ++ ++#include <pkcs11/pkcs11.h> ++ ++#endif /* ___CRYPTOKI_H_INC___ */ +diff --git a/lib/isc/unix/pk11_api.c b/lib/isc/unix/pk11_api.c +new file mode 100644 +index 0000000..9ccb959 +--- /dev/null ++++ b/lib/isc/unix/pk11_api.c +@@ -0,0 +1,673 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <string.h> ++#include <dlfcn.h> ++ ++#include <isc/log.h> ++#include <isc/mem.h> ++#include <isc/once.h> ++#include <isc/stdio.h> ++#include <isc/thread.h> ++#include <isc/util.h> ++ ++#include <pkcs11/cryptoki.h> ++#include <pkcs11/pkcs11.h> ++ ++#define KEEP_PKCS11_NAMES ++#include <pk11/pk11.h> ++#include <pk11/internal.h> ++ ++static void *hPK11 = NULL; ++ ++CK_RV ++pkcs_C_Initialize(CK_VOID_PTR pReserved) { ++ CK_C_Initialize sym; ++ ++ if (hPK11 != NULL) ++ return (CKR_LIBRARY_ALREADY_INITIALIZED); ++ ++ hPK11 = dlopen(pk11_get_lib_name(), RTLD_NOW); ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ sym = (CK_C_Initialize)dlsym(hPK11, "C_Initialize"); ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(pReserved); ++} ++ ++CK_RV ++pkcs_C_Finalize(CK_VOID_PTR pReserved) { ++ CK_C_Finalize sym; ++ CK_RV rv; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ sym = (CK_C_Finalize)dlsym(hPK11, "C_Finalize"); ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ rv = (*sym)(pReserved); ++ if ((rv == CKR_OK) && (dlclose(hPK11) != 0)) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ hPK11 = NULL; ++ return (rv); ++} ++ ++CK_RV ++pkcs_C_GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, ++ CK_ULONG_PTR pulCount) ++{ ++ static CK_C_GetSlotList sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GetSlotList)dlsym(hPK11, "C_GetSlotList"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(tokenPresent, pSlotList, pulCount); ++} ++ ++CK_RV ++pkcs_C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { ++ static CK_C_GetTokenInfo sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GetTokenInfo)dlsym(hPK11, "C_GetTokenInfo"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(slotID, pInfo); ++} ++ ++CK_RV ++pkcs_C_GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, ++ CK_MECHANISM_INFO_PTR pInfo) ++{ ++ static CK_C_GetMechanismInfo sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GetMechanismInfo)dlsym(hPK11, ++ "C_GetMechanismInfo"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(slotID, type, pInfo); ++} ++ ++CK_RV ++pkcs_C_OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, ++ CK_VOID_PTR pApplication, ++ CK_RV (*Notify) (CK_SESSION_HANDLE hSession, ++ CK_NOTIFICATION event, ++ CK_VOID_PTR pApplication), ++ CK_SESSION_HANDLE_PTR phSession) ++{ ++ static CK_C_OpenSession sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ hPK11 = dlopen(pk11_get_lib_name(), RTLD_NOW); ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_OpenSession)dlsym(hPK11, "C_OpenSession"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(slotID, flags, pApplication, Notify, phSession); ++} ++ ++CK_RV ++pkcs_C_CloseSession(CK_SESSION_HANDLE hSession) { ++ static CK_C_CloseSession sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_CloseSession)dlsym(hPK11, "C_CloseSession"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession); ++} ++ ++CK_RV ++pkcs_C_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, ++ CK_CHAR_PTR pPin, CK_ULONG usPinLen) ++{ ++ static CK_C_Login sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_Login)dlsym(hPK11, "C_Login"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, userType, pPin, usPinLen); ++} ++ ++CK_RV ++pkcs_C_Logout(CK_SESSION_HANDLE hSession) { ++ static CK_C_Logout sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_Logout)dlsym(hPK11, "C_Logout"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession); ++} ++ ++CK_RV ++pkcs_C_CreateObject(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG usCount, CK_OBJECT_HANDLE_PTR phObject) ++{ ++ static CK_C_CreateObject sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_CreateObject)dlsym(hPK11, "C_CreateObject"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pTemplate, usCount, phObject); ++} ++ ++CK_RV ++pkcs_C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { ++ static CK_C_DestroyObject sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_DestroyObject)dlsym(hPK11, "C_DestroyObject"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, hObject); ++} ++ ++CK_RV ++pkcs_C_GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, ++ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount) ++{ ++ static CK_C_GetAttributeValue sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GetAttributeValue)dlsym(hPK11, ++ "C_GetAttributeValue"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, hObject, pTemplate, usCount); ++} ++ ++CK_RV ++pkcs_C_SetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, ++ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG usCount) ++{ ++ static CK_C_SetAttributeValue sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_SetAttributeValue)dlsym(hPK11, ++ "C_SetAttributeValue"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, hObject, pTemplate, usCount); ++} ++ ++CK_RV ++pkcs_C_FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG usCount) ++{ ++ static CK_C_FindObjectsInit sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_FindObjectsInit)dlsym(hPK11, "C_FindObjectsInit"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pTemplate, usCount); ++} ++ ++CK_RV ++pkcs_C_FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, ++ CK_ULONG usMaxObjectCount, CK_ULONG_PTR pusObjectCount) ++{ ++ static CK_C_FindObjects sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_FindObjects)dlsym(hPK11, "C_FindObjects"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, phObject, usMaxObjectCount, pusObjectCount); ++} ++ ++CK_RV ++pkcs_C_FindObjectsFinal(CK_SESSION_HANDLE hSession) ++{ ++ static CK_C_FindObjectsFinal sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_FindObjectsFinal)dlsym(hPK11, ++ "C_FindObjectsFinal"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession); ++} ++ ++CK_RV ++pkcs_C_EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ static CK_C_EncryptInit sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_EncryptInit)dlsym(hPK11, "C_EncryptInit"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pMechanism, hKey); ++} ++ ++CK_RV ++pkcs_C_Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, ++ CK_ULONG_PTR pulEncryptedDataLen) ++{ ++ static CK_C_Encrypt sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_Encrypt)dlsym(hPK11, "C_Encrypt"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pData, ulDataLen, ++ pEncryptedData, pulEncryptedDataLen); ++} ++ ++CK_RV ++pkcs_C_DigestInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { ++ static CK_C_DigestInit sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_DigestInit)dlsym(hPK11, "C_DigestInit"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pMechanism); ++} ++ ++CK_RV ++pkcs_C_DigestUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen) ++{ ++ static CK_C_DigestUpdate sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_DigestUpdate)dlsym(hPK11, "C_DigestUpdate"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pPart, ulPartLen); ++} ++ ++CK_RV ++pkcs_C_DigestFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, ++ CK_ULONG_PTR pulDigestLen) ++{ ++ static CK_C_DigestFinal sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_DigestFinal)dlsym(hPK11, "C_DigestFinal"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pDigest, pulDigestLen); ++} ++ ++CK_RV ++pkcs_C_SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ static CK_C_SignInit sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_SignInit)dlsym(hPK11, "C_SignInit"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pMechanism, hKey); ++} ++ ++CK_RV ++pkcs_C_Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, ++ CK_ULONG_PTR pulSignatureLen) ++{ ++ static CK_C_Sign sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_Sign)dlsym(hPK11, "C_Sign"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pData, ulDataLen, pSignature, pulSignatureLen); ++} ++ ++CK_RV ++pkcs_C_SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen) ++{ ++ static CK_C_SignUpdate sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_SignUpdate)dlsym(hPK11, "C_SignUpdate"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pPart, ulPartLen); ++} ++ ++CK_RV ++pkcs_C_SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, ++ CK_ULONG_PTR pulSignatureLen) ++{ ++ static CK_C_SignFinal sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_SignFinal)dlsym(hPK11, "C_SignFinal"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pSignature, pulSignatureLen); ++} ++ ++CK_RV ++pkcs_C_VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hKey) ++{ ++ static CK_C_VerifyInit sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_VerifyInit)dlsym(hPK11, "C_VerifyInit"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pMechanism, hKey); ++} ++ ++CK_RV ++pkcs_C_Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ++ CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, ++ CK_ULONG ulSignatureLen) ++{ ++ static CK_C_Verify sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_Verify)dlsym(hPK11, "C_Verify"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pData, ulDataLen, pSignature, ulSignatureLen); ++} ++ ++CK_RV ++pkcs_C_VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, ++ CK_ULONG ulPartLen) ++{ ++ static CK_C_VerifyUpdate sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_VerifyUpdate)dlsym(hPK11, "C_VerifyUpdate"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pPart, ulPartLen); ++} ++ ++CK_RV ++pkcs_C_VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, ++ CK_ULONG ulSignatureLen) ++{ ++ static CK_C_VerifyFinal sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_VerifyFinal)dlsym(hPK11, "C_VerifyFinal"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pSignature, ulSignatureLen); ++} ++ ++CK_RV ++pkcs_C_GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, ++ CK_OBJECT_HANDLE_PTR phKey) ++{ ++ static CK_C_GenerateKey sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GenerateKey)dlsym(hPK11, "C_GenerateKey"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pMechanism, pTemplate, ulCount, phKey); ++} ++ ++CK_RV ++pkcs_C_GenerateKeyPair(CK_SESSION_HANDLE hSession, ++ CK_MECHANISM_PTR pMechanism, ++ CK_ATTRIBUTE_PTR pPublicKeyTemplate, ++ CK_ULONG usPublicKeyAttributeCount, ++ CK_ATTRIBUTE_PTR pPrivateKeyTemplate, ++ CK_ULONG usPrivateKeyAttributeCount, ++ CK_OBJECT_HANDLE_PTR phPrivateKey, ++ CK_OBJECT_HANDLE_PTR phPublicKey) ++{ ++ static CK_C_GenerateKeyPair sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GenerateKeyPair)dlsym(hPK11, "C_GenerateKeyPair"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, ++ pMechanism, ++ pPublicKeyTemplate, ++ usPublicKeyAttributeCount, ++ pPrivateKeyTemplate, ++ usPrivateKeyAttributeCount, ++ phPrivateKey, ++ phPublicKey); ++} ++ ++CK_RV ++pkcs_C_DeriveKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, ++ CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, ++ CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) ++{ ++ static CK_C_DeriveKey sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_DeriveKey)dlsym(hPK11, "C_DeriveKey"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, ++ pMechanism, ++ hBaseKey, ++ pTemplate, ++ ulAttributeCount, ++ phKey); ++} ++ ++CK_RV ++pkcs_C_SeedRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, ++ CK_ULONG ulSeedLen) ++{ ++ static CK_C_SeedRandom sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_SeedRandom)dlsym(hPK11, "C_SeedRandom"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, pSeed, ulSeedLen); ++} ++ ++CK_RV ++pkcs_C_GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, ++ CK_ULONG ulRandomLen) ++{ ++ static CK_C_GenerateRandom sym = NULL; ++ static void *pPK11 = NULL; ++ ++ if (hPK11 == NULL) ++ return (CKR_LIBRARY_FAILED_TO_LOAD); ++ if ((sym == NULL) || (hPK11 != pPK11)) { ++ pPK11 = hPK11; ++ sym = (CK_C_GenerateRandom)dlsym(hPK11, "C_GenerateRandom"); ++ } ++ if (sym == NULL) ++ return (CKR_SYMBOL_RESOLUTION_FAILED); ++ return (*sym)(hSession, RandomData, ulRandomLen); ++} +-- +2.1.0 + diff --git a/SOURCES/bind-9.9.1-P2-dlz-libdb.patch b/SOURCES/bind-9.9.1-P2-dlz-libdb.patch new file mode 100644 index 0000000..7c62d87 --- /dev/null +++ b/SOURCES/bind-9.9.1-P2-dlz-libdb.patch @@ -0,0 +1,27 @@ +diff -up bind-9.9.4/contrib/dlz/config.dlz.in.libdb bind-9.9.4/contrib/dlz/config.dlz.in +--- bind-9.9.4/contrib/dlz/config.dlz.in.libdb 2014-01-06 13:24:24.669256364 +0100 ++++ bind-9.9.4/contrib/dlz/config.dlz.in 2014-01-06 13:26:29.861420493 +0100 +@@ -257,7 +257,7 @@ case "$use_dlz_bdb" in + # Check other locations for includes. + # Order is important (sigh). + +- bdb_incdirs="/ /db48/ /db47/ /db46/ /db45/ /db44/ /db43/ /db42/ /db41/ /db4/ /db/" ++ bdb_incdirs="/ /db48/ /db47/ /db46/ /db45/ /db44/ /db43/ /db42/ /db41/ /db4/ /libdb/ /db/" + for d in $bdb_incdirs + do + if test -f "$dd/include${d}db.h" +@@ -283,13 +283,7 @@ case "$use_dlz_bdb" in + do + if test -f "$dd/${target_lib}/lib${d}.so" + then +- if test "$dd" != "/usr" +- then +- dlz_bdb_libs="-L${dd}/${target_lib} " +- else +- dlz_bdb_libs="" +- fi +- dlz_bdb_libs="${dlz_bdb_libs}-l${d}" ++ dlz_bdb_libs="-L${dd}/${target_lib}/libdb -l${d}" + break + fi + done diff --git a/SOURCES/bind-9.9.1-P2-multlib-conflict.patch b/SOURCES/bind-9.9.1-P2-multlib-conflict.patch new file mode 100644 index 0000000..03d5f5c --- /dev/null +++ b/SOURCES/bind-9.9.1-P2-multlib-conflict.patch @@ -0,0 +1,66 @@ +diff -up bind-9.9.3rc2/config.h.in.multlib-conflict bind-9.9.3rc2/config.h.in +--- bind-9.9.3rc2/config.h.in.multlib-conflict 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/config.h.in 2013-05-13 12:10:22.514870894 +0200 +@@ -416,7 +416,7 @@ int sigwait(const unsigned int *set, int + #undef PORT_NONBLOCK + + /* The size of `void *', as computed by sizeof. */ +-#undef SIZEOF_VOID_P ++/* #undef SIZEOF_VOID_P */ + + /* Define to 1 if you have the ANSI C header files. */ + #undef STDC_HEADERS +diff -up bind-9.9.3rc2/configure.in.multlib-conflict bind-9.9.3rc2/configure.in +--- bind-9.9.3rc2/configure.in.multlib-conflict 2013-05-13 12:10:22.481870901 +0200 ++++ bind-9.9.3rc2/configure.in 2013-05-13 12:10:22.515870894 +0200 +@@ -2251,7 +2251,9 @@ int getnameinfo(const struct sockaddr *, + size_t, char *, size_t, int);], + [ return (0);], + [AC_MSG_RESULT(size_t for buflen; int for flags) +- AC_DEFINE(IRS_GETNAMEINFO_BUFLEN_T, size_t) ++ # Changed to solve multilib conflict on Fedora ++ #AC_DEFINE(IRS_GETNAMEINFO_BUFLEN_T, size_t) ++ AC_DEFINE(IRS_GETNAMEINFO_BUFLEN_T, socklen_t) + AC_DEFINE(IRS_GETNAMEINFO_FLAGS_T, int)], + [AC_MSG_RESULT(not match any subspecies; assume standard definition) + AC_DEFINE(IRS_GETNAMEINFO_BUFLEN_T, socklen_t) +diff -up bind-9.9.3rc2/isc-config.sh.in.multlib-conflict bind-9.9.3rc2/isc-config.sh.in +--- bind-9.9.3rc2/isc-config.sh.in.multlib-conflict 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/isc-config.sh.in 2013-05-13 12:26:40.258698745 +0200 +@@ -21,7 +21,18 @@ prefix=@prefix@ + exec_prefix=@exec_prefix@ + exec_prefix_set= + includedir=@includedir@ +-libdir=@libdir@ ++arch=$(uname -m) ++ ++case $arch in ++ x86_64 | amd64 | sparc64 | s390x | ppc64) ++ libdir=/usr/lib64 ++ sec_libdir=/usr/lib ++ ;; ++ * ) ++ libdir=/usr/lib ++ sec_libdir=/usr/lib64 ++ ;; ++esac + + usage() + { +@@ -133,6 +144,16 @@ if test x"$echo_libs" = x"true"; then + if test x"${exec_prefix_set}" = x"true"; then + includes="-L${exec_prefix}/lib" + else ++ if [ ! -x $libdir/libisc.so ] ; then ++ if [ ! -x $sec_libdir/libisc.so ] ; then ++ echo "Error: ISC libs not found in $libdir" ++ if [ -d $sec_libdir ] ; then ++ echo "Error: ISC libs not found in $sec_libdir" ++ fi ++ exit 1 ++ fi ++ libdir=$sec_libdir ++ fi + libs="-L${libdir}" + fi + if test x"$liblwres" = x"true" ; then diff --git a/SOURCES/bind-9.9.3-include-update-h.patch b/SOURCES/bind-9.9.3-include-update-h.patch new file mode 100644 index 0000000..f7ea486 --- /dev/null +++ b/SOURCES/bind-9.9.3-include-update-h.patch @@ -0,0 +1,12 @@ +diff -up bind-9.9.3/lib/dns/include/dns/Makefile.in.update bind-9.9.3/lib/dns/include/dns/Makefile.in +--- bind-9.9.3/lib/dns/include/dns/Makefile.in.update 2013-06-03 09:29:41.049197873 +0200 ++++ bind-9.9.3/lib/dns/include/dns/Makefile.in 2013-06-03 09:30:09.229213170 +0200 +@@ -30,7 +30,7 @@ HEADERS = acl.h adb.h byaddr.h cache.h c + rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ + rdataslab.h rdatatype.h request.h resolver.h result.h \ + rootns.h rpz.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \ +- tcpmsg.h time.h tkey.h tsig.h ttl.h types.h \ ++ tcpmsg.h time.h tkey.h tsig.h ttl.h types.h update.h\ + validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h \ + forward.h rrl.h + diff --git a/SOURCES/bind-95-rh452060.patch b/SOURCES/bind-95-rh452060.patch new file mode 100644 index 0000000..58808b0 --- /dev/null +++ b/SOURCES/bind-95-rh452060.patch @@ -0,0 +1,40 @@ +diff -up bind-9.5.0-P2/bin/dig/dighost.c.rh452060 bind-9.5.0-P2/bin/dig/dighost.c +--- bind-9.5.0-P2/bin/dig/dighost.c.rh452060 2008-12-01 22:30:01.000000000 +0100 ++++ bind-9.5.0-P2/bin/dig/dighost.c 2008-12-01 22:30:07.000000000 +0100 +@@ -1280,6 +1280,12 @@ clear_query(dig_query_t *query) { + + debug("clear_query(%p)", query); + ++ if (query->waiting_senddone) { ++ debug("send_done not yet called"); ++ query->pending_free = ISC_TRUE; ++ return; ++ } ++ + lookup = query->lookup; + + if (lookup->current_query == query) +@@ -1301,10 +1307,7 @@ clear_query(dig_query_t *query) { + isc_mempool_put(commctx, query->recvspace); + isc_buffer_invalidate(&query->recvbuf); + isc_buffer_invalidate(&query->lengthbuf); +- if (query->waiting_senddone) +- query->pending_free = ISC_TRUE; +- else +- isc_mem_free(mctx, query); ++ isc_mem_free(mctx, query); + } + + /*% +@@ -2175,9 +2178,9 @@ send_done(isc_task_t *_task, isc_event_t + isc_event_free(&event); + + if (query->pending_free) +- isc_mem_free(mctx, query); ++ clear_query(query); + +- check_if_done(); ++ check_next_lookup(l); + UNLOCK_LOOKUP; + } + diff --git a/SOURCES/bind-96-old-api.patch b/SOURCES/bind-96-old-api.patch new file mode 100644 index 0000000..d181d3e --- /dev/null +++ b/SOURCES/bind-96-old-api.patch @@ -0,0 +1,23 @@ +diff -up bind-9.6.0b1/contrib/sdb/ldap/ldapdb.c.old-api bind-9.6.0b1/contrib/sdb/ldap/ldapdb.c +--- bind-9.6.0b1/contrib/sdb/ldap/ldapdb.c.old-api 2008-11-24 13:28:13.000000000 +0100 ++++ bind-9.6.0b1/contrib/sdb/ldap/ldapdb.c 2008-11-24 13:28:23.000000000 +0100 +@@ -25,6 +25,7 @@ + /* Using LDAPv3 by default, change this if you want v2 */ + #ifndef LDAPDB_LDAP_VERSION + #define LDAPDB_LDAP_VERSION 3 ++#define LDAP_DEPRECATED 1 + #endif + + #include <config.h> +diff -up bind-9.6.0b1/contrib/sdb/ldap/zone2ldap.c.old-api bind-9.6.0b1/contrib/sdb/ldap/zone2ldap.c +--- bind-9.6.0b1/contrib/sdb/ldap/zone2ldap.c.old-api 2008-11-24 13:29:05.000000000 +0100 ++++ bind-9.6.0b1/contrib/sdb/ldap/zone2ldap.c 2008-11-24 13:29:14.000000000 +0100 +@@ -13,6 +13,8 @@ + * ditched dNSDomain2 schema support. Version 0.3-ALPHA + */ + ++#define LDAP_DEPRECATED 1 ++ + #include <errno.h> + #include <string.h> + #include <stdlib.h> diff --git a/SOURCES/bind-99-socket-maxevents.patch b/SOURCES/bind-99-socket-maxevents.patch new file mode 100644 index 0000000..75fe038 --- /dev/null +++ b/SOURCES/bind-99-socket-maxevents.patch @@ -0,0 +1,13 @@ +diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c +index 05eaeaa..82d0d16 100644 +--- a/lib/isc/unix/socket.c ++++ b/lib/isc/unix/socket.c +@@ -214,7 +214,7 @@ typedef enum { poll_idle, poll_active, poll_checking } pollstate_t; + */ + #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) + #ifndef ISC_SOCKET_MAXEVENTS +-#define ISC_SOCKET_MAXEVENTS 64 ++#define ISC_SOCKET_MAXEVENTS 2048 + #endif + #endif + diff --git a/SOURCES/bind-nonexec.patch b/SOURCES/bind-nonexec.patch new file mode 100644 index 0000000..780ffed --- /dev/null +++ b/SOURCES/bind-nonexec.patch @@ -0,0 +1,72 @@ +diff -up bind-9.7.0rc2/lib/bind9/Makefile.in.nonexec bind-9.7.0rc2/lib/bind9/Makefile.in +--- bind-9.7.0rc2/lib/bind9/Makefile.in.nonexec 2009-12-06 00:31:40.000000000 +0100 ++++ bind-9.7.0rc2/lib/bind9/Makefile.in 2010-01-28 12:13:33.406696161 +0100 +@@ -78,7 +78,7 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libbind9.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libbind9.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f libbind9.@A@ timestamp +diff -up bind-9.7.0rc2/lib/dns/Makefile.in.nonexec bind-9.7.0rc2/lib/dns/Makefile.in +--- bind-9.7.0rc2/lib/dns/Makefile.in.nonexec 2009-12-06 00:31:40.000000000 +0100 ++++ bind-9.7.0rc2/lib/dns/Makefile.in 2010-01-28 12:13:33.406696161 +0100 +@@ -131,7 +131,7 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libdns.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f libdns.@A@ timestamp +diff -up bind-9.7.0rc2/lib/isccc/Makefile.in.nonexec bind-9.7.0rc2/lib/isccc/Makefile.in +--- bind-9.7.0rc2/lib/isccc/Makefile.in.nonexec 2009-12-06 00:31:41.000000000 +0100 ++++ bind-9.7.0rc2/lib/isccc/Makefile.in 2010-01-28 12:13:33.406696161 +0100 +@@ -80,7 +80,7 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisccc.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisccc.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f libisccc.@A@ timestamp +diff -up bind-9.7.0rc2/lib/isccfg/Makefile.in.nonexec bind-9.7.0rc2/lib/isccfg/Makefile.in +--- bind-9.7.0rc2/lib/isccfg/Makefile.in.nonexec 2009-12-06 00:31:41.000000000 +0100 ++++ bind-9.7.0rc2/lib/isccfg/Makefile.in 2010-01-28 12:13:33.406696161 +0100 +@@ -77,7 +77,7 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisccfg.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisccfg.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f libisccfg.@A@ timestamp +diff -up bind-9.7.0rc2/lib/isc/Makefile.in.nonexec bind-9.7.0rc2/lib/isc/Makefile.in +--- bind-9.7.0rc2/lib/isc/Makefile.in.nonexec 2009-12-18 05:09:55.000000000 +0100 ++++ bind-9.7.0rc2/lib/isc/Makefile.in 2010-01-28 12:13:53.566696766 +0100 +@@ -121,7 +121,7 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisc.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f libisc.@A@ libisc-nosymtbl.@A@ libisc.la \ +diff -up bind-9.7.0rc2/lib/lwres/Makefile.in.nonexec bind-9.7.0rc2/lib/lwres/Makefile.in +--- bind-9.7.0rc2/lib/lwres/Makefile.in.nonexec 2007-06-20 01:47:22.000000000 +0200 ++++ bind-9.7.0rc2/lib/lwres/Makefile.in 2010-01-28 12:13:33.406696161 +0100 +@@ -78,7 +78,7 @@ installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} liblwres.@A@ ${DESTDIR}${libdir} ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} liblwres.@A@ ${DESTDIR}${libdir} + + clean distclean:: + rm -f liblwres.@A@ liblwres.la timestamp diff --git a/SOURCES/bind.keys b/SOURCES/bind.keys new file mode 100644 index 0000000..db22d4b --- /dev/null +++ b/SOURCES/bind.keys @@ -0,0 +1,69 @@ +# The bind.keys file is used to override the built-in DNSSEC trust anchors +# which are included as part of BIND 9. As of the current release, the only +# trust anchors it contains are those for the DNS root zone ("."), and for +# the ISC DNSSEC Lookaside Validation zone ("dlv.isc.org"). Trust anchors +# for any other zones MUST be configured elsewhere; if they are configured +# here, they will not be recognized or used by named. +# +# The built-in trust anchors are provided for convenience of configuration. +# They are not activated within named.conf unless specifically switched on. +# To use the built-in root key, set "dnssec-validation auto;" in +# named.conf options. To use the built-in DLV key, set +# "dnssec-lookaside auto;". Without these options being set, +# the keys in this file are ignored. +# +# This file is NOT expected to be user-configured. +# +# These keys are current as of Feburary 2017. If any key fails to +# initialize correctly, it may have expired. In that event you should +# replace this file with a current version. The latest version of +# bind.keys can always be obtained from ISC at https://www.isc.org/bind-keys. + +managed-keys { + # ISC DLV: See https://www.isc.org/solutions/dlv for details. + # + # NOTE: The ISC DLV zone is being phased out as of February 2017; + # the key will remain in place but the zone will be otherwise empty. + # Configuring "dnssec-lookaside auto;" to activate this key is + # harmless, but is no longer useful and is not recommended. + dlv.isc.org. initial-key 257 3 5 "BEAAAAPHMu/5onzrEE7z1egmhg/WPO0+juoZrW3euWEn4MxDCE1+lLy2 + brhQv5rN32RKtMzX6Mj70jdzeND4XknW58dnJNPCxn8+jAGl2FZLK8t+ + 1uq4W+nnA3qO2+DL+k6BD4mewMLbIYFwe0PG73Te9fZ2kJb56dhgMde5 + ymX4BI/oQ+cAK50/xvJv00Frf8kw6ucMTwFlgPe+jnGxPPEmHAte/URk + Y62ZfkLoBAADLHQ9IrS2tryAe7mbBZVcOwIeU/Rw/mRx/vwwMCTgNboM + QKtUdvNXDrYJDSHZws3xiRXF1Rf+al9UmZfSav/4NWLKjHzpT59k/VSt + TDN0YUuWrBNh"; + + # ROOT KEYS: See https://data.iana.org/root-anchors/root-anchors.xml + # for current trust anchor information. + # + # These keys are activated by setting "dnssec-validation auto;" + # in named.conf. + # + # This key (19036) is to be phased out starting in 2017. It will + # remain in the root zone for some time after its successor key + # has been added. It will remain this file until it is removed from + # the root zone. + . initial-key 257 3 8 "AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF + FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX + bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD + X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz + W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS + Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq + QxA+Uk1ihz0="; + + # This key (20326) is to be published in the root zone in 2017. + # Servers which were already using the old key (19036) should + # roll seamlessly to this new one via RFC 5011 rollover. Servers + # being set up for the first time can use the contents of this + # file as initializing keys; thereafter, the keys in the + # managed key database will be trusted and maintained + # automatically. + . initial-key 257 3 8 "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3 + +/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kv + ArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF + 0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+e + oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfd + RUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwN + R1AkUTV74bU="; +}; diff --git a/SOURCES/bind.tmpfiles.d b/SOURCES/bind.tmpfiles.d new file mode 100644 index 0000000..640a656 --- /dev/null +++ b/SOURCES/bind.tmpfiles.d @@ -0,0 +1 @@ +d /run/named 0755 named named - diff --git a/SOURCES/bind93-rh490837.patch b/SOURCES/bind93-rh490837.patch new file mode 100644 index 0000000..230d7a7 --- /dev/null +++ b/SOURCES/bind93-rh490837.patch @@ -0,0 +1,95 @@ +? patch +? lib/isc/lex.c.rh490837 +Index: lib/isc/lex.c +=================================================================== +RCS file: /var/snap/bind9/lib/isc/lex.c,v +retrieving revision 1.86 +diff -p -u -r1.86 lex.c +--- lib/isc/lex.c 17 Sep 2007 09:56:29 -0000 1.86 ++++ lib/isc/lex.c 6 Apr 2009 13:24:15 -0000 +@@ -425,17 +425,14 @@ isc_lex_gettoken(isc_lex_t *lex, unsigne + if (source->is_file) { + stream = source->input; + +-#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED) +- c = getc_unlocked(stream); +-#else +- c = getc(stream); +-#endif +- if (c == EOF) { +- if (ferror(stream)) { +- source->result = ISC_R_IOERROR; +- result = source->result; ++ result = isc_stdio_fgetc(stream, &c); ++ ++ if (result != ISC_R_SUCCESS) { ++ if (result != ISC_R_EOF) { ++ source->result = result; + goto done; + } ++ + source->at_eof = ISC_TRUE; + } + } else { +Index: lib/isc/include/isc/stdio.h +=================================================================== +RCS file: /var/snap/bind9/lib/isc/include/isc/stdio.h,v +retrieving revision 1.13 +diff -p -u -r1.13 stdio.h +--- lib/isc/include/isc/stdio.h 19 Jun 2007 23:47:18 -0000 1.13 ++++ lib/isc/include/isc/stdio.h 6 Apr 2009 13:24:15 -0000 +@@ -72,6 +72,9 @@ isc_stdio_sync(FILE *f); + * direct counterpart in the stdio library. + */ + ++isc_result_t ++isc_stdio_fgetc(FILE *f, int *ret); ++ + ISC_LANG_ENDDECLS + + #endif /* ISC_STDIO_H */ +Index: lib/isc/unix/errno2result.c +=================================================================== +RCS file: /var/snap/bind9/lib/isc/unix/errno2result.c,v +retrieving revision 1.17 +diff -p -u -r1.17 errno2result.c +--- lib/isc/unix/errno2result.c 19 Jun 2007 23:47:18 -0000 1.17 ++++ lib/isc/unix/errno2result.c 6 Apr 2009 13:24:15 -0000 +@@ -43,6 +43,7 @@ isc__errno2result(int posixerrno) { + case EINVAL: /* XXX sometimes this is not for files */ + case ENAMETOOLONG: + case EBADF: ++ case EISDIR: + return (ISC_R_INVALIDFILE); + case ENOENT: + return (ISC_R_FILENOTFOUND); +Index: lib/isc/unix/stdio.c +=================================================================== +RCS file: /var/snap/bind9/lib/isc/unix/stdio.c,v +retrieving revision 1.8 +diff -p -u -r1.8 stdio.c +--- lib/isc/unix/stdio.c 19 Jun 2007 23:47:18 -0000 1.8 ++++ lib/isc/unix/stdio.c 6 Apr 2009 13:24:15 -0000 +@@ -115,3 +115,22 @@ isc_stdio_sync(FILE *f) { + return (isc__errno2result(errno)); + } + ++isc_result_t ++isc_stdio_fgetc(FILE *f, int *ret) { ++ int r; ++ isc_result_t result = ISC_R_SUCCESS; ++ ++#if defined(HAVE_FLOCKFILE) && defined(HAVE_GETCUNLOCKED) ++ r = fgetc_unlocked(f); ++#else ++ r = fgets(f); ++#endif ++ ++ if (r == EOF) ++ result = ferror(f) ? isc__errno2result(errno) : ISC_R_EOF; ++ ++ *ret = r; ++ ++ return result; ++} ++ diff --git a/SOURCES/bind95-rh461409.patch b/SOURCES/bind95-rh461409.patch new file mode 100644 index 0000000..8c0c772 --- /dev/null +++ b/SOURCES/bind95-rh461409.patch @@ -0,0 +1,19 @@ +diff -up bind-9.5.1b1/bin/dig/dighost.c.rh461409 bind-9.5.1b1/bin/dig/dighost.c +--- bind-9.5.1b1/bin/dig/dighost.c.rh461409 2008-09-16 14:04:03.000000000 +0200 ++++ bind-9.5.1b1/bin/dig/dighost.c 2008-09-16 14:06:06.000000000 +0200 +@@ -3665,6 +3665,15 @@ output_filter (isc_buffer_t *buffer, uns + (void) strcpy (tmp1, tmp2); + free (tmp2); + ++ tmp2 = stringprep_utf8_to_locale (tmp1); ++ if (tmp2 == NULL) { ++ debug ("output_filter: stringprep_utf8_to_locale failed"); ++ return ISC_R_SUCCESS; ++ } ++ ++ (void) strcpy (tmp1, tmp2); ++ free (tmp2); ++ + tolen = strlen (tmp1); + if (absolute && !end_with_dot && tmp1[tolen - 1] == '.') + tolen--; diff --git a/SOURCES/bind97-exportlib.patch b/SOURCES/bind97-exportlib.patch new file mode 100644 index 0000000..4468ef5 --- /dev/null +++ b/SOURCES/bind97-exportlib.patch @@ -0,0 +1,226 @@ +diff -up bind-9.9.3rc2/isc-config.sh.in.exportlib bind-9.9.3rc2/isc-config.sh.in +diff -up bind-9.9.3rc2/lib/export/dns/Makefile.in.exportlib bind-9.9.3rc2/lib/export/dns/Makefile.in +--- bind-9.9.3rc2/lib/export/dns/Makefile.in.exportlib 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/lib/export/dns/Makefile.in 2013-05-13 10:45:22.574089729 +0200 +@@ -35,9 +35,9 @@ CDEFINES = -DUSE_MD5 @USE_OPENSSL@ @USE_ + + CWARNINGS = + +-ISCLIBS = ../isc/libisc.@A@ ++ISCLIBS = ../isc/libisc-export.@A@ + +-ISCDEPLIBS = ../isc/libisc.@A@ ++ISCDEPLIBS = ../isc/libisc-export.@A@ + + LIBS = @LIBS@ + +@@ -116,29 +116,29 @@ version.@O@: ${srcdir}/version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libdns.@SA@: ${OBJS} ++libdns-export.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libdns.la: ${OBJS} ++libdns-export.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns.la \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libdns-export.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS} + +-timestamp: libdns.@A@ ++timestamp: libdns-export.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libdns.@A@ \ ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libdns-export.@A@ \ + ${DESTDIR}${export_libdir}/ + + clean distclean:: +- rm -f libdns.@A@ timestamp ++ rm -f libdns-export.@A@ timestamp + rm -f gen code.h include/dns/enumtype.h include/dns/enumclass.h + rm -f include/dns/rdatastruct.h + +diff -up bind-9.9.3rc2/lib/export/irs/Makefile.in.exportlib bind-9.9.3rc2/lib/export/irs/Makefile.in +--- bind-9.9.3rc2/lib/export/irs/Makefile.in.exportlib 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/lib/export/irs/Makefile.in 2013-05-13 10:45:22.575089729 +0200 +@@ -43,9 +43,9 @@ SRCS = context.c \ + gai_sterror.c getaddrinfo.c getnameinfo.c \ + resconf.c + +-ISCLIBS = ../isc/libisc.@A@ +-DNSLIBS = ../dns/libdns.@A@ +-ISCCFGLIBS = ../isccfg/libisccfg.@A@ ++ISCLIBS = ../isc/libisc-export.@A@ ++DNSLIBS = ../dns/libdns-export.@A@ ++ISCCFGLIBS = ../isccfg/libisccfg-export.@A@ + + LIBS = @LIBS@ + +@@ -62,26 +62,26 @@ version.@O@: ${srcdir}/version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libirs.@SA@: ${OBJS} version.@O@ ++libirs-export.@SA@: ${OBJS} version.@O@ + ${AR} ${ARFLAGS} $@ ${OBJS} version.@O@ + ${RANLIB} $@ + +-libirs.la: ${OBJS} version.@O@ ++libirs-export.la: ${OBJS} version.@O@ + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libirs.la \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libirs-export.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} version.@O@ ${LIBS} ${ISCCFGLIBS} ${DNSLIBS} ${ISCLIBS} + +-timestamp: libirs.@A@ ++timestamp: libirs-export.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libirs.@A@ \ ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libirs-export.@A@ \ + ${DESTDIR}${export_libdir}/ + + clean distclean:: +- rm -f libirs.@A@ libirs.la timestamp ++ rm -f libirs-export.@A@ libirs-export.la timestamp +diff -up bind-9.9.3rc2/lib/export/isccfg/Makefile.in.exportlib bind-9.9.3rc2/lib/export/isccfg/Makefile.in +--- bind-9.9.3rc2/lib/export/isccfg/Makefile.in.exportlib 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/lib/export/isccfg/Makefile.in 2013-05-13 10:45:22.576089729 +0200 +@@ -30,11 +30,11 @@ CINCLUDES = -I. ${DNS_INCLUDES} -I${expo + CDEFINES = + CWARNINGS = + +-ISCLIBS = ../isc/libisc.@A@ +-DNSLIBS = ../dns/libdns.@A@ @DNS_CRYPTO_LIBS@ ++ISCLIBS = ../isc/libisc-export.@A@ ++DNSLIBS = ../dns/libdns-export.@A@ @DNS_CRYPTO_LIBS@ + + ISCDEPLIBS = ../../lib/isc/libisc.@A@ +-ISCCFGDEPLIBS = libisccfg.@A@ ++ISCCFGDEPLIBS = libisccfg-export.@A@ + + LIBS = @LIBS@ + +@@ -58,26 +58,26 @@ version.@O@: ${srcdir}/version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libisccfg.@SA@: ${OBJS} ++libisccfg-export.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libisccfg.la: ${OBJS} ++libisccfg-export.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccfg.la \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisccfg-export.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} ${DNSLIBS} ${ISCLIBS} + +-timestamp: libisccfg.@A@ ++timestamp: libisccfg-export.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisccfg.@A@ \ ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisccfg-export.@A@ \ + ${DESTDIR}${export_libdir}/ + + clean distclean:: +- rm -f libisccfg.@A@ timestamp ++ rm -f libisccfg-export.@A@ timestamp +diff -up bind-9.9.3rc2/lib/export/isc/Makefile.in.exportlib bind-9.9.3rc2/lib/export/isc/Makefile.in +--- bind-9.9.3rc2/lib/export/isc/Makefile.in.exportlib 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/lib/export/isc/Makefile.in 2013-05-13 10:45:22.576089729 +0200 +@@ -100,6 +100,10 @@ SRCS = @ISC_EXTRA_SRCS@ \ + + LIBS = @LIBS@ + ++# Note: the order of SUBDIRS is important. ++# Attempt to disable parallel processing. ++.NOTPARALLEL: ++.NO_PARALLEL: + SUBDIRS = include unix nls @ISC_THREAD_DIR@ + TARGETS = timestamp + +@@ -113,26 +117,26 @@ version.@O@: ${srcdir}/version.c + -DLIBAGE=${LIBAGE} \ + -c ${srcdir}/version.c + +-libisc.@SA@: ${OBJS} ++libisc-export.@SA@: ${OBJS} + ${AR} ${ARFLAGS} $@ ${OBJS} + ${RANLIB} $@ + +-libisc.la: ${OBJS} ++libisc-export.la: ${OBJS} + ${LIBTOOL_MODE_LINK} \ +- ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc.la \ ++ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libisc-export.la \ + -rpath ${export_libdir} \ + -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ + ${OBJS} ${LIBS} + +-timestamp: libisc.@A@ ++timestamp: libisc-export.@A@ + touch timestamp + + installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${export_libdir} + + install:: timestamp installdirs +- ${LIBTOOL_MODE_INSTALL} ${INSTALL_DATA} libisc.@A@ \ ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} libisc-export.@A@ \ + ${DESTDIR}${export_libdir} + + clean distclean:: +- rm -f libisc.@A@ libisc.la timestamp ++ rm -f libisc-export.@A@ libisc-export.la timestamp +diff -up bind-9.9.3rc2/lib/export/samples/Makefile.in.exportlib bind-9.9.3rc2/lib/export/samples/Makefile.in +--- bind-9.9.3rc2/lib/export/samples/Makefile.in.exportlib 2013-04-30 08:38:46.000000000 +0200 ++++ bind-9.9.3rc2/lib/export/samples/Makefile.in 2013-05-13 10:45:22.577089729 +0200 +@@ -31,15 +31,15 @@ CINCLUDES = -I${srcdir}/include -I../dns + CDEFINES = + CWARNINGS = + +-DNSLIBS = ../dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +-ISCLIBS = ../isc/libisc.@A@ +-ISCCFGLIBS = ../isccfg/libisccfg.@A@ +-IRSLIBS = ../irs/libirs.@A@ ++DNSLIBS = ../dns/libdns-export.@A@ @DNS_CRYPTO_LIBS@ ++ISCLIBS = ../isc/libisc-export.@A@ ++ISCCFGLIBS = ../isccfg/libisccfg-export.@A@ ++IRSLIBS = ../irs/libirs-export.@A@ + +-DNSDEPLIBS = ../dns/libdns.@A@ +-ISCDEPLIBS = ../isc/libisc.@A@ +-ISCCFGDEPLIBS = ../isccfg/libisccfg.@A@ +-IRSDEPLIBS = ../irs/libirs.@A@ ++DNSDEPLIBS = ../dns/libdns-export.@A@ ++ISCDEPLIBS = ../isc/libisc-export.@A@ ++ISCCFGDEPLIBS = ../isccfg/libisccfg-export.@A@ ++IRSDEPLIBS = ../irs/libirs-export.@A@ + + DEPLIBS = ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} + diff --git a/SOURCES/bind97-rh478718.patch b/SOURCES/bind97-rh478718.patch new file mode 100644 index 0000000..c6ea596 --- /dev/null +++ b/SOURCES/bind97-rh478718.patch @@ -0,0 +1,30 @@ +diff -up bind-9.7.0/configure.in.rh478718 bind-9.7.0/configure.in +--- bind-9.7.0/configure.in.rh478718 2010-03-01 14:50:02.331207076 +0100 ++++ bind-9.7.0/configure.in 2010-03-01 14:50:21.501207488 +0100 +@@ -2540,6 +2540,10 @@ main() { + AC_MSG_RESULT($arch) + fi + ++if test ! "$arch" = "x86_64" -a "$have_xaddq" = "yes"; then ++ AC_MSG_ERROR([XADDQ present but disabled by Fedora patch!]) ++fi ++ + if test "$have_atomic" = "yes"; then + AC_MSG_CHECKING([compiler support for inline assembly code]) + +diff -up bind-9.7.0/lib/isc/include/isc/platform.h.in.rh478718 bind-9.7.0/lib/isc/include/isc/platform.h.in +--- bind-9.7.0/lib/isc/include/isc/platform.h.in.rh478718 2010-03-01 14:50:31.421207522 +0100 ++++ bind-9.7.0/lib/isc/include/isc/platform.h.in 2010-03-01 14:50:40.313707286 +0100 +@@ -255,7 +255,11 @@ + * If the "xaddq" operation (64bit xadd) is available on this architecture, + * ISC_PLATFORM_HAVEXADDQ will be defined. + */ +-@ISC_PLATFORM_HAVEXADDQ@ ++#ifdef __x86_64__ ++#define ISC_PLATFORM_HAVEXADDQ 1 ++#else ++#undef ISC_PLATFORM_HAVEXADDQ ++#endif + + /* + * If the "atomic swap" operation is available on this architecture, diff --git a/SOURCES/bind97-rh570851.patch b/SOURCES/bind97-rh570851.patch new file mode 100644 index 0000000..e24b94c --- /dev/null +++ b/SOURCES/bind97-rh570851.patch @@ -0,0 +1,153 @@ +diff -up bind-9.7.2b1/bin/dig/dighost.c.rh570851 bind-9.7.2b1/bin/dig/dighost.c +--- bind-9.7.2b1/bin/dig/dighost.c.rh570851 2010-08-10 12:55:14.219403986 +0200 ++++ bind-9.7.2b1/bin/dig/dighost.c 2010-08-10 12:56:40.716015777 +0200 +@@ -126,7 +126,8 @@ isc_boolean_t + usesearch = ISC_FALSE, + showsearch = ISC_FALSE, + qr = ISC_FALSE, +- is_dst_up = ISC_FALSE; ++ is_dst_up = ISC_FALSE, ++ verbose = ISC_FALSE; + in_port_t port = 53; + unsigned int timeout = 0; + unsigned int extrabytes; +@@ -1240,10 +1241,24 @@ setup_system(void) { + } + } + ++ if (lwconf->resdebug) { ++ verbose = ISC_TRUE; ++ debug("verbose is on"); ++ } + if (ndots == -1) { + ndots = lwconf->ndots; + debug("ndots is %d.", ndots); + } ++ if (lwconf->attempts) { ++ tries = lwconf->attempts + 1; ++ if (tries < 2) ++ tries = 2; ++ debug("tries is %d.", tries); ++ } ++ if (lwconf->timeout) { ++ timeout = lwconf->timeout; ++ debug("timeout is %d.", timeout); ++ } + + /* If user doesn't specify server use nameservers from resolv.conf. */ + if (ISC_LIST_EMPTY(server_list)) +diff -up bind-9.7.2b1/bin/dig/host.c.rh570851 bind-9.7.2b1/bin/dig/host.c +--- bind-9.7.2b1/bin/dig/host.c.rh570851 2010-08-10 12:57:16.032758098 +0200 ++++ bind-9.7.2b1/bin/dig/host.c 2010-08-10 13:02:12.848559845 +0200 +@@ -659,6 +659,7 @@ parse_args(isc_boolean_t is_batchfile, i + + lookup->servfail_stops = ISC_FALSE; + lookup->comments = ISC_FALSE; ++ short_form = !verbose; + + while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { + switch (c) { +@@ -869,8 +870,8 @@ main(int argc, char **argv) { + result = isc_app_start(); + check_result(result, "isc_app_start"); + setup_libs(); +- parse_args(ISC_FALSE, argc, argv); + setup_system(); ++ parse_args(ISC_FALSE, argc, argv); + result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); + check_result(result, "isc_app_onrun"); + isc_app_run(); +diff -up bind-9.7.2b1/bin/dig/include/dig/dig.h.rh570851 bind-9.7.2b1/bin/dig/include/dig/dig.h +--- bind-9.7.2b1/bin/dig/include/dig/dig.h.rh570851 2010-08-10 13:02:32.722244088 +0200 ++++ bind-9.7.2b1/bin/dig/include/dig/dig.h 2010-08-10 13:02:48.465158159 +0200 +@@ -278,6 +278,7 @@ extern isc_boolean_t debugging, memdebug + extern char *progname; + extern int tries; + extern int fatalexit; ++extern isc_boolean_t verbose; + #ifdef WITH_IDN + extern int idnoptions; + #endif +diff -up bind-9.7.2b1/lib/lwres/include/lwres/lwres.h.rh570851 bind-9.7.2b1/lib/lwres/include/lwres/lwres.h +--- bind-9.7.2b1/lib/lwres/include/lwres/lwres.h.rh570851 2010-08-10 13:04:40.465780506 +0200 ++++ bind-9.7.2b1/lib/lwres/include/lwres/lwres.h 2010-08-10 13:05:57.559867830 +0200 +@@ -243,6 +243,8 @@ typedef struct { + lwres_uint8_t resdebug; /*%< non-zero if 'options debug' set */ + lwres_uint8_t ndots; /*%< set to n in 'options ndots:n' */ + lwres_uint8_t no_tld_query; /*%< non-zero if 'options no_tld_query' */ ++ lwres_int32_t attempts; /*%< set to n in 'options attempts:n' */ ++ lwres_int32_t timeout; /*%< set to n in 'options timeout:n' */ + } lwres_conf_t; + + #define LWRES_ADDRTYPE_V4 0x00000001U /*%< ipv4 */ +diff -up bind-9.7.2b1/lib/lwres/lwconfig.c.rh570851 bind-9.7.2b1/lib/lwres/lwconfig.c +--- bind-9.7.2b1/lib/lwres/lwconfig.c.rh570851 2010-08-10 13:06:08.051778429 +0200 ++++ bind-9.7.2b1/lib/lwres/lwconfig.c 2010-08-10 13:09:53.972555776 +0200 +@@ -237,6 +237,8 @@ lwres_conf_init(lwres_context_t *ctx) { + confdata->resdebug = 0; + confdata->ndots = 1; + confdata->no_tld_query = 0; ++ confdata->attempts = 0; ++ confdata->timeout = 0; + + for (i = 0; i < LWRES_CONFMAXNAMESERVERS; i++) + lwres_resetaddr(&confdata->nameservers[i]); +@@ -289,6 +291,8 @@ lwres_conf_clear(lwres_context_t *ctx) { + confdata->resdebug = 0; + confdata->ndots = 1; + confdata->no_tld_query = 0; ++ confdata->attempts = 0; ++ confdata->timeout = 0; + } + + static lwres_result_t +@@ -530,6 +534,8 @@ static lwres_result_t + lwres_conf_parseoption(lwres_context_t *ctx, FILE *fp) { + int delim; + long ndots; ++ long attempts; ++ long timeout; + char *p; + char word[LWRES_CONFMAXLINELEN]; + lwres_conf_t *confdata; +@@ -546,6 +552,8 @@ lwres_conf_parseoption(lwres_context_t * + confdata->resdebug = 1; + } else if (strcmp("no_tld_query", word) == 0) { + confdata->no_tld_query = 1; ++ } else if (strcmp("debug", word) == 0) { ++ confdata->resdebug = 1; + } else if (strncmp("ndots:", word, 6) == 0) { + ndots = strtol(word + 6, &p, 10); + if (*p != '\0') /* Bad string. */ +@@ -553,6 +561,18 @@ lwres_conf_parseoption(lwres_context_t * + if (ndots < 0 || ndots > 0xff) /* Out of range. */ + return (LWRES_R_FAILURE); + confdata->ndots = (lwres_uint8_t)ndots; ++ } else if (strncmp("timeout:", word, 8) == 0) { ++ timeout = strtol(word + 8, &p, 10); ++ if (*p != '\0') /* Bad string. */ ++ return (LWRES_R_FAILURE); ++ confdata->timeout = (lwres_int32_t)timeout; ++ } else if (strncmp("attempts:", word, 9) == 0) { ++ attempts = strtol(word + 9, &p, 10); ++ if (*p != '\0') /* Bad string. */ ++ return (LWRES_R_FAILURE); ++ if (attempts < 0) /* Out of range. */ ++ return (LWRES_R_FAILURE); ++ confdata->attempts = (lwres_int32_t)attempts; + } + + if (delim == EOF || delim == '\n') +@@ -716,6 +736,12 @@ lwres_conf_print(lwres_context_t *ctx, F + if (confdata->no_tld_query) + fprintf(fp, "options no_tld_query\n"); + ++ if (confdata->attempts) ++ fprintf(fp, "options attempts:%d\n", confdata->attempts); ++ ++ if (confdata->timeout) ++ fprintf(fp, "options timeout:%d\n", confdata->timeout); ++ + return (LWRES_R_SUCCESS); + } + diff --git a/SOURCES/bind97-rh645544.patch b/SOURCES/bind97-rh645544.patch new file mode 100644 index 0000000..d1d8429 --- /dev/null +++ b/SOURCES/bind97-rh645544.patch @@ -0,0 +1,30 @@ +diff -up bind-9.9.4rc2/lib/dns/resolver.c.rh645544 bind-9.9.4rc2/lib/dns/resolver.c +--- bind-9.9.4rc2/lib/dns/resolver.c.rh645544 2013-08-19 10:30:52.000000000 +0200 ++++ bind-9.9.4rc2/lib/dns/resolver.c 2013-09-06 17:58:03.864165823 +0200 +@@ -1138,7 +1138,7 @@ log_edns(fetchctx_t *fctx) { + */ + dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_EDNS_DISABLED, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), + "success resolving '%s' (in '%s'?) after %s", + fctx->info, domainbuf, fctx->reason); + +@@ -3804,7 +3804,7 @@ log_lame(fetchctx_t *fctx, dns_adbaddrin + dns_name_format(&fctx->domain, domainbuf, sizeof(domainbuf)); + isc_sockaddr_format(&addrinfo->sockaddr, addrbuf, sizeof(addrbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_LAME_SERVERS, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_INFO, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), + "lame server resolving '%s' (in '%s'?): %s", + namebuf, domainbuf, addrbuf); + } +@@ -3831,7 +3831,7 @@ log_formerr(fetchctx_t *fctx, const char + } + + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +- DNS_LOGMODULE_RESOLVER, ISC_LOG_NOTICE, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(1), + "DNS format error from %s resolving %s%s%s: %s", + nsbuf, fctx->info, clmsg, clbuf, msgbuf); + } diff --git a/SOURCES/bind97-rh669163.patch b/SOURCES/bind97-rh669163.patch new file mode 100644 index 0000000..125049f --- /dev/null +++ b/SOURCES/bind97-rh669163.patch @@ -0,0 +1,14 @@ +diff -up bind-9.7.2-P3/lib/lwres/lwconfig.c.rh669163 bind-9.7.2-P3/lib/lwres/lwconfig.c +--- bind-9.7.2-P3/lib/lwres/lwconfig.c.rh669163 2011-01-28 14:48:38.934472578 +0100 ++++ bind-9.7.2-P3/lib/lwres/lwconfig.c 2011-01-28 14:49:50.421326035 +0100 +@@ -612,6 +612,10 @@ lwres_conf_parse(lwres_context_t *ctx, c + break; + } + ++ /* Ignore options with no parameters */ ++ if (stopchar == '\n') ++ continue; ++ + if (strlen(word) == 0U) + rval = LWRES_R_SUCCESS; + else if (strcmp(word, "nameserver") == 0) diff --git a/SOURCES/bind97-rh693982.patch b/SOURCES/bind97-rh693982.patch new file mode 100644 index 0000000..57bf812 --- /dev/null +++ b/SOURCES/bind97-rh693982.patch @@ -0,0 +1,35 @@ +diff -up bind-9.7.3-P3/bin/named/server.c.rh693982 bind-9.7.3-P3/bin/named/server.c +--- bind-9.7.3-P3/bin/named/server.c.rh693982 2011-08-12 17:18:55.611978110 +0200 ++++ bind-9.7.3-P3/bin/named/server.c 2011-08-12 17:19:36.009975303 +0200 +@@ -4444,15 +4444,6 @@ load_configuration(const char *filename, + ns_os_changeuser(); + + /* +- * Check that the working directory is writable. +- */ +- if (access(".", W_OK) != 0) { +- isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, +- NS_LOGMODULE_SERVER, ISC_LOG_ERROR, +- "the working directory is not writable"); +- } +- +- /* + * Configure the logging system. + * + * Do this after changing UID to make sure that any log +@@ -4498,6 +4489,15 @@ load_configuration(const char *filename, + } + + /* ++ * Check that the working directory is writable. ++ */ ++ if (access(".", W_OK) != 0) { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), ++ "the working directory is not writable"); ++ } ++ ++ /* + * Set the default value of the query logging flag depending + * whether a "queries" category has been defined. This is + * a disgusting hack, but we need to do this for BIND 8 diff --git a/SOURCES/bind98-rh735103.patch b/SOURCES/bind98-rh735103.patch new file mode 100644 index 0000000..77acfa8 --- /dev/null +++ b/SOURCES/bind98-rh735103.patch @@ -0,0 +1,40 @@ +diff -up bind-9.8.1rc1/lib/isc/unix/socket.c.rh735103 bind-9.8.1rc1/lib/isc/unix/socket.c +--- bind-9.8.1rc1/lib/isc/unix/socket.c.rh735103 2011-07-29 04:19:20.000000000 +0200 ++++ bind-9.8.1rc1/lib/isc/unix/socket.c 2011-09-07 18:49:54.100215897 +0200 +@@ -57,6 +57,20 @@ + #include <isc/util.h> + #include <isc/xml.h> + ++/* See task.c about the following definition: */ ++#ifdef BIND9 ++#ifdef ISC_PLATFORM_USETHREADS ++#define USE_WATCHER_THREAD ++#else ++#define USE_SHARED_MANAGER ++#endif /* ISC_PLATFORM_USETHREADS */ ++#else /* BIND9 */ ++#undef ISC_PLATFORM_HAVESYSUNH ++#undef ISC_PLATFORM_HAVEKQUEUE ++#undef ISC_PLATFORM_HAVEEPOLL ++#undef ISC_PLATFORM_HAVEDEVPOLL ++#endif /* BIND9 */ ++ + #ifdef ISC_PLATFORM_HAVESYSUNH + #include <sys/un.h> + #endif +@@ -76,15 +90,6 @@ + + #include "errno2result.h" + +-/* See task.c about the following definition: */ +-#ifdef BIND9 +-#ifdef ISC_PLATFORM_USETHREADS +-#define USE_WATCHER_THREAD +-#else +-#define USE_SHARED_MANAGER +-#endif /* ISC_PLATFORM_USETHREADS */ +-#endif /* BIND9 */ +- + #ifndef USE_WATCHER_THREAD + #include "socket_p.h" + #include "../task_p.h" diff --git a/SOURCES/bind99-CVE-2014-0591.patch b/SOURCES/bind99-CVE-2014-0591.patch new file mode 100644 index 0000000..ba225b1 --- /dev/null +++ b/SOURCES/bind99-CVE-2014-0591.patch @@ -0,0 +1,53 @@ +diff -pruN bind-9.9.4-P1/bin/named/query.c bind-9.9.4-P2/bin/named/query.c +--- bind-9.9.4-P1/bin/named/query.c 2013-10-16 01:04:32.000000000 +0200 ++++ bind-9.9.4-P2/bin/named/query.c 2013-12-20 01:28:28.000000000 +0100 +@@ -5260,8 +5260,7 @@ query_findclosestnsec3(dns_name_t *qname + dns_fixedname_t fixed; + dns_hash_t hash; + dns_name_t name; +- int order; +- unsigned int count; ++ unsigned int skip = 0, labels; + dns_rdata_nsec3_t nsec3; + dns_rdata_t rdata = DNS_RDATA_INIT; + isc_boolean_t optout; +@@ -5276,6 +5275,7 @@ query_findclosestnsec3(dns_name_t *qname + + dns_name_init(&name, NULL); + dns_name_clone(qname, &name); ++ labels = dns_name_countlabels(&name); + dns_clientinfomethods_init(&cm, ns_client_sourceip); + dns_clientinfo_init(&ci, client); + +@@ -5309,13 +5309,14 @@ query_findclosestnsec3(dns_name_t *qname + dns_rdata_reset(&rdata); + optout = ISC_TF((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0); + if (found != NULL && optout && +- dns_name_fullcompare(&name, dns_db_origin(db), &order, +- &count) == dns_namereln_subdomain) { ++ dns_name_issubdomain(&name, dns_db_origin(db))) ++ { + dns_rdataset_disassociate(rdataset); + if (dns_rdataset_isassociated(sigrdataset)) + dns_rdataset_disassociate(sigrdataset); +- count = dns_name_countlabels(&name) - 1; +- dns_name_getlabelsequence(&name, 1, count, &name); ++ skip++; ++ dns_name_getlabelsequence(qname, skip, labels - skip, ++ &name); + ns_client_log(client, DNS_LOGCATEGORY_DNSSEC, + NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(3), + "looking for closest provable encloser"); +@@ -5333,7 +5334,11 @@ query_findclosestnsec3(dns_name_t *qname + ns_client_log(client, DNS_LOGCATEGORY_DNSSEC, + NS_LOGMODULE_QUERY, ISC_LOG_WARNING, + "expected covering NSEC3, got an exact match"); +- if (found != NULL) ++ if (found == qname) { ++ if (skip != 0U) ++ dns_name_getlabelsequence(qname, skip, labels - skip, ++ found); ++ } else if (found != NULL) + dns_name_copy(&name, found, NULL); + return; + } diff --git a/SOURCES/bind99-CVE-2014-8500.patch b/SOURCES/bind99-CVE-2014-8500.patch new file mode 100644 index 0000000..1369769 --- /dev/null +++ b/SOURCES/bind99-CVE-2014-8500.patch @@ -0,0 +1,924 @@ +diff -up bind-9.9.4/bin/named/config.c.CVE-2014-8500 bind-9.9.4/bin/named/config.c +--- bind-9.9.4/bin/named/config.c.CVE-2014-8500 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/bin/named/config.c 2014-12-10 14:56:24.959552559 +0100 +@@ -160,6 +160,8 @@ options {\n\ + dnssec-accept-expired no;\n\ + clients-per-query 10;\n\ + max-clients-per-query 100;\n\ ++ max-recursion-depth 7;\n\ ++ max-recursion-queries 50;\n\ + zero-no-soa-ttl-cache no;\n\ + nsec3-test-zone no;\n\ + allow-new-zones no;\n\ +diff -up bind-9.9.4/bin/named/query.c.CVE-2014-8500 bind-9.9.4/bin/named/query.c +--- bind-9.9.4/bin/named/query.c.CVE-2014-8500 2014-12-10 14:56:24.945552543 +0100 ++++ bind-9.9.4/bin/named/query.c 2014-12-10 14:56:24.960552560 +0100 +@@ -3872,12 +3872,11 @@ query_recurse(ns_client_t *client, dns_r + peeraddr = &client->peeraddr; + else + peeraddr = NULL; +- result = dns_resolver_createfetch2(client->view->resolver, ++ result = dns_resolver_createfetch3(client->view->resolver, + qname, qtype, qdomain, nameservers, + NULL, peeraddr, client->message->id, +- client->query.fetchoptions, +- client->task, +- query_resume, client, ++ client->query.fetchoptions, 0, NULL, ++ client->task, query_resume, client, + rdataset, sigrdataset, + &client->query.fetch); + +diff -up bind-9.9.4/bin/named/server.c.CVE-2014-8500 bind-9.9.4/bin/named/server.c +--- bind-9.9.4/bin/named/server.c.CVE-2014-8500 2014-12-10 14:56:24.913552507 +0100 ++++ bind-9.9.4/bin/named/server.c 2014-12-10 14:56:24.961552561 +0100 +@@ -3205,6 +3205,16 @@ configure_view(dns_view_t *view, cfg_obj + cfg_obj_asuint32(obj), + max_clients_per_query); + ++ obj = NULL; ++ result = ns_config_get(maps, "max-recursion-depth", &obj); ++ INSIST(result == ISC_R_SUCCESS); ++ dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj)); ++ ++ obj = NULL; ++ result = ns_config_get(maps, "max-recursion-queries", &obj); ++ INSIST(result == ISC_R_SUCCESS); ++ dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj)); ++ + #ifdef ALLOW_FILTER_AAAA_ON_V4 + obj = NULL; + result = ns_config_get(maps, "filter-aaaa-on-v4", &obj); +diff -up bind-9.9.4/doc/arm/Bv9ARM-book.xml.CVE-2014-8500 bind-9.9.4/doc/arm/Bv9ARM-book.xml +--- bind-9.9.4/doc/arm/Bv9ARM-book.xml.CVE-2014-8500 2014-12-10 14:56:24.957552556 +0100 ++++ bind-9.9.4/doc/arm/Bv9ARM-book.xml 2014-12-10 15:00:53.108931629 +0100 +@@ -4874,6 +4874,8 @@ badresp:1,adberr:0,findfail:0,valfail:0] + <optional> max-acache-size <replaceable>size_spec</replaceable> ; </optional> + <optional> clients-per-query <replaceable>number</replaceable> ; </optional> + <optional> max-clients-per-query <replaceable>number</replaceable> ; </optional> ++ <optional> max-recursion-depth <replaceable>number</replaceable> ; </optional> ++ <optional> max-recursion-queries <replaceable>number</replaceable> ; </optional> + <optional> masterfile-format (<constant>text</constant>|<constant>raw</constant>) ; </optional> + <optional> empty-server <replaceable>name</replaceable> ; </optional> + <optional> empty-contact <replaceable>name</replaceable> ; </optional> +@@ -8623,6 +8625,35 @@ avoid-v6-udp-ports { 40000; range 50000 + </para> + </listitem> + </varlistentry> ++ ++ <varlistentry id="max-recursion-depth"> ++ <term><command>max-recursion-depth</command></term> ++ <listitem> ++ <para> ++ Sets the maximum number of levels of recursion ++ that are permitted at any one time while servicing ++ a recursive query. Resolving a name may require ++ looking up a name server address, which in turn ++ requires resolving another name, etc; if the number ++ of indirections exceeds this value, the recursive ++ query is terminated and returns SERVFAIL. The ++ default is 7. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry id="max-recursion-queries"> ++ <term><command>max-recursion-queries</command></term> ++ <listitem> ++ <para> ++ Sets the maximum number of iterative queries that ++ may be sent while servicing a recursive query. ++ If more queries are sent, the recursive query ++ is terminated and returns SERVFAIL. The default ++ is 50. ++ </para> ++ </listitem> ++ </varlistentry> + + <varlistentry> + <term><command>notify-delay</command></term> +diff -up bind-9.9.4/doc/misc/options.CVE-2014-8500 bind-9.9.4/doc/misc/options +--- bind-9.9.4/doc/misc/options.CVE-2014-8500 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/doc/misc/options 2014-12-10 14:56:24.964552564 +0100 +@@ -162,6 +162,8 @@ options { + max-ixfr-log-size <size>; // obsolete + max-journal-size <size_no_default>; + max-ncache-ttl <integer>; ++ max-recursion-depth <integer>; ++ max-recursion-queries <integer>; + max-refresh-time <integer>; + max-retry-time <integer>; + max-rsa-exponent-size <integer>; +@@ -385,6 +387,8 @@ view <string> <optional_class> { + max-ixfr-log-size <size>; // obsolete + max-journal-size <size_no_default>; + max-ncache-ttl <integer>; ++ max-recursion-depth <integer>; ++ max-recursion-queries <integer>; + max-refresh-time <integer>; + max-retry-time <integer>; + max-transfer-idle-in <integer>; +diff -up bind-9.9.4/lib/dns/adb.c.CVE-2014-8500 bind-9.9.4/lib/dns/adb.c +--- bind-9.9.4/lib/dns/adb.c.CVE-2014-8500 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/dns/adb.c 2014-12-10 14:56:24.965552566 +0100 +@@ -201,6 +201,7 @@ struct dns_adbfetch { + unsigned int magic; + dns_fetch_t *fetch; + dns_rdataset_t rdataset; ++ unsigned int depth; + }; + + /*% +@@ -300,8 +301,7 @@ static inline isc_boolean_t dec_entry_re + static inline void violate_locking_hierarchy(isc_mutex_t *, isc_mutex_t *); + static isc_boolean_t clean_namehooks(dns_adb_t *, dns_adbnamehooklist_t *); + static void clean_target(dns_adb_t *, dns_name_t *); +-static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, +- unsigned int); ++static void clean_finds_at_name(dns_adbname_t *, isc_eventtype_t, unsigned int); + static isc_boolean_t check_expire_namehooks(dns_adbname_t *, isc_stdtime_t); + static isc_boolean_t check_expire_entry(dns_adb_t *, dns_adbentry_t **, + isc_stdtime_t); +@@ -309,6 +309,7 @@ static void cancel_fetches_at_name(dns_a + static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, + dns_rdatatype_t); + static isc_result_t fetch_name(dns_adbname_t *, isc_boolean_t, ++ unsigned int, isc_counter_t *qc, + dns_rdatatype_t); + static inline void check_exit(dns_adb_t *); + static void destroy(dns_adb_t *); +@@ -2770,6 +2771,19 @@ dns_adb_createfind(dns_adb_t *adb, isc_t + isc_stdtime_t now, dns_name_t *target, + in_port_t port, dns_adbfind_t **findp) + { ++ return (dns_adb_createfind2(adb, task, action, arg, name, ++ qname, qtype, options, now, ++ target, port, 0, NULL, findp)); ++} ++ ++isc_result_t ++dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, ++ void *arg, dns_name_t *name, dns_name_t *qname, ++ dns_rdatatype_t qtype, unsigned int options, ++ isc_stdtime_t now, dns_name_t *target, ++ in_port_t port, unsigned int depth, isc_counter_t *qc, ++ dns_adbfind_t **findp) ++{ + dns_adbfind_t *find; + dns_adbname_t *adbname; + int bucket; +@@ -3000,7 +3014,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_t + * Start V4. + */ + if (WANT_INET(wanted_fetches) && +- fetch_name(adbname, start_at_zone, ++ fetch_name(adbname, start_at_zone, depth, qc, + dns_rdatatype_a) == ISC_R_SUCCESS) { + DP(DEF_LEVEL, + "dns_adb_createfind: started A fetch for name %p", +@@ -3011,7 +3025,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_t + * Start V6. + */ + if (WANT_INET6(wanted_fetches) && +- fetch_name(adbname, start_at_zone, ++ fetch_name(adbname, start_at_zone, depth, qc, + dns_rdatatype_aaaa) == ISC_R_SUCCESS) { + DP(DEF_LEVEL, + "dns_adb_createfind: " +@@ -3754,6 +3768,12 @@ fetch_callback(isc_task_t *task, isc_eve + DP(DEF_LEVEL, "adb: fetch of '%s' %s failed: %s", + buf, address_type == DNS_ADBFIND_INET ? "A" : "AAAA", + dns_result_totext(dev->result)); ++ /* ++ * Don't record a failure unless this is the initial ++ * fetch of a chain. ++ */ ++ if (fetch->depth > 1) ++ goto out; + /* XXXMLG Don't pound on bad servers. */ + if (address_type == DNS_ADBFIND_INET) { + name->expire_v4 = ISC_MIN(name->expire_v4, now + 300); +@@ -3791,9 +3811,8 @@ fetch_callback(isc_task_t *task, isc_eve + } + + static isc_result_t +-fetch_name(dns_adbname_t *adbname, +- isc_boolean_t start_at_zone, +- dns_rdatatype_t type) ++fetch_name(dns_adbname_t *adbname, isc_boolean_t start_at_zone, ++ unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type) + { + isc_result_t result; + dns_adbfetch_t *fetch = NULL; +@@ -3838,12 +3857,14 @@ fetch_name(dns_adbname_t *adbname, + result = ISC_R_NOMEMORY; + goto cleanup; + } ++ fetch->depth = depth; + +- result = dns_resolver_createfetch(adb->view->resolver, &adbname->name, +- type, name, nameservers, NULL, +- options, adb->task, fetch_callback, +- adbname, &fetch->rdataset, NULL, +- &fetch->fetch); ++ result = dns_resolver_createfetch3(adb->view->resolver, &adbname->name, ++ type, name, nameservers, NULL, ++ NULL, 0, options, depth, qc, ++ adb->task, fetch_callback, adbname, ++ &fetch->rdataset, NULL, ++ &fetch->fetch); + if (result != ISC_R_SUCCESS) + goto cleanup; + +diff -up bind-9.9.4/lib/dns/include/dns/adb.h.CVE-2014-8500 bind-9.9.4/lib/dns/include/dns/adb.h +--- bind-9.9.4/lib/dns/include/dns/adb.h.CVE-2014-8500 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/dns/include/dns/adb.h 2014-12-10 14:56:24.965552566 +0100 +@@ -334,6 +334,13 @@ dns_adb_createfind(dns_adb_t *adb, isc_t + dns_rdatatype_t qtype, unsigned int options, + isc_stdtime_t now, dns_name_t *target, + in_port_t port, dns_adbfind_t **find); ++isc_result_t ++dns_adb_createfind2(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, ++ void *arg, dns_name_t *name, dns_name_t *qname, ++ dns_rdatatype_t qtype, unsigned int options, ++ isc_stdtime_t now, dns_name_t *target, in_port_t port, ++ unsigned int depth, isc_counter_t *qc, ++ dns_adbfind_t **find); + /*%< + * Main interface for clients. The adb will look up the name given in + * "name" and will build up a list of found addresses, and perhaps start +diff -up bind-9.9.4/lib/dns/include/dns/resolver.h.CVE-2014-8500 bind-9.9.4/lib/dns/include/dns/resolver.h +--- bind-9.9.4/lib/dns/include/dns/resolver.h.CVE-2014-8500 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/dns/include/dns/resolver.h 2014-12-10 14:56:24.965552566 +0100 +@@ -274,6 +274,18 @@ dns_resolver_createfetch2(dns_resolver_t + dns_rdataset_t *rdataset, + dns_rdataset_t *sigrdataset, + dns_fetch_t **fetchp); ++isc_result_t ++dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name, ++ dns_rdatatype_t type, ++ dns_name_t *domain, dns_rdataset_t *nameservers, ++ dns_forwarders_t *forwarders, ++ isc_sockaddr_t *client, isc_uint16_t id, ++ unsigned int options, unsigned int depth, ++ isc_counter_t *qc, isc_task_t *task, ++ isc_taskaction_t action, void *arg, ++ dns_rdataset_t *rdataset, ++ dns_rdataset_t *sigrdataset, ++ dns_fetch_t **fetchp); + /*%< + * Recurse to answer a question. + * +@@ -573,6 +585,30 @@ dns_resolver_printbadcache(dns_resolver_ + * + * Requires: + * \li resolver to be valid. ++ */ ++ ++void ++dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth); ++unsigned int ++dns_resolver_getmaxdepth(dns_resolver_t *resolver); ++/*% ++ * Get and set how many NS indirections will be followed when looking for ++ * nameserver addresses. ++ * ++ * Requires: ++ * \li resolver to be valid. ++ */ ++ ++void ++dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries); ++unsigned int ++dns_resolver_getmaxqueries(dns_resolver_t *resolver); ++/*% ++ * Get and set how many iterative queries will be allowed before ++ * terminating a recursive query. ++ * ++ * Requires: ++ * \li resolver to be valid. + */ + + ISC_LANG_ENDDECLS +diff -up bind-9.9.4/lib/dns/resolver.c.CVE-2014-8500 bind-9.9.4/lib/dns/resolver.c +--- bind-9.9.4/lib/dns/resolver.c.CVE-2014-8500 2014-12-10 14:56:24.952552551 +0100 ++++ bind-9.9.4/lib/dns/resolver.c 2014-12-10 15:01:56.855970646 +0100 +@@ -21,6 +21,7 @@ + + #include <config.h> + ++#include <isc/counter.h> + #include <isc/log.h> + #include <isc/platform.h> + #include <isc/print.h> +@@ -130,6 +131,16 @@ + #define MAXIMUM_QUERY_TIMEOUT 30 /* The maximum time in seconds for the whole query to live. */ + #endif + ++/* The default maximum number of recursions to follow before giving up. */ ++#ifndef DEFAULT_RECURSION_DEPTH ++#define DEFAULT_RECURSION_DEPTH 7 ++#endif ++ ++/* The default maximum number of iterative queries to allow before giving up. */ ++#ifndef DEFAULT_MAX_QUERIES ++#define DEFAULT_MAX_QUERIES 50 ++#endif ++ + /*% + * Maximum EDNS0 input packet size. + */ +@@ -233,12 +244,13 @@ struct fetchctx { + isc_sockaddrlist_t edns; + isc_sockaddrlist_t edns512; + isc_sockaddrlist_t bad_edns; +- dns_validator_t *validator; ++ dns_validator_t * validator; + ISC_LIST(dns_validator_t) validators; + dns_db_t * cache; + dns_adb_t * adb; + isc_boolean_t ns_ttl_ok; + isc_uint32_t ns_ttl; ++ isc_counter_t * qc; + + /*% + * The number of events we're waiting for. +@@ -306,6 +318,7 @@ struct fetchctx { + isc_boolean_t timeout; + dns_adbaddrinfo_t *addrinfo; + isc_sockaddr_t *client; ++ unsigned int depth; + }; + + #define FCTX_MAGIC ISC_MAGIC('F', '!', '!', '!') +@@ -418,6 +431,8 @@ struct dns_resolver { + isc_timer_t * spillattimer; + isc_boolean_t zero_no_soa_ttl; + unsigned int query_timeout; ++ unsigned int maxdepth; ++ unsigned int maxqueries; + + /* Locked by lock. */ + unsigned int references; +@@ -1533,6 +1548,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddr + if (result != ISC_R_SUCCESS) + goto cleanup_dispatch; + } ++ + fctx->querysent++; + + ISC_LIST_APPEND(fctx->queries, query, link); +@@ -2186,9 +2202,9 @@ fctx_finddone(isc_task_t *task, isc_even + */ + INSIST(!SHUTTINGDOWN(fctx)); + fctx->attributes &= ~FCTX_ATTR_ADDRWAIT; +- if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) ++ if (event->ev_type == DNS_EVENT_ADBMOREADDRESSES) { + want_try = ISC_TRUE; +- else { ++ } else { + fctx->findfail++; + if (fctx->pending == 0) { + /* +@@ -2471,12 +2487,13 @@ findname(fetchctx_t *fctx, dns_name_t *n + * See what we know about this address. + */ + find = NULL; +- result = dns_adb_createfind(fctx->adb, +- res->buckets[fctx->bucketnum].task, +- fctx_finddone, fctx, name, +- &fctx->name, fctx->type, +- options, now, NULL, +- res->view->dstport, &find); ++ result = dns_adb_createfind2(fctx->adb, ++ res->buckets[fctx->bucketnum].task, ++ fctx_finddone, fctx, name, ++ &fctx->name, fctx->type, ++ options, now, NULL, ++ res->view->dstport, ++ fctx->depth + 1, fctx->qc, &find); + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_ALIAS) { + /* +@@ -2584,6 +2601,14 @@ fctx_getaddresses(fetchctx_t *fctx, isc_ + + res = fctx->res; + ++ if (fctx->depth > res->maxdepth) { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), ++ "too much NS indirection resolving '%s'", ++ fctx->info); ++ return (DNS_R_SERVFAIL); ++ } ++ + /* + * Forwarders. + */ +@@ -3059,6 +3084,16 @@ fctx_try(fetchctx_t *fctx, isc_boolean_t + } + } + ++ result = isc_counter_increment(fctx->qc); ++ if (result != ISC_R_SUCCESS) { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, ++ DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), ++ "exceeded max queries resolving '%s'", ++ fctx->info); ++ fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); ++ return; ++ } ++ + result = fctx_query(fctx, addrinfo, fctx->options); + if (result != ISC_R_SUCCESS) + fctx_done(fctx, result, __LINE__); +@@ -3157,6 +3192,7 @@ fctx_destroy(fetchctx_t *fctx) { + isc_mem_put(fctx->mctx, sa, sizeof(*sa)); + } + ++ isc_counter_detach(&fctx->qc); + isc_timer_detach(&fctx->timer); + dns_message_destroy(&fctx->rmessage); + dns_message_destroy(&fctx->qmessage); +@@ -3485,7 +3521,8 @@ log_ns_ttl(fetchctx_t *fctx, const char + static isc_result_t + fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type, + dns_name_t *domain, dns_rdataset_t *nameservers, +- unsigned int options, unsigned int bucketnum, fetchctx_t **fctxp) ++ unsigned int options, unsigned int bucketnum, unsigned int depth, ++ isc_counter_t *qc, fetchctx_t **fctxp) + { + fetchctx_t *fctx; + isc_result_t result; +@@ -3507,6 +3544,21 @@ fctx_create(dns_resolver_t *res, dns_nam + fctx = isc_mem_get(mctx, sizeof(*fctx)); + if (fctx == NULL) + return (ISC_R_NOMEMORY); ++ ++ fctx->qc = NULL; ++ if (qc != NULL) { ++ isc_counter_attach(qc, &fctx->qc); ++ } else { ++ result = isc_counter_create(res->mctx, ++ res->maxqueries, &fctx->qc); ++ if (result != ISC_R_SUCCESS) ++ goto cleanup_fetch; ++ } ++ ++ /* ++ * Make fctx->info point to a copy of a formatted string ++ * "name/type". ++ */ + dns_name_format(name, buf, sizeof(buf)); + dns_rdatatype_format(type, typebuf, sizeof(typebuf)); + strcat(buf, "/"); /* checked */ +@@ -3514,7 +3566,7 @@ fctx_create(dns_resolver_t *res, dns_nam + fctx->info = isc_mem_strdup(mctx, buf); + if (fctx->info == NULL) { + result = ISC_R_NOMEMORY; +- goto cleanup_fetch; ++ goto cleanup_counter; + } + FCTXTRACE("create"); + dns_name_init(&fctx->name, NULL); +@@ -3537,6 +3589,7 @@ fctx_create(dns_resolver_t *res, dns_nam + fctx->state = fetchstate_init; + fctx->want_shutdown = ISC_FALSE; + fctx->cloned = ISC_FALSE; ++ fctx->depth = depth; + ISC_LIST_INIT(fctx->queries); + ISC_LIST_INIT(fctx->finds); + ISC_LIST_INIT(fctx->altfinds); +@@ -3742,6 +3795,9 @@ fctx_create(dns_resolver_t *res, dns_nam + cleanup_info: + isc_mem_free(mctx, fctx->info); + ++ cleanup_counter: ++ isc_counter_detach(&fctx->qc); ++ + cleanup_fetch: + isc_mem_put(mctx, fctx, sizeof(*fctx)); + +@@ -5655,7 +5711,7 @@ noanswer_response(fetchctx_t *fctx, dns_ + char qbuf[DNS_NAME_FORMATSIZE]; + char nbuf[DNS_NAME_FORMATSIZE]; + char tbuf[DNS_RDATATYPE_FORMATSIZE]; +- dns_rdatatype_format(fctx->type, tbuf, ++ dns_rdatatype_format(type, tbuf, + sizeof(tbuf)); + dns_name_format(name, nbuf, + sizeof(nbuf)); +@@ -5664,7 +5720,7 @@ noanswer_response(fetchctx_t *fctx, dns_ + log_formerr(fctx, + "unrelated %s %s in " + "%s authority section", +- tbuf, qbuf, nbuf); ++ tbuf, nbuf, qbuf); + return (DNS_R_FORMERR); + } + if (type == dns_rdatatype_ns) { +@@ -7725,6 +7781,8 @@ dns_resolver_create(dns_view_t *view, + res->spillattimer = NULL; + res->zero_no_soa_ttl = ISC_FALSE; + res->query_timeout = DEFAULT_QUERY_TIMEOUT; ++ res->maxdepth = DEFAULT_RECURSION_DEPTH; ++ res->maxqueries = DEFAULT_MAX_QUERIES; + res->nbuckets = ntasks; + res->activebuckets = ntasks; + res->buckets = isc_mem_get(view->mctx, +@@ -8163,9 +8221,9 @@ dns_resolver_createfetch(dns_resolver_t + dns_rdataset_t *sigrdataset, + dns_fetch_t **fetchp) + { +- return (dns_resolver_createfetch2(res, name, type, domain, ++ return (dns_resolver_createfetch3(res, name, type, domain, + nameservers, forwarders, NULL, 0, +- options, task, action, arg, ++ options, 0, NULL, task, action, arg, + rdataset, sigrdataset, fetchp)); + } + +@@ -8181,6 +8239,25 @@ dns_resolver_createfetch2(dns_resolver_t + dns_rdataset_t *sigrdataset, + dns_fetch_t **fetchp) + { ++ return (dns_resolver_createfetch3(res, name, type, domain, ++ nameservers, forwarders, client, id, ++ options, 0, NULL, task, action, arg, ++ rdataset, sigrdataset, fetchp)); ++} ++ ++isc_result_t ++dns_resolver_createfetch3(dns_resolver_t *res, dns_name_t *name, ++ dns_rdatatype_t type, ++ dns_name_t *domain, dns_rdataset_t *nameservers, ++ dns_forwarders_t *forwarders, ++ isc_sockaddr_t *client, dns_messageid_t id, ++ unsigned int options, unsigned int depth, ++ isc_counter_t *qc, isc_task_t *task, ++ isc_taskaction_t action, void *arg, ++ dns_rdataset_t *rdataset, ++ dns_rdataset_t *sigrdataset, ++ dns_fetch_t **fetchp) ++{ + dns_fetch_t *fetch; + fetchctx_t *fctx = NULL; + isc_result_t result = ISC_R_SUCCESS; +@@ -8269,11 +8346,12 @@ dns_resolver_createfetch2(dns_resolver_t + + if (fctx == NULL) { + result = fctx_create(res, name, type, domain, nameservers, +- options, bucketnum, &fctx); ++ options, bucketnum, depth, qc, &fctx); + if (result != ISC_R_SUCCESS) + goto unlock; + new_fctx = ISC_TRUE; +- } ++ } else if (fctx->depth > depth) ++ fctx->depth = depth; + + result = fctx_join(fctx, task, client, id, action, arg, + rdataset, sigrdataset, fetch); +@@ -9045,3 +9123,27 @@ dns_resolver_settimeout(dns_resolver_t * + + resolver->query_timeout = seconds; + } ++ ++void ++dns_resolver_setmaxdepth(dns_resolver_t *resolver, unsigned int maxdepth) { ++ REQUIRE(VALID_RESOLVER(resolver)); ++ resolver->maxdepth = maxdepth; ++} ++ ++unsigned int ++dns_resolver_getmaxdepth(dns_resolver_t *resolver) { ++ REQUIRE(VALID_RESOLVER(resolver)); ++ return (resolver->maxdepth); ++} ++ ++void ++dns_resolver_setmaxqueries(dns_resolver_t *resolver, unsigned int queries) { ++ REQUIRE(VALID_RESOLVER(resolver)); ++ resolver->maxqueries = queries; ++} ++ ++unsigned int ++dns_resolver_getmaxqueries(dns_resolver_t *resolver) { ++ REQUIRE(VALID_RESOLVER(resolver)); ++ return (resolver->maxqueries); ++} +diff -up bind-9.9.4/lib/export/isc/Makefile.in.CVE-2014-8500 bind-9.9.4/lib/export/isc/Makefile.in +--- bind-9.9.4/lib/export/isc/Makefile.in.CVE-2014-8500 2014-12-10 14:56:24.907552500 +0100 ++++ bind-9.9.4/lib/export/isc/Makefile.in 2014-12-10 14:56:24.967552568 +0100 +@@ -63,7 +63,7 @@ WIN32OBJS = win32/condition.@O@ win32/d + # Alphabetically + OBJS = @ISC_EXTRA_OBJS@ \ + assertions.@O@ backtrace.@O@ backtrace-emptytbl.@O@ base32.@O@ \ +- base64.@O@ buffer.@O@ bufferlist.@O@ \ ++ base64.@O@ buffer.@O@ bufferlist.@O@ counter.@O@ \ + error.@O@ event.@O@ \ + hash.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \ + inet_aton.@O@ iterated_hash.@O@ lex.@O@ lfsr.@O@ log.@O@ \ +@@ -85,7 +85,7 @@ ISCDRIVERSRCS = mem.c task.c lib.c timer + + SRCS = @ISC_EXTRA_SRCS@ \ + assertions.c backtrace.c backtrace-emptytbl.c base32.c \ +- base64.c buffer.c bufferlist.c \ ++ base64.c buffer.c bufferlist.c counter.c \ + error.c event.c \ + hash.c hex.c hmacmd5.c hmacsha.c \ + inet_aton.c iterated_hash.c lex.c log.c lfsr.c \ +diff -up bind-9.9.4/lib/isccfg/namedconf.c.CVE-2014-8500 bind-9.9.4/lib/isccfg/namedconf.c +--- bind-9.9.4/lib/isccfg/namedconf.c.CVE-2014-8500 2014-12-10 14:56:24.969552570 +0100 ++++ bind-9.9.4/lib/isccfg/namedconf.c 2014-12-10 15:04:14.636091707 +0100 +@@ -1421,6 +1421,8 @@ view_clauses[] = { + { "max-cache-ttl", &cfg_type_uint32, 0 }, + { "max-clients-per-query", &cfg_type_uint32, 0 }, + { "max-ncache-ttl", &cfg_type_uint32, 0 }, ++ { "max-recursion-depth", &cfg_type_uint32, 0 }, ++ { "max-recursion-queries", &cfg_type_uint32, 0 }, + { "max-udp-size", &cfg_type_uint32, 0 }, + { "min-roots", &cfg_type_uint32, CFG_CLAUSEFLAG_NOTIMP }, + { "minimal-responses", &cfg_type_boolean, 0 }, +diff -up bind-9.9.4/lib/isc/counter.c.CVE-2014-8500 bind-9.9.4/lib/isc/counter.c +--- bind-9.9.4/lib/isc/counter.c.CVE-2014-8500 2014-12-10 14:56:24.968552569 +0100 ++++ bind-9.9.4/lib/isc/counter.c 2014-12-10 14:56:24.968552569 +0100 +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <stddef.h> ++ ++#include <isc/counter.h> ++#include <isc/magic.h> ++#include <isc/mem.h> ++#include <isc/util.h> ++ ++#define COUNTER_MAGIC ISC_MAGIC('C', 'n', 't', 'r') ++#define VALID_COUNTER(r) ISC_MAGIC_VALID(r, COUNTER_MAGIC) ++ ++struct isc_counter { ++ unsigned int magic; ++ isc_mem_t *mctx; ++ isc_mutex_t lock; ++ unsigned int references; ++ unsigned int limit; ++ unsigned int used; ++}; ++ ++isc_result_t ++isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp) { ++ isc_result_t result; ++ isc_counter_t *counter; ++ ++ REQUIRE(counterp != NULL && *counterp == NULL); ++ ++ counter = isc_mem_get(mctx, sizeof(*counter)); ++ if (counter == NULL) ++ return (ISC_R_NOMEMORY); ++ ++ result = isc_mutex_init(&counter->lock); ++ if (result != ISC_R_SUCCESS) { ++ isc_mem_put(mctx, counter, sizeof(*counter)); ++ return (result); ++ } ++ ++ counter->mctx = NULL; ++ isc_mem_attach(mctx, &counter->mctx); ++ ++ counter->references = 1; ++ counter->limit = limit; ++ counter->used = 0; ++ ++ counter->magic = COUNTER_MAGIC; ++ *counterp = counter; ++ return (ISC_R_SUCCESS); ++} ++ ++isc_result_t ++isc_counter_increment(isc_counter_t *counter) { ++ isc_result_t result = ISC_R_SUCCESS; ++ ++ LOCK(&counter->lock); ++ counter->used++; ++ if (counter->limit != 0 && counter->used >= counter->limit) ++ result = ISC_R_QUOTA; ++ UNLOCK(&counter->lock); ++ ++ return (result); ++} ++ ++unsigned int ++isc_counter_used(isc_counter_t *counter) { ++ REQUIRE(VALID_COUNTER(counter)); ++ ++ return (counter->used); ++} ++ ++void ++isc_counter_setlimit(isc_counter_t *counter, int limit) { ++ REQUIRE(VALID_COUNTER(counter)); ++ ++ LOCK(&counter->lock); ++ counter->limit = limit; ++ UNLOCK(&counter->lock); ++} ++ ++void ++isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp) { ++ REQUIRE(VALID_COUNTER(source)); ++ REQUIRE(targetp != NULL && *targetp == NULL); ++ ++ LOCK(&source->lock); ++ source->references++; ++ INSIST(source->references > 0); ++ UNLOCK(&source->lock); ++ ++ *targetp = source; ++} ++ ++static void ++destroy(isc_counter_t *counter) { ++ counter->magic = 0; ++ isc_mutex_destroy(&counter->lock); ++ isc_mem_putanddetach(&counter->mctx, counter, sizeof(*counter)); ++} ++ ++void ++isc_counter_detach(isc_counter_t **counterp) { ++ isc_counter_t *counter; ++ isc_boolean_t want_destroy = ISC_FALSE; ++ ++ REQUIRE(counterp != NULL && *counterp != NULL); ++ counter = *counterp; ++ REQUIRE(VALID_COUNTER(counter)); ++ ++ *counterp = NULL; ++ ++ LOCK(&counter->lock); ++ INSIST(counter->references > 0); ++ counter->references--; ++ if (counter->references == 0) ++ want_destroy = ISC_TRUE; ++ UNLOCK(&counter->lock); ++ ++ if (want_destroy) ++ destroy(counter); ++} +diff -up bind-9.9.4/lib/isc/include/isc/counter.h.CVE-2014-8500 bind-9.9.4/lib/isc/include/isc/counter.h +--- bind-9.9.4/lib/isc/include/isc/counter.h.CVE-2014-8500 2014-12-10 14:56:24.968552569 +0100 ++++ bind-9.9.4/lib/isc/include/isc/counter.h 2014-12-10 14:56:24.968552569 +0100 +@@ -0,0 +1,90 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef ISC_COUNTER_H ++#define ISC_COUNTER_H 1 ++ ++/***** ++ ***** Module Info ++ *****/ ++ ++/*! \file isc/counter.h ++ * ++ * \brief The isc_counter_t object is a simplified version of the ++ * isc_quota_t object; it tracks the consumption of limited ++ * resources, returning an error condition when the quota is ++ * exceeded. However, unlike isc_quota_t, attaching and detaching ++ * from a counter object does not increment or decrement the counter. ++ */ ++ ++/*** ++ *** Imports. ++ ***/ ++ ++#include <isc/lang.h> ++#include <isc/mutex.h> ++#include <isc/types.h> ++ ++/***** ++ ***** Types. ++ *****/ ++ ++ISC_LANG_BEGINDECLS ++ ++isc_result_t ++isc_counter_create(isc_mem_t *mctx, int limit, isc_counter_t **counterp); ++/*%< ++ * Allocate and initialize a counter object. ++ */ ++ ++isc_result_t ++isc_counter_increment(isc_counter_t *counter); ++/*%< ++ * Increment the counter. ++ * ++ * If the counter limit is nonzero and has been reached, then ++ * return ISC_R_QUOTA, otherwise ISC_R_SUCCESS. (The counter is ++ * incremented regardless of return value.) ++ */ ++ ++unsigned int ++isc_counter_used(isc_counter_t *counter); ++/*%< ++ * Return the current counter value. ++ */ ++ ++void ++isc_counter_setlimit(isc_counter_t *counter, int limit); ++/*%< ++ * Set the counter limit. ++ */ ++ ++void ++isc_counter_attach(isc_counter_t *source, isc_counter_t **targetp); ++/*%< ++ * Attach to a counter object, increasing its reference counter. ++ */ ++ ++void ++isc_counter_detach(isc_counter_t **counterp); ++/*%< ++ * Detach (and destroy if reference counter has dropped to zero) ++ * a counter object. ++ */ ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* ISC_COUNTER_H */ +diff -up bind-9.9.4/lib/isc/include/isc/Makefile.in.CVE-2014-8500 bind-9.9.4/lib/isc/include/isc/Makefile.in +--- bind-9.9.4/lib/isc/include/isc/Makefile.in.CVE-2014-8500 2014-12-10 15:02:34.811005903 +0100 ++++ bind-9.9.4/lib/isc/include/isc/Makefile.in 2014-12-10 15:03:01.099030322 +0100 +@@ -27,7 +27,7 @@ top_srcdir = @top_srcdir@ + # install target below. + # + HEADERS = app.h assertions.h base64.h bind9.h bitstring.h boolean.h \ +- buffer.h bufferlist.h commandline.h entropy.h error.h event.h \ ++ buffer.h bufferlist.h commandline.h counter.h entropy.h error.h event.h \ + eventclass.h file.h formatcheck.h fsaccess.h \ + hash.h heap.h hex.h hmacmd5.h hmacsha.h \ + httpd.h \ +diff -up bind-9.9.4/lib/isc/include/isc/types.h.CVE-2014-8500 bind-9.9.4/lib/isc/include/isc/types.h +--- bind-9.9.4/lib/isc/include/isc/types.h.CVE-2014-8500 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/isc/include/isc/types.h 2014-12-10 14:56:24.968552569 +0100 +@@ -50,6 +50,7 @@ typedef struct isc_buffer isc_buffer_t; + typedef ISC_LIST(isc_buffer_t) isc_bufferlist_t; /*%< Buffer List */ + typedef struct isc_constregion isc_constregion_t; /*%< Const region */ + typedef struct isc_consttextregion isc_consttextregion_t; /*%< Const Text Region */ ++typedef struct isc_counter isc_counter_t; /*%< Counter */ + typedef struct isc_entropy isc_entropy_t; /*%< Entropy */ + typedef struct isc_entropysource isc_entropysource_t; /*%< Entropy Source */ + typedef struct isc_event isc_event_t; /*%< Event */ +diff -up bind-9.9.4/lib/isc/Makefile.in.CVE-2014-8500 bind-9.9.4/lib/isc/Makefile.in +--- bind-9.9.4/lib/isc/Makefile.in.CVE-2014-8500 2014-12-10 14:56:24.860552447 +0100 ++++ bind-9.9.4/lib/isc/Makefile.in 2014-12-10 14:56:24.968552569 +0100 +@@ -53,7 +53,7 @@ WIN32OBJS = win32/condition.@O@ win32/d + OBJS = @ISC_EXTRA_OBJS@ \ + assertions.@O@ backtrace.@O@ base32.@O@ base64.@O@ \ + bitstring.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \ +- error.@O@ event.@O@ \ ++ counter.@O@ error.@O@ event.@O@ \ + hash.@O@ heap.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \ + httpd.@O@ inet_aton.@O@ iterated_hash.@O@ \ + lex.@O@ lfsr.@O@ lib.@O@ log.@O@ \ +@@ -70,8 +70,8 @@ SYMTBLOBJS = backtrace-emptytbl.@O@ + # Alphabetically + SRCS = @ISC_EXTRA_SRCS@ \ + assertions.c backtrace.c base32.c base64.c bitstring.c \ +- buffer.c bufferlist.c commandline.c error.c event.c \ +- heap.c hex.c hmacmd5.c hmacsha.c \ ++ buffer.c bufferlist.c commandline.c counter.c \ ++ error.c event.c heap.c hex.c hmacmd5.c hmacsha.c \ + httpd.c inet_aton.c iterated_hash.c \ + lex.c lfsr.c lib.c log.c \ + md5.c mem.c mutexblock.c \ diff --git a/SOURCES/bind99-CVE-2015-1349.patch b/SOURCES/bind99-CVE-2015-1349.patch new file mode 100644 index 0000000..e484587 --- /dev/null +++ b/SOURCES/bind99-CVE-2015-1349.patch @@ -0,0 +1,25 @@ +diff -up bind-9.9.4/lib/dns/zone.c.CVE-2015-1349 bind-9.9.4/lib/dns/zone.c +--- bind-9.9.4/lib/dns/zone.c.CVE-2015-1349 2015-03-02 11:18:36.138872044 +0100 ++++ bind-9.9.4/lib/dns/zone.c 2015-03-02 11:20:15.941032102 +0100 +@@ -8456,6 +8456,12 @@ keyfetch_done(isc_task_t *task, isc_even + namebuf, tag); + trustkey = ISC_TRUE; + } ++ } else { ++ /* ++ * No previously known key, and the key is not ++ * secure, so skip it. ++ */ ++ continue; + } + + /* Delete old version */ +@@ -8504,7 +8510,7 @@ keyfetch_done(isc_task_t *task, isc_even + trust_key(zone, keyname, &dnskey, mctx); + } + +- if (!deletekey) ++ if (secure && !deletekey) + set_refreshkeytimer(zone, &keydata, now); + } + diff --git a/SOURCES/bind99-CVE-2015-4620.patch b/SOURCES/bind99-CVE-2015-4620.patch new file mode 100644 index 0000000..b0468be --- /dev/null +++ b/SOURCES/bind99-CVE-2015-4620.patch @@ -0,0 +1,21 @@ +diff --git a/lib/dns/validator.c b/lib/dns/validator.c +--- a/lib/dns/validator.c ++++ b/lib/dns/validator.c +@@ -1422,7 +1422,6 @@ compute_keytag(dns_rdata_t *rdata, dns_rdata_dnskey_t *key) { + */ + static isc_boolean_t + isselfsigned(dns_validator_t *val) { +- dns_fixedname_t fixed; + dns_rdataset_t *rdataset, *sigrdataset; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_t sigrdata = DNS_RDATA_INIT; +@@ -1478,8 +1477,7 @@ isselfsigned(dns_validator_t *val) { + result = dns_dnssec_verify3(name, rdataset, dstkey, + ISC_TRUE, + val->view->maxbits, +- mctx, &sigrdata, +- dns_fixedname_name(&fixed)); ++ mctx, &sigrdata, NULL); + dst_key_free(&dstkey); + if (result != ISC_R_SUCCESS) + continue; diff --git a/SOURCES/bind99-CVE-2015-5477.patch b/SOURCES/bind99-CVE-2015-5477.patch new file mode 100644 index 0000000..c3a6e29 --- /dev/null +++ b/SOURCES/bind99-CVE-2015-5477.patch @@ -0,0 +1,11 @@ +diff -up bind-9.9.4/lib/dns/tkey.c.CVE-2015-5477 bind-9.9.4/lib/dns/tkey.c +--- bind-9.9.4/lib/dns/tkey.c.CVE-2015-5477 2015-07-27 22:36:02.318505839 +0200 ++++ bind-9.9.4/lib/dns/tkey.c 2015-07-27 22:36:39.764698712 +0200 +@@ -650,6 +650,7 @@ dns_tkey_processquery(dns_message_t *msg + * Try the answer section, since that's where Win2000 + * puts it. + */ ++ name = NULL; + if (dns_message_findname(msg, DNS_SECTION_ANSWER, qname, + dns_rdatatype_tkey, 0, &name, + &tkeyset) != ISC_R_SUCCESS) { diff --git a/SOURCES/bind99-CVE-2015-5722.patch b/SOURCES/bind99-CVE-2015-5722.patch new file mode 100644 index 0000000..bb240ac --- /dev/null +++ b/SOURCES/bind99-CVE-2015-5722.patch @@ -0,0 +1,449 @@ +diff --git a/lib/dns/hmac_link.c b/lib/dns/hmac_link.c +index 7a56c79..3ac01a8 100644 +--- a/lib/dns/hmac_link.c ++++ b/lib/dns/hmac_link.c +@@ -76,7 +76,7 @@ hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) { + hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t)); + if (hmacmd5ctx == NULL) + return (ISC_R_NOMEMORY); +- isc_hmacmd5_init(hmacmd5ctx, hkey->key, ISC_SHA1_BLOCK_LENGTH); ++ isc_hmacmd5_init(hmacmd5ctx, hkey->key, ISC_MD5_BLOCK_LENGTH); + dctx->ctxdata.hmacmd5ctx = hmacmd5ctx; + return (ISC_R_SUCCESS); + } +@@ -139,7 +139,7 @@ hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) { + else if (hkey1 == NULL || hkey2 == NULL) + return (ISC_FALSE); + +- if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH)) ++ if (isc_safe_memcmp(hkey1->key, hkey2->key, ISC_MD5_BLOCK_LENGTH)) + return (ISC_TRUE); + else + return (ISC_FALSE); +@@ -150,17 +150,17 @@ hmacmd5_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { + isc_buffer_t b; + isc_result_t ret; + unsigned int bytes; +- unsigned char data[ISC_SHA1_BLOCK_LENGTH]; ++ unsigned char data[ISC_MD5_BLOCK_LENGTH]; + + UNUSED(callback); + + bytes = (key->key_size + 7) / 8; +- if (bytes > ISC_SHA1_BLOCK_LENGTH) { +- bytes = ISC_SHA1_BLOCK_LENGTH; +- key->key_size = ISC_SHA1_BLOCK_LENGTH * 8; ++ if (bytes > ISC_MD5_BLOCK_LENGTH) { ++ bytes = ISC_MD5_BLOCK_LENGTH; ++ key->key_size = ISC_MD5_BLOCK_LENGTH * 8; + } + +- memset(data, 0, ISC_SHA1_BLOCK_LENGTH); ++ memset(data, 0, ISC_MD5_BLOCK_LENGTH); + ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0)); + + if (ret != ISC_R_SUCCESS) +@@ -169,7 +169,7 @@ hmacmd5_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { + isc_buffer_init(&b, data, bytes); + isc_buffer_add(&b, bytes); + ret = hmacmd5_fromdns(key, &b); +- memset(data, 0, ISC_SHA1_BLOCK_LENGTH); ++ memset(data, 0, ISC_MD5_BLOCK_LENGTH); + + return (ret); + } +@@ -223,7 +223,7 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { + + memset(hkey->key, 0, sizeof(hkey->key)); + +- if (r.length > ISC_SHA1_BLOCK_LENGTH) { ++ if (r.length > ISC_MD5_BLOCK_LENGTH) { + isc_md5_init(&md5ctx); + isc_md5_update(&md5ctx, r.base, r.length); + isc_md5_final(&md5ctx, hkey->key); +@@ -237,6 +237,8 @@ hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) { + key->key_size = keylen * 8; + key->keydata.hmacmd5 = hkey; + ++ isc_buffer_forward(data, r.length); ++ + return (ISC_R_SUCCESS); + } + +@@ -518,6 +520,8 @@ hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) { + key->key_size = keylen * 8; + key->keydata.hmacsha1 = hkey; + ++ isc_buffer_forward(data, r.length); ++ + return (ISC_R_SUCCESS); + } + +@@ -804,6 +808,8 @@ hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) { + key->key_size = keylen * 8; + key->keydata.hmacsha224 = hkey; + ++ isc_buffer_forward(data, r.length); ++ + return (ISC_R_SUCCESS); + } + +@@ -1090,6 +1096,8 @@ hmacsha256_fromdns(dst_key_t *key, isc_buffer_t *data) { + key->key_size = keylen * 8; + key->keydata.hmacsha256 = hkey; + ++ isc_buffer_forward(data, r.length); ++ + return (ISC_R_SUCCESS); + } + +@@ -1376,6 +1384,8 @@ hmacsha384_fromdns(dst_key_t *key, isc_buffer_t *data) { + key->key_size = keylen * 8; + key->keydata.hmacsha384 = hkey; + ++ isc_buffer_forward(data, r.length); ++ + return (ISC_R_SUCCESS); + } + +@@ -1662,6 +1672,8 @@ hmacsha512_fromdns(dst_key_t *key, isc_buffer_t *data) { + key->key_size = keylen * 8; + key->keydata.hmacsha512 = hkey; + ++ isc_buffer_forward(data, r.length); ++ + return (ISC_R_SUCCESS); + } + +diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h +index bdbd269..37853aa 100644 +--- a/lib/dns/include/dst/dst.h ++++ b/lib/dns/include/dst/dst.h +@@ -69,6 +69,7 @@ typedef struct dst_context dst_context_t; + #define DST_ALG_HMACSHA256 163 /* XXXMPA */ + #define DST_ALG_HMACSHA384 164 /* XXXMPA */ + #define DST_ALG_HMACSHA512 165 /* XXXMPA */ ++#define DST_ALG_INDIRECT 252 + #define DST_ALG_PRIVATE 254 + #define DST_ALG_EXPAND 255 + #define DST_MAX_ALGS 255 +diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c +index bcb3d05..3114954 100644 +--- a/lib/dns/ncache.c ++++ b/lib/dns/ncache.c +@@ -614,13 +614,11 @@ dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, + dns_name_fromregion(&tname, &remaining); + INSIST(remaining.length >= tname.length); + isc_buffer_forward(&source, tname.length); +- remaining.length -= tname.length; +- remaining.base += tname.length; ++ isc_region_consume(&remaining, tname.length); + + INSIST(remaining.length >= 2); + type = isc_buffer_getuint16(&source); +- remaining.length -= 2; +- remaining.base += 2; ++ isc_region_consume(&remaining, 2); + + if (type != dns_rdatatype_rrsig || + !dns_name_equal(&tname, name)) { +@@ -632,8 +630,7 @@ dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, + INSIST(remaining.length >= 1); + trust = isc_buffer_getuint8(&source); + INSIST(trust <= dns_trust_ultimate); +- remaining.length -= 1; +- remaining.base += 1; ++ isc_region_consume(&remaining, 1); + + raw = remaining.base; + count = raw[0] * 256 + raw[1]; +diff --git a/lib/dns/openssldh_link.c b/lib/dns/openssldh_link.c +index 55752da..f0cee8d 100644 +--- a/lib/dns/openssldh_link.c ++++ b/lib/dns/openssldh_link.c +@@ -266,8 +266,10 @@ openssldh_destroy(dst_key_t *key) { + + static void + uint16_toregion(isc_uint16_t val, isc_region_t *region) { +- *region->base++ = (val & 0xff00) >> 8; +- *region->base++ = (val & 0x00ff); ++ *region->base = (val & 0xff00) >> 8; ++ isc_region_consume(region, 1); ++ *region->base = (val & 0x00ff); ++ isc_region_consume(region, 1); + } + + static isc_uint16_t +@@ -278,7 +280,8 @@ uint16_fromregion(isc_region_t *region) { + val = ((unsigned int)(cp[0])) << 8; + val |= ((unsigned int)(cp[1])); + +- region->base += 2; ++ isc_region_consume(region, 2); ++ + return (val); + } + +@@ -319,16 +322,16 @@ openssldh_todns(const dst_key_t *key, isc_buffer_t *data) { + } + else + BN_bn2bin(dh->p, r.base); +- r.base += plen; ++ isc_region_consume(&r, plen); + + uint16_toregion(glen, &r); + if (glen > 0) + BN_bn2bin(dh->g, r.base); +- r.base += glen; ++ isc_region_consume(&r, glen); + + uint16_toregion(publen, &r); + BN_bn2bin(dh->pub_key, r.base); +- r.base += publen; ++ isc_region_consume(&r, publen); + + isc_buffer_add(data, dnslen); + +@@ -369,10 +372,12 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { + return (DST_R_INVALIDPUBLICKEY); + } + if (plen == 1 || plen == 2) { +- if (plen == 1) +- special = *r.base++; +- else ++ if (plen == 1) { ++ special = *r.base; ++ isc_region_consume(&r, 1); ++ } else { + special = uint16_fromregion(&r); ++ } + switch (special) { + case 1: + dh->p = &bn768; +@@ -387,10 +392,9 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } +- } +- else { ++ } else { + dh->p = BN_bin2bn(r.base, plen, NULL); +- r.base += plen; ++ isc_region_consume(&r, plen); + } + + /* +@@ -421,15 +425,14 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { + return (DST_R_INVALIDPUBLICKEY); + } + } +- } +- else { ++ } else { + if (glen == 0) { + DH_free(dh); + return (DST_R_INVALIDPUBLICKEY); + } + dh->g = BN_bin2bn(r.base, glen, NULL); + } +- r.base += glen; ++ isc_region_consume(&r, glen); + + if (r.length < 2) { + DH_free(dh); +@@ -441,7 +444,7 @@ openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) { + return (DST_R_INVALIDPUBLICKEY); + } + dh->pub_key = BN_bin2bn(r.base, publen, NULL); +- r.base += publen; ++ isc_region_consume(&r, publen); + + key->key_size = BN_num_bits(dh->p); + +diff --git a/lib/dns/openssldsa_link.c b/lib/dns/openssldsa_link.c +index fd6e91e..8e16557 100644 +--- a/lib/dns/openssldsa_link.c ++++ b/lib/dns/openssldsa_link.c +@@ -137,6 +135,7 @@ openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { + DSA *dsa = key->keydata.dsa; + isc_region_t r; + DSA_SIG *dsasig; ++ unsigned int klen; + #if USE_EVP + EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx; + EVP_PKEY *pkey; +@@ -209,11 +209,17 @@ openssldsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { + "DSA_do_sign", + DST_R_SIGNFAILURE)); + #endif +- *r.base++ = (key->key_size - 512)/64; ++ ++ klen = (key->key_size - 512)/64; ++ if (klen > 255) ++ return (ISC_R_FAILURE); ++ *r.base = klen; ++ isc_region_consume(&r, 1); ++ + BN_bn2bin_fixed(dsasig->r, r.base, ISC_SHA1_DIGESTLENGTH); +- r.base += ISC_SHA1_DIGESTLENGTH; ++ isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH); + BN_bn2bin_fixed(dsasig->s, r.base, ISC_SHA1_DIGESTLENGTH); +- r.base += ISC_SHA1_DIGESTLENGTH; ++ isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH); + DSA_SIG_free(dsasig); + isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH * 2 + 1); + +@@ -446,15 +452,16 @@ openssldsa_todns(const dst_key_t *key, isc_buffer_t *data) { + if (r.length < (unsigned int) dnslen) + return (ISC_R_NOSPACE); + +- *r.base++ = t; ++ *r.base = t; ++ isc_region_consume(&r, 1); + BN_bn2bin_fixed(dsa->q, r.base, ISC_SHA1_DIGESTLENGTH); +- r.base += ISC_SHA1_DIGESTLENGTH; ++ isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH); + BN_bn2bin_fixed(dsa->p, r.base, key->key_size/8); +- r.base += p_bytes; ++ isc_region_consume(&r, p_bytes); + BN_bn2bin_fixed(dsa->g, r.base, key->key_size/8); +- r.base += p_bytes; ++ isc_region_consume(&r, p_bytes); + BN_bn2bin_fixed(dsa->pub_key, r.base, key->key_size/8); +- r.base += p_bytes; ++ isc_region_consume(&r, p_bytes); + + isc_buffer_add(data, dnslen); + +@@ -479,29 +486,30 @@ openssldsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + return (ISC_R_NOMEMORY); + dsa->flags &= ~DSA_FLAG_CACHE_MONT_P; + +- t = (unsigned int) *r.base++; ++ t = (unsigned int) *r.base; ++ isc_region_consume(&r, 1); + if (t > 8) { + DSA_free(dsa); + return (DST_R_INVALIDPUBLICKEY); + } + p_bytes = 64 + 8 * t; + +- if (r.length < 1 + ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) { ++ if (r.length < ISC_SHA1_DIGESTLENGTH + 3 * p_bytes) { + DSA_free(dsa); + return (DST_R_INVALIDPUBLICKEY); + } + + dsa->q = BN_bin2bn(r.base, ISC_SHA1_DIGESTLENGTH, NULL); +- r.base += ISC_SHA1_DIGESTLENGTH; ++ isc_region_consume(&r, ISC_SHA1_DIGESTLENGTH); + + dsa->p = BN_bin2bn(r.base, p_bytes, NULL); +- r.base += p_bytes; ++ isc_region_consume(&r, p_bytes); + + dsa->g = BN_bin2bn(r.base, p_bytes, NULL); +- r.base += p_bytes; ++ isc_region_consume(&r, p_bytes); + + dsa->pub_key = BN_bin2bn(r.base, p_bytes, NULL); +- r.base += p_bytes; ++ isc_region_consume(&r, p_bytes); + + key->key_size = p_bytes * 8; + +diff --git a/lib/dns/opensslecdsa_link.c b/lib/dns/opensslecdsa_link.c +index c64cc55..40c612b 100644 +--- a/lib/dns/opensslecdsa_link.c ++++ b/lib/dns/opensslecdsa_link.c +@@ -159,9 +157,9 @@ opensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { + "ECDSA_do_sign", + DST_R_SIGNFAILURE)); + BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2); +- r.base += siglen / 2; ++ isc_region_consume(&r, siglen / 2); + BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2); +- r.base += siglen / 2; ++ isc_region_consume(&r, siglen / 2); + ECDSA_SIG_free(ecdsasig); + isc_buffer_add(sig, siglen); + ret = ISC_R_SUCCESS; +diff --git a/lib/dns/opensslrsa_link.c b/lib/dns/opensslrsa_link.c +index 1edeb8d..53c6d4b 100644 +--- a/lib/dns/opensslrsa_link.c ++++ b/lib/dns/opensslrsa_link.c +@@ -965,6 +965,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + RSA *rsa; + isc_region_t r; + unsigned int e_bytes; ++ unsigned int length; + #if USE_EVP + EVP_PKEY *pkey; + #endif +@@ -972,6 +973,7 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + isc_buffer_remainingregion(data, &r); + if (r.length == 0) + return (ISC_R_SUCCESS); ++ length = r.length; + + rsa = RSA_new(); + if (rsa == NULL) +@@ -982,17 +984,18 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + RSA_free(rsa); + return (DST_R_INVALIDPUBLICKEY); + } +- e_bytes = *r.base++; +- r.length--; ++ e_bytes = *r.base; ++ isc_region_consume(&r, 1); + + if (e_bytes == 0) { + if (r.length < 2) { + RSA_free(rsa); + return (DST_R_INVALIDPUBLICKEY); + } +- e_bytes = ((*r.base++) << 8); +- e_bytes += *r.base++; +- r.length -= 2; ++ e_bytes = (*r.base) << 8; ++ isc_region_consume(&r, 1); ++ e_bytes += *r.base; ++ isc_region_consume(&r, 1); + } + + if (r.length < e_bytes) { +@@ -1000,14 +1003,13 @@ opensslrsa_fromdns(dst_key_t *key, isc_buffer_t *data) { + return (DST_R_INVALIDPUBLICKEY); + } + rsa->e = BN_bin2bn(r.base, e_bytes, NULL); +- r.base += e_bytes; +- r.length -= e_bytes; ++ isc_region_consume(&r, e_bytes); + + rsa->n = BN_bin2bn(r.base, r.length, NULL); + + key->key_size = BN_num_bits(rsa->n); + +- isc_buffer_forward(data, r.length); ++ isc_buffer_forward(data, length); + + #if USE_EVP + pkey = EVP_PKEY_new(); +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 2004b0b..c7971b1 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -8959,6 +8959,12 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, dns_name_t *name, + + REQUIRE(VALID_RESOLVER(resolver)); + ++ /* ++ * DH is unsupported for DNSKEYs, see RFC 4034 sec. A.1. ++ */ ++ if ((alg == DST_ALG_DH) || (alg == DST_ALG_INDIRECT)) ++ return (ISC_FALSE); ++ + #if USE_ALGLOCK + RWLOCK(&resolver->alglock, isc_rwlocktype_read); + #endif + diff --git a/SOURCES/bind99-CVE-2015-8000.patch b/SOURCES/bind99-CVE-2015-8000.patch new file mode 100644 index 0000000..c7247f5 --- /dev/null +++ b/SOURCES/bind99-CVE-2015-8000.patch @@ -0,0 +1,179 @@ +diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h +index a6862fa..d999e75 100644 +--- a/lib/dns/include/dns/message.h ++++ b/lib/dns/include/dns/message.h +@@ -210,6 +210,8 @@ struct dns_message { + unsigned int verify_attempted : 1; + unsigned int free_query : 1; + unsigned int free_saved : 1; ++ unsigned int tkey : 1; ++ unsigned int rdclass_set : 1; + + unsigned int opt_reserved; + unsigned int sig_reserved; +@@ -1374,6 +1376,15 @@ dns_message_buildopt(dns_message_t *msg, dns_rdataset_t **opt, + * \li other. + */ + ++void ++dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass); ++/*%< ++ * Set the expected class of records in the response. ++ * ++ * Requires: ++ * \li msg be a valid message with parsing intent. ++ */ ++ + ISC_LANG_ENDDECLS + + #endif /* DNS_MESSAGE_H */ +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 53efc5a..73def73 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -436,6 +436,8 @@ msginit(dns_message_t *m) { + m->saved.base = NULL; + m->saved.length = 0; + m->free_saved = 0; ++ m->tkey = 0; ++ m->rdclass_set = 0; + m->querytsig = NULL; + } + +@@ -1086,13 +1088,19 @@ getquestions(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + * If this class is different than the one we already read, + * this is an error. + */ +- if (msg->state == DNS_SECTION_ANY) { +- msg->state = DNS_SECTION_QUESTION; ++ if (msg->rdclass_set == 0) { + msg->rdclass = rdclass; ++ msg->rdclass_set = 1; + } else if (msg->rdclass != rdclass) + DO_FORMERR; + + /* ++ * Is this a TKEY query? ++ */ ++ if (rdtype == dns_rdatatype_tkey) ++ msg->tkey = 1; ++ ++ /* + * Can't ask the same question twice. + */ + result = dns_message_find(name, rdclass, rdtype, 0, NULL); +@@ -1236,12 +1244,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + * If there was no question section, we may not yet have + * established a class. Do so now. + */ +- if (msg->state == DNS_SECTION_ANY && ++ if (msg->rdclass_set == 0 && + rdtype != dns_rdatatype_opt && /* class is UDP SIZE */ + rdtype != dns_rdatatype_tsig && /* class is ANY */ + rdtype != dns_rdatatype_tkey) { /* class is undefined */ + msg->rdclass = rdclass; +- msg->state = DNS_SECTION_QUESTION; ++ msg->rdclass_set = 1; + } + + /* +@@ -1251,7 +1259,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + if (msg->opcode != dns_opcode_update + && rdtype != dns_rdatatype_tsig + && rdtype != dns_rdatatype_opt +- && rdtype != dns_rdatatype_dnskey /* in a TKEY query */ ++ && rdtype != dns_rdatatype_key /* in a TKEY query */ + && rdtype != dns_rdatatype_sig /* SIG(0) */ + && rdtype != dns_rdatatype_tkey /* Win2000 TKEY */ + && msg->rdclass != dns_rdataclass_any +@@ -1259,6 +1267,16 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + DO_FORMERR; + + /* ++ * If this is not a TKEY query/response then the KEY ++ * record's class needs to match. ++ */ ++ if (msg->opcode != dns_opcode_update && !msg->tkey && ++ rdtype == dns_rdatatype_key && ++ msg->rdclass != dns_rdataclass_any && ++ msg->rdclass != rdclass) ++ DO_FORMERR; ++ ++ /* + * Special type handling for TSIG, OPT, and TKEY. + */ + if (rdtype == dns_rdatatype_tsig) { +@@ -1372,6 +1390,10 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + skip_name_search = ISC_TRUE; + skip_type_search = ISC_TRUE; + issigzero = ISC_TRUE; ++ } else { ++ if (msg->rdclass != dns_rdataclass_any && ++ msg->rdclass != rdclass) ++ DO_FORMERR; + } + } else + covers = 0; +@@ -1610,6 +1632,7 @@ dns_message_parse(dns_message_t *msg, isc_buffer_t *source, + msg->counts[DNS_SECTION_ADDITIONAL] = isc_buffer_getuint16(source); + + msg->header_ok = 1; ++ msg->state = DNS_SECTION_QUESTION; + + /* + * -1 means no EDNS. +@@ -3550,3 +3573,15 @@ dns_message_buildopt(dns_message_t *message, dns_rdataset_t **rdatasetp, + dns_message_puttemprdatalist(message, &rdatalist); + return (result); + } ++ ++void ++dns_message_setclass(dns_message_t *msg, dns_rdataclass_t rdclass) { ++ ++ REQUIRE(DNS_MESSAGE_VALID(msg)); ++ REQUIRE(msg->from_to_wire == DNS_MESSAGE_INTENTPARSE); ++ REQUIRE(msg->state == DNS_SECTION_ANY); ++ REQUIRE(msg->rdclass_set == 0); ++ ++ msg->rdclass = rdclass; ++ msg->rdclass_set = 1; ++} +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index aa23b11..d220986 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6964,6 +6964,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + goto done; + } + ++ dns_message_setclass(message, fctx->res->rdclass); ++ + result = dns_message_parse(message, &devent->buffer, 0); + if (result != ISC_R_SUCCESS) { + switch (result) { +@@ -7036,6 +7038,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + */ + log_packet(message, ISC_LOG_DEBUG(10), fctx->res->mctx); + ++ if (message->rdclass != fctx->res->rdclass) { ++ resend = ISC_TRUE; ++ FCTXTRACE("bad class"); ++ goto done; ++ } ++ + /* + * Process receive opt record. + */ +diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c +index 9ad8960..938373a 100644 +--- a/lib/dns/xfrin.c ++++ b/lib/dns/xfrin.c +@@ -1241,6 +1241,8 @@ xfrin_recv_done(isc_task_t *task, isc_event_t *ev) { + msg->tsigctx = xfr->tsigctx; + xfr->tsigctx = NULL; + ++ dns_message_setclass(msg, xfr->rdclass); ++ + if (xfr->nmsg > 0) + msg->tcp_continuation = 1; + diff --git a/SOURCES/bind99-CVE-2015-8704.patch b/SOURCES/bind99-CVE-2015-8704.patch new file mode 100644 index 0000000..4aa41f2 --- /dev/null +++ b/SOURCES/bind99-CVE-2015-8704.patch @@ -0,0 +1,22 @@ +diff --git a/lib/dns/rdata/in_1/apl_42.c b/lib/dns/rdata/in_1/apl_42.c +index eb927b9..df35025 100644 +--- a/lib/dns/rdata/in_1/apl_42.c ++++ b/lib/dns/rdata/in_1/apl_42.c +@@ -116,7 +116,7 @@ totext_in_apl(ARGS_TOTEXT) { + isc_uint8_t len; + isc_boolean_t neg; + unsigned char buf[16]; +- char txt[sizeof(" !64000")]; ++ char txt[sizeof(" !64000:")]; + const char *sep = ""; + int n; + +@@ -140,7 +140,7 @@ totext_in_apl(ARGS_TOTEXT) { + isc_region_consume(&sr, 1); + INSIST(len <= sr.length); + n = snprintf(txt, sizeof(txt), "%s%s%u:", sep, +- neg ? "!": "", afi); ++ neg ? "!" : "", afi); + INSIST(n < (int)sizeof(txt)); + RETERR(str_totext(txt, target)); + switch (afi) { diff --git a/SOURCES/bind99-CVE-2016-1285-CVE-2016-1286.patch b/SOURCES/bind99-CVE-2016-1285-CVE-2016-1286.patch new file mode 100644 index 0000000..920825b --- /dev/null +++ b/SOURCES/bind99-CVE-2016-1285-CVE-2016-1286.patch @@ -0,0 +1,431 @@ +diff --git a/bin/named/control.c b/bin/named/control.c +index fabe442..06eadce 100644 +--- a/bin/named/control.c ++++ b/bin/named/control.c +@@ -69,7 +69,7 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { + #endif + + data = isccc_alist_lookup(message, "_data"); +- if (data == NULL) { ++ if (!isccc_alist_alistp(data)) { + /* + * No data section. + */ +diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c +index c46a6e1..ef32790 100644 +--- a/bin/named/controlconf.c ++++ b/bin/named/controlconf.c +@@ -396,7 +396,7 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) { + * Limit exposure to replay attacks. + */ + _ctrl = isccc_alist_lookup(request, "_ctrl"); +- if (_ctrl == NULL) { ++ if (!isccc_alist_alistp(_ctrl)) { + log_invalid(&conn->ccmsg, ISC_R_FAILURE); + goto cleanup_request; + } +diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c +index ba2c3f6..9a007e2 100644 +--- a/bin/rndc/rndc.c ++++ b/bin/rndc/rndc.c +@@ -252,8 +252,8 @@ rndc_recvdone(isc_task_t *task, isc_event_t *event) { + DO("parse message", isccc_cc_fromwire(&source, &response, &secret)); + + data = isccc_alist_lookup(response, "_data"); +- if (data == NULL) +- fatal("no data section in response"); ++ if (!isccc_alist_alistp(data)) ++ fatal("bad or missing data section in response"); + result = isccc_cc_lookupstring(data, "err", &errormsg); + if (result == ISC_R_SUCCESS) { + failed = ISC_TRUE; +@@ -316,8 +316,8 @@ rndc_recvnonce(isc_task_t *task, isc_event_t *event) { + DO("parse message", isccc_cc_fromwire(&source, &response, &secret)); + + _ctrl = isccc_alist_lookup(response, "_ctrl"); +- if (_ctrl == NULL) +- fatal("_ctrl section missing"); ++ if (!isccc_alist_alistp(_ctrl)) ++ fatal("bad or missing ctrl section in response"); + nonce = 0; + if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS) + nonce = 0; +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index d220986..8696b15 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -5408,14 +5408,11 @@ cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { + } + + static inline isc_result_t +-dname_target(fetchctx_t *fctx, dns_rdataset_t *rdataset, dns_name_t *qname, +- dns_name_t *oname, dns_fixedname_t *fixeddname) ++dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, ++ unsigned int nlabels, dns_fixedname_t *fixeddname) + { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; +- unsigned int nlabels; +- int order; +- dns_namereln_t namereln; + dns_rdata_dname_t dname; + dns_fixedname_t prefix; + +@@ -5430,21 +5427,6 @@ dname_target(fetchctx_t *fctx, dns_rdataset_t *rdataset, dns_name_t *qname, + if (result != ISC_R_SUCCESS) + return (result); + +- /* +- * Get the prefix of qname. +- */ +- namereln = dns_name_fullcompare(qname, oname, &order, &nlabels); +- if (namereln != dns_namereln_subdomain) { +- char qbuf[DNS_NAME_FORMATSIZE]; +- char obuf[DNS_NAME_FORMATSIZE]; +- +- dns_rdata_freestruct(&dname); +- dns_name_format(qname, qbuf, sizeof(qbuf)); +- dns_name_format(oname, obuf, sizeof(obuf)); +- log_formerr(fctx, "unrelated DNAME in answer: " +- "%s is not in %s", qbuf, obuf); +- return (DNS_R_FORMERR); +- } + dns_fixedname_init(&prefix); + dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); + dns_fixedname_init(fixeddname); +@@ -6057,13 +6039,13 @@ static isc_result_t + answer_response(fetchctx_t *fctx) { + isc_result_t result; + dns_message_t *message; +- dns_name_t *name, *qname, tname, *ns_name; ++ dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; + dns_rdataset_t *rdataset, *ns_rdataset; + isc_boolean_t done, external, chaining, aa, found, want_chaining; + isc_boolean_t have_answer, found_cname, found_type, wanted_chaining; + unsigned int aflag; + dns_rdatatype_t type; +- dns_fixedname_t dname, fqname; ++ dns_fixedname_t fdname, fqname; + dns_view_t *view; + + FCTXTRACE("answer_response"); +@@ -6091,10 +6073,15 @@ answer_response(fetchctx_t *fctx) { + view = fctx->res->view; + result = dns_message_firstname(message, DNS_SECTION_ANSWER); + while (!done && result == ISC_R_SUCCESS) { ++ dns_namereln_t namereln; ++ int order; ++ unsigned int nlabels; ++ + name = NULL; + dns_message_currentname(message, DNS_SECTION_ANSWER, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); +- if (dns_name_equal(name, qname)) { ++ namereln = dns_name_fullcompare(qname, name, &order, &nlabels); ++ if (namereln == dns_namereln_equal) { + wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; +@@ -6219,10 +6206,11 @@ answer_response(fetchctx_t *fctx) { + */ + INSIST(!external); + if (aflag == +- DNS_RDATASETATTR_ANSWER) ++ DNS_RDATASETATTR_ANSWER) { + have_answer = ISC_TRUE; +- name->attributes |= +- DNS_NAMEATTR_ANSWER; ++ name->attributes |= ++ DNS_NAMEATTR_ANSWER; ++ } + rdataset->attributes |= aflag; + if (aa) + rdataset->trust = +@@ -6277,6 +6265,8 @@ answer_response(fetchctx_t *fctx) { + if (wanted_chaining) + chaining = ISC_TRUE; + } else { ++ dns_rdataset_t *dnameset = NULL; ++ + /* + * Look for a DNAME (or its SIG). Anything else is + * ignored. +@@ -6284,32 +6274,56 @@ answer_response(fetchctx_t *fctx) { + wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; +- rdataset = ISC_LIST_NEXT(rdataset, link)) { +- isc_boolean_t found_dname = ISC_FALSE; +- dns_name_t *dname_name; ++ rdataset = ISC_LIST_NEXT(rdataset, link)) ++ { ++ /* ++ * Only pass DNAME or RRSIG(DNAME). ++ */ ++ if (rdataset->type != dns_rdatatype_dname && ++ (rdataset->type != dns_rdatatype_rrsig || ++ rdataset->covers != dns_rdatatype_dname)) ++ continue; ++ ++ /* ++ * If we're not chaining, then the DNAME and ++ * its signature should not be external. ++ */ ++ if (!chaining && external) { ++ char qbuf[DNS_NAME_FORMATSIZE]; ++ char obuf[DNS_NAME_FORMATSIZE]; ++ ++ dns_name_format(name, qbuf, ++ sizeof(qbuf)); ++ dns_name_format(&fctx->domain, obuf, ++ sizeof(obuf)); ++ log_formerr(fctx, "external DNAME or " ++ "RRSIG covering DNAME " ++ "in answer: %s is " ++ "not in %s", qbuf, obuf); ++ return (DNS_R_FORMERR); ++ } ++ ++ if (namereln != dns_namereln_subdomain) { ++ char qbuf[DNS_NAME_FORMATSIZE]; ++ char obuf[DNS_NAME_FORMATSIZE]; ++ ++ dns_name_format(qname, qbuf, ++ sizeof(qbuf)); ++ dns_name_format(name, obuf, ++ sizeof(obuf)); ++ log_formerr(fctx, "unrelated DNAME " ++ "in answer: %s is " ++ "not in %s", qbuf, obuf); ++ return (DNS_R_FORMERR); ++ } + +- found = ISC_FALSE; + aflag = 0; + if (rdataset->type == dns_rdatatype_dname) { +- /* +- * We're looking for something else, +- * but we found a DNAME. +- * +- * If we're not chaining, then the +- * DNAME should not be external. +- */ +- if (!chaining && external) { +- log_formerr(fctx, +- "external DNAME"); +- return (DNS_R_FORMERR); +- } +- found = ISC_TRUE; + want_chaining = ISC_TRUE; + POST(want_chaining); + aflag = DNS_RDATASETATTR_ANSWER; +- result = dname_target(fctx, rdataset, +- qname, name, +- &dname); ++ result = dname_target(rdataset, qname, ++ nlabels, &fdname); + if (result == ISC_R_NOSPACE) { + /* + * We can't construct the +@@ -6321,90 +6335,73 @@ answer_response(fetchctx_t *fctx) { + } else if (result != ISC_R_SUCCESS) + return (result); + else +- found_dname = ISC_TRUE; ++ dnameset = rdataset; + +- dname_name = dns_fixedname_name(&dname); ++ dname = dns_fixedname_name(&fdname); + if (!is_answertarget_allowed(view, +- qname, +- rdataset->type, +- dname_name, +- &fctx->domain)) { ++ qname, rdataset->type, ++ dname, &fctx->domain)) { + return (DNS_R_SERVFAIL); + } +- } else if (rdataset->type == dns_rdatatype_rrsig +- && rdataset->covers == +- dns_rdatatype_dname) { ++ } else { + /* + * We've found a signature that + * covers the DNAME. + */ +- found = ISC_TRUE; + aflag = DNS_RDATASETATTR_ANSWERSIG; + } + +- if (found) { ++ /* ++ * We've found an answer to our ++ * question. ++ */ ++ name->attributes |= DNS_NAMEATTR_CACHE; ++ rdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ rdataset->trust = dns_trust_answer; ++ if (!chaining) { + /* +- * We've found an answer to our +- * question. ++ * This data is "the" answer to ++ * our question only if we're ++ * not chaining. + */ +- name->attributes |= +- DNS_NAMEATTR_CACHE; +- rdataset->attributes |= +- DNS_RDATASETATTR_CACHE; +- rdataset->trust = dns_trust_answer; +- if (!chaining) { +- /* +- * This data is "the" answer +- * to our question only if +- * we're not chaining. +- */ +- INSIST(!external); +- if (aflag == +- DNS_RDATASETATTR_ANSWER) +- have_answer = ISC_TRUE; ++ INSIST(!external); ++ if (aflag == DNS_RDATASETATTR_ANSWER) { ++ have_answer = ISC_TRUE; + name->attributes |= + DNS_NAMEATTR_ANSWER; +- rdataset->attributes |= aflag; +- if (aa) +- rdataset->trust = +- dns_trust_authanswer; +- } else if (external) { +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; +- } +- +- /* +- * DNAME chaining. +- */ +- if (found_dname) { +- /* +- * Copy the dname into the +- * qname fixed name. +- * +- * Although we check for +- * failure of the copy +- * operation, in practice it +- * should never fail since +- * we already know that the +- * result fits in a fixedname. +- */ +- dns_fixedname_init(&fqname); +- result = dns_name_copy( +- dns_fixedname_name(&dname), +- dns_fixedname_name(&fqname), +- NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- wanted_chaining = ISC_TRUE; +- name->attributes |= +- DNS_NAMEATTR_CHAINING; +- rdataset->attributes |= +- DNS_RDATASETATTR_CHAINING; +- qname = dns_fixedname_name( +- &fqname); + } ++ rdataset->attributes |= aflag; ++ if (aa) ++ rdataset->trust = ++ dns_trust_authanswer; ++ } else if (external) { ++ rdataset->attributes |= ++ DNS_RDATASETATTR_EXTERNAL; + } + } ++ ++ /* ++ * DNAME chaining. ++ */ ++ if (dnameset != NULL) { ++ /* ++ * Copy the dname into the qname fixed name. ++ * ++ * Although we check for failure of the copy ++ * operation, in practice it should never fail ++ * since we already know that the result fits ++ * in a fixedname. ++ */ ++ dns_fixedname_init(&fqname); ++ qname = dns_fixedname_name(&fqname); ++ result = dns_name_copy(dname, qname, NULL); ++ if (result != ISC_R_SUCCESS) ++ return (result); ++ wanted_chaining = ISC_TRUE; ++ name->attributes |= DNS_NAMEATTR_CHAINING; ++ dnameset->attributes |= ++ DNS_RDATASETATTR_CHAINING; ++ } + if (wanted_chaining) + chaining = ISC_TRUE; + } +diff --git a/lib/isccc/cc.c b/lib/isccc/cc.c +index ae5391a..10e5dc9 100644 +--- a/lib/isccc/cc.c ++++ b/lib/isccc/cc.c +@@ -286,10 +286,10 @@ verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length, + * Extract digest. + */ + _auth = isccc_alist_lookup(alist, "_auth"); +- if (_auth == NULL) ++ if (!isccc_alist_alistp(_auth)) + return (ISC_R_FAILURE); + hmd5 = isccc_alist_lookup(_auth, "hmd5"); +- if (hmd5 == NULL) ++ if (!isccc_sexpr_binaryp(hmd5)) + return (ISC_R_FAILURE); + /* + * Compute digest. +@@ -543,7 +543,7 @@ isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok, + REQUIRE(ackp != NULL && *ackp == NULL); + + _ctrl = isccc_alist_lookup(message, "_ctrl"); +- if (_ctrl == NULL || ++ if (!isccc_alist_alistp(_ctrl) || + isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS || + isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS) + return (ISC_R_FAILURE); +@@ -588,7 +588,7 @@ isccc_cc_isack(isccc_sexpr_t *message) + isccc_sexpr_t *_ctrl; + + _ctrl = isccc_alist_lookup(message, "_ctrl"); +- if (_ctrl == NULL) ++ if (!isccc_alist_alistp(_ctrl)) + return (ISC_FALSE); + if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS) + return (ISC_TRUE); +@@ -601,7 +601,7 @@ isccc_cc_isreply(isccc_sexpr_t *message) + isccc_sexpr_t *_ctrl; + + _ctrl = isccc_alist_lookup(message, "_ctrl"); +- if (_ctrl == NULL) ++ if (!isccc_alist_alistp(_ctrl)) + return (ISC_FALSE); + if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS) + return (ISC_TRUE); +@@ -621,7 +621,7 @@ isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now, + + _ctrl = isccc_alist_lookup(message, "_ctrl"); + _data = isccc_alist_lookup(message, "_data"); +- if (_ctrl == NULL || _data == NULL || ++ if (!isccc_alist_alistp(_ctrl) || !isccc_alist_alistp(_data) || + isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS || + isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS) + return (ISC_R_FAILURE); +@@ -810,7 +810,7 @@ isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message, + isccc_sexpr_t *_ctrl; + + _ctrl = isccc_alist_lookup(message, "_ctrl"); +- if (_ctrl == NULL || ++ if (!isccc_alist_alistp(_ctrl) || + isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS || + isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS) + return (ISC_R_FAILURE); diff --git a/SOURCES/bind99-CVE-2016-2775.patch b/SOURCES/bind99-CVE-2016-2775.patch new file mode 100644 index 0000000..bc5ac47 --- /dev/null +++ b/SOURCES/bind99-CVE-2016-2775.patch @@ -0,0 +1,66 @@ +From 062b04898be720ed0855efc192847fcbc667b3e1 Mon Sep 17 00:00:00 2001 +From: Mark Andrews <marka@isc.org> +Date: Thu, 7 Jul 2016 12:52:47 +1000 +Subject: [PATCH] 4406. [bug] getrrsetbyname with a non absolute + name could trigger a infinite recursion bug in lwresd + and named with lwres configured if when combined + with a search list entry the resulting name is + too long. [RT #42694] + +(cherry picked from commit 38cc2d14e218e536e0102fa70deef99461354232) +--- + bin/named/lwdgrbn.c | 16 ++++++++++------ + bin/tests/system/lwresd/lwtest.c | 8 ++++++++ + 2 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/bin/named/lwdgrbn.c b/bin/named/lwdgrbn.c +index 584ab25..37211eb 100644 +--- a/bin/named/lwdgrbn.c ++++ b/bin/named/lwdgrbn.c +@@ -403,14 +403,18 @@ start_lookup(ns_lwdclient_t *client) { + INSIST(client->lookup == NULL); + + dns_fixedname_init(&absname); +- result = ns_lwsearchctx_current(&client->searchctx, +- dns_fixedname_name(&absname)); ++ + /* +- * This will return failure if relative name + suffix is too long. +- * In this case, just go on to the next entry in the search path. ++ * Perform search across all search domains until success ++ * is returned. Return in case of failure. + */ +- if (result != ISC_R_SUCCESS) +- start_lookup(client); ++ while (ns_lwsearchctx_current(&client->searchctx, ++ dns_fixedname_name(&absname)) != ISC_R_SUCCESS) { ++ if (ns_lwsearchctx_next(&client->searchctx) != ISC_R_SUCCESS) { ++ ns_lwdclient_errorpktsend(client, LWRES_R_FAILURE); ++ return; ++ } ++ } + + result = dns_lookup_create(cm->mctx, + dns_fixedname_name(&absname), +diff --git a/bin/tests/system/lwresd/lwtest.c b/bin/tests/system/lwresd/lwtest.c +index 02647cb..c2be95d 100644 +--- a/bin/tests/system/lwresd/lwtest.c ++++ b/bin/tests/system/lwresd/lwtest.c +@@ -768,6 +768,14 @@ main(void) { + test_getrrsetbyname("e.example1.", 1, 46, 2, 0, 1); + test_getrrsetbyname("", 1, 1, 0, 0, 0); + ++ test_getrrsetbyname("123456789.123456789.123456789.123456789." ++ "123456789.123456789.123456789.123456789." ++ "123456789.123456789.123456789.123456789." ++ "123456789.123456789.123456789.123456789." ++ "123456789.123456789.123456789.123456789." ++ "123456789.123456789.123456789.123456789." ++ "123456789", 1, 1, 0, 0, 0); ++ + if (fails == 0) + printf("I:ok\n"); + return (fails); +-- +2.7.4 + diff --git a/SOURCES/bind99-CVE-2016-2776.patch b/SOURCES/bind99-CVE-2016-2776.patch new file mode 100644 index 0000000..6a02094 --- /dev/null +++ b/SOURCES/bind99-CVE-2016-2776.patch @@ -0,0 +1,89 @@ +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 73def73..3d2de4f 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -1736,7 +1736,7 @@ dns_message_renderbegin(dns_message_t *msg, dns_compress_t *cctx, + if (r.length < DNS_MESSAGE_HEADERLEN) + return (ISC_R_NOSPACE); + +- if (r.length < msg->reserved) ++ if (r.length - DNS_MESSAGE_HEADERLEN < msg->reserved) + return (ISC_R_NOSPACE); + + /* +@@ -1863,8 +1863,29 @@ norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options) + + return (ISC_TRUE); + } +- + #endif ++ ++static isc_result_t ++renderset(dns_rdataset_t *rdataset, dns_name_t *owner_name, ++ dns_compress_t *cctx, isc_buffer_t *target, ++ unsigned int reserved, unsigned int options, unsigned int *countp) ++{ ++ isc_result_t result; ++ ++ /* ++ * Shrink the space in the buffer by the reserved amount. ++ */ ++ if (target->length - target->used < reserved) ++ return (ISC_R_NOSPACE); ++ ++ target->length -= reserved; ++ result = dns_rdataset_towire(rdataset, owner_name, ++ cctx, target, options, countp); ++ target->length += reserved; ++ ++ return (result); ++} ++ + isc_result_t + dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, + unsigned int options) +@@ -1907,6 +1928,8 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, + /* + * Shrink the space in the buffer by the reserved amount. + */ ++ if (msg->buffer->length - msg->buffer->used < msg->reserved) ++ return (ISC_R_NOSPACE); + msg->buffer->length -= msg->reserved; + + total = 0; +@@ -2183,9 +2206,8 @@ dns_message_renderend(dns_message_t *msg) { + * Render. + */ + count = 0; +- result = dns_rdataset_towire(msg->opt, dns_rootname, +- msg->cctx, msg->buffer, 0, +- &count); ++ result = renderset(msg->opt, dns_rootname, msg->cctx, ++ msg->buffer, msg->reserved, 0, &count); + msg->counts[DNS_SECTION_ADDITIONAL] += count; + if (result != ISC_R_SUCCESS) + return (result); +@@ -2201,9 +2223,8 @@ dns_message_renderend(dns_message_t *msg) { + if (result != ISC_R_SUCCESS) + return (result); + count = 0; +- result = dns_rdataset_towire(msg->tsig, msg->tsigname, +- msg->cctx, msg->buffer, 0, +- &count); ++ result = renderset(msg->tsig, msg->tsigname, msg->cctx, ++ msg->buffer, msg->reserved, 0, &count); + msg->counts[DNS_SECTION_ADDITIONAL] += count; + if (result != ISC_R_SUCCESS) + return (result); +@@ -2224,9 +2245,8 @@ dns_message_renderend(dns_message_t *msg) { + * the owner name of a SIG(0) is irrelevant, and will not + * be set in a message being rendered. + */ +- result = dns_rdataset_towire(msg->sig0, dns_rootname, +- msg->cctx, msg->buffer, 0, +- &count); ++ result = renderset(msg->sig0, dns_rootname, msg->cctx, ++ msg->buffer, msg->reserved, 0, &count); + msg->counts[DNS_SECTION_ADDITIONAL] += count; + if (result != ISC_R_SUCCESS) + return (result); diff --git a/SOURCES/bind99-CVE-2016-8864.patch b/SOURCES/bind99-CVE-2016-8864.patch new file mode 100644 index 0000000..5e54f08 --- /dev/null +++ b/SOURCES/bind99-CVE-2016-8864.patch @@ -0,0 +1,174 @@ +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 5ef2dd6..1b987dd 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -526,7 +526,9 @@ valcreate(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, dns_name_t *name, + valarg->addrinfo = addrinfo; + + if (!ISC_LIST_EMPTY(fctx->validators)) +- INSIST((valoptions & DNS_VALIDATOR_DEFER) != 0); ++ valoptions |= DNS_VALIDATOR_DEFER; ++ else ++ valoptions &= ~DNS_VALIDATOR_DEFER; + + result = dns_validator_create(fctx->res->view, name, type, rdataset, + sigrdataset, fctx->rmessage, +@@ -4872,13 +4874,6 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, + rdataset, + sigrdataset, + valoptions, task); +- /* +- * Defer any further validations. +- * This prevents multiple validators +- * from manipulating fctx->rmessage +- * simultaneously. +- */ +- valoptions |= DNS_VALIDATOR_DEFER; + } + } else if (CHAINING(rdataset)) { + if (rdataset->type == dns_rdatatype_cname) +@@ -4984,6 +4979,11 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, + eresult == DNS_R_NCACHENXRRSET); + } + event->result = eresult; ++ if (adbp != NULL && *adbp != NULL) { ++ if (anodep != NULL && *anodep != NULL) ++ dns_db_detachnode(*adbp, anodep); ++ dns_db_detach(adbp); ++ } + dns_db_attach(fctx->cache, adbp); + dns_db_transfernode(fctx->cache, &node, anodep); + clone_results(fctx); +@@ -5231,6 +5231,11 @@ ncache_message(fetchctx_t *fctx, dns_adbaddrinfo_t *addrinfo, + fctx->attributes |= FCTX_ATTR_HAVEANSWER; + if (event != NULL) { + event->result = eresult; ++ if (adbp != NULL && *adbp != NULL) { ++ if (anodep != NULL && *anodep != NULL) ++ dns_db_detachnode(*adbp, anodep); ++ dns_db_detach(adbp); ++ } + dns_db_attach(fctx->cache, adbp); + dns_db_transfernode(fctx->cache, &node, anodep); + clone_results(fctx); +@@ -6039,13 +6044,15 @@ static isc_result_t + answer_response(fetchctx_t *fctx) { + isc_result_t result; + dns_message_t *message; +- dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; ++ dns_name_t *name, *dname = NULL, *qname, *dqname, tname, *ns_name; ++ dns_name_t *cname = NULL; + dns_rdataset_t *rdataset, *ns_rdataset; + isc_boolean_t done, external, chaining, aa, found, want_chaining; +- isc_boolean_t have_answer, found_cname, found_type, wanted_chaining; ++ isc_boolean_t have_answer, found_cname, found_dname, found_type; ++ isc_boolean_t wanted_chaining; + unsigned int aflag; + dns_rdatatype_t type; +- dns_fixedname_t fdname, fqname; ++ dns_fixedname_t fdname, fqname, fqdname; + dns_view_t *view; + + FCTXTRACE("answer_response"); +@@ -6059,6 +6066,7 @@ answer_response(fetchctx_t *fctx) { + + done = ISC_FALSE; + found_cname = ISC_FALSE; ++ found_dname = ISC_FALSE; + found_type = ISC_FALSE; + chaining = ISC_FALSE; + have_answer = ISC_FALSE; +@@ -6068,12 +6076,13 @@ answer_response(fetchctx_t *fctx) { + aa = ISC_TRUE; + else + aa = ISC_FALSE; +- qname = &fctx->name; ++ dqname = qname = &fctx->name; + type = fctx->type; + view = fctx->res->view; ++ dns_fixedname_init(&fqdname); + result = dns_message_firstname(message, DNS_SECTION_ANSWER); + while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln; ++ dns_namereln_t namereln, dnamereln; + int order; + unsigned int nlabels; + +@@ -6081,6 +6090,8 @@ answer_response(fetchctx_t *fctx) { + dns_message_currentname(message, DNS_SECTION_ANSWER, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); + namereln = dns_name_fullcompare(qname, name, &order, &nlabels); ++ dnamereln = dns_name_fullcompare(dqname, name, &order, ++ &nlabels); + if (namereln == dns_namereln_equal) { + wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); +@@ -6205,9 +6216,16 @@ answer_response(fetchctx_t *fctx) { + * a CNAME or DNAME). + */ + INSIST(!external); +- if (aflag == +- DNS_RDATASETATTR_ANSWER) { ++ if ((rdataset->type != ++ dns_rdatatype_cname) || ++ !found_dname || ++ (aflag == ++ DNS_RDATASETATTR_ANSWER)) ++ { + have_answer = ISC_TRUE; ++ if (rdataset->type == ++ dns_rdatatype_cname) ++ cname = name; + name->attributes |= + DNS_NAMEATTR_ANSWER; + } +@@ -6303,11 +6321,11 @@ answer_response(fetchctx_t *fctx) { + return (DNS_R_FORMERR); + } + +- if (namereln != dns_namereln_subdomain) { ++ if (dnamereln != dns_namereln_subdomain) { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; + +- dns_name_format(qname, qbuf, ++ dns_name_format(dqname, qbuf, + sizeof(qbuf)); + dns_name_format(name, obuf, + sizeof(obuf)); +@@ -6322,7 +6340,7 @@ answer_response(fetchctx_t *fctx) { + want_chaining = ISC_TRUE; + POST(want_chaining); + aflag = DNS_RDATASETATTR_ANSWER; +- result = dname_target(rdataset, qname, ++ result = dname_target(rdataset, dqname, + nlabels, &fdname); + if (result == ISC_R_NOSPACE) { + /* +@@ -6339,10 +6357,13 @@ answer_response(fetchctx_t *fctx) { + + dname = dns_fixedname_name(&fdname); + if (!is_answertarget_allowed(view, +- qname, rdataset->type, +- dname, &fctx->domain)) { ++ dqname, rdataset->type, ++ dname, &fctx->domain)) ++ { + return (DNS_R_SERVFAIL); + } ++ dqname = dns_fixedname_name(&fqdname); ++ dns_name_copy(dname, dqname, NULL); + } else { + /* + * We've found a signature that +@@ -6367,6 +6388,10 @@ answer_response(fetchctx_t *fctx) { + INSIST(!external); + if (aflag == DNS_RDATASETATTR_ANSWER) { + have_answer = ISC_TRUE; ++ found_dname = ISC_TRUE; ++ if (cname != NULL) ++ cname->attributes &= ++ ~DNS_NAMEATTR_ANSWER; + name->attributes |= + DNS_NAMEATTR_ANSWER; + } diff --git a/SOURCES/bind99-CVE-2016-9131.patch b/SOURCES/bind99-CVE-2016-9131.patch new file mode 100644 index 0000000..29e381c --- /dev/null +++ b/SOURCES/bind99-CVE-2016-9131.patch @@ -0,0 +1,37 @@ +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 2bc4461..d9de369 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6533,6 +6533,19 @@ answer_response(fetchctx_t *fctx) { + log_formerr(fctx, "NSEC3 in answer"); + return (DNS_R_FORMERR); + } ++ if (rdataset->type == dns_rdatatype_tkey) { ++ /* ++ * TKEY is not a valid record in a ++ * response to any query we can make. ++ */ ++ log_formerr(fctx, "TKEY in answer"); ++ return (DNS_R_FORMERR); ++ } ++ if (rdataset->rdclass != fctx->res->rdclass) { ++ log_formerr(fctx, "Mismatched class " ++ "in answer"); ++ return (DNS_R_FORMERR); ++ } + + /* + * Apply filters, if given, on answers to reject +@@ -6719,6 +6732,12 @@ answer_response(fetchctx_t *fctx) { + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { ++ if (rdataset->rdclass != fctx->res->rdclass) { ++ log_formerr(fctx, "Mismatched class " ++ "in answer"); ++ return (DNS_R_FORMERR); ++ } ++ + /* + * Only pass DNAME or RRSIG(DNAME). + */ diff --git a/SOURCES/bind99-CVE-2016-9147.patch b/SOURCES/bind99-CVE-2016-9147.patch new file mode 100644 index 0000000..221ff94 --- /dev/null +++ b/SOURCES/bind99-CVE-2016-9147.patch @@ -0,0 +1,31 @@ +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 9ad5f81..ffdde5e 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6229,15 +6229,19 @@ answer_response(fetchctx_t *fctx) { + * a CNAME or DNAME). + */ + INSIST(!external); +- if ((rdataset->type != +- dns_rdatatype_cname) || +- !found_dname || +- (aflag == +- DNS_RDATASETATTR_ANSWER)) ++ /* ++ * Don't use found_cname here ++ * as we have just set it ++ * above. ++ */ ++ if (cname == NULL && ++ !found_dname && ++ aflag == ++ DNS_RDATASETATTR_ANSWER) + { + have_answer = ISC_TRUE; +- if (rdataset->type == +- dns_rdatatype_cname) ++ if (found_cname && ++ cname == NULL) + cname = name; + name->attributes |= + DNS_NAMEATTR_ANSWER; diff --git a/SOURCES/bind99-CVE-2016-9444.patch b/SOURCES/bind99-CVE-2016-9444.patch new file mode 100644 index 0000000..17ee09f --- /dev/null +++ b/SOURCES/bind99-CVE-2016-9444.patch @@ -0,0 +1,147 @@ +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 869d258..c1f9498 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -1150,6 +1150,63 @@ update(dns_section_t section, dns_rdataclass_t rdclass) { + return (ISC_FALSE); + } + ++/* ++ * Check to confirm that all DNSSEC records (DS, NSEC, NSEC3) have ++ * covering RRSIGs. ++ */ ++static isc_boolean_t ++auth_signed(dns_namelist_t *section) { ++ dns_name_t *name; ++ ++ for (name = ISC_LIST_HEAD(*section); ++ name != NULL; ++ name = ISC_LIST_NEXT(name, link)) ++ { ++ int auth_dnssec = 0, auth_rrsig = 0; ++ dns_rdataset_t *rds; ++ ++ for (rds = ISC_LIST_HEAD(name->list); ++ rds != NULL; ++ rds = ISC_LIST_NEXT(rds, link)) ++ { ++ switch (rds->type) { ++ case dns_rdatatype_ds: ++ auth_dnssec |= 0x1; ++ break; ++ case dns_rdatatype_nsec: ++ auth_dnssec |= 0x2; ++ break; ++ case dns_rdatatype_nsec3: ++ auth_dnssec |= 0x4; ++ break; ++ case dns_rdatatype_rrsig: ++ break; ++ default: ++ continue; ++ } ++ ++ switch (rds->covers) { ++ case dns_rdatatype_ds: ++ auth_rrsig |= 0x1; ++ break; ++ case dns_rdatatype_nsec: ++ auth_rrsig |= 0x2; ++ break; ++ case dns_rdatatype_nsec3: ++ auth_rrsig |= 0x4; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ if (auth_dnssec != auth_rrsig) ++ return (ISC_FALSE); ++ } ++ ++ return (ISC_TRUE); ++} ++ + static isc_result_t + getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + dns_section_t sectionid, unsigned int options) +@@ -1175,12 +1232,12 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + best_effort = ISC_TF(options & DNS_MESSAGEPARSE_BESTEFFORT); + seen_problem = ISC_FALSE; + ++ section = &msg->sections[sectionid]; ++ + for (count = 0; count < msg->counts[sectionid]; count++) { + int recstart = source->current; + isc_boolean_t skip_name_search, skip_type_search; + +- section = &msg->sections[sectionid]; +- + skip_name_search = ISC_FALSE; + skip_type_search = ISC_FALSE; + free_rdataset = ISC_FALSE; +@@ -1354,7 +1411,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + goto cleanup; + rdata->rdclass = rdclass; + issigzero = ISC_FALSE; +- if (rdtype == dns_rdatatype_rrsig && ++ if (rdtype == dns_rdatatype_rrsig && + rdata->flags == 0) { + covers = dns_rdata_covers(rdata); + if (covers == 0) +@@ -1565,6 +1622,19 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + INSIST(free_rdataset == ISC_FALSE); + } + ++ /* ++ * If any of DS, NSEC or NSEC3 appeared in the ++ * authority section of a query response without ++ * a covering RRSIG, FORMERR ++ */ ++ if (sectionid == DNS_SECTION_AUTHORITY && ++ msg->opcode == dns_opcode_query && ++ ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) && ++ ((msg->flags & DNS_MESSAGEFLAG_TC) == 0) && ++ !preserve_order && ++ !auth_signed(section)) ++ DO_FORMERR; ++ + if (seen_problem) + return (DNS_R_RECOVERABLE); + return (ISC_R_SUCCESS); +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 2bc4461..e5600a3 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -5194,13 +5194,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, + rdataset->type, + &noqname); + if (tresult == ISC_R_SUCCESS && +- noqname != NULL) { +- tresult = +- dns_rdataset_addnoqname( ++ noqname != NULL) ++ (void) dns_rdataset_addnoqname( + rdataset, noqname); +- RUNTIME_CHECK(tresult == +- ISC_R_SUCCESS); +- } + } + addedrdataset = ardataset; + result = dns_db_addrdataset(fctx->cache, node, +@@ -5330,11 +5326,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, dns_adbaddrinfo_t *addrinfo, + tresult = findnoqname(fctx, name, + rdataset->type, &noqname); + if (tresult == ISC_R_SUCCESS && +- noqname != NULL) { +- tresult = dns_rdataset_addnoqname( +- rdataset, noqname); +- RUNTIME_CHECK(tresult == ISC_R_SUCCESS); +- } ++ noqname != NULL) ++ (void) dns_rdataset_addnoqname( ++ rdataset, noqname); + } + + /* diff --git a/SOURCES/bind99-CVE-2017-3135.patch b/SOURCES/bind99-CVE-2017-3135.patch new file mode 100644 index 0000000..2c43c67 --- /dev/null +++ b/SOURCES/bind99-CVE-2017-3135.patch @@ -0,0 +1,193 @@ +From f05af77f32742b8e601d766e1f2fe6a480c7e735 Mon Sep 17 00:00:00 2001 +From: rpm-build <rpm-build> +Date: Wed, 8 Feb 2017 12:23:20 +0100 +Subject: [PATCH] 4557. [security] Combining dns64 and rpz can result in + dereferencing a NULL pointer (read). (CVE-2017-3135) + [RT#44434] + +--- + bin/named/query.c | 59 +++++++++++++++++++++++++----------------------------- + lib/dns/message.c | 6 +++--- + lib/dns/rdataset.c | 1 + + 3 files changed, 31 insertions(+), 35 deletions(-) + +diff --git a/bin/named/query.c b/bin/named/query.c +index 1975dfc..f60078b 100644 +--- a/bin/named/query.c ++++ b/bin/named/query.c +@@ -5591,9 +5591,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + dns_rpz_st_t *rpz_st; + isc_boolean_t resuming; + int line = -1; +- isc_boolean_t dns64_exclude, dns64; ++ isc_boolean_t dns64_exclude, dns64, rpz; + dns_clientinfomethods_t cm; + dns_clientinfo_t ci; ++ dns_name_t *rpzqname; + + CTRACE("query_find"); + +@@ -5619,7 +5620,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + zone = NULL; + need_wildcardproof = ISC_FALSE; + empty_wild = ISC_FALSE; +- dns64_exclude = dns64 = ISC_FALSE; ++ dns64_exclude = dns64 = rpz = ISC_FALSE; + options = 0; + resuming = ISC_FALSE; + is_zone = ISC_FALSE; +@@ -5736,6 +5737,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + authoritative = ISC_FALSE; + version = NULL; + need_wildcardproof = ISC_FALSE; ++ rpz = ISC_FALSE; + + if (client->view->checknames && + !dns_rdata_checkowner(client->query.qname, +@@ -5860,11 +5862,29 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + } + + /* +- * Now look for an answer in the database. ++ * Now look for an answer in the database. If this is a dns64 ++ * AAAA lookup on a rpz database adjust the qname. + */ +- result = dns_db_findext(db, client->query.qname, version, type, ++ if (dns64 && rpz) ++ rpzqname = client->query.rpz_st->qname; ++ else ++ rpzqname = client->query.qname; ++ ++ result = dns_db_findext(db, rpzqname, version, type, + client->query.dboptions, client->now, + &node, fname, &cm, &ci, rdataset, sigrdataset); ++ /* ++ * Fixup fname and sigrdataset. ++ */ ++ if (dns64 && rpz) { ++ isc_result_t rresult; ++ ++ rresult = dns_name_copy(client->query.qname, fname, NULL); ++ RUNTIME_CHECK(rresult == ISC_R_SUCCESS); ++ if (sigrdataset != NULL && ++ dns_rdataset_isassociated(sigrdataset)) ++ dns_rdataset_disassociate(sigrdataset); ++ } + + resume: + CTRACE("query_find: resume"); +@@ -6067,9 +6087,11 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + switch (rpz_st->m.policy) { + case DNS_RPZ_POLICY_NXDOMAIN: + result = DNS_R_NXDOMAIN; ++ rpz = ISC_TRUE; + break; + case DNS_RPZ_POLICY_NODATA: + result = DNS_R_NXRRSET; ++ rpz = ISC_TRUE; + break; + case DNS_RPZ_POLICY_RECORD: + result = rpz_st->m.result; +@@ -6089,6 +6111,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + rdataset->ttl = ISC_MIN(rdataset->ttl, + rpz_st->m.ttl); + } ++ rpz = ISC_TRUE; + break; + case DNS_RPZ_POLICY_WILDCNAME: + result = dns_rdataset_first(rdataset); +@@ -6130,7 +6153,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC | + DNS_MESSAGEFLAG_AD); + query_putrdataset(client, &sigrdataset); +- rpz_st->q.is_zone = is_zone; + is_zone = ISC_TRUE; + rpz_log_rewrite(client, ISC_FALSE, rpz_st->m.policy, + rpz_st->m.type, zone, rpz_st->qname); +@@ -6509,15 +6531,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + rdataset = NULL; + sigrdataset = NULL; + type = qtype = dns_rdatatype_a; +- rpz_st = client->query.rpz_st; +- if (rpz_st != NULL) { +- /* +- * Arrange for RPZ rewriting of any A records. +- */ +- if ((rpz_st->state & DNS_RPZ_REWRITTEN) != 0) +- is_zone = rpz_st->q.is_zone; +- rpz_st_clear(client); +- } + dns64 = ISC_TRUE; + goto db_find; + } +@@ -6786,15 +6799,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + sigrdataset = NULL; + fname = NULL; + type = qtype = dns_rdatatype_a; +- rpz_st = client->query.rpz_st; +- if (rpz_st != NULL) { +- /* +- * Arrange for RPZ rewriting of any A records. +- */ +- if ((rpz_st->state & DNS_RPZ_REWRITTEN) != 0) +- is_zone = rpz_st->q.is_zone; +- rpz_st_clear(client); +- } + dns64 = ISC_TRUE; + goto db_find; + } +@@ -7296,15 +7300,6 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + rdataset = NULL; + sigrdataset = NULL; + type = qtype = dns_rdatatype_a; +- rpz_st = client->query.rpz_st; +- if (rpz_st != NULL) { +- /* +- * Arrange for RPZ rewriting of any A records. +- */ +- if ((rpz_st->state & DNS_RPZ_REWRITTEN) != 0) +- is_zone = rpz_st->q.is_zone; +- rpz_st_clear(client); +- } + dns64_exclude = dns64 = ISC_TRUE; + goto db_find; + } +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 884107e..1417067 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -1234,8 +1234,8 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + { + isc_region_t r; + unsigned int count, rdatalen; +- dns_name_t *name; +- dns_name_t *name2; ++ dns_name_t *name = NULL; ++ dns_name_t *name2 = NULL; + dns_offsets_t *offsets; + dns_rdataset_t *rdataset; + dns_rdatalist_t *rdatalist; +@@ -1245,7 +1245,7 @@ getsection(isc_buffer_t *source, dns_message_t *msg, dns_decompress_t *dctx, + dns_rdata_t *rdata; + dns_ttl_t ttl; + dns_namelist_t *section; +- isc_boolean_t free_name, free_rdataset; ++ isc_boolean_t free_name = ISC_FALSE, free_rdataset = ISC_FALSE; + isc_boolean_t preserve_order, best_effort, seen_problem; + isc_boolean_t issigzero; + +diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c +index 026d771..483ddfb 100644 +--- a/lib/dns/rdataset.c ++++ b/lib/dns/rdataset.c +@@ -336,6 +336,7 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name, + */ + + REQUIRE(DNS_RDATASET_VALID(rdataset)); ++ REQUIRE(rdataset->methods != NULL); + REQUIRE(countp != NULL); + REQUIRE((order == NULL) == (order_arg == NULL)); + REQUIRE(cctx != NULL && cctx->mctx != NULL); +-- +2.9.3 + diff --git a/SOURCES/bind99-CVE-2017-3136.patch b/SOURCES/bind99-CVE-2017-3136.patch new file mode 100644 index 0000000..f83f93e --- /dev/null +++ b/SOURCES/bind99-CVE-2017-3136.patch @@ -0,0 +1,26 @@ +From d4d151cf34fab415e2823deada3433df7f475c71 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com> +Date: Tue, 11 Apr 2017 16:19:08 +0200 +Subject: [PATCH 1/3] 4575. [security] DNS64 with "break-dnssec yes;" + can result in an assertion failure. (CVE-2017-3136) + [RT #44653] + +--- + bin/named/query.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/bin/named/query.c b/bin/named/query.c +index f60078b..6e988f5 100644 +--- a/bin/named/query.c ++++ b/bin/named/query.c +@@ -7324,6 +7324,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype) + result = query_dns64(client, &fname, rdataset, + sigrdataset, dbuf, + DNS_SECTION_ANSWER); ++ noqname = NULL; + dns_rdataset_disassociate(rdataset); + dns_message_puttemprdataset(client->message, &rdataset); + if (result == ISC_R_NOMORE) { +-- +2.9.3 + diff --git a/SOURCES/bind99-CVE-2017-3137.patch b/SOURCES/bind99-CVE-2017-3137.patch new file mode 100644 index 0000000..a0d97e5 --- /dev/null +++ b/SOURCES/bind99-CVE-2017-3137.patch @@ -0,0 +1,1126 @@ +From 93aec4d3d80a0d1cdb6553f70f35a2e2cb1fbaa8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= <pemensik@redhat.com> +Date: Tue, 11 Apr 2017 16:19:51 +0200 +Subject: [PATCH 2/3] 4578. [security] Some chaining (CNAME or DNAME) + responses to upstream queries could trigger assertion + failures. (CVE-2017-3137) [RT #44734] + +(including part of commit fea8a9d) +--- + bin/tests/system/dname/ans3/ans.pl | 16 +- + bin/tests/system/dname/ns1/root.db | 2 +- + bin/tests/system/dname/ns2/example.db | 3 +- + bin/tests/system/dname/tests.sh | 17 +- + lib/dns/name.c | 2 - + lib/dns/resolver.c | 850 +++++++++++++--------------------- + 6 files changed, 349 insertions(+), 541 deletions(-) + +diff --git a/bin/tests/system/dname/ans3/ans.pl b/bin/tests/system/dname/ans3/ans.pl +index 271fc7d..af338fe 100644 +--- a/bin/tests/system/dname/ans3/ans.pl ++++ b/bin/tests/system/dname/ans3/ans.pl +@@ -1,10 +1,18 @@ + #!/usr/bin/env perl + # +-# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC") ++# Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC") + # +-# This Source Code Form is subject to the terms of the Mozilla Public +-# License, v. 2.0. If a copy of the MPL was not distributed with this +-# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. + + use strict; + use warnings; +diff --git a/bin/tests/system/dname/ns1/root.db b/bin/tests/system/dname/ns1/root.db +index 2e84ae0..3d55ace 100644 +--- a/bin/tests/system/dname/ns1/root.db ++++ b/bin/tests/system/dname/ns1/root.db +@@ -1,4 +1,4 @@ +-; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") ++; Copyright (C) 2011, 2017 Internet Systems Consortium, Inc. ("ISC") + ; + ; Permission to use, copy, modify, and/or distribute this software for any + ; purpose with or without fee is hereby granted, provided that the above +diff --git a/bin/tests/system/dname/ns2/example.db b/bin/tests/system/dname/ns2/example.db +index 4289134..c0193de 100644 +--- a/bin/tests/system/dname/ns2/example.db ++++ b/bin/tests/system/dname/ns2/example.db +@@ -1,4 +1,4 @@ +-; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") ++; Copyright (C) 2011, 2017 Internet Systems Consortium, Inc. ("ISC") + ; + ; Permission to use, copy, modify, and/or distribute this software for any + ; purpose with or without fee is hereby granted, provided that the above +@@ -29,6 +29,7 @@ a.short A 10.0.0.1 + short-dname DNAME short + a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 + long-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong ++toolong-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong + cname CNAME a.cnamedname + cnamedname DNAME target + a.target A 10.0.0.3 +diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh +index 6dc9e88..1487bd9 100644 +--- a/bin/tests/system/dname/tests.sh ++++ b/bin/tests/system/dname/tests.sh +@@ -1,6 +1,6 @@ + #!/bin/sh + # +-# Copyright (C) 2011, 2012 Internet Systems Consortium, Inc. ("ISC") ++# Copyright (C) 2011, 2012, 2017 Internet Systems Consortium, Inc. ("ISC") + # + # Permission to use, copy, modify, and/or distribute this software for any + # purpose with or without fee is hereby granted, provided that the above +@@ -57,10 +57,19 @@ grep "status: YXDOMAIN" dig.out.ns2.toolong > /dev/null || ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + +-echo "I:checking (too) long dname from recursive" ++echo "I:checking (too) long dname from recursive with cached DNAME" + ret=0 +-$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.toolong || ret=1 +-grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1 ++$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.long-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cachedtoolong || ret=1 ++grep "status: YXDOMAIN" dig.out.ns4.cachedtoolong > /dev/null || ret=1 ++grep '^long-dname\.example\..*DNAME.*long' dig.out.ns4.cachedtoolong > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ ++echo "I:checking (too) long dname from recursive without cached DNAME" ++ret=0 ++$DIG 01234567890123456789012345678901234567890123456789.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglonglong.longlonglonglonglonglonglonglonglonglonglonglonglonglong.toolong-dname.example @10.53.0.4 a -p 5300 > dig.out.ns4.uncachedtoolong || ret=1 ++grep "status: YXDOMAIN" dig.out.ns4.uncachedtoolong > /dev/null || ret=1 ++grep '^toolong-dname\.example\..*DNAME.*long' dig.out.ns4.uncachedtoolong > /dev/null || ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + +diff --git a/lib/dns/name.c b/lib/dns/name.c +index 93173ee..d02e713 100644 +--- a/lib/dns/name.c ++++ b/lib/dns/name.c +@@ -2119,11 +2119,9 @@ dns_name_split(dns_name_t *name, unsigned int suffixlabels, + REQUIRE(prefix != NULL || suffix != NULL); + REQUIRE(prefix == NULL || + (VALID_NAME(prefix) && +- prefix->buffer != NULL && + BINDABLE(prefix))); + REQUIRE(suffix == NULL || + (VALID_NAME(suffix) && +- suffix->buffer != NULL && + BINDABLE(suffix))); + + splitlabel = name->labels - suffixlabels; +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index c3607fa..860a792 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -3817,6 +3817,7 @@ is_lame(fetchctx_t *fctx) { + isc_result_t result; + + if (message->rcode != dns_rcode_noerror && ++ message->rcode != dns_rcode_yxdomain && + message->rcode != dns_rcode_nxdomain) + return (ISC_FALSE); + +@@ -5386,79 +5387,6 @@ chase_additional(fetchctx_t *fctx) { + goto again; + } + +-static inline isc_result_t +-cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { +- isc_result_t result; +- dns_rdata_t rdata = DNS_RDATA_INIT; +- dns_rdata_cname_t cname; +- +- result = dns_rdataset_first(rdataset); +- if (result != ISC_R_SUCCESS) +- return (result); +- dns_rdataset_current(rdataset, &rdata); +- result = dns_rdata_tostruct(&rdata, &cname, NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- dns_name_init(tname, NULL); +- dns_name_clone(&cname.cname, tname); +- dns_rdata_freestruct(&cname); +- +- return (ISC_R_SUCCESS); +-} +- +-/*% +- * Construct the synthesised CNAME from the existing QNAME and +- * the DNAME RR and store it in 'target'. +- */ +-static inline isc_result_t +-dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, +- unsigned int nlabels, dns_name_t *target) +-{ +- isc_result_t result; +- dns_rdata_t rdata = DNS_RDATA_INIT; +- dns_rdata_dname_t dname; +- dns_fixedname_t prefix; +- +- /* +- * Get the target name of the DNAME. +- */ +- result = dns_rdataset_first(rdataset); +- if (result != ISC_R_SUCCESS) +- return (result); +- dns_rdataset_current(rdataset, &rdata); +- result = dns_rdata_tostruct(&rdata, &dname, NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- +- dns_fixedname_init(&prefix); +- dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); +- result = dns_name_concatenate(dns_fixedname_name(&prefix), +- &dname.dname, target, NULL); +- dns_rdata_freestruct(&dname); +- return (result); +-} +- +-/*% +- * Check if it was possible to construct 'qname' from 'lastcname' +- * and 'rdataset'. +- */ +-static inline isc_result_t +-fromdname(dns_rdataset_t *rdataset, dns_name_t *lastcname, +- unsigned int nlabels, const dns_name_t *qname) +-{ +- dns_fixedname_t fixed; +- isc_result_t result; +- dns_name_t *target; +- +- dns_fixedname_init(&fixed); +- target = dns_fixedname_name(&fixed); +- result = dname_target(rdataset, lastcname, nlabels, target); +- if (result != ISC_R_SUCCESS || !dns_name_equal(qname, target)) +- return (ISC_R_NOTFOUND); +- +- return (ISC_R_SUCCESS); +-} +- + static isc_boolean_t + is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, + dns_rdataset_t *rdataset) +@@ -5534,9 +5462,8 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, + } + + static isc_boolean_t +-is_answertarget_allowed(dns_view_t *view, dns_name_t *name, +- dns_rdatatype_t type, dns_name_t *tname, +- dns_name_t *domain) ++is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname, ++ dns_rdataset_t *rdataset, isc_boolean_t *chainingp) + { + isc_result_t result; + dns_rbtnode_t *node = NULL; +@@ -5544,8 +5471,57 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, + char tnamebuf[DNS_NAME_FORMATSIZE]; + char classbuf[64]; + char typebuf[64]; ++ dns_name_t *tname = NULL; ++ dns_rdata_cname_t cname; ++ dns_rdata_dname_t dname; ++ dns_view_t *view = fctx->res->view; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ unsigned int nlabels; ++ dns_fixedname_t fixed; ++ dns_name_t prefix; ++ ++ REQUIRE(rdataset != NULL); ++ REQUIRE(rdataset->type == dns_rdatatype_cname || ++ rdataset->type == dns_rdatatype_dname); ++ ++ /* ++ * By default, we allow any target name. ++ * If newqname != NULL we also need to extract the newqname. ++ */ ++ if (chainingp == NULL && view->denyanswernames == NULL) ++ return (ISC_TRUE); ++ ++ result = dns_rdataset_first(rdataset); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ dns_rdataset_current(rdataset, &rdata); ++ switch (rdataset->type) { ++ case dns_rdatatype_cname: ++ result = dns_rdata_tostruct(&rdata, &cname, NULL); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ tname = &cname.cname; ++ break; ++ case dns_rdatatype_dname: ++ result = dns_rdata_tostruct(&rdata, &dname, NULL); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ dns_name_init(&prefix, NULL); ++ dns_fixedname_init(&fixed); ++ tname = dns_fixedname_name(&fixed); ++ nlabels = dns_name_countlabels(qname) - ++ dns_name_countlabels(rname); ++ dns_name_split(qname, nlabels, &prefix, NULL); ++ result = dns_name_concatenate(&prefix, &dname.dname, tname, ++ NULL); ++ if (result == DNS_R_NAMETOOLONG) ++ return (ISC_TRUE); ++ RUNTIME_CHECK(result == ISC_R_SUCCESS); ++ break; ++ default: ++ INSIST(0); ++ } ++ ++ if (chainingp != NULL) ++ *chainingp = ISC_TRUE; + +- /* By default, we allow any target name. */ + if (view->denyanswernames == NULL) + return (ISC_TRUE); + +@@ -5554,8 +5530,8 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, + * or partially, allow it. + */ + if (view->answernames_exclude != NULL) { +- result = dns_rbt_findnode(view->answernames_exclude, name, NULL, +- &node, NULL, 0, NULL, NULL); ++ result = dns_rbt_findnode(view->answernames_exclude, qname, ++ NULL, &node, NULL, 0, NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + return (ISC_TRUE); + } +@@ -5563,7 +5539,7 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, + /* + * If the target name is a subdomain of the search domain, allow it. + */ +- if (dns_name_issubdomain(tname, domain)) ++ if (dns_name_issubdomain(tname, &fctx->domain)) + return (ISC_TRUE); + + /* +@@ -5572,9 +5548,9 @@ is_answertarget_allowed(dns_view_t *view, dns_name_t *name, + result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node, + NULL, 0, NULL, NULL); + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { +- dns_name_format(name, qnamebuf, sizeof(qnamebuf)); ++ dns_name_format(qname, qnamebuf, sizeof(qnamebuf)); + dns_name_format(tname, tnamebuf, sizeof(tnamebuf)); +- dns_rdatatype_format(type, typebuf, sizeof(typebuf)); ++ dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf)); + dns_rdataclass_format(view->rdclass, classbuf, + sizeof(classbuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, +@@ -6057,473 +6033,301 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, + return (ISC_R_SUCCESS); + } + ++static isc_boolean_t ++validinanswer(dns_rdataset_t *rdataset, fetchctx_t *fctx) { ++ if (rdataset->type == dns_rdatatype_nsec3) { ++ /* ++ * NSEC3 records are not allowed to ++ * appear in the answer section. ++ */ ++ log_formerr(fctx, "NSEC3 in answer"); ++ return (ISC_FALSE); ++ } ++ if (rdataset->type == dns_rdatatype_tkey) { ++ /* ++ * TKEY is not a valid record in a ++ * response to any query we can make. ++ */ ++ log_formerr(fctx, "TKEY in answer"); ++ return (ISC_FALSE); ++ } ++ if (rdataset->rdclass != fctx->res->rdclass) { ++ log_formerr(fctx, "Mismatched class in answer"); ++ return (ISC_FALSE); ++ } ++ return (ISC_TRUE); ++} ++ + static isc_result_t + answer_response(fetchctx_t *fctx) { + isc_result_t result; +- dns_message_t *message; +- dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; +- dns_name_t *cname = NULL, *lastcname = NULL; +- dns_rdataset_t *rdataset, *ns_rdataset; +- isc_boolean_t done, external, aa, found, want_chaining; +- isc_boolean_t have_answer, found_cname, found_dname, found_type; +- isc_boolean_t wanted_chaining; +- unsigned int aflag, chaining; ++ dns_message_t *message = NULL; ++ dns_name_t *name = NULL, *qname = NULL, *ns_name = NULL; ++ dns_name_t *aname = NULL, *cname = NULL, *dname = NULL; ++ dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; ++ dns_rdataset_t *ardataset = NULL, *crdataset = NULL; ++ dns_rdataset_t *drdataset = NULL, *ns_rdataset = NULL; ++ isc_boolean_t done = ISC_FALSE, aa; ++ unsigned int dname_labels, domain_labels; ++ isc_boolean_t chaining = ISC_FALSE; + dns_rdatatype_t type; +- dns_fixedname_t fdname, fqname; +- dns_view_t *view; ++ dns_view_t *view = NULL; ++ dns_trust_t trust; ++ ++ REQUIRE(VALID_FCTX(fctx)); + + FCTXTRACE("answer_response"); + + message = fctx->rmessage; ++ qname = &fctx->name; ++ view = fctx->res->view; ++ type = fctx->type; + + /* +- * Examine the answer section, marking those rdatasets which are +- * part of the answer and should be cached. ++ * There can be multiple RRSIG and SIG records at a name so ++ * we treat these types as a subset of ANY. + */ ++ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_sig) { ++ type = dns_rdatatype_any; ++ } + +- done = ISC_FALSE; +- found_cname = ISC_FALSE; +- found_dname = ISC_FALSE; +- found_type = ISC_FALSE; +- have_answer = ISC_FALSE; +- want_chaining = ISC_FALSE; +- chaining = 0; +- POST(want_chaining); +- if ((message->flags & DNS_MESSAGEFLAG_AA) != 0) +- aa = ISC_TRUE; +- else +- aa = ISC_FALSE; +- qname = &fctx->name; +- type = fctx->type; +- view = fctx->res->view; +- result = dns_message_firstname(message, DNS_SECTION_ANSWER); +- while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln, lastreln; +- int order, lastorder; +- unsigned int nlabels, lastnlabels; ++ /* ++ * Bigger than any valid DNAME label count. ++ */ ++ dname_labels = dns_name_countlabels(qname); ++ domain_labels = dns_name_countlabels(&fctx->domain); ++ ++ /* ++ * Perform a single pass looking for the answer, cname or covering ++ * dname. ++ */ ++ for (result = dns_message_firstname(message, DNS_SECTION_ANSWER); ++ result == ISC_R_SUCCESS; ++ result = dns_message_nextname(message, DNS_SECTION_ANSWER)) ++ { ++ int order; ++ unsigned int nlabels; ++ dns_namereln_t namereln; + + name = NULL; + dns_message_currentname(message, DNS_SECTION_ANSWER, &name); +- external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); + namereln = dns_name_fullcompare(qname, name, &order, &nlabels); +- +- if (namereln == dns_namereln_equal) { +- wanted_chaining = ISC_FALSE; ++ switch (namereln) { ++ case dns_namereln_equal: + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; +- rdataset = ISC_LIST_NEXT(rdataset, link)) { +- found = ISC_FALSE; +- want_chaining = ISC_FALSE; +- aflag = 0; +- if (rdataset->type == dns_rdatatype_nsec3) { +- /* +- * NSEC3 records are not allowed to +- * appear in the answer section. +- */ +- log_formerr(fctx, "NSEC3 in answer"); +- return (DNS_R_FORMERR); +- } +- if (rdataset->type == dns_rdatatype_tkey) { +- /* +- * TKEY is not a valid record in a +- * response to any query we can make. +- */ +- log_formerr(fctx, "TKEY in answer"); +- return (DNS_R_FORMERR); +- } +- if (rdataset->rdclass != fctx->res->rdclass) { +- log_formerr(fctx, "Mismatched class " +- "in answer"); +- return (DNS_R_FORMERR); +- } +- +- /* +- * Apply filters, if given, on answers to reject +- * a malicious attempt of rebinding. +- */ +- if ((rdataset->type == dns_rdatatype_a || +- rdataset->type == dns_rdatatype_aaaa) && +- !is_answeraddress_allowed(view, name, +- rdataset)) { +- return (DNS_R_SERVFAIL); +- } +- +- if (rdataset->type == type && !found_cname) { +- /* +- * We've found an ordinary answer. +- */ +- found = ISC_TRUE; +- found_type = ISC_TRUE; +- done = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWER; +- } else if (type == dns_rdatatype_any) { +- /* +- * We've found an answer matching +- * an ANY query. There may be +- * more. +- */ +- found = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWER; +- } else if (rdataset->type == dns_rdatatype_rrsig +- && rdataset->covers == type +- && !found_cname) { +- /* +- * We've found a signature that +- * covers the type we're looking for. +- */ +- found = ISC_TRUE; +- found_type = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWERSIG; +- } else if (rdataset->type == +- dns_rdatatype_cname +- && !found_type) { +- /* +- * We're looking for something else, +- * but we found a CNAME. +- * +- * Getting a CNAME response for some +- * query types is an error, see +- * RFC 4035, Section 2.5. +- */ +- if (type == dns_rdatatype_rrsig || +- type == dns_rdatatype_key || +- type == dns_rdatatype_nsec) { +- char buf[DNS_RDATATYPE_FORMATSIZE]; +- dns_rdatatype_format(fctx->type, +- buf, sizeof(buf)); +- log_formerr(fctx, +- "CNAME response " +- "for %s RR", buf); +- return (DNS_R_FORMERR); +- } +- found = ISC_TRUE; +- found_cname = ISC_TRUE; +- want_chaining = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWER; +- result = cname_target(rdataset, +- &tname); +- if (result != ISC_R_SUCCESS) +- return (result); +- /* Apply filters on the target name. */ +- if (!is_answertarget_allowed(view, +- name, +- rdataset->type, +- &tname, +- &fctx->domain)) { +- return (DNS_R_SERVFAIL); ++ rdataset = ISC_LIST_NEXT(rdataset, link)) ++ { ++ if (rdataset->type == type || ++ type == dns_rdatatype_any) ++ { ++ aname = name; ++ if (type != dns_rdatatype_any) { ++ ardataset = rdataset; + } +- lastcname = name; +- } else if (rdataset->type == dns_rdatatype_rrsig +- && rdataset->covers == +- dns_rdatatype_cname +- && !found_type) { +- /* +- * We're looking for something else, +- * but we found a SIG CNAME. +- */ +- found = ISC_TRUE; +- found_cname = ISC_TRUE; +- aflag = DNS_RDATASETATTR_ANSWERSIG; ++ break; + } +- +- if (found) { +- /* +- * We've found an answer to our +- * question. +- */ +- name->attributes |= +- DNS_NAMEATTR_CACHE; +- rdataset->attributes |= +- DNS_RDATASETATTR_CACHE; +- rdataset->trust = dns_trust_answer; +- if (chaining == 0) { +- /* +- * This data is "the" answer +- * to our question only if +- * we're not chaining (i.e. +- * if we haven't followed +- * a CNAME or DNAME). +- */ +- INSIST(!external); +- /* +- * Don't use found_cname here +- * as we have just set it +- * above. +- */ +- if (cname == NULL && +- !found_dname && +- aflag == +- DNS_RDATASETATTR_ANSWER) +- { +- have_answer = ISC_TRUE; +- if (found_cname && +- cname == NULL) +- cname = name; +- name->attributes |= +- DNS_NAMEATTR_ANSWER; +- } +- rdataset->attributes |= aflag; +- if (aa) +- rdataset->trust = +- dns_trust_authanswer; +- } else if (external) { +- /* +- * This data is outside of +- * our query domain, and +- * may not be cached. +- */ +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; +- } +- +- /* +- * Mark any additional data related +- * to this rdataset. +- */ +- (void)dns_rdataset_additionaldata( +- rdataset, +- check_related, +- fctx); +- +- /* +- * CNAME chaining. +- */ +- if (want_chaining) { +- wanted_chaining = ISC_TRUE; +- name->attributes |= +- DNS_NAMEATTR_CHAINING; +- rdataset->attributes |= +- DNS_RDATASETATTR_CHAINING; +- qname = &tname; +- } ++ if (rdataset->type == dns_rdatatype_cname) { ++ cname = name; ++ crdataset = rdataset; ++ break; + } +- /* +- * We could add an "else" clause here and +- * log that we're ignoring this rdataset. +- */ + } ++ break; ++ ++ case dns_namereln_subdomain: + /* +- * If wanted_chaining is true, we've done +- * some chaining as the result of processing +- * this node, and thus we need to set +- * chaining to true. +- * +- * We don't set chaining inside of the +- * rdataset loop because doing that would +- * cause us to ignore the signatures of +- * CNAMEs. ++ * In-scope DNAME records must have at least ++ * as many labels as the domain being queried. ++ * They also must be less that qname's labels ++ * and any previously found dname. + */ +- if (wanted_chaining && chaining < 2U) +- chaining++; +- } else { +- dns_rdataset_t *dnameset = NULL; +- isc_boolean_t synthcname = ISC_FALSE; +- +- if (lastcname != NULL) { +- lastreln = dns_name_fullcompare(lastcname, +- name, +- &lastorder, +- &lastnlabels); +- if (lastreln == dns_namereln_subdomain && +- lastnlabels == dns_name_countlabels(name)) +- synthcname = ISC_TRUE; ++ if (nlabels >= dname_labels || nlabels < domain_labels) ++ { ++ continue; + } + + /* +- * Look for a DNAME (or its SIG). Anything else is +- * ignored. ++ * We are looking for the shortest DNAME if there ++ * are multiple ones (which there shouldn't be). + */ +- wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); + rdataset != NULL; + rdataset = ISC_LIST_NEXT(rdataset, link)) + { +- if (rdataset->rdclass != fctx->res->rdclass) { +- log_formerr(fctx, "Mismatched class " +- "in answer"); +- return (DNS_R_FORMERR); +- } +- +- /* +- * Only pass DNAME or RRSIG(DNAME). +- */ +- if (rdataset->type != dns_rdatatype_dname && +- (rdataset->type != dns_rdatatype_rrsig || +- rdataset->covers != dns_rdatatype_dname)) ++ if (rdataset->type != dns_rdatatype_dname) { + continue; +- +- /* +- * If we're not chaining, then the DNAME and +- * its signature should not be external. +- */ +- if (chaining == 0 && external) { +- char qbuf[DNS_NAME_FORMATSIZE]; +- char obuf[DNS_NAME_FORMATSIZE]; +- +- dns_name_format(name, qbuf, +- sizeof(qbuf)); +- dns_name_format(&fctx->domain, obuf, +- sizeof(obuf)); +- log_formerr(fctx, "external DNAME or " +- "RRSIG covering DNAME " +- "in answer: %s is " +- "not in %s", qbuf, obuf); +- return (DNS_R_FORMERR); +- } +- +- /* +- * If DNAME + synthetic CNAME then the +- * namereln is dns_namereln_subdomain. +- */ +- if (namereln != dns_namereln_subdomain && +- !synthcname) +- { +- char qbuf[DNS_NAME_FORMATSIZE]; +- char obuf[DNS_NAME_FORMATSIZE]; +- +- dns_name_format(qname, qbuf, +- sizeof(qbuf)); +- dns_name_format(name, obuf, +- sizeof(obuf)); +- log_formerr(fctx, "unrelated DNAME " +- "in answer: %s is " +- "not in %s", qbuf, obuf); +- return (DNS_R_FORMERR); + } ++ dname = name; ++ drdataset = rdataset; ++ dname_labels = nlabels; ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++ } + +- aflag = 0; +- if (rdataset->type == dns_rdatatype_dname) { +- want_chaining = ISC_TRUE; +- POST(want_chaining); +- aflag = DNS_RDATASETATTR_ANSWER; +- dns_fixedname_init(&fdname); +- dname = dns_fixedname_name(&fdname); +- if (synthcname) { +- result = fromdname(rdataset, +- lastcname, +- lastnlabels, +- qname); +- } else { +- result = dname_target(rdataset, +- qname, +- nlabels, +- dname); +- } +- if (result == ISC_R_NOSPACE) { +- /* +- * We can't construct the +- * DNAME target. Do not +- * try to continue. +- */ +- want_chaining = ISC_FALSE; +- POST(want_chaining); +- } else if (result != ISC_R_SUCCESS) +- return (result); +- else +- dnameset = rdataset; ++ if (dname != NULL) { ++ aname = NULL; ++ ardataset = NULL; ++ cname = NULL; ++ crdataset = NULL; ++ } else if (aname != NULL) { ++ cname = NULL; ++ crdataset = NULL; ++ } + +- if (!synthcname && +- !is_answertarget_allowed(view, +- qname, rdataset->type, +- dname, &fctx->domain)) +- { +- return (DNS_R_SERVFAIL); +- } +- } else { +- /* +- * We've found a signature that +- * covers the DNAME. +- */ +- aflag = DNS_RDATASETATTR_ANSWERSIG; +- } ++ aa = ISC_TF((message->flags & DNS_MESSAGEFLAG_AA) != 0); ++ trust = aa ? dns_trust_authanswer : dns_trust_answer; + +- /* +- * We've found an answer to our +- * question. +- */ +- name->attributes |= DNS_NAMEATTR_CACHE; +- rdataset->attributes |= DNS_RDATASETATTR_CACHE; +- rdataset->trust = dns_trust_answer; +- /* +- * If we are not chaining or the first CNAME +- * is a synthesised CNAME before the DNAME. +- */ +- if ((chaining == 0) || +- (chaining == 1U && synthcname)) +- { +- /* +- * This data is "the" answer to +- * our question only if we're +- * not chaining. +- */ +- INSIST(!external); +- if (aflag == DNS_RDATASETATTR_ANSWER) { +- have_answer = ISC_TRUE; +- found_dname = ISC_TRUE; +- if (cname != NULL && +- synthcname) +- { +- cname->attributes &= +- ~DNS_NAMEATTR_ANSWER; +- } +- name->attributes |= +- DNS_NAMEATTR_ANSWER; +- } +- rdataset->attributes |= aflag; +- if (aa) +- rdataset->trust = +- dns_trust_authanswer; +- } else if (external) { +- rdataset->attributes |= +- DNS_RDATASETATTR_EXTERNAL; +- } ++ if (aname != NULL && type == dns_rdatatype_any) { ++ for (rdataset = ISC_LIST_HEAD(aname->list); ++ rdataset != NULL; ++ rdataset = ISC_LIST_NEXT(rdataset, link)) ++ { ++ if (!validinanswer(rdataset, fctx)) { ++ return (DNS_R_FORMERR); + } +- +- /* +- * DNAME chaining. +- */ +- if (dnameset != NULL) { +- if (!synthcname) { +- /* +- * Copy the dname into the qname fixed +- * name. +- * +- * Although we check for failure of the +- * copy operation, in practice it +- * should never fail since we already +- * know that the result fits in a +- * fixedname. +- */ +- dns_fixedname_init(&fqname); +- qname = dns_fixedname_name(&fqname); +- result = dns_name_copy(dname, qname, +- NULL); +- if (result != ISC_R_SUCCESS) +- return (result); +- } +- wanted_chaining = ISC_TRUE; +- name->attributes |= DNS_NAMEATTR_CHAINING; +- dnameset->attributes |= +- DNS_RDATASETATTR_CHAINING; ++ if ((fctx->type == dns_rdatatype_sig || ++ fctx->type == dns_rdatatype_rrsig) && ++ rdataset->type != fctx->type) ++ { ++ continue; + } +- /* +- * Ensure that we can't ever get chaining == 1 +- * above if we have processed a DNAME. +- */ +- if (wanted_chaining && chaining < 2U) +- chaining += 2; ++ if ((rdataset->type == dns_rdatatype_a || ++ rdataset->type == dns_rdatatype_aaaa) && ++ !is_answeraddress_allowed(view, aname, rdataset)) ++ { ++ return (DNS_R_SERVFAIL); ++ } ++ if ((rdataset->type == dns_rdatatype_cname || ++ rdataset->type == dns_rdatatype_dname) && ++ !is_answertarget_allowed(fctx, qname, aname, ++ rdataset, NULL)) ++ { ++ return (DNS_R_SERVFAIL); ++ } ++ aname->attributes |= DNS_NAMEATTR_CACHE; ++ aname->attributes |= DNS_NAMEATTR_ANSWER; ++ rdataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ rdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ rdataset->trust = trust; ++ (void)dns_rdataset_additionaldata(rdataset, ++ check_related, ++ fctx); + } +- result = dns_message_nextname(message, DNS_SECTION_ANSWER); +- } +- if (result == ISC_R_NOMORE) +- result = ISC_R_SUCCESS; +- if (result != ISC_R_SUCCESS) +- return (result); +- +- /* +- * We should have found an answer. +- */ +- if (!have_answer) { ++ } else if (aname != NULL) { ++ if (!validinanswer(ardataset, fctx)) ++ return (DNS_R_FORMERR); ++ if ((ardataset->type == dns_rdatatype_a || ++ ardataset->type == dns_rdatatype_aaaa) && ++ !is_answeraddress_allowed(view, aname, ardataset)) { ++ return (DNS_R_SERVFAIL); ++ } ++ if ((ardataset->type == dns_rdatatype_cname || ++ ardataset->type == dns_rdatatype_dname) && ++ !is_answertarget_allowed(fctx, qname, aname, ardataset, ++ NULL)) ++ { ++ return (DNS_R_SERVFAIL); ++ } ++ aname->attributes |= DNS_NAMEATTR_CACHE; ++ aname->attributes |= DNS_NAMEATTR_ANSWER; ++ ardataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ ardataset->attributes |= DNS_RDATASETATTR_CACHE; ++ ardataset->trust = trust; ++ (void)dns_rdataset_additionaldata(ardataset, check_related, ++ fctx); ++ for (sigrdataset = ISC_LIST_HEAD(aname->list); ++ sigrdataset != NULL; ++ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) { ++ if (!validinanswer(sigrdataset, fctx)) ++ return (DNS_R_FORMERR); ++ if (sigrdataset->type != dns_rdatatype_rrsig || ++ sigrdataset->covers != type) ++ continue; ++ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; ++ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ sigrdataset->trust = trust; ++ break; ++ } ++ } else if (cname != NULL) { ++ if (!validinanswer(crdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (type == dns_rdatatype_rrsig || type == dns_rdatatype_key || ++ type == dns_rdatatype_nsec) ++ { ++ char buf[DNS_RDATATYPE_FORMATSIZE]; ++ dns_rdatatype_format(type, buf, sizeof(buf)); ++ log_formerr(fctx, "CNAME response for %s RR", buf); ++ return (DNS_R_FORMERR); ++ } ++ if (!is_answertarget_allowed(fctx, qname, cname, crdataset, ++ NULL)) ++ { ++ return (DNS_R_SERVFAIL); ++ } ++ cname->attributes |= DNS_NAMEATTR_CACHE; ++ cname->attributes |= DNS_NAMEATTR_ANSWER; ++ cname->attributes |= DNS_NAMEATTR_CHAINING; ++ crdataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ crdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ crdataset->attributes |= DNS_RDATASETATTR_CHAINING; ++ crdataset->trust = trust; ++ for (sigrdataset = ISC_LIST_HEAD(cname->list); ++ sigrdataset != NULL; ++ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) ++ { ++ if (!validinanswer(sigrdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (sigrdataset->type != dns_rdatatype_rrsig || ++ sigrdataset->covers != dns_rdatatype_cname) ++ { ++ continue; ++ } ++ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; ++ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ sigrdataset->trust = trust; ++ break; ++ } ++ chaining = ISC_TRUE; ++ } else if (dname != NULL) { ++ if (!validinanswer(drdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (!is_answertarget_allowed(fctx, qname, dname, drdataset, ++ &chaining)) { ++ return (DNS_R_SERVFAIL); ++ } ++ dname->attributes |= DNS_NAMEATTR_CACHE; ++ dname->attributes |= DNS_NAMEATTR_ANSWER; ++ dname->attributes |= DNS_NAMEATTR_CHAINING; ++ drdataset->attributes |= DNS_RDATASETATTR_ANSWER; ++ drdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ drdataset->attributes |= DNS_RDATASETATTR_CHAINING; ++ drdataset->trust = trust; ++ for (sigrdataset = ISC_LIST_HEAD(dname->list); ++ sigrdataset != NULL; ++ sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) ++ { ++ if (!validinanswer(sigrdataset, fctx)) { ++ return (DNS_R_FORMERR); ++ } ++ if (sigrdataset->type != dns_rdatatype_rrsig || ++ sigrdataset->covers != dns_rdatatype_dname) ++ { ++ continue; ++ } ++ sigrdataset->attributes |= DNS_RDATASETATTR_ANSWERSIG; ++ sigrdataset->attributes |= DNS_RDATASETATTR_CACHE; ++ sigrdataset->trust = trust; ++ break; ++ } ++ } else { + log_formerr(fctx, "reply has no answer"); + return (DNS_R_FORMERR); + } +@@ -6536,14 +6340,8 @@ answer_response(fetchctx_t *fctx) { + /* + * Did chaining end before we got the final answer? + */ +- if (chaining != 0) { +- /* +- * Yes. This may be a negative reply, so hand off +- * authority section processing to the noanswer code. +- * If it isn't a noanswer response, no harm will be +- * done. +- */ +- return (noanswer_response(fctx, qname, 0)); ++ if (chaining) { ++ return (ISC_R_SUCCESS); + } + + /* +@@ -6562,11 +6360,9 @@ answer_response(fetchctx_t *fctx) { + * We expect there to be only one owner name for all the rdatasets + * in this section, and we expect that it is not external. + */ +- done = ISC_FALSE; +- ns_name = NULL; +- ns_rdataset = NULL; + result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + while (!done && result == ISC_R_SUCCESS) { ++ isc_boolean_t external; + name = NULL; + dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); +@@ -6585,12 +6381,13 @@ answer_response(fetchctx_t *fctx) { + DNS_NAMEATTR_CACHE; + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; +- if (aa && chaining == 0) ++ if (aa && !chaining) { + rdataset->trust = + dns_trust_authauthority; +- else ++ } else { + rdataset->trust = + dns_trust_additional; ++ } + + if (rdataset->type == dns_rdatatype_ns) + { +@@ -7249,6 +7046,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + * Is the remote server broken, or does it dislike us? + */ + if (message->rcode != dns_rcode_noerror && ++ message->rcode != dns_rcode_yxdomain && + message->rcode != dns_rcode_nxdomain) { + if (((message->rcode == dns_rcode_formerr || + message->rcode == dns_rcode_notimp) || +@@ -7293,13 +7091,6 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + log_formerr(fctx, "server sent FORMERR"); + result = DNS_R_FORMERR; + } +- } else if (message->rcode == dns_rcode_yxdomain) { +- /* +- * DNAME mapping failed because the new name +- * was too long. There's no chance of success +- * for this fetch. +- */ +- result = DNS_R_YXDOMAIN; + } else if (message->rcode == dns_rcode_badvers) { + unsigned int flags, mask; + unsigned int version; +@@ -7404,6 +7195,7 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + */ + if (message->counts[DNS_SECTION_ANSWER] > 0 && + (message->rcode == dns_rcode_noerror || ++ message->rcode == dns_rcode_yxdomain || + message->rcode == dns_rcode_nxdomain)) { + /* + * [normal case] +-- +2.9.3 + diff --git a/SOURCES/bind99-CVE-2017-3142+3143.patch b/SOURCES/bind99-CVE-2017-3142+3143.patch new file mode 100644 index 0000000..a0190f4 --- /dev/null +++ b/SOURCES/bind99-CVE-2017-3142+3143.patch @@ -0,0 +1,497 @@ +diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c +index 00a0080..336c4da 100644 +--- a/lib/dns/dnssec.c ++++ b/lib/dns/dnssec.c +@@ -982,6 +982,8 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, + mctx = msg->mctx; + + msg->verify_attempted = 1; ++ msg->verified_sig = 0; ++ msg->sig0status = dns_tsigerror_badsig; + + if (is_response(msg)) { + if (msg->query.base == NULL) +@@ -1076,6 +1078,7 @@ dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg, + } + + msg->verified_sig = 1; ++ msg->sig0status = dns_rcode_noerror; + + dst_context_destroy(&ctx); + dns_rdata_freestruct(&sig); +diff --git a/lib/dns/message.c b/lib/dns/message.c +index 1417067..0621175 100644 +--- a/lib/dns/message.c ++++ b/lib/dns/message.c +@@ -3052,12 +3052,19 @@ dns_message_signer(dns_message_t *msg, dns_name_t *signer) { + + result = dns_rdata_tostruct(&rdata, &tsig, NULL); + INSIST(result == ISC_R_SUCCESS); +- if (msg->tsigstatus != dns_rcode_noerror) ++ if (msg->verified_sig && ++ msg->tsigstatus == dns_rcode_noerror && ++ tsig.error == dns_rcode_noerror) ++ { ++ result = ISC_R_SUCCESS; ++ } else if ((!msg->verified_sig) || ++ (msg->tsigstatus != dns_rcode_noerror)) ++ { + result = DNS_R_TSIGVERIFYFAILURE; +- else if (tsig.error != dns_rcode_noerror) ++ } else { ++ INSIST(tsig.error != dns_rcode_noerror); + result = DNS_R_TSIGERRORSET; +- else +- result = ISC_R_SUCCESS; ++ } + dns_rdata_freestruct(&tsig); + + if (msg->tsigkey == NULL) { +diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c +index 3239bff..7b91d1e 100644 +--- a/lib/dns/tsig.c ++++ b/lib/dns/tsig.c +@@ -941,11 +941,20 @@ dns_tsig_sign(dns_message_t *msg) { + isc_buffer_putuint48(&otherbuf, tsig.timesigned); + } + +- if (key->key != NULL && tsig.error != dns_tsigerror_badsig) { ++ if ((key->key != NULL) && ++ (tsig.error != dns_tsigerror_badsig) && ++ (tsig.error != dns_tsigerror_badkey)) ++ { + unsigned char header[DNS_MESSAGE_HEADERLEN]; + isc_buffer_t headerbuf; + isc_uint16_t digestbits; + ++ /* ++ * If it is a response, we assume that the request MAC ++ * has validated at this point. This is why we include a ++ * MAC length > 0 in the reply. ++ */ ++ + ret = dst_context_create3(key->key, mctx, + DNS_LOGCATEGORY_DNSSEC, + ISC_TRUE, &ctx); +@@ -953,7 +962,7 @@ dns_tsig_sign(dns_message_t *msg) { + return (ret); + + /* +- * If this is a response, digest the query signature. ++ * If this is a response, digest the request's MAC. + */ + if (response) { + dns_rdata_t querytsigrdata = DNS_RDATA_INIT; +@@ -1083,6 +1092,17 @@ dns_tsig_sign(dns_message_t *msg) { + dst_context_destroy(&ctx); + digestbits = dst_key_getbits(key->key); + if (digestbits != 0) { ++ /* ++ * XXXRAY: Is this correct? What is the ++ * expected behavior when digestbits is not an ++ * integral multiple of 8? It looks like bytes ++ * should either be (digestbits/8) or ++ * (digestbits+7)/8. ++ * ++ * In any case, for current algorithms, ++ * digestbits are an integral multiple of 8, so ++ * it has the same effect as (digestbits/8). ++ */ + unsigned int bytes = (digestbits + 1) / 8; + if (response && bytes < querytsig.siglen) + bytes = querytsig.siglen; +@@ -1196,6 +1216,8 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey)); + + msg->verify_attempted = 1; ++ msg->verified_sig = 0; ++ msg->tsigstatus = dns_tsigerror_badsig; + + if (msg->tcp_continuation) { + if (tsigkey == NULL || msg->querytsig == NULL) +@@ -1294,19 +1316,6 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + key = tsigkey->key; + + /* +- * Is the time ok? +- */ +- if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { +- msg->tsigstatus = dns_tsigerror_badtime; +- tsig_log(msg->tsigkey, 2, "signature has expired"); +- return (DNS_R_CLOCKSKEW); +- } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) { +- msg->tsigstatus = dns_tsigerror_badtime; +- tsig_log(msg->tsigkey, 2, "signature is in the future"); +- return (DNS_R_CLOCKSKEW); +- } +- +- /* + * Check digest length. + */ + alg = dst_key_alg(key); +@@ -1315,31 +1324,19 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + return (ret); + if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 || + alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 || +- alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) { +- isc_uint16_t digestbits = dst_key_getbits(key); ++ alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) ++ { + if (tsig.siglen > siglen) { +- tsig_log(msg->tsigkey, 2, "signature length to big"); ++ tsig_log(msg->tsigkey, 2, "signature length too big"); + return (DNS_R_FORMERR); + } + if (tsig.siglen > 0 && +- (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) { ++ (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) ++ { + tsig_log(msg->tsigkey, 2, + "signature length below minimum"); + return (DNS_R_FORMERR); + } +- if (tsig.siglen > 0 && digestbits != 0 && +- tsig.siglen < ((digestbits + 1) / 8)) { +- msg->tsigstatus = dns_tsigerror_badtrunc; +- tsig_log(msg->tsigkey, 2, +- "truncated signature length too small"); +- return (DNS_R_TSIGVERIFYFAILURE); +- } +- if (tsig.siglen > 0 && digestbits == 0 && +- tsig.siglen < siglen) { +- msg->tsigstatus = dns_tsigerror_badtrunc; +- tsig_log(msg->tsigkey, 2, "signature length too small"); +- return (DNS_R_TSIGVERIFYFAILURE); +- } + } + + if (tsig.siglen > 0) { +@@ -1451,34 +1448,92 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg, + + ret = dst_context_verify(ctx, &sig_r); + if (ret == DST_R_VERIFYFAILURE) { +- msg->tsigstatus = dns_tsigerror_badsig; + ret = DNS_R_TSIGVERIFYFAILURE; + tsig_log(msg->tsigkey, 2, + "signature failed to verify(1)"); + goto cleanup_context; +- } else if (ret != ISC_R_SUCCESS) ++ } else if (ret != ISC_R_SUCCESS) { + goto cleanup_context; +- +- dst_context_destroy(&ctx); ++ } + } else if (tsig.error != dns_tsigerror_badsig && + tsig.error != dns_tsigerror_badkey) { +- msg->tsigstatus = dns_tsigerror_badsig; + tsig_log(msg->tsigkey, 2, "signature was empty"); + return (DNS_R_TSIGVERIFYFAILURE); + } + +- msg->tsigstatus = dns_rcode_noerror; ++ /* ++ * Here at this point, the MAC has been verified. Even if any of ++ * the following code returns a TSIG error, the reply will be ++ * signed and WILL always include the request MAC in the digest ++ * computation. ++ */ ++ ++ /* ++ * Is the time ok? ++ */ ++ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { ++ msg->tsigstatus = dns_tsigerror_badtime; ++ tsig_log(msg->tsigkey, 2, "signature has expired"); ++ ret = DNS_R_CLOCKSKEW; ++ goto cleanup_context; ++ } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) { ++ msg->tsigstatus = dns_tsigerror_badtime; ++ tsig_log(msg->tsigkey, 2, "signature is in the future"); ++ ret = DNS_R_CLOCKSKEW; ++ goto cleanup_context; ++ } ++ ++ if ( ++#ifndef PK11_MD5_DISABLE ++ alg == DST_ALG_HMACMD5 || ++#endif ++ alg == DST_ALG_HMACSHA1 || ++ alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 || ++ alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) ++ { ++ isc_uint16_t digestbits = dst_key_getbits(key); ++ ++ /* ++ * XXXRAY: Is this correct? What is the expected ++ * behavior when digestbits is not an integral multiple ++ * of 8? It looks like bytes should either be ++ * (digestbits/8) or (digestbits+7)/8. ++ * ++ * In any case, for current algorithms, digestbits are ++ * an integral multiple of 8, so it has the same effect ++ * as (digestbits/8). ++ */ ++ if (tsig.siglen > 0 && digestbits != 0 && ++ tsig.siglen < ((digestbits + 1) / 8)) ++ { ++ msg->tsigstatus = dns_tsigerror_badtrunc; ++ tsig_log(msg->tsigkey, 2, ++ "truncated signature length too small"); ++ ret = DNS_R_TSIGVERIFYFAILURE; ++ goto cleanup_context; ++ } ++ if (tsig.siglen > 0 && digestbits == 0 && ++ tsig.siglen < siglen) ++ { ++ msg->tsigstatus = dns_tsigerror_badtrunc; ++ tsig_log(msg->tsigkey, 2, "signature length too small"); ++ ret = DNS_R_TSIGVERIFYFAILURE; ++ goto cleanup_context; ++ } ++ } + + if (tsig.error != dns_rcode_noerror) { ++ msg->tsigstatus = tsig.error; + if (tsig.error == dns_tsigerror_badtime) +- return (DNS_R_CLOCKSKEW); ++ ret = DNS_R_CLOCKSKEW; + else +- return (DNS_R_TSIGERRORSET); ++ ret = DNS_R_TSIGERRORSET; ++ goto cleanup_context; + } + ++ msg->tsigstatus = dns_rcode_noerror; + msg->verified_sig = 1; +- +- return (ISC_R_SUCCESS); ++ ret = ISC_R_SUCCESS; + + cleanup_context: + if (ctx != NULL) +@@ -1503,6 +1558,8 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + isc_uint16_t addcount, id; + isc_boolean_t has_tsig = ISC_FALSE; + isc_mem_t *mctx; ++ unsigned int siglen; ++ unsigned int alg; + + REQUIRE(source != NULL); + REQUIRE(msg != NULL); +@@ -1510,12 +1567,16 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + REQUIRE(msg->tcp_continuation == 1); + REQUIRE(msg->querytsig != NULL); + ++ msg->verified_sig = 0; ++ msg->tsigstatus = dns_tsigerror_badsig; ++ + if (!is_response(msg)) + return (DNS_R_EXPECTEDRESPONSE); + + mctx = msg->mctx; + + tsigkey = dns_message_gettsigkey(msg); ++ key = tsigkey->key; + + /* + * Extract and parse the previous TSIG +@@ -1548,7 +1609,8 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + * Do the key name and algorithm match that of the query? + */ + if (!dns_name_equal(keyname, &tsigkey->name) || +- !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) { ++ !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) ++ { + msg->tsigstatus = dns_tsigerror_badkey; + ret = DNS_R_TSIGVERIFYFAILURE; + tsig_log(msg->tsigkey, 2, +@@ -1557,27 +1619,40 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + } + + /* +- * Is the time ok? ++ * Check digest length. + */ +- isc_stdtime_get(&now); +- +- if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { +- msg->tsigstatus = dns_tsigerror_badtime; +- tsig_log(msg->tsigkey, 2, "signature has expired"); +- ret = DNS_R_CLOCKSKEW; +- goto cleanup_querystruct; +- } else if (now + msg->timeadjust < +- tsig.timesigned - tsig.fudge) { +- msg->tsigstatus = dns_tsigerror_badtime; +- tsig_log(msg->tsigkey, 2, +- "signature is in the future"); +- ret = DNS_R_CLOCKSKEW; ++ alg = dst_key_alg(key); ++ ret = dst_key_sigsize(key, &siglen); ++ if (ret != ISC_R_SUCCESS) + goto cleanup_querystruct; ++ if ( ++#ifndef PK11_MD5_DISABLE ++ alg == DST_ALG_HMACMD5 || ++#endif ++ alg == DST_ALG_HMACSHA1 || ++ alg == DST_ALG_HMACSHA224 || ++ alg == DST_ALG_HMACSHA256 || ++ alg == DST_ALG_HMACSHA384 || ++ alg == DST_ALG_HMACSHA512) ++ { ++ if (tsig.siglen > siglen) { ++ tsig_log(tsigkey, 2, ++ "signature length too big"); ++ ret = DNS_R_FORMERR; ++ goto cleanup_querystruct; ++ } ++ if (tsig.siglen > 0 && ++ (tsig.siglen < 10 || ++ tsig.siglen < ((siglen + 1) / 2))) ++ { ++ tsig_log(tsigkey, 2, ++ "signature length below minimum"); ++ ret = DNS_R_FORMERR; ++ goto cleanup_querystruct; ++ } + } + } + +- key = tsigkey->key; +- + if (msg->tsigctx == NULL) { + ret = dst_context_create3(key, mctx, + DNS_LOGCATEGORY_DNSSEC, +@@ -1670,10 +1745,12 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + sig_r.length = tsig.siglen; + if (tsig.siglen == 0) { + if (tsig.error != dns_rcode_noerror) { +- if (tsig.error == dns_tsigerror_badtime) ++ msg->tsigstatus = tsig.error; ++ if (tsig.error == dns_tsigerror_badtime) { + ret = DNS_R_CLOCKSKEW; +- else ++ } else { + ret = DNS_R_TSIGERRORSET; ++ } + } else { + tsig_log(msg->tsigkey, 2, + "signature is empty"); +@@ -1684,29 +1761,111 @@ tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) { + + ret = dst_context_verify(msg->tsigctx, &sig_r); + if (ret == DST_R_VERIFYFAILURE) { +- msg->tsigstatus = dns_tsigerror_badsig; + tsig_log(msg->tsigkey, 2, + "signature failed to verify(2)"); + ret = DNS_R_TSIGVERIFYFAILURE; + goto cleanup_context; ++ } else if (ret != ISC_R_SUCCESS) { ++ goto cleanup_context; + } +- else if (ret != ISC_R_SUCCESS) ++ ++ /* ++ * Here at this point, the MAC has been verified. Even ++ * if any of the following code returns a TSIG error, ++ * the reply will be signed and WILL always include the ++ * request MAC in the digest computation. ++ */ ++ ++ /* ++ * Is the time ok? ++ */ ++ isc_stdtime_get(&now); ++ ++ if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) { ++ msg->tsigstatus = dns_tsigerror_badtime; ++ tsig_log(msg->tsigkey, 2, "signature has expired"); ++ ret = DNS_R_CLOCKSKEW; ++ goto cleanup_context; ++ } else if (now + msg->timeadjust < ++ tsig.timesigned - tsig.fudge) ++ { ++ msg->tsigstatus = dns_tsigerror_badtime; ++ tsig_log(msg->tsigkey, 2, ++ "signature is in the future"); ++ ret = DNS_R_CLOCKSKEW; + goto cleanup_context; ++ } + +- dst_context_destroy(&msg->tsigctx); ++ alg = dst_key_alg(key); ++ ret = dst_key_sigsize(key, &siglen); ++ if (ret != ISC_R_SUCCESS) ++ goto cleanup_context; ++ if ( ++#ifndef PK11_MD5_DISABLE ++ alg == DST_ALG_HMACMD5 || ++#endif ++ alg == DST_ALG_HMACSHA1 || ++ alg == DST_ALG_HMACSHA224 || ++ alg == DST_ALG_HMACSHA256 || ++ alg == DST_ALG_HMACSHA384 || ++ alg == DST_ALG_HMACSHA512) ++ { ++ isc_uint16_t digestbits = dst_key_getbits(key); ++ ++ /* ++ * XXXRAY: Is this correct? What is the ++ * expected behavior when digestbits is not an ++ * integral multiple of 8? It looks like bytes ++ * should either be (digestbits/8) or ++ * (digestbits+7)/8. ++ * ++ * In any case, for current algorithms, ++ * digestbits are an integral multiple of 8, so ++ * it has the same effect as (digestbits/8). ++ */ ++ if (tsig.siglen > 0 && digestbits != 0 && ++ tsig.siglen < ((digestbits + 1) / 8)) ++ { ++ msg->tsigstatus = dns_tsigerror_badtrunc; ++ tsig_log(msg->tsigkey, 2, ++ "truncated signature length " ++ "too small"); ++ ret = DNS_R_TSIGVERIFYFAILURE; ++ goto cleanup_context; ++ } ++ if (tsig.siglen > 0 && digestbits == 0 && ++ tsig.siglen < siglen) ++ { ++ msg->tsigstatus = dns_tsigerror_badtrunc; ++ tsig_log(msg->tsigkey, 2, ++ "signature length too small"); ++ ret = DNS_R_TSIGVERIFYFAILURE; ++ goto cleanup_context; ++ } ++ } ++ ++ if (tsig.error != dns_rcode_noerror) { ++ msg->tsigstatus = tsig.error; ++ if (tsig.error == dns_tsigerror_badtime) ++ ret = DNS_R_CLOCKSKEW; ++ else ++ ret = DNS_R_TSIGERRORSET; ++ goto cleanup_context; ++ } + } + + msg->tsigstatus = dns_rcode_noerror; +- return (ISC_R_SUCCESS); ++ msg->verified_sig = 1; ++ ret = ISC_R_SUCCESS; + + cleanup_context: +- dst_context_destroy(&msg->tsigctx); ++ if (msg->tsigctx != NULL) ++ dst_context_destroy(&msg->tsigctx); + + cleanup_querystruct: + dns_rdata_freestruct(&querytsig); + + return (ret); +- + } + + isc_result_t diff --git a/SOURCES/bind99-ISC-Bugs-34738.patch b/SOURCES/bind99-ISC-Bugs-34738.patch new file mode 100644 index 0000000..c866ac4 --- /dev/null +++ b/SOURCES/bind99-ISC-Bugs-34738.patch @@ -0,0 +1,61 @@ +From 18df9e628ea10c7d607f43fcfd935e7924731f24 Mon Sep 17 00:00:00 2001 +From: Evan Hunt <each@isc.org> +Date: Mon, 9 Sep 2013 22:12:47 -0700 +Subject: [PATCH] [master] strdup journal filename + +3646. [bug] Journal filename string could be set incorrectly, + causing garbage in log messages. [RT #34738] +--- + lib/dns/journal.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/lib/dns/journal.c b/lib/dns/journal.c +index 08aabd5..46a52e1 100644 +--- a/lib/dns/journal.c ++++ b/lib/dns/journal.c +@@ -307,7 +307,7 @@ struct dns_journal { + unsigned int magic; /*%< JOUR */ + isc_mem_t *mctx; /*%< Memory context */ + journal_state_t state; +- const char *filename; /*%< Journal file name */ ++ char *filename; /*%< Journal file name */ + FILE * fp; /*%< File handle */ + isc_offset_t offset; /*%< Current file offset */ + journal_header_t header; /*%< In-core journal header */ +@@ -573,10 +573,13 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, + isc_mem_attach(mctx, &j->mctx); + j->state = JOURNAL_STATE_INVALID; + j->fp = NULL; +- j->filename = filename; ++ j->filename = isc_mem_strdup(mctx, filename); + j->index = NULL; + j->rawindex = NULL; + ++ if (j->filename == NULL) ++ FAIL(ISC_R_NOMEMORY); ++ + result = isc_stdio_open(j->filename, write ? "rb+" : "rb", &fp); + + if (result == ISC_R_FILENOTFOUND) { +@@ -679,6 +682,8 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write, + sizeof(journal_rawpos_t)); + j->index = NULL; + } ++ if (j->filename != NULL) ++ isc_mem_free(j->mctx, j->filename); + if (j->fp != NULL) + (void)isc_stdio_close(j->fp); + isc_mem_putanddetach(&j->mctx, j, sizeof(*j)); +@@ -1242,7 +1247,8 @@ dns_journal_destroy(dns_journal_t **journalp) { + isc_mem_put(j->mctx, j->it.target.base, j->it.target.length); + if (j->it.source.base != NULL) + isc_mem_put(j->mctx, j->it.source.base, j->it.source.length); +- ++ if (j->filename != NULL) ++ isc_mem_free(j->mctx, j->filename); + if (j->fp != NULL) + (void)isc_stdio_close(j->fp); + j->magic = 0; +-- +1.8.3.1 + diff --git a/SOURCES/bind99-ISC-Bugs-34870-v3.patch b/SOURCES/bind99-ISC-Bugs-34870-v3.patch new file mode 100644 index 0000000..2869213 --- /dev/null +++ b/SOURCES/bind99-ISC-Bugs-34870-v3.patch @@ -0,0 +1,213 @@ +diff -up bind-9.9.4/bin/dig/dighost.c.send_buffers bind-9.9.4/bin/dig/dighost.c +--- bind-9.9.4/bin/dig/dighost.c.send_buffers 2013-10-31 14:22:20.296811613 +0100 ++++ bind-9.9.4/bin/dig/dighost.c 2013-10-31 14:57:00.336400190 +0100 +@@ -194,6 +194,7 @@ isc_boolean_t validated = ISC_TRUE; + isc_entropy_t *entp = NULL; + isc_mempool_t *commctx = NULL; + isc_boolean_t debugging = ISC_FALSE; ++isc_boolean_t debugtiming = ISC_FALSE; + isc_boolean_t memdebugging = ISC_FALSE; + char *progname = NULL; + isc_mutex_t lookup_lock; +@@ -553,6 +554,12 @@ debug(const char *format, ...) { + + if (debugging) { + fflush(stdout); ++ if (debugtiming) { ++ struct timeval tv; ++ (void)gettimeofday(&tv, NULL); ++ fprintf(stderr, "%ld.%06ld: ", (long)tv.tv_sec, ++ (long)tv.tv_usec); ++ } + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +@@ -2416,8 +2423,10 @@ send_done(isc_task_t *_task, isc_event_t + + for (b = ISC_LIST_HEAD(sevent->bufferlist); + b != NULL; +- b = ISC_LIST_HEAD(sevent->bufferlist)) ++ b = ISC_LIST_HEAD(sevent->bufferlist)) { + ISC_LIST_DEQUEUE(sevent->bufferlist, b, link); ++ isc_mem_free(mctx, b); ++ } + + query = event->ev_arg; + query->waiting_senddone = ISC_FALSE; +@@ -2609,6 +2618,17 @@ send_tcp_connect(dig_query_t *query) { + } + } + ++static isc_buffer_t * ++clone_buffer(isc_buffer_t *source) { ++ isc_buffer_t *buffer; ++ buffer = isc_mem_allocate(mctx, sizeof(*buffer)); ++ if (buffer == NULL) ++ fatal("memory allocation failure in %s:%d", ++ __FILE__, __LINE__); ++ *buffer = *source; ++ return (buffer); ++} ++ + /*% + * Send a UDP packet to the remote nameserver, possible starting the + * recv action as well. Also make sure that the timer is running and +@@ -2618,6 +2638,7 @@ static void + send_udp(dig_query_t *query) { + dig_lookup_t *l = NULL; + isc_result_t result; ++ isc_buffer_t *sendbuf; + + debug("send_udp(%p)", query); + +@@ -2664,14 +2685,16 @@ send_udp(dig_query_t *query) { + debug("recvcount=%d", recvcount); + } + ISC_LIST_INIT(query->sendlist); +- ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link); ++ sendbuf = clone_buffer(&query->sendbuf); ++ ISC_LIST_ENQUEUE(query->sendlist, sendbuf, link); + debug("sending a request"); + TIME_NOW(&query->time_sent); + INSIST(query->sock != NULL); + query->waiting_senddone = ISC_TRUE; +- result = isc_socket_sendtov(query->sock, &query->sendlist, +- global_task, send_done, query, +- &query->sockaddr, NULL); ++ result = isc_socket_sendtov2(query->sock, &query->sendlist, ++ global_task, send_done, query, ++ &query->sockaddr, NULL, ++ ISC_SOCKFLAG_NORETRY); + check_result(result, "isc_socket_sendtov"); + sendcount++; + } +@@ -2838,6 +2861,7 @@ static void + launch_next_query(dig_query_t *query, isc_boolean_t include_question) { + isc_result_t result; + dig_lookup_t *l; ++ isc_buffer_t *buffer; + + INSIST(!free_now); + +@@ -2861,9 +2885,15 @@ launch_next_query(dig_query_t *query, is + isc_buffer_putuint16(&query->slbuf, (isc_uint16_t) query->sendbuf.used); + ISC_LIST_INIT(query->sendlist); + ISC_LINK_INIT(&query->slbuf, link); +- ISC_LIST_ENQUEUE(query->sendlist, &query->slbuf, link); +- if (include_question) +- ISC_LIST_ENQUEUE(query->sendlist, &query->sendbuf, link); ++ if (!query->first_soa_rcvd) { ++ buffer = clone_buffer(&query->slbuf); ++ ISC_LIST_ENQUEUE(query->sendlist, buffer, link); ++ if (include_question) { ++ buffer = clone_buffer(&query->sendbuf); ++ ISC_LIST_ENQUEUE(query->sendlist, buffer, link); ++ } ++ } ++ + ISC_LINK_INIT(&query->lengthbuf, link); + ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link); + +diff -up bind-9.9.4/bin/dig/host.c.send_buffers bind-9.9.4/bin/dig/host.c +--- bind-9.9.4/bin/dig/host.c.send_buffers 2013-10-31 14:22:20.270811568 +0100 ++++ bind-9.9.4/bin/dig/host.c 2013-10-31 14:22:20.328811669 +0100 +@@ -638,6 +638,8 @@ pre_parse_args(int argc, char **argv) { + case 'w': break; + case 'C': break; + case 'D': ++ if (debugging) ++ debugtiming = ISC_TRUE; + debugging = ISC_TRUE; + break; + case 'N': break; +diff -up bind-9.9.4/bin/dig/include/dig/dig.h.send_buffers bind-9.9.4/bin/dig/include/dig/dig.h +--- bind-9.9.4/bin/dig/include/dig/dig.h.send_buffers 2013-10-31 14:22:20.270811568 +0100 ++++ bind-9.9.4/bin/dig/include/dig/dig.h 2013-10-31 14:22:20.328811669 +0100 +@@ -275,7 +275,7 @@ extern isc_boolean_t validated; + extern isc_taskmgr_t *taskmgr; + extern isc_task_t *global_task; + extern isc_boolean_t free_now; +-extern isc_boolean_t debugging, memdebugging; ++extern isc_boolean_t debugging, debugtiming, memdebugging; + + extern char *progname; + extern int tries; +diff -up bind-9.9.4/lib/isc/include/isc/namespace.h.send_buffers bind-9.9.4/lib/isc/include/isc/namespace.h +--- bind-9.9.4/lib/isc/include/isc/namespace.h.send_buffers 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/isc/include/isc/namespace.h 2013-10-31 14:22:20.328811669 +0100 +@@ -106,6 +106,7 @@ + #define isc_socket_sendv isc__socket_sendv + #define isc_socket_sendtov isc__socket_sendtov + #define isc_socket_sendto2 isc__socket_sendto2 ++#define isc_socket_sendtov2 isc__socket_sendtov2 + #define isc_socket_cleanunix isc__socket_cleanunix + #define isc_socket_permunix isc__socket_permunix + #define isc_socket_bind isc__socket_bind +diff -up bind-9.9.4/lib/isc/include/isc/socket.h.send_buffers bind-9.9.4/lib/isc/include/isc/socket.h +--- bind-9.9.4/lib/isc/include/isc/socket.h.send_buffers 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/isc/include/isc/socket.h 2013-10-31 14:22:20.328811669 +0100 +@@ -866,6 +866,11 @@ isc_socket_sendtov(isc_socket_t *sock, i + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); + isc_result_t ++isc_socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist, ++ isc_task_t *task, isc_taskaction_t action, const void *arg, ++ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, ++ unsigned int flags); ++isc_result_t + isc_socket_sendto2(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, +diff -up bind-9.9.4/lib/isc/unix/socket.c.send_buffers bind-9.9.4/lib/isc/unix/socket.c +--- bind-9.9.4/lib/isc/unix/socket.c.send_buffers 2013-10-31 14:22:20.293811608 +0100 ++++ bind-9.9.4/lib/isc/unix/socket.c 2013-10-31 14:22:20.330811673 +0100 +@@ -510,6 +510,11 @@ isc__socket_sendtov(isc_socket_t *sock, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo); + ISC_SOCKETFUNC_SCOPE isc_result_t ++isc__socket_sendtov2(isc_socket_t *sock, isc_bufferlist_t *buflist, ++ isc_task_t *task, isc_taskaction_t action, const void *arg, ++ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, ++ unsigned int flags); ++ISC_SOCKETFUNC_SCOPE isc_result_t + isc__socket_sendto2(isc_socket_t *sock, isc_region_t *region, + isc_task_t *task, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, +@@ -4796,15 +4801,25 @@ ISC_SOCKETFUNC_SCOPE isc_result_t + isc__socket_sendv(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg) + { +- return (isc__socket_sendtov(sock, buflist, task, action, arg, NULL, +- NULL)); ++ return (isc__socket_sendtov2(sock, buflist, task, action, arg, NULL, ++ NULL, 0)); + } + + ISC_SOCKETFUNC_SCOPE isc_result_t +-isc__socket_sendtov(isc_socket_t *sock0, isc_bufferlist_t *buflist, ++isc__socket_sendtov(isc_socket_t *sock, isc_bufferlist_t *buflist, + isc_task_t *task, isc_taskaction_t action, const void *arg, + isc_sockaddr_t *address, struct in6_pktinfo *pktinfo) + { ++ return (isc__socket_sendtov2(sock, buflist, task, action, arg, address, ++ pktinfo, 0)); ++} ++ ++ISC_SOCKETFUNC_SCOPE isc_result_t ++isc__socket_sendtov2(isc_socket_t *sock0, isc_bufferlist_t *buflist, ++ isc_task_t *task, isc_taskaction_t action, const void *arg, ++ isc_sockaddr_t *address, struct in6_pktinfo *pktinfo, ++ unsigned int flags) ++{ + isc__socket_t *sock = (isc__socket_t *)sock0; + isc_socketevent_t *dev; + isc__socketmgr_t *manager; +@@ -4837,7 +4852,7 @@ isc__socket_sendtov(isc_socket_t *sock0, + buffer = ISC_LIST_HEAD(*buflist); + } + +- return (socket_send(sock, dev, task, address, pktinfo, 0)); ++ return (socket_send(sock, dev, task, address, pktinfo, flags)); + } + + ISC_SOCKETFUNC_SCOPE isc_result_t diff --git a/SOURCES/bind99-ISC-Bugs-35073.patch b/SOURCES/bind99-ISC-Bugs-35073.patch new file mode 100644 index 0000000..c8be3ed --- /dev/null +++ b/SOURCES/bind99-ISC-Bugs-35073.patch @@ -0,0 +1,31 @@ +diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c +index 486c102..dc12a85 100644 +--- a/bin/nsupdate/nsupdate.c ++++ b/bin/nsupdate/nsupdate.c +@@ -1566,16 +1566,20 @@ evaluate_realm(char *cmdline) { + #ifdef GSSAPI + char *word; + char buf[1024]; ++ int n; + +- word = nsu_strsep(&cmdline, " \t\r\n"); +- if (word == NULL || *word == 0) { +- if (realm != NULL) +- isc_mem_free(mctx, realm); ++ if (realm != NULL) { ++ isc_mem_free(mctx, realm); + realm = NULL; +- return (STATUS_MORE); + } + +- snprintf(buf, sizeof(buf), "@%s", word); ++ word = nsu_strsep(&cmdline, " \t\r\n"); ++ if (word == NULL || *word == 0) ++ return (STATUS_MORE); ++ ++ n = snprintf(buf, sizeof(buf), "@%s", word); ++ if (n < 0 || (size_t)n >= sizeof(buf)) ++ fatal("realm is too long"); + realm = isc_mem_strdup(mctx, buf); + if (realm == NULL) + fatal("out of memory"); diff --git a/SOURCES/bind99-ISC-Bugs-35080.patch b/SOURCES/bind99-ISC-Bugs-35080.patch new file mode 100644 index 0000000..14c383f --- /dev/null +++ b/SOURCES/bind99-ISC-Bugs-35080.patch @@ -0,0 +1,42 @@ +commit 3a2ea636103eaf40404fb82f228605d384c36434 +Author: Mark Andrews <marka@isc.org> +Date: Tue Dec 17 09:08:59 2013 +1100 + + 3692. [bug] Two calls to dns_db_getoriginnode were fatal if there + was no data at the node. [RT #35080] + + (cherry picked from commit 161e803a5608956271d8120be37a1b383d14b647) + +diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c +index 2dd4aa0..941b77e 100644 +--- a/lib/dns/rbtdb.c ++++ b/lib/dns/rbtdb.c +@@ -1638,8 +1638,11 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + + nodelock = &rbtdb->node_locks[bucket]; + ++#define KEEP_NODE(n, r) \ ++ ((n)->data != NULL || (n)->down != NULL || (n) == (r)->origin_node) ++ + /* Handle easy and typical case first. */ +- if (!node->dirty && (node->data != NULL || node->down != NULL)) { ++ if (!node->dirty && KEEP_NODE(node, rbtdb)) { + dns_rbtnode_refdecrement(node, &nrefs); + INSIST((int)nrefs >= 0); + if (nrefs == 0) { +@@ -1708,12 +1711,11 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node, + isc_refcount_decrement(&nodelock->references, &refs); + INSIST((int)refs >= 0); + +- /* +- * XXXDCL should this only be done for cache zones? +- */ +- if (node->data != NULL || node->down != NULL) ++ if (KEEP_NODE(node, rbtdb)) + goto restore_locks; + ++#undef KEEP_NODE ++ + if (write_locked) { + /* + * We can now delete the node. diff --git a/SOURCES/bind99-automatic-interface-scanning-rh1294506.patch b/SOURCES/bind99-automatic-interface-scanning-rh1294506.patch new file mode 100644 index 0000000..0aec0c5 --- /dev/null +++ b/SOURCES/bind99-automatic-interface-scanning-rh1294506.patch @@ -0,0 +1,685 @@ +From 5013230b31da1d94ce5682e5c5c38011da744971 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Wed, 11 May 2016 15:17:55 +0200 +Subject: [PATCH] Added support for automatic interface scan when new address + is assigned to any interface + +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + bin/named/config.c | 1 + + bin/named/control.c | 3 + + bin/named/include/named/control.h | 1 + + bin/named/include/named/server.h | 8 +++ + bin/named/interfacemgr.c | 144 ++++++++++++++++++++++++++++++++++++++ + bin/named/named.conf.docbook | 1 + + bin/named/server.c | 31 +++++++- + bin/named/statschannel.c | 5 ++ + bin/rndc/rndc.c | 1 + + bin/rndc/rndc.docbook | 12 ++++ + config.h.in | 12 ++++ + configure.in | 5 +- + doc/arm/Bv9ARM-book.xml | 22 +++++- + lib/isc/include/isc/socket.h | 10 ++- + lib/isc/unix/socket.c | 59 ++++++++++++++++ + lib/isccfg/namedconf.c | 1 + + 16 files changed, 310 insertions(+), 6 deletions(-) + +diff --git a/bin/named/config.c b/bin/named/config.c +index f6d0263..b43c0fc 100644 +--- a/bin/named/config.c ++++ b/bin/named/config.c +@@ -52,6 +52,7 @@ + /*% default configuration */ + static char defaultconf[] = "\ + options {\n\ ++ automatic-interface-scan yes;\n\ + # blackhole {none;};\n" + #ifndef WIN32 + " coresize default;\n\ +diff --git a/bin/named/control.c b/bin/named/control.c +index 06eadce..86fa691 100644 +--- a/bin/named/control.c ++++ b/bin/named/control.c +@@ -185,6 +185,9 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) { + command_compare(command, NS_COMMAND_THAW)) { + result = ns_server_freeze(ns_g_server, ISC_FALSE, command, + text); ++ } else if (command_compare(command, NS_COMMAND_SCAN)) { ++ result = ISC_R_SUCCESS; ++ ns_server_scan_interfaces(ns_g_server); + } else if (command_compare(command, NS_COMMAND_SYNC)) { + result = ns_server_sync(ns_g_server, command, text); + } else if (command_compare(command, NS_COMMAND_RECURSING)) { +diff --git a/bin/named/include/named/control.h b/bin/named/include/named/control.h +index d730a83..52ed583 100644 +--- a/bin/named/include/named/control.h ++++ b/bin/named/include/named/control.h +@@ -59,6 +59,7 @@ + #define NS_COMMAND_NULL "null" + #define NS_COMMAND_NOTIFY "notify" + #define NS_COMMAND_VALIDATION "validation" ++#define NS_COMMAND_SCAN "scan" + #define NS_COMMAND_SIGN "sign" + #define NS_COMMAND_LOADKEYS "loadkeys" + #define NS_COMMAND_ADDZONE "addzone" +diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h +index ff0bfd3..83622f4 100644 +--- a/bin/named/include/named/server.h ++++ b/bin/named/include/named/server.h +@@ -37,6 +37,7 @@ + #define NS_EVENTCLASS ISC_EVENTCLASS(0x4E43) + #define NS_EVENT_RELOAD (NS_EVENTCLASS + 0) + #define NS_EVENT_CLIENTCONTROL (NS_EVENTCLASS + 1) ++#define NS_EVENT_IFSCAN (NS_EVENTCLASS + 2) + + /*% + * Name server state. Better here than in lots of separate global variables. +@@ -114,6 +115,7 @@ struct ns_server { + dns_name_t *session_keyname; + unsigned int session_keyalg; + isc_uint16_t session_keybits; ++ isc_boolean_t interface_auto; + }; + + #define NS_SERVER_MAGIC ISC_MAGIC('S','V','E','R') +@@ -201,6 +203,12 @@ ns_server_reloadwanted(ns_server_t *server); + */ + + void ++ns_server_scan_interfaces(ns_server_t *server); ++/*%< ++ * Trigger a interface scan. ++ */ ++ ++void + ns_server_flushonshutdown(ns_server_t *server, isc_boolean_t flush); + /*%< + * Inform the server that the zones should be flushed to disk on shutdown. +diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c +index 4f6b0f3..a9aa4a4 100644 +--- a/bin/named/interfacemgr.c ++++ b/bin/named/interfacemgr.c +@@ -33,6 +33,28 @@ + #include <named/client.h> + #include <named/log.h> + #include <named/interfacemgr.h> ++#include <named/server.h> ++ ++#ifdef HAVE_NET_ROUTE_H ++#include <net/route.h> ++#if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR) ++#define USE_ROUTE_SOCKET 1 ++#define ROUTE_SOCKET_PROTOCOL PF_ROUTE ++#define MSGHDR rt_msghdr ++#define MSGTYPE rtm_type ++#endif ++#endif ++ ++#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) ++#include <linux/netlink.h> ++#include <linux/rtnetlink.h> ++#if defined(RTM_NEWADDR) && defined(RTM_DELADDR) ++#define USE_ROUTE_SOCKET 1 ++#define ROUTE_SOCKET_PROTOCOL PF_NETLINK ++#define MSGHDR nlmsghdr ++#define MSGTYPE nlmsg_type ++#endif ++#endif + + #define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G') + #define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC) +@@ -55,6 +77,11 @@ struct ns_interfacemgr { + dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */ + ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */ + ISC_LIST(isc_sockaddr_t) listenon; ++#ifdef USE_ROUTE_SOCKET ++ isc_task_t * task; ++ isc_socket_t * route; ++ unsigned char buf[2048]; ++#endif + }; + + static void +@@ -63,6 +90,71 @@ purge_old_interfaces(ns_interfacemgr_t *mgr); + static void + clearlistenon(ns_interfacemgr_t *mgr); + ++#ifdef USE_ROUTE_SOCKET ++static void ++route_event(isc_task_t *task, isc_event_t *event) { ++ isc_socketevent_t *sevent = NULL; ++ ns_interfacemgr_t *mgr = NULL; ++ isc_region_t r; ++ isc_result_t result; ++ struct MSGHDR *rtm; ++ ++ UNUSED(task); ++ ++ REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); ++ mgr = event->ev_arg; ++ sevent = (isc_socketevent_t *)event; ++ ++ if (sevent->result != ISC_R_SUCCESS) { ++ if (sevent->result != ISC_R_CANCELED) ++ isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, ++ "automatic interface scanning " ++ "terminated: %s", ++ isc_result_totext(sevent->result)); ++ ns_interfacemgr_detach(&mgr); ++ isc_event_free(&event); ++ return; ++ } ++ ++ rtm = (struct MSGHDR *)mgr->buf; ++#ifdef RTM_VERSION ++ if (rtm->rtm_version != RTM_VERSION) { ++ isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, ++ "automatic interface rescanning disabled: " ++ "rtm->rtm_version mismatch (%u != %u) " ++ "recompile required", rtm->rtm_version, ++ RTM_VERSION); ++ isc_task_detach(&mgr->task); ++ isc_socket_detach(&mgr->route); ++ ns_interfacemgr_detach(&mgr); ++ isc_event_free(&event); ++ return; ++ } ++#endif ++ ++ switch (rtm->MSGTYPE) { ++ case RTM_NEWADDR: ++ case RTM_DELADDR: ++ if (ns_g_server->interface_auto) ++ ns_server_scan_interfaces(ns_g_server); ++ break; ++ default: ++ break; ++ } ++ ++ /* ++ * Look for next route event. ++ */ ++ r.base = mgr->buf; ++ r.length = sizeof(mgr->buf); ++ result = isc_socket_recv(mgr->route, &r, 1, mgr->task, ++ route_event, mgr); ++ if (result != ISC_R_SUCCESS) ++ ns_interfacemgr_detach(&mgr); ++ isc_event_free(&event); ++} ++#endif ++ + isc_result_t + ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + isc_socketmgr_t *socketmgr, +@@ -112,11 +204,52 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + mgr->aclenv.geoip = ns_g_geoip; + #endif + ++#ifdef USE_ROUTE_SOCKET ++ mgr->route = NULL; ++ result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL, ++ isc_sockettype_raw, &mgr->route); ++ switch (result) { ++ case ISC_R_NOPERM: ++ case ISC_R_SUCCESS: ++ case ISC_R_NOTIMPLEMENTED: ++ case ISC_R_FAMILYNOSUPPORT: ++ break; ++ default: ++ goto cleanup_aclenv; ++ } ++ ++ mgr->task = NULL; ++ if (mgr->route != NULL) { ++ result = isc_task_create(taskmgr, 0, &mgr->task); ++ if (result != ISC_R_SUCCESS) ++ goto cleanup_route; ++ } ++ mgr->references = (mgr->route != NULL) ? 2 : 1; ++#else + mgr->references = 1; ++#endif + mgr->magic = IFMGR_MAGIC; + *mgrp = mgr; ++ ++#ifdef USE_ROUTE_SOCKET ++ if (mgr->route != NULL) { ++ isc_region_t r = { mgr->buf, sizeof(mgr->buf) }; ++ ++ result = isc_socket_recv(mgr->route, &r, 1, mgr->task, ++ route_event, mgr); ++ if (result != ISC_R_SUCCESS) ++ ns_interfacemgr_detach(&mgr); ++ } ++#endif + return (ISC_R_SUCCESS); + ++#ifdef USE_ROUTE_SOCKET ++ cleanup_route: ++ if (mgr->route != NULL) ++ isc_socket_detach(&mgr->route); ++ cleanup_aclenv: ++ dns_aclenv_destroy(&mgr->aclenv); ++#endif + cleanup_listenon: + ns_listenlist_detach(&mgr->listenon4); + ns_listenlist_detach(&mgr->listenon6); +@@ -128,6 +261,13 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + static void + ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) { + REQUIRE(NS_INTERFACEMGR_VALID(mgr)); ++ ++#ifdef USE_ROUTE_SOCKET ++ if (mgr->route != NULL) ++ isc_socket_detach(&mgr->route); ++ if (mgr->task != NULL) ++ isc_task_detach(&mgr->task); ++#endif + dns_aclenv_destroy(&mgr->aclenv); + ns_listenlist_detach(&mgr->listenon4); + ns_listenlist_detach(&mgr->listenon6); +@@ -179,6 +319,10 @@ ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { + * consider all interfaces "old". + */ + mgr->generation++; ++#ifdef USE_ROUTE_SOCKET ++ if (mgr->route != NULL) ++ isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV); ++#endif + purge_old_interfaces(mgr); + } + +diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook +index 8c23e52..a8cd31e 100644 +--- a/bin/named/named.conf.docbook ++++ b/bin/named/named.conf.docbook +@@ -373,6 +373,7 @@ options { + zero-no-soa-ttl <replaceable>boolean</replaceable>; + zero-no-soa-ttl-cache <replaceable>boolean</replaceable>; + dnssec-secure-to-insecure <replaceable>boolean</replaceable>; ++ automatic-interface-scan <replaceable>boolean</replaceable>; + deny-answer-addresses { + <replaceable>address_match_list</replaceable> + } <optional> except-from { <replaceable>namelist</replaceable> } </optional>; +diff --git a/bin/named/server.c b/bin/named/server.c +index 24b31c3..942bab6 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -4485,8 +4485,9 @@ adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) { + } + + /* +- * This event callback is invoked to do periodic network +- * interface scanning. ++ * This event callback is invoked to do periodic network interface ++ * scanning. It is also called by ns_server_scan_interfaces(), ++ * invoked by "rndc scan" + */ + static void + interface_timer_tick(isc_task_t *task, isc_event_t *event) { +@@ -4494,7 +4495,14 @@ interface_timer_tick(isc_task_t *task, isc_event_t *event) { + ns_server_t *server = (ns_server_t *) event->ev_arg; + INSIST(task == server->task); + UNUSED(task); ++ ++ if (event->ev_type == NS_EVENT_IFSCAN) ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_DEBUG(1), ++ "automatic interface rescan"); ++ + isc_event_free(&event); ++ + /* + * XXX should scan interfaces unlocked and get exclusive access + * only to replace ACLs. +@@ -5419,6 +5427,14 @@ load_configuration(const char *filename, ns_server_t *server, + server->interface_interval = interface_interval; + + /* ++ * Enable automatic interface scans. ++ */ ++ obj = NULL; ++ result = ns_config_get(maps, "automatic-interface-scan", &obj); ++ INSIST(result == ISC_R_SUCCESS); ++ server->interface_auto = cfg_obj_asboolean(obj); ++ ++ /* + * Configure the dialup heartbeat timer. + */ + obj = NULL; +@@ -6637,6 +6653,17 @@ ns_server_reloadwanted(ns_server_t *server) { + UNLOCK(&server->reload_event_lock); + } + ++void ++ns_server_scan_interfaces(ns_server_t *server) { ++ isc_event_t *event; ++ ++ event = isc_event_allocate(ns_g_mctx, server, NS_EVENT_IFSCAN, ++ interface_timer_tick, server, ++ sizeof(isc_event_t)); ++ if (event != NULL) ++ isc_task_send(server->task, &event); ++} ++ + static char * + next_token(char **stringp, const char *delim) { + char *res; +diff --git a/bin/named/statschannel.c b/bin/named/statschannel.c +index 37e98a8..b985f62 100644 +--- a/bin/named/statschannel.c ++++ b/bin/named/statschannel.c +@@ -341,6 +341,7 @@ init_desc(void) { + SET_SOCKSTATDESC(tcp4open, "TCP/IPv4 sockets opened", "TCP4Open"); + SET_SOCKSTATDESC(tcp6open, "TCP/IPv6 sockets opened", "TCP6Open"); + SET_SOCKSTATDESC(unixopen, "Unix domain sockets opened", "UnixOpen"); ++ SET_SOCKSTATDESC(rawopen, "Raw sockets opened", "RawOpen"); + SET_SOCKSTATDESC(udp4openfail, "UDP/IPv4 socket open failures", + "UDP4OpenFail"); + SET_SOCKSTATDESC(udp6openfail, "UDP/IPv6 socket open failures", +@@ -351,6 +352,8 @@ init_desc(void) { + "TCP6OpenFail"); + SET_SOCKSTATDESC(unixopenfail, "Unix domain socket open failures", + "UnixOpenFail"); ++ SET_SOCKSTATDESC(rawopenfail, "Raw socket open failures", ++ "RawOpenFail"); + SET_SOCKSTATDESC(udp4close, "UDP/IPv4 sockets closed", "UDP4Close"); + SET_SOCKSTATDESC(udp6close, "UDP/IPv6 sockets closed", "UDP6Close"); + SET_SOCKSTATDESC(tcp4close, "TCP/IPv4 sockets closed", "TCP4Close"); +@@ -358,6 +361,7 @@ init_desc(void) { + SET_SOCKSTATDESC(unixclose, "Unix domain sockets closed", "UnixClose"); + SET_SOCKSTATDESC(fdwatchclose, "FDwatch sockets closed", + "FDWatchClose"); ++ SET_SOCKSTATDESC(rawclose, "Raw sockets closed", "RawClose"); + SET_SOCKSTATDESC(udp4bindfail, "UDP/IPv4 socket bind failures", + "UDP4BindFail"); + SET_SOCKSTATDESC(udp6bindfail, "UDP/IPv6 socket bind failures", +@@ -424,6 +428,7 @@ init_desc(void) { + "UnixRecvErr"); + SET_SOCKSTATDESC(fdwatchrecvfail, "FDwatch recv errors", + "FDwatchRecvErr"); ++ SET_SOCKSTATDESC(rawrecvfail, "Raw recv errors", "RawRecvErr"); + INSIST(i == isc_sockstatscounter_max); + + /* Initialize DNSSEC statistics */ +diff --git a/bin/rndc/rndc.c b/bin/rndc/rndc.c +index 9a007e2..be198b1 100644 +--- a/bin/rndc/rndc.c ++++ b/bin/rndc/rndc.c +@@ -160,6 +160,7 @@ command is one of the following:\n\ + Add zone to given view. Requires new-zone-file option.\n\ + delzone [\"file\"] zone [class [view]]\n\ + Removes zone from given view. Requires new-zone-file option.\n\ ++ scan Scan available network interfaces for changes.\n\ + signing -list zone [class [view]]\n\ + List the private records showing the state of DNSSEC\n\ + signing in the given zone.\n\ +diff --git a/bin/rndc/rndc.docbook b/bin/rndc/rndc.docbook +index 1789aaa..5b37b7f 100644 +--- a/bin/rndc/rndc.docbook ++++ b/bin/rndc/rndc.docbook +@@ -330,6 +330,18 @@ + </varlistentry> + + <varlistentry> ++ <term><userinput>scan</userinput></term> ++ <listitem> ++ <para> ++ Scan the list of available network interfaces ++ for changes, without performing a full ++ <command>reconfig</command> or waiting for the ++ <command>interface-interval</command> timer. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> + <term><userinput>sync <optional>-clean</optional> <optional><replaceable>zone</replaceable> <optional><replaceable>class</replaceable> <optional><replaceable>view</replaceable></optional></optional></optional></userinput></term> + <listitem> + <para> +diff --git a/config.h.in b/config.h.in +index 6ed8381..3515f69 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -280,6 +280,12 @@ int sigwait(const unsigned int *set, int *sig); + /* Define to 1 if you have the <linux/capability.h> header file. */ + #undef HAVE_LINUX_CAPABILITY_H + ++/* Define to 1 if you have the <linux/netlink.h> header file. */ ++#undef HAVE_LINUX_NETLINK_H ++ ++/* Define to 1 if you have the <linux/rtnetlink.h> header file. */ ++#undef HAVE_LINUX_RTNETLINK_H ++ + /* Define to 1 if you have the <linux/types.h> header file. */ + #undef HAVE_LINUX_TYPES_H + +@@ -295,6 +301,9 @@ int sigwait(const unsigned int *set, int *sig); + /* Define to 1 if you have the <net/if6.h> header file. */ + #undef HAVE_NET_IF6_H + ++/* Define to 1 if you have the <net/route.h> header file. */ ++#undef HAVE_NET_ROUTE_H ++ + /* Define if your OpenSSL version supports ECDSA. */ + #undef HAVE_OPENSSL_ECDSA + +@@ -358,6 +367,9 @@ int sigwait(const unsigned int *set, int *sig); + /* Define to 1 if you have the <sys/select.h> header file. */ + #undef HAVE_SYS_SELECT_H + ++/* Define to 1 if you have the <sys/socket.h> header file. */ ++#undef HAVE_SYS_SOCKET_H ++ + /* Define to 1 if you have the <sys/sockio.h> header file. */ + #undef HAVE_SYS_SOCKIO_H + +diff --git a/configure.in b/configure.in +index d72093f..38e626d 100644 +--- a/configure.in ++++ b/configure.in +@@ -375,11 +375,14 @@ fi + + AC_HEADER_STDC + +-AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h,,, ++AC_CHECK_HEADERS(fcntl.h regex.h sys/time.h unistd.h sys/sockio.h sys/select.h sys/param.h sys/sysctl.h net/if6.h sys/socket.h net/route.h linux/netlink.h linux/rtnetlink.h,,, + [$ac_includes_default + #ifdef HAVE_SYS_PARAM_H + # include <sys/param.h> + #endif ++#ifdef HAVE_SYS_SOCKET_H ++# include <sys/socket.h> ++#endif + ]) + + AC_C_CONST +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index 92c7b72..4c47d92 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -4964,7 +4964,9 @@ badresp:1,adberr:0,findfail:0,valfail:0] + <optional> policy given | disabled | passthru | nxdomain | nodata | cname <replaceable>domain</replaceable> </optional> + <optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional> ; + } <optional> recursive-only <replaceable>yes_or_no</replaceable> </optional> <optional> max-policy-ttl <replaceable>number</replaceable> </optional> +- <optional> break-dnssec <replaceable>yes_or_no</replaceable> </optional> <optional> min-ns-dots <replaceable>number</replaceable> </optional> ; </optional> ++ <optional> break-dnssec <replaceable>yes_or_no</replaceable> </optional> <optional> min-ns-dots <replaceable>number</replaceable> </optional> ++ <optional> automatic-interface-scan <replaceable>yes_or_no</replaceable> </optional> ++ ; </optional> + }; + </programlisting> + +@@ -5726,6 +5728,23 @@ options { + <variablelist> + + <varlistentry> ++ <term><command>automatic-interface-scan</command></term> ++ <listitem> ++ <para> ++ If <userinput>yes</userinput> and supported by the OS, ++ automatically rescan network interfaces when the interface ++ addresses are added or removed. The default is ++ <userinput>yes</userinput>. ++ </para> ++ <para> ++ Currently the OS needs to support routing sockets for ++ <command>automatic-interface-scan</command> to be ++ supported. ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> + <term><command>allow-new-zones</command></term> + <listitem> + <para> +@@ -10494,6 +10513,7 @@ zone <replaceable>zone_name</replaceable> <optional><replaceable>class</replacea + <optional> allow-query-on { <replaceable>address_match_list</replaceable> }; </optional> + <optional> allow-transfer { <replaceable>address_match_list</replaceable> }; </optional> + <optional> allow-update-forwarding { <replaceable>address_match_list</replaceable> }; </optional> ++ <optional> automatic-interface-scan { <replaceable>yes_or_no</replaceable> }; </optional> + <optional> dnssec-update-mode ( <replaceable>maintain</replaceable> | <replaceable>no-resign</replaceable> ); </optional> + <optional> update-check-ksk <replaceable>yes_or_no</replaceable>; </optional> + <optional> dnssec-dnskey-kskonly <replaceable>yes_or_no</replaceable>; </optional> +diff --git a/lib/isc/include/isc/socket.h b/lib/isc/include/isc/socket.h +index c5a753a..1cd90bb 100644 +--- a/lib/isc/include/isc/socket.h ++++ b/lib/isc/include/isc/socket.h +@@ -150,7 +150,12 @@ enum { + isc_sockstatscounter_unixrecvfail = 50, + isc_sockstatscounter_fdwatchrecvfail = 51, + +- isc_sockstatscounter_max = 52 ++ isc_sockstatscounter_rawopen = 52, ++ isc_sockstatscounter_rawopenfail = 53, ++ isc_sockstatscounter_rawclose = 54, ++ isc_sockstatscounter_rawrecvfail = 55, ++ ++ isc_sockstatscounter_max = 56 + }; + + /*** +@@ -221,7 +226,8 @@ typedef enum { + isc_sockettype_udp = 1, + isc_sockettype_tcp = 2, + isc_sockettype_unix = 3, +- isc_sockettype_fdwatch = 4 ++ isc_sockettype_fdwatch = 4, ++ isc_sockettype_raw = 5 + } isc_sockettype_t; + + /*@{*/ +diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c +index 82d0d16..cbc506b 100644 +--- a/lib/isc/unix/socket.c ++++ b/lib/isc/unix/socket.c +@@ -28,6 +28,11 @@ + #include <sys/time.h> + #include <sys/uio.h> + ++#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) ++#include <linux/netlink.h> ++#include <linux/rtnetlink.h> ++#endif ++ + #include <errno.h> + #include <fcntl.h> + #include <stddef.h> +@@ -708,6 +713,18 @@ static const isc_statscounter_t fdwatchstatsindex[] = { + isc_sockstatscounter_fdwatchsendfail, + isc_sockstatscounter_fdwatchrecvfail + }; ++static const isc_statscounter_t rawstatsindex[] = { ++ isc_sockstatscounter_rawopen, ++ isc_sockstatscounter_rawopenfail, ++ isc_sockstatscounter_rawclose, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ -1, ++ isc_sockstatscounter_rawrecvfail, ++}; + + #if defined(USE_KQUEUE) || defined(USE_EPOLL) || defined(USE_DEVPOLL) || \ + defined(USE_WATCHER_THREAD) +@@ -1744,6 +1761,7 @@ doio_recv(isc__socket_t *sock, isc_socketevent_t *dev) { + return (DOIO_EOF); + break; + case isc_sockettype_udp: ++ case isc_sockettype_raw: + break; + case isc_sockettype_fdwatch: + default: +@@ -2306,6 +2324,44 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, + case isc_sockettype_unix: + sock->fd = socket(sock->pf, SOCK_STREAM, 0); + break; ++ case isc_sockettype_raw: ++ errno = EPFNOSUPPORT; ++ /* ++ * PF_ROUTE is a alias for PF_NETLINK on linux. ++ */ ++#if defined(PF_ROUTE) ++ if (sock->fd == -1 && sock->pf == PF_ROUTE) { ++#ifdef NETLINK_ROUTE ++ sock->fd = socket(sock->pf, SOCK_RAW, ++ NETLINK_ROUTE); ++#else ++ sock->fd = socket(sock->pf, SOCK_RAW, 0); ++#endif ++ if (sock->fd != -1) { ++#ifdef NETLINK_ROUTE ++ struct sockaddr_nl sa; ++ int n; ++ ++ /* ++ * Do an implicit bind. ++ */ ++ memset(&sa, 0, sizeof(sa)); ++ sa.nl_family = AF_NETLINK; ++ sa.nl_groups = RTMGRP_IPV4_IFADDR | ++ RTMGRP_IPV6_IFADDR; ++ n = bind(sock->fd, ++ (struct sockaddr *) &sa, ++ sizeof(sa)); ++ if (n < 0) { ++ close(sock->fd); ++ sock->fd = -1; ++ } ++#endif ++ sock->bound = 1; ++ } ++ } ++ #endif ++ break; + case isc_sockettype_fdwatch: + /* + * We should not be called for isc_sockettype_fdwatch +@@ -2602,6 +2658,9 @@ socket_create(isc_socketmgr_t *manager0, int pf, isc_sockettype_t type, + case isc_sockettype_unix: + sock->statsindex = unixstatsindex; + break; ++ case isc_sockettype_raw: ++ sock->statsindex = rawstatsindex; ++ break; + default: + INSIST(0); + } +diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c +index f5ff8e3..f49ff70 100644 +--- a/lib/isccfg/namedconf.c ++++ b/lib/isccfg/namedconf.c +@@ -931,6 +931,7 @@ bindkeys_clauses[] = { + */ + static cfg_clausedef_t + options_clauses[] = { ++ { "automatic-interface-scan", &cfg_type_boolean, 0 }, + { "avoid-v4-udp-ports", &cfg_type_bracketed_portlist, 0 }, + { "avoid-v6-udp-ports", &cfg_type_bracketed_portlist, 0 }, + { "bindkeys-file", &cfg_type_qstring, 0 }, +-- +2.5.5 + diff --git a/SOURCES/bind99-coverity-fixes.patch b/SOURCES/bind99-coverity-fixes.patch new file mode 100644 index 0000000..0e60017 --- /dev/null +++ b/SOURCES/bind99-coverity-fixes.patch @@ -0,0 +1,307 @@ +From 127701d9d32e568f09c775e722286e9c0b8c72ec Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Fri, 22 May 2015 16:56:25 +0200 +Subject: [PATCH] Fix coverity issues + +http://cov01.lab.eng.brq.redhat.com/covscanhub/waiving/9377/ +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + bin/named/server.c | 8 +++----- + lib/dns/dispatch.c | 5 +++-- + lib/dns/dst_api.c | 6 ++++++ + lib/dns/gen.c | 16 +++++++++++++++- + lib/dns/name.c | 8 ++------ + lib/dns/nsec3.c | 4 ++-- + lib/dns/rcode.c | 4 +++- + lib/isc/netaddr.c | 1 + + lib/isc/pk11.c | 21 ++++++++++++++------- + 9 files changed, 49 insertions(+), 24 deletions(-) + +diff --git a/bin/named/server.c b/bin/named/server.c +index 227c646..5e94660 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -8018,9 +8018,11 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) { + dns_zone_t *zone = NULL; + char classstr[DNS_RDATACLASS_FORMATSIZE]; + char zonename[DNS_NAME_FORMATSIZE]; +- const char *vname, *sep, *msg = NULL, *arg; ++ const char *vname, *sep, *arg; + isc_boolean_t cleanup = ISC_FALSE; + ++ UNUSED(text); ++ + (void) next_token(&args, " \t"); + + arg = next_token(&args, " \t"); +@@ -8061,10 +8063,6 @@ ns_server_sync(ns_server_t *server, char *args, isc_buffer_t *text) { + result = synczone(zone, &cleanup); + isc_task_endexclusive(server->task); + +- if (msg != NULL && strlen(msg) < isc_buffer_availablelength(text)) +- isc_buffer_putmem(text, (const unsigned char *)msg, +- strlen(msg) + 1); +- + view = dns_zone_getview(zone); + if (strcmp(view->name, "_default") == 0 || + strcmp(view->name, "_bind") == 0) +diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c +index 5063914..c93651d 100644 +--- a/lib/dns/dispatch.c ++++ b/lib/dns/dispatch.c +@@ -2278,9 +2278,10 @@ dns_dispatchmgr_setudp(dns_dispatchmgr_t *mgr, + + /* Create or adjust socket pool */ + if (mgr->spool != NULL) { +- if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2) ++ if (maxrequests < DNS_DISPATCH_POOLSOCKS * 2) { + isc_mempool_setmaxalloc(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2); + isc_mempool_setfreemax(mgr->spool, DNS_DISPATCH_POOLSOCKS * 2); ++ } + UNLOCK(&mgr->buffer_lock); + return (ISC_R_SUCCESS); + } +@@ -3765,7 +3766,7 @@ dns_dispatchset_create(isc_mem_t *mctx, isc_socketmgr_t *sockmgr, + goto fail_alloc; + + dset->dispatches = isc_mem_get(mctx, sizeof(dns_dispatch_t *) * n); +- if (dset == NULL) { ++ if (dset->dispatches == NULL) { + result = ISC_R_NOMEMORY; + goto fail_lock; + } +diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c +index d96473f..e71f202 100644 +--- a/lib/dns/dst_api.c ++++ b/lib/dns/dst_api.c +@@ -1882,6 +1882,9 @@ dst__entropy_getdata(void *buf, unsigned int len, isc_boolean_t pseudo) { + #ifdef BIND9 + unsigned int flags = dst_entropy_flags; + ++ if (dst_entropy_pool == NULL) ++ return (ISC_R_FAILURE); ++ + if (len == 0) + return (ISC_R_SUCCESS); + +@@ -1914,6 +1917,9 @@ dst__entropy_status(void) { + unsigned char buf[32]; + static isc_boolean_t first = ISC_TRUE; + ++ if (dst_entropy_pool == NULL) ++ return (0); ++ + if (first) { + /* Someone believes RAND_status() initializes the PRNG */ + flags &= ~ISC_ENTROPY_GOODONLY; +diff --git a/lib/dns/gen.c b/lib/dns/gen.c +index 6b533dd..548f892 100644 +--- a/lib/dns/gen.c ++++ b/lib/dns/gen.c +@@ -335,10 +335,14 @@ insert_into_typenames(int type, const char *typename, const char *attr) { + typename); + exit(1); + } ++ + strncpy(ttn->typename, typename, sizeof(ttn->typename)); +- ttn->type = type; ++ ttn->typename[sizeof(ttn->typename) - 1] = '\0'; + + strncpy(ttn->macroname, ttn->typename, sizeof(ttn->macroname)); ++ ttn->macroname[sizeof(ttn->macroname) - 1] = '\0'; ++ ++ ttn->type = type; + c = strlen(ttn->macroname); + while (c > 0) { + if (ttn->macroname[c - 1] == '-') +@@ -364,7 +368,10 @@ insert_into_typenames(int type, const char *typename, const char *attr) { + attr, typename); + exit(1); + } ++ + strncpy(ttn->attr, attr, sizeof(ttn->attr)); ++ ttn->attr[sizeof(ttn->attr) - 1] = '\0'; ++ + ttn->sorted = 0; + if (maxtype < type) + maxtype = type; +@@ -393,11 +400,17 @@ add(int rdclass, const char *classname, int type, const char *typename, + newtt->next = NULL; + newtt->rdclass = rdclass; + newtt->type = type; ++ + strncpy(newtt->classname, classname, sizeof(newtt->classname)); ++ newtt->classname[sizeof(newtt->classname) - 1] = '\0'; ++ + strncpy(newtt->typename, typename, sizeof(newtt->typename)); ++ newtt->typename[sizeof(newtt->typename) - 1] = '\0'; ++ + if (strncmp(dirname, "./", 2) == 0) + dirname += 2; + strncpy(newtt->dirname, dirname, sizeof(newtt->dirname)); ++ newtt->dirname[sizeof(newtt->dirname) - 1] = '\0'; + + tt = types; + oldtt = NULL; +@@ -436,6 +449,7 @@ add(int rdclass, const char *classname, int type, const char *typename, + } + newcc->rdclass = rdclass; + strncpy(newcc->classname, classname, sizeof(newcc->classname)); ++ newcc->classname[sizeof(newcc->classname) - 1] = '\0'; + cc = classes; + oldcc = NULL; + +diff --git a/lib/dns/name.c b/lib/dns/name.c +index 4fcabb1..93173ee 100644 +--- a/lib/dns/name.c ++++ b/lib/dns/name.c +@@ -1859,7 +1859,6 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source, + 0) + return (DNS_R_DISALLOWED); + new_current = c & 0x3F; +- n = 1; + state = fw_newcurrent; + } else + return (DNS_R_BADLABELTYPE); +@@ -1867,8 +1866,6 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source, + case fw_ordinary: + if (downcase) + c = maptolower[c]; +- /* FALLTHROUGH */ +- case fw_copy: + *ndata++ = c; + n--; + if (n == 0) +@@ -1877,9 +1874,6 @@ dns_name_fromwire(dns_name_t *name, isc_buffer_t *source, + case fw_newcurrent: + new_current *= 256; + new_current += c; +- n--; +- if (n != 0) +- break; + if (new_current >= biggest_pointer) + return (DNS_R_BADPOINTER); + biggest_pointer = new_current; +@@ -2398,6 +2392,8 @@ dns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) { + + isc_buffer_usedregion(&buf, ®); + p = isc_mem_allocate(mctx, reg.length + 1); ++ if (p == NULL) ++ return (ISC_R_NOMEMORY); + memcpy(p, (char *) reg.base, (int) reg.length); + p[reg.length] = '\0'; + +diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c +index 935f515..86fad33 100644 +--- a/lib/dns/nsec3.c ++++ b/lib/dns/nsec3.c +@@ -842,8 +842,8 @@ dns_nsec3_addnsec3(dns_db_t *db, dns_dbversion_t *version, + dns_db_detachnode(db, &newnode); + } while (1); + +- if (result == ISC_R_NOMORE) +- result = ISC_R_SUCCESS; ++ /* result cannot be ISC_R_NOMORE here */ ++ INSIST(result != ISC_R_NOMORE); + + failure: + if (dbit != NULL) +diff --git a/lib/dns/rcode.c b/lib/dns/rcode.c +index 0b7fe8c..091b3c7 100644 +--- a/lib/dns/rcode.c ++++ b/lib/dns/rcode.c +@@ -216,7 +216,9 @@ maybe_numeric(unsigned int *valuep, isc_textregion_t *source, + * isc_parse_uint32(). isc_parse_uint32() requires + * null termination, so we must make a copy. + */ +- strncpy(buffer, source->base, NUMBERSIZE); ++ strncpy(buffer, source->base, sizeof(buffer)); ++ buffer[sizeof(buffer) - 1] = '\0'; ++ + INSIST(buffer[source->length] == '\0'); + + result = isc_parse_uint32(&n, buffer, 10); +diff --git a/lib/isc/netaddr.c b/lib/isc/netaddr.c +index 5cce1bc..6706542 100644 +--- a/lib/isc/netaddr.c ++++ b/lib/isc/netaddr.c +@@ -235,6 +235,7 @@ isc_netaddr_prefixok(const isc_netaddr_t *na, unsigned int prefixlen) { + nbytes = prefixlen / 8; + nbits = prefixlen % 8; + if (nbits != 0) { ++ INSIST(nbytes < ipbytes); + if ((p[nbytes] & (0xff>>nbits)) != 0U) + return (ISC_R_FAILURE); + nbytes++; +diff --git a/lib/isc/pk11.c b/lib/isc/pk11.c +index 015bff2..de4479b 100644 +--- a/lib/isc/pk11.c ++++ b/lib/isc/pk11.c +@@ -130,7 +130,10 @@ + #include <pkcs11/cryptoki.h> + #include <pkcs11/pkcs11.h> + +-#define PINLEN 32 ++/* was 32 octets, Petr Spacek suggested 1024, SoftHSMv2 uses 256... */ ++#ifndef PINLEN ++#define PINLEN 256 ++#endif + + #ifndef PK11_NO_LOGERR + #define PK11_NO_LOGERR 1 +@@ -163,7 +166,7 @@ struct pk11_token { + char manuf[32]; + char model[16]; + char serial[16]; +- char pin[PINLEN]; ++ char pin[PINLEN + 1]; + }; + static ISC_LIST(pk11_token_t) tokens; + +@@ -498,7 +501,9 @@ pk11_get_session(pk11_context_t *ctx, pk11_optype_t optype, + + /* Override the token's PIN */ + if (logon && pin != NULL && *pin != '\0') { +- memset(token->pin, 0, PINLEN); ++ if (strlen(pin) > PINLEN) ++ return ISC_R_RANGE; ++ memset(token->pin, 0, PINLEN + 1); + strncpy(token->pin, pin, PINLEN); + } + +@@ -1099,7 +1104,7 @@ pk11_parse_uri(pk11_object_t *obj, const char *label, + char *uri, *p, *a, *na, *v; + size_t len, l; + FILE *stream = NULL; +- char pin[PINLEN]; ++ char pin[PINLEN + 1]; + isc_boolean_t gotpin = ISC_FALSE; + isc_result_t ret; + +@@ -1207,10 +1212,12 @@ pk11_parse_uri(pk11_object_t *obj, const char *label, + ret = isc_stdio_open(v, "r", &stream); + if (ret != ISC_R_SUCCESS) + goto err; +- memset(pin, 0, PINLEN); +- ret = isc_stdio_read(pin, 1, PINLEN - 1, stream, NULL); ++ memset(pin, 0, PINLEN + 1); ++ ret = isc_stdio_read(pin, 1, PINLEN + 1, stream, &l); + if ((ret != ISC_R_SUCCESS) && (ret != ISC_R_EOF)) + goto err; ++ if (l > PINLEN) ++ DST_RET(ISC_R_RANGE); + ret = isc_stdio_close(stream); + stream = NULL; + if (ret != ISC_R_SUCCESS) +@@ -1238,7 +1245,7 @@ pk11_parse_uri(pk11_object_t *obj, const char *label, + DST_RET(ISC_R_NOTFOUND); + obj->slot = token->slotid; + if (gotpin) { +- memmove(token->pin, pin, PINLEN); ++ memmove(token->pin, pin, PINLEN + 1); + obj->reqlogon = ISC_TRUE; + } + +-- +2.1.0 + diff --git a/SOURCES/bind99-coverity-fixes2.patch b/SOURCES/bind99-coverity-fixes2.patch new file mode 100644 index 0000000..14dab6c --- /dev/null +++ b/SOURCES/bind99-coverity-fixes2.patch @@ -0,0 +1,44 @@ +From 1f3ac11cb4ecfab52f517ebf78493b0f05318be2 Mon Sep 17 00:00:00 2001 +From: Evan Hunt <each@isc.org> +Date: Mon, 16 Jun 2014 15:31:04 -0700 +Subject: [PATCH] [v9_9] null terminate strings for coverity + +--- + bin/dig/dig.c | 1 + + bin/tests/system/dlzexternal/driver.c | 6 ++++++ + 2 files changed, 7 insertions(+) + +diff --git a/bin/dig/dig.c b/bin/dig/dig.c +index 8a5fead..6af0964 100644 +--- a/bin/dig/dig.c ++++ b/bin/dig/dig.c +@@ -1453,6 +1453,7 @@ dash_option(char *option, char *next, dig_lookup_t **lookup, + ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { + strncpy((*lookup)->textname, textname, + sizeof((*lookup)->textname)); ++ (*lookup)->textname[sizeof((*lookup)->textname)-1] = 0; + debug("looking up %s", (*lookup)->textname); + (*lookup)->trace_root = ISC_TF((*lookup)->trace || + (*lookup)->ns_search_only); +diff --git a/bin/tests/system/dlzexternal/driver.c b/bin/tests/system/dlzexternal/driver.c +index 053c25a..f99ac14 100644 +--- a/bin/tests/system/dlzexternal/driver.c ++++ b/bin/tests/system/dlzexternal/driver.c +@@ -133,8 +133,14 @@ add_name(struct dlz_example_data *state, struct record *list, + return (ISC_R_NOSPACE); + + strncpy(list[i].name, name, sizeof(list[i].name)); ++ list[i].name[sizeof(list[i].name) - 1] = '\0'; ++ + strncpy(list[i].type, type, sizeof(list[i].type)); ++ list[i].type[sizeof(list[i].type) - 1] = '\0'; ++ + strncpy(list[i].data, data, sizeof(list[i].data)); ++ list[i].data[sizeof(list[i].data) - 1] = '\0'; ++ + list[i].ttl = ttl; + + return (ISC_R_SUCCESS); +-- +2.9.3 + diff --git a/SOURCES/bind99-dyndb.patch b/SOURCES/bind99-dyndb.patch new file mode 100644 index 0000000..a021ef8 --- /dev/null +++ b/SOURCES/bind99-dyndb.patch @@ -0,0 +1,5176 @@ +From a86e8e75d0ac3266756df18575e16baff7743ccd Mon Sep 17 00:00:00 2001 +From: Evan Hunt <each@isc.org> +Date: Mon, 28 Sep 2015 23:12:35 -0700 +Subject: [PATCH] merge dyndb +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +4224. [func] Added support for "dyndb", a new interface for loading + zone data from an external database, developed by + Red Hat for the FreeIPA project. + + DynDB drivers fully implement the BIND database + API, and are capable of significantly better + performance and functionality than DLZ drivers, + while taking advantage of advanced database + features not available in BIND such as multi-master + replication. + + Thanks to Adam Tkac and Petr Spacek of Red Hat. + [RT #35271] + +(cherry picked from commit a00f9e2f50675bd43cc6a9fe2669709162a2ccb4) + +Make backport compilable + +add missing libraries + +(cherry picked from commit ac6bb3dd36149bc51e0367eba7c50e15dc076c9b) + +(cherry picked from commit ab8b419a797fae25f441273aca3ec18d8d0c1106) + +address linking issues + +(cherry picked from commit 1a0e5b0504576a17a99817d9eef10c4937ef0d63) + +silence compiler warnings + +(cherry picked from commit 0d990f57aefcb3a2e82a91367fc600ccf69eea63) + +remove deadcode; move NULL assignment arlier + +(cherry picked from commit 30f8d5e386a283c7e3a24683b78e489881c16c34) + +Updated WIN32 files (rt40877) +Use only differences in dyndb files, do not update win32 projects + +(cherry picked from commit 343aeac7176d28c4a1b9d246b1f7311b4cd5da7d) + +remove unnecessary return + +(cherry picked from commit 7f79448198139145cebc2540188b16b1861b98c5) + +add missing dependancy + +(cherry picked from commit 97e9fc9e53039c141e1a14adab0865a04225848a) + +4386.[bug]Remove shadowed overmem function/variable. [RT #42706] + +(cherry picked from commit 96beefd76f597b77d4fcd51f8d766e5e59a2d216) + +update dyndb_init inline documentationi [RT #43050] + +(cherry picked from commit 8c2c6b8b42766c8221c79bd43680dbfbaed17147) + +[master] fix dyndb issues; isc_errno_toresult() + +4445. [cleanup] isc_errno_toresult() can now be used to call the + formerly private function isc__errno2result(). + [RT #43050] + +4444. [bug] Fixed some issues related to dyndb: A bug caused + braces to be omitted when passing configuration text + from named.conf to a dyndb driver, and there was a + use-after-free in the sample dyndb driver. [RT #43050] + +Patch for dyndb driver submitted by Petr Spacek at Red Hat. + +(cherry picked from commit 3390d74e33385337631b19e68760025e0ca5d6ec) + +[master] pass source file and line to dyndb load function + +4455. [cleanup] Allow dyndb modules to correctly log the filename + and line number when processing configuration text + from named.conf. [RT #43050] + +(cherry picked from commit 02fb764681d145e4607c59280a48617013e886ac) + +install isc/errno.h + +(cherry picked from commit dec17fb66215d0b02ff9a5810658cdcd0215d240) + +4493. [bug] bin/tests/system/dyndb/driver/Makefile.in should use + SO_TARGETS. [RT# 43336] + +(cherry picked from commit c910fc24ce2aad5fa9e9a2d304f818fd8e996e6f) + +Include dyndb in tests building + +(picked by hand from master commit 93c211afc97e7a072c12ef346581065e4065ff15) + +Do not test type of a pointer + +Skip DEEPBIND - works only with shared library, but works. And fix dyndb test + +Backported to 9.9.4 + +Include commandline.c in export libraries + +Signed-off-by: Petr Menšík <pemensik@redhat.com> +--- + COPYRIGHT | 17 +- + bin/named/Makefile.in | 3 +- + bin/named/main.c | 1 + + bin/named/server.c | 68 ++- + bin/tests/Makefile.in | 2 - + bin/tests/system/Makefile.in | 2 +- + bin/tests/system/checkconf/good.conf | 9 + + bin/tests/system/conf.sh.in | 4 +- + bin/tests/system/dlzexternal/tests.sh | 2 - + bin/tests/system/dyndb/Makefile.in | 26 + + bin/tests/system/dyndb/clean.sh | 25 + + bin/tests/system/dyndb/driver/.gitignore | 1 + + bin/tests/system/dyndb/driver/AUTHORS | 8 + + bin/tests/system/dyndb/driver/COPYING | 15 + + bin/tests/system/dyndb/driver/Makefile.in | 60 +++ + bin/tests/system/dyndb/driver/README | 65 +++ + bin/tests/system/dyndb/driver/db.c | 848 ++++++++++++++++++++++++++++++ + bin/tests/system/dyndb/driver/db.h | 15 + + bin/tests/system/dyndb/driver/driver.c | 143 +++++ + bin/tests/system/dyndb/driver/instance.c | 161 ++++++ + bin/tests/system/dyndb/driver/instance.h | 47 ++ + bin/tests/system/dyndb/driver/lock.c | 56 ++ + bin/tests/system/dyndb/driver/lock.h | 17 + + bin/tests/system/dyndb/driver/log.c | 21 + + bin/tests/system/dyndb/driver/log.h | 27 + + bin/tests/system/dyndb/driver/syncptr.c | 265 ++++++++++ + bin/tests/system/dyndb/driver/syncptr.h | 15 + + bin/tests/system/dyndb/driver/util.h | 57 ++ + bin/tests/system/dyndb/driver/zone.c | 192 +++++++ + bin/tests/system/dyndb/driver/zone.h | 15 + + bin/tests/system/dyndb/ns1/named.conf | 42 ++ + bin/tests/system/dyndb/prereq.sh | 21 + + bin/tests/system/dyndb/tests.sh | 155 ++++++ + configure | 7 +- + configure.in | 3 + + doc/arm/Bv9ARM-book.xml | 2 + + doc/arm/dyndb.xml | 105 ++++ + lib/dns/Makefile.in | 8 +- + lib/dns/dlz.c | 64 +-- + lib/dns/dyndb.c | 486 +++++++++++++++++ + lib/dns/include/dns/Makefile.in | 4 +- + lib/dns/include/dns/dyndb.h | 166 ++++++ + lib/dns/include/dns/log.h | 1 + + lib/dns/include/dns/types.h | 1 + + lib/dns/lib.c | 4 +- + lib/dns/log.c | 1 + + lib/dns/win32/libdns.def | 4 + + lib/export/isc/Makefile.in | 6 +- + lib/isc/Makefile.in | 8 +- + lib/isc/commandline.c | 60 +++ + lib/isc/hash.c | 28 +- + lib/isc/include/isc/Makefile.in | 4 +- + lib/isc/include/isc/commandline.h | 18 +- + lib/isc/include/isc/errno.h | 25 + + lib/isc/include/isc/hash.h | 4 +- + lib/isc/include/isc/lex.h | 21 +- + lib/isc/lex.c | 110 +++- + lib/isc/tests/Makefile.in | 11 +- + lib/isc/tests/errno_test.c | 102 ++++ + lib/isc/unix/Makefile.in | 8 +- + lib/isc/unix/errno.c | 21 + + lib/isc/unix/errno2result.c | 14 +- + lib/isc/unix/errno2result.h | 7 +- + lib/isc/win32/Makefile.in | 8 +- + lib/isc/win32/errno.c | 18 + + lib/isc/win32/errno2result.c | 14 +- + lib/isc/win32/errno2result.h | 5 +- + lib/isc/win32/libisc.def | 2 + + lib/isc/win32/libisc.dsp | 8 + + lib/isc/win32/libisc.mak | 23 + + lib/isc/win32/socket.c | 4 +- + lib/isccfg/include/isccfg/grammar.h | 1 + + lib/isccfg/namedconf.c | 18 + + lib/isccfg/parser.c | 46 ++ + 74 files changed, 3703 insertions(+), 152 deletions(-) + create mode 100644 bin/tests/system/dyndb/Makefile.in + create mode 100644 bin/tests/system/dyndb/clean.sh + create mode 100644 bin/tests/system/dyndb/driver/.gitignore + create mode 100644 bin/tests/system/dyndb/driver/AUTHORS + create mode 100644 bin/tests/system/dyndb/driver/COPYING + create mode 100644 bin/tests/system/dyndb/driver/Makefile.in + create mode 100644 bin/tests/system/dyndb/driver/README + create mode 100644 bin/tests/system/dyndb/driver/db.c + create mode 100644 bin/tests/system/dyndb/driver/db.h + create mode 100644 bin/tests/system/dyndb/driver/driver.c + create mode 100644 bin/tests/system/dyndb/driver/instance.c + create mode 100644 bin/tests/system/dyndb/driver/instance.h + create mode 100644 bin/tests/system/dyndb/driver/lock.c + create mode 100644 bin/tests/system/dyndb/driver/lock.h + create mode 100644 bin/tests/system/dyndb/driver/log.c + create mode 100644 bin/tests/system/dyndb/driver/log.h + create mode 100644 bin/tests/system/dyndb/driver/syncptr.c + create mode 100644 bin/tests/system/dyndb/driver/syncptr.h + create mode 100644 bin/tests/system/dyndb/driver/util.h + create mode 100644 bin/tests/system/dyndb/driver/zone.c + create mode 100644 bin/tests/system/dyndb/driver/zone.h + create mode 100644 bin/tests/system/dyndb/ns1/named.conf + create mode 100644 bin/tests/system/dyndb/prereq.sh + create mode 100644 bin/tests/system/dyndb/tests.sh + create mode 100644 doc/arm/dyndb.xml + create mode 100644 lib/dns/dyndb.c + create mode 100644 lib/dns/include/dns/dyndb.h + create mode 100644 lib/isc/include/isc/errno.h + create mode 100644 lib/isc/tests/errno_test.c + create mode 100644 lib/isc/unix/errno.c + create mode 100644 lib/isc/win32/errno.c + +diff --git a/COPYRIGHT b/COPYRIGHT +index 525c222..137db13 100644 +--- a/COPYRIGHT ++++ b/COPYRIGHT +@@ -161,7 +161,7 @@ POSSIBILITY OF SUCH DAMAGE. + + ----------------------------------------------------------------------------- + +-Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan ++Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan + (Royal Institute of Technology, Stockholm, Sweden). + All rights reserved. + +@@ -516,3 +516,18 @@ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + OF THE POSSIBILITY OF SUCH DAMAGE. + ++----------------------------------------------------------------------------- ++ ++Copyright (C) 2008-2011 Red Hat, Inc. ++ ++Permission to use, copy, modify, and/or distribute this software for any ++purpose with or without fee is hereby granted, provided that the above ++copyright notice and this permission notice appear in all copies. ++ ++THE SOFTWARE IS PROVIDED "AS IS" AND Red Hat DISCLAIMS ALL WARRANTIES WITH ++REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++AND FITNESS. IN NO EVENT SHALL Red Hat BE LIABLE FOR ANY SPECIAL, DIRECT, ++INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++PERFORMANCE OF THIS SOFTWARE. +diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in +index cd65777..8ec9ad7 100644 +--- a/bin/named/Makefile.in ++++ b/bin/named/Makefile.in +@@ -13,8 +13,6 @@ + # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + # PERFORMANCE OF THIS SOFTWARE. + +-# $Id: Makefile.in,v 1.116 2011/03/10 23:47:49 tbox Exp $ +- + srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ +@@ -138,6 +136,7 @@ config.@O@: config.c bind.keys.h + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} \ + -DVERSION=\"${VERSION}\" \ + -DSRCID=\"${SRCID}\" \ ++ -DDYNDB_LIBDIR=\"@libdir@/bind\" \ + -DNS_LOCALSTATEDIR=\"${localstatedir}\" \ + -DNS_SYSCONFDIR=\"${sysconfdir}\" \ + -c ${srcdir}/config.c +diff --git a/bin/named/main.c b/bin/named/main.c +index 6e12847..d26783f 100644 +--- a/bin/named/main.c ++++ b/bin/named/main.c +@@ -45,6 +45,7 @@ + #include <isccc/result.h> + + #include <dns/dispatch.h> ++#include <dns/dyndb.h> + #include <dns/name.h> + #include <dns/result.h> + #include <dns/view.h> +diff --git a/bin/named/server.c b/bin/named/server.c +index daa5b0e..6260f8f 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -30,6 +30,7 @@ + + #include <isc/app.h> + #include <isc/base64.h> ++#include <isc/commandline.h> + #include <isc/dir.h> + #include <isc/entropy.h> + #include <isc/file.h> +@@ -64,6 +65,7 @@ + #include <dns/dispatch.h> + #include <dns/dlz.h> + #include <dns/dns64.h> ++#include <dns/dyndb.h> + #include <dns/forward.h> + #include <dns/journal.h> + #include <dns/keytable.h> +@@ -1243,6 +1245,33 @@ configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) { + } + + static isc_result_t ++configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, ++ const dns_dyndbctx_t *dctx) ++{ ++ isc_result_t result = ISC_R_SUCCESS; ++ const cfg_obj_t *obj; ++ const char *name, *library; ++ ++ /* Get the name of the dyndb instance and the library path . */ ++ name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name")); ++ library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library")); ++ ++ obj = cfg_tuple_get(dyndb, "parameters"); ++ if (obj != NULL) ++ result = dns_dyndb_load(library, name, cfg_obj_asstring(obj), ++ cfg_obj_file(obj), cfg_obj_line(obj), ++ mctx, dctx); ++ ++ if (result != ISC_R_SUCCESS) ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_ERROR, ++ "dynamic database '%s' configuration failed: %s", ++ name, isc_result_totext(result)); ++ return (result); ++} ++ ++ ++static isc_result_t + disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) { + isc_result_t result; + const cfg_obj_t *algorithms; +@@ -2058,6 +2087,7 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + const cfg_obj_t *dlz; + unsigned int dlzargc; + char **dlzargv; ++ const cfg_obj_t *dyndb_list; + const cfg_obj_t *disabled; + const cfg_obj_t *obj; + const cfg_listelt_t *element; +@@ -2097,6 +2127,7 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + unsigned int query_timeout, ndisp; + struct cfg_context *nzctx; + dns_rpz_zone_t *rpz; ++ dns_dyndbctx_t *dctx = NULL; + + REQUIRE(DNS_VIEW_VALID(view)); + +@@ -2317,7 +2348,8 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + goto cleanup; + } + +- result = dns_dlzstrtoargv(mctx, s, &dlzargc, &dlzargv); ++ result = isc_commandline_strtoargv(mctx, s, &dlzargc, ++ &dlzargv, 0); + if (result != ISC_R_SUCCESS) { + isc_mem_free(mctx, s); + goto cleanup; +@@ -3261,6 +3293,31 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + dns_view_setrootdelonly(view, ISC_FALSE); + + /* ++ * Load DynDB modules. ++ */ ++ dyndb_list = NULL; ++ if (voptions != NULL) ++ (void)cfg_map_get(voptions, "dyndb", &dyndb_list); ++ else ++ (void)cfg_map_get(config, "dyndb", &dyndb_list); ++ ++ for (element = cfg_list_first(dyndb_list); ++ element != NULL; ++ element = cfg_list_next(element)) ++ { ++ const cfg_obj_t *dyndb = cfg_listelt_value(element); ++ ++ if (dctx == NULL) ++ CHECK(dns_dyndb_createctx(mctx, isc_hashctx, ++ ns_g_lctx, view, ++ ns_g_server->zonemgr, ++ ns_g_server->task, ++ ns_g_timermgr, &dctx)); ++ ++ CHECK(configure_dyndb(dyndb, mctx, dctx)); ++ } ++ ++ /* + * Setup automatic empty zones. If recursion is off then + * they are disabled by default. + */ +@@ -3445,6 +3502,8 @@ configure_view(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig, + + if (cache != NULL) + dns_cache_detach(&cache); ++ if (dctx != NULL) ++ dns_dyndb_destroyctx(&dctx); + + return (result); + } +@@ -4915,6 +4974,11 @@ load_configuration(const char *filename, ns_server_t *server, + CHECK(cfg_aclconfctx_create(ns_g_mctx, &ns_g_aclconfctx)); + + /* ++ * Shut down all dyndb instances. ++ */ ++ dns_dyndb_cleanup(ISC_FALSE); ++ ++ /* + * Parse the global default pseudo-config file. + */ + if (first_time) { +@@ -6043,6 +6107,8 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { + dns_view_detach(&view); + } + ++ dns_dyndb_cleanup(ISC_TRUE); ++ + while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { + ISC_LIST_UNLINK(server->cachelist, nsc, link); + dns_cache_detach(&nsc->cache); +diff --git a/bin/tests/Makefile.in b/bin/tests/Makefile.in +index 2020bf4..8477ae5 100644 +--- a/bin/tests/Makefile.in ++++ b/bin/tests/Makefile.in +@@ -13,8 +13,6 @@ + # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + # PERFORMANCE OF THIS SOFTWARE. + +-# $Id: Makefile.in,v 1.145 2011/02/03 05:41:53 marka Exp $ +- + srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ +diff --git a/bin/tests/system/Makefile.in b/bin/tests/system/Makefile.in +index f7bcc26..af8b82c 100644 +--- a/bin/tests/system/Makefile.in ++++ b/bin/tests/system/Makefile.in +@@ -21,7 +21,7 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-SUBDIRS = dlzexternal filter-aaaa lwresd rpz rrl \ ++SUBDIRS = dlzexternal dyndb filter-aaaa lwresd rpz rrl \ + rsabigexponent tkey tsiggss + TARGETS = + +diff --git a/bin/tests/system/checkconf/good.conf b/bin/tests/system/checkconf/good.conf +index 5444fdd..a6310cd 100644 +--- a/bin/tests/system/checkconf/good.conf ++++ b/bin/tests/system/checkconf/good.conf +@@ -104,3 +104,12 @@ view "second" { + dnssec-validation auto; + zone-statistics full; + }; ++dyndb "name" "library.so" { ++ this; ++ \}; ++ is a { ++ "test" { \{ of; the; }; ++ } bracketed; ++ "text \""; ++ system; ++}; +diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in +index c40e8f1..eb02236 100644 +--- a/bin/tests/system/conf.sh.in ++++ b/bin/tests/system/conf.sh.in +@@ -60,8 +60,8 @@ SAMPLE=$TOP/lib/export/samples/sample + # v6synth + SUBDIRS="acl additional allow_query addzone autosign builtin + cacheclean checkconf @CHECKDS@ checknames checkzone @COVERAGE@ +- database dlv dlvauto dlz dlzexternal dname dns64 dnssec ecdsa +- formerr forward glue gost ixfr inline limits logfileconfig ++ database dlv dlvauto dlz dlzexternal dname dns64 dnssec dyndb ++ ecdsa formerr forward glue gost ixfr inline limits logfileconfig + lwresd masterfile masterformat metadata notify nsupdate pending + @PKCS11_TEST@ redirect resolver rndc rpz rrl rrsetorder rsabigexponent + smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown +diff --git a/bin/tests/system/dlzexternal/tests.sh b/bin/tests/system/dlzexternal/tests.sh +index bd2eeac..103d4c9 100644 +--- a/bin/tests/system/dlzexternal/tests.sh ++++ b/bin/tests/system/dlzexternal/tests.sh +@@ -1,6 +1,4 @@ + #!/bin/sh +-# tests for TSIG-GSS updates +- + SYSTEMTESTTOP=.. + . $SYSTEMTESTTOP/conf.sh + +diff --git a/bin/tests/system/dyndb/Makefile.in b/bin/tests/system/dyndb/Makefile.in +new file mode 100644 +index 0000000..c7792f2 +--- /dev/null ++++ b/bin/tests/system/dyndb/Makefile.in +@@ -0,0 +1,26 @@ ++# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_VERSION@ ++ ++@BIND9_MAKE_INCLUDES@ ++ ++SUBDIRS = driver ++TARGETS = ++ ++@BIND9_MAKE_RULES@ +diff --git a/bin/tests/system/dyndb/clean.sh b/bin/tests/system/dyndb/clean.sh +new file mode 100644 +index 0000000..2273396 +--- /dev/null ++++ b/bin/tests/system/dyndb/clean.sh +@@ -0,0 +1,25 @@ ++#!/bin/sh ++# ++# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# ++# Clean up after dyndb tests. ++# ++rm -f ns1/named.memstats ++rm -f ns1/update.txt ++rm -f added.a.out.* ++rm -f added.ptr.out.* ++rm -f deleted.a.out.* ++rm -f deleted.ptr.out.* +diff --git a/bin/tests/system/dyndb/driver/.gitignore b/bin/tests/system/dyndb/driver/.gitignore +new file mode 100644 +index 0000000..c3af857 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/.gitignore +@@ -0,0 +1 @@ ++lib/ +diff --git a/bin/tests/system/dyndb/driver/AUTHORS b/bin/tests/system/dyndb/driver/AUTHORS +new file mode 100644 +index 0000000..acc109c +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/AUTHORS +@@ -0,0 +1,8 @@ ++This sample driver is based on bind-dyndb-ldap project and small portions ++of code from ISC BIND 9.10. ++ ++Authors listed in alphabetical order: ++Adam Tkac <atkac@redhat.com> ++Jiri Kuncar <jkuncar@redhat.com> ++Martin Nagy <mnagy@redhat.com> ++Petr Spacek <pspacek@redhat.com> +diff --git a/bin/tests/system/dyndb/driver/COPYING b/bin/tests/system/dyndb/driver/COPYING +new file mode 100644 +index 0000000..08d4d77 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/COPYING +@@ -0,0 +1,15 @@ ++Copyright (C) 2009-2015 Red Hat ++Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC") ++Copyright (C) 1999-2003 Internet Software Consortium. ++ ++Permission to use, copy, modify, and/or distribute this software for any ++purpose with or without fee is hereby granted, provided that the above ++copyright notice and this permission notice appear in all copies. ++ ++THE SOFTWARE IS PROVIDED "AS IS" AND AUTHORS DISCLAIMS ALL WARRANTIES WITH ++REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++PERFORMANCE OF THIS SOFTWARE. +diff --git a/bin/tests/system/dyndb/driver/Makefile.in b/bin/tests/system/dyndb/driver/Makefile.in +new file mode 100644 +index 0000000..e23c563 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/Makefile.in +@@ -0,0 +1,60 @@ ++# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_MAKE_INCLUDES@ ++ ++CINCLUDES = ${DNS_INCLUDES} ${ISC_INCLUDES} ++ ++CDEFINES = ++CWARNINGS = ++ ++DNSLIBS = ../../../../../lib/dns/libdns.@A@ ++ISCLIBS = ../../../../../lib/isc/libisc.@A@ ++ ++DNSDEPLIBS = ../../../../../lib/dns/libdns.@A@ ++ISCDEPLIBS = ../../../../../lib/isc/libisc.@A@ ++ ++DEPLIBS = ${DNSDEPLIBS} ${ISCDEPLIBS} ++ ++LIBS = ${DNSLIBS} ${ISCLIBS} @LIBS@ ++ ++ ++SRCS = db.c driver.c instance.c \ ++ lock.c log.c syncptr.c zone.c ++ ++OBJS = db.@O@ driver.@O@ instance.@O@ \ ++ lock.@O@ log.@O@ syncptr.@O@ zone.@O@ ++ ++SO_TARGETS = lib/sample.@SO@ ++TARGETS = @SO_TARGETS@ ++ ++@BIND9_MAKE_RULES@ ++ ++CFLAGS = @CFLAGS@ @SO_CFLAGS@ ++SO_LDFLAGS = @LDFLAGS@ ++ ++lib/sample.@SO@: sample.@SO@ ++ $(SHELL) ${top_srcdir}/mkinstalldirs `pwd`/lib ++ ${LIBTOOL_MODE_INSTALL} ${INSTALL} sample.@SO@ `pwd`/lib ++ ++sample.@SO@: ${OBJS} ${DNSDEPLIBS} ${ISCDEPLIBS} ++ ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ ${OBJS} \ ++ ${DNSLIBS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${LIBS} ++ ++clean distclean:: ++ rm -f ${OBJS} sample.so lib/sample.so +diff --git a/bin/tests/system/dyndb/driver/README b/bin/tests/system/dyndb/driver/README +new file mode 100644 +index 0000000..9aac0a6 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/README +@@ -0,0 +1,65 @@ ++To use the Dynamic DB sample driver, run named and check the log. ++ ++ $ cd testing ++ $ named -gc named.conf ++ ++You should be able to see something like: ++ ++zone test/IN: loaded serial 0 ++zone arpa/IN: loaded serial 0 ++ ++This means that the sample driver created empty zones "test." and ++"arpa." as defined by "arg" parameters in named.conf. ++ ++$ dig @localhost test. ++ ++should work as usual and you should be able to see the dummy zone with ++NS record pointing to the zone apex and A record with 127.0.0.1: ++ ++;; ANSWER SECTION: ++test. 86400 IN A 127.0.0.1 ++test. 86400 IN NS test. ++test. 86400 IN SOA test. test. 0 28800 7200 604800 86400 ++ ++This driver creates two empty zones and allows query/transfer/update to ++all IP addresses for demonstration purposes. ++ ++The driver wraps the RBT database implementation used natively by BIND, ++and modifies the addrdataset() and substractrdataset() functions to do ++additional work during dynamic updates. ++ ++A dynamic update modifies the target zone as usual. After that, the ++driver detects whether the modified RR was of type A or AAAA, and if so, ++attempts to appropriately generate or delete a matching PTR record in ++one of the two zones managed by the driver. ++ ++E.g.: ++ ++$ nsupdate ++> update add a.test. 300 IN A 192.0.2.1 ++> send ++ ++will add the A record ++a.test. 300 IN A 192.0.2.1 ++ ++and also automatically generate the PTR record ++1.2.0.192.in-addr.arpa. 300 IN PTR a.test. ++ ++AXFR and RR deletion via dynamic updates should work as usual. Deletion ++of a type A or AAAA record should delete the corresponding PTR record ++too. ++ ++The zone is stored only in memory, and all changes will be lost on ++reload/reconfig. ++ ++Hints for code readers: ++- Driver initialization starts in driver.c: dyndb_init() function. ++- New database implementation is registered by calling dns_db_register() ++ and passing a function pointer to it. This sample uses the function ++ create_db() to initialize the database. ++- Zones are created later in instance.c: load_sample_instance_zones(). ++- Database entry points are in structure db.c: dns_dbmethods_t ++ sampledb_methods ++- sampledb_methods points to an implementation of the database interface. ++ See the db.c: addrdataset() implementation and look at how the RBT ++ database instance is wrapped into an additional layer of logic. +diff --git a/bin/tests/system/dyndb/driver/db.c b/bin/tests/system/dyndb/driver/db.c +new file mode 100644 +index 0000000..d2ca023 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/db.c +@@ -0,0 +1,848 @@ ++/* ++ * Database API implementation. The interface is defined in lib/dns/db.h. ++ * ++ * dns_db_*() calls on database instances backed by this driver use ++ * struct sampledb_methods to find appropriate function implementation. ++ * ++ * This example re-uses RBT DB implementation from original BIND and blindly ++ * proxies most of dns_db_*() calls to this underlying RBT DB. ++ * See struct sampledb below. ++ * ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++#include <config.h> ++ ++#include <isc/string.h> ++ ++#include <dns/db.h> ++#include <dns/diff.h> ++#include <dns/enumclass.h> ++#include <dns/rbt.h> ++#include <dns/rdatalist.h> ++#include <dns/rdatastruct.h> ++#include <dns/soa.h> ++#include <dns/types.h> ++ ++#include "db.h" ++#include "instance.h" ++#include "syncptr.h" ++#include "util.h" ++ ++#define SAMPLEDB_MAGIC ISC_MAGIC('S', 'M', 'D', 'B') ++#define VALID_SAMPLEDB(sampledb) \ ++ ((sampledb) != NULL && (sampledb)->common.impmagic == SAMPLEDB_MAGIC) ++ ++struct sampledb { ++ dns_db_t common; ++ isc_refcount_t refs; ++ sample_instance_t *inst; ++ ++ /* ++ * Internal RBT database implementation provided by BIND. ++ * Most dns_db_* calls (find(), createiterator(), etc.) ++ * are blindly forwarded to this RBT DB. ++ */ ++ dns_db_t *rbtdb; ++}; ++ ++typedef struct sampledb sampledb_t; ++ ++/* ++ * Get full DNS name from the node. ++ * ++ * @warning ++ * The code silently expects that "node" came from RBTDB and thus ++ * assumption dns_dbnode_t (from RBTDB) == dns_rbtnode_t is correct. ++ * ++ * This should work as long as we use only RBTDB and nothing else. ++ */ ++static isc_result_t ++sample_name_fromnode(dns_dbnode_t *node, dns_name_t *name) { ++ dns_rbtnode_t *rbtnode = (dns_rbtnode_t *) node; ++ return (dns_rbt_fullnamefromnode(rbtnode, name)); ++} ++ ++static void ++attach(dns_db_t *source, dns_db_t **targetp) { ++ sampledb_t *sampledb = (sampledb_t *)source; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ isc_refcount_increment(&sampledb->refs, NULL); ++ *targetp = source; ++} ++ ++static void ++free_sampledb(sampledb_t *sampledb) { ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_detach(&sampledb->rbtdb); ++ dns_name_free(&sampledb->common.origin, sampledb->common.mctx); ++ isc_mem_putanddetach(&sampledb->common.mctx, sampledb, sizeof(*sampledb)); ++} ++ ++static void ++detach(dns_db_t **dbp) { ++ sampledb_t *sampledb = (sampledb_t *)(*dbp); ++ unsigned int refs; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ isc_refcount_decrement(&sampledb->refs, &refs); ++ if (refs == 0) ++ free_sampledb(sampledb); ++ *dbp = NULL; ++} ++ ++/* ++ * This method should never be called, because DB is "persistent". ++ * See ispersistent() function. It means that database do not need to be ++ * loaded in the usual sense. ++ */ ++static isc_result_t ++beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) { ++ UNUSED(db); ++ UNUSED(addp); ++ UNUSED(dbloadp); ++ ++ fatal_error("current implementation should never call beginload()"); ++ ++ /* Not reached */ ++ return (ISC_R_SUCCESS); ++} ++ ++/* ++ * This method should never be called, because DB is "persistent". ++ * See ispersistent() function. It means that database do not need to be ++ * loaded in the usual sense. ++ */ ++static isc_result_t ++endload(dns_db_t *db, dns_dbload_t **dbloadp) { ++ UNUSED(db); ++ UNUSED(dbloadp); ++ ++ fatal_error("current implementation should never call endload()"); ++ ++ /* Not reached */ ++ return (ISC_R_SUCCESS); ++} ++ ++#if 0 ++static isc_result_t ++serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_serialize(sampledb->rbtdb, version, file)); ++} ++#endif ++ ++static isc_result_t ++dump(dns_db_t *db, dns_dbversion_t *version, const char *filename, ++ dns_masterformat_t masterformat) ++{ ++ ++ UNUSED(db); ++ UNUSED(version); ++ UNUSED(filename); ++ UNUSED(masterformat); ++ ++ fatal_error("current implementation should never call dump()"); ++ ++ /* Not reached */ ++ return (ISC_R_SUCCESS); ++} ++ ++static void ++currentversion(dns_db_t *db, dns_dbversion_t **versionp) { ++ sampledb_t *sampledb = (sampledb_t *)db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_currentversion(sampledb->rbtdb, versionp); ++} ++ ++static isc_result_t ++newversion(dns_db_t *db, dns_dbversion_t **versionp) { ++ sampledb_t *sampledb = (sampledb_t *)db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_newversion(sampledb->rbtdb, versionp)); ++} ++ ++static void ++attachversion(dns_db_t *db, dns_dbversion_t *source, ++ dns_dbversion_t **targetp) ++{ ++ sampledb_t *sampledb = (sampledb_t *)db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_attachversion(sampledb->rbtdb, source, targetp); ++} ++ ++static void ++closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) { ++ sampledb_t *sampledb = (sampledb_t *)db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_closeversion(sampledb->rbtdb, versionp, commit); ++} ++ ++static isc_result_t ++findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, ++ dns_dbnode_t **nodep) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_findnode(sampledb->rbtdb, name, create, nodep)); ++} ++ ++static isc_result_t ++find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, ++ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, ++ dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset, ++ dns_rdataset_t *sigrdataset) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_find(sampledb->rbtdb, name, version, type, ++ options, now, nodep, foundname, ++ rdataset, sigrdataset)); ++} ++ ++static isc_result_t ++findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options, ++ isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname, ++ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_findzonecut(sampledb->rbtdb, name, options, ++ now, nodep, foundname, rdataset, ++ sigrdataset)); ++} ++ ++static void ++attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_attachnode(sampledb->rbtdb, source, targetp); ++ ++} ++ ++static void ++detachnode(dns_db_t *db, dns_dbnode_t **targetp) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_detachnode(sampledb->rbtdb, targetp); ++} ++ ++static isc_result_t ++expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_expirenode(sampledb->rbtdb, node, now)); ++} ++ ++static void ++printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_printnode(sampledb->rbtdb, node, out); ++} ++ ++static isc_result_t ++createiterator(dns_db_t *db, unsigned int options, ++ dns_dbiterator_t **iteratorp) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_createiterator(sampledb->rbtdb, options, iteratorp)); ++} ++ ++static isc_result_t ++findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, ++ dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now, ++ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_findrdataset(sampledb->rbtdb, node, version, type, ++ covers, now, rdataset, sigrdataset)); ++} ++ ++static isc_result_t ++allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, ++ isc_stdtime_t now, dns_rdatasetiter_t **iteratorp) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_allrdatasets(sampledb->rbtdb, node, version, ++ now, iteratorp)); ++} ++ ++static isc_result_t ++addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, ++ isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options, ++ dns_rdataset_t *addedrdataset) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ isc_result_t result; ++ dns_fixedname_t name; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_fixedname_init(&name); ++ CHECK(dns_db_addrdataset(sampledb->rbtdb, node, version, now, ++ rdataset, options, addedrdataset)); ++ if (rdataset->type == dns_rdatatype_a || ++ rdataset->type == dns_rdatatype_aaaa) { ++ CHECK(sample_name_fromnode(node, dns_fixedname_name(&name))); ++ CHECK(syncptrs(sampledb->inst, dns_fixedname_name(&name), ++ rdataset, DNS_DIFFOP_ADD)); ++ } ++ ++cleanup: ++ return (result); ++} ++ ++static isc_result_t ++subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, ++ dns_rdataset_t *rdataset, unsigned int options, ++ dns_rdataset_t *newrdataset) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ isc_result_t result; ++ dns_fixedname_t name; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_fixedname_init(&name); ++ result = dns_db_subtractrdataset(sampledb->rbtdb, node, version, ++ rdataset, options, newrdataset); ++ if (result != ISC_R_SUCCESS && result != DNS_R_NXRRSET) ++ goto cleanup; ++ ++ if (rdataset->type == dns_rdatatype_a || ++ rdataset->type == dns_rdatatype_aaaa) { ++ CHECK(sample_name_fromnode(node, dns_fixedname_name(&name))); ++ CHECK(syncptrs(sampledb->inst, dns_fixedname_name(&name), ++ rdataset, DNS_DIFFOP_DEL)); ++ } ++ ++cleanup: ++ return (result); ++} ++ ++/* ++ * deleterdataset() function is not used during DNS update processing so syncptr ++ * implementation is left as an exercise to the reader. ++ */ ++static isc_result_t ++deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, ++ dns_rdatatype_t type, dns_rdatatype_t covers) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_deleterdataset(sampledb->rbtdb, node, version, ++ type, covers)); ++} ++ ++static isc_boolean_t ++issecure(dns_db_t *db) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_issecure(sampledb->rbtdb)); ++} ++ ++static unsigned int ++nodecount(dns_db_t *db) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_nodecount(sampledb->rbtdb)); ++} ++ ++/* ++ * The database does not need to be loaded from disk or written to disk. ++ * Always return ISC_TRUE. ++ */ ++static isc_boolean_t ++ispersistent(dns_db_t *db) { ++ UNUSED(db); ++ ++ return (ISC_TRUE); ++} ++ ++static void ++overmem(dns_db_t *db, isc_boolean_t over) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_overmem(sampledb->rbtdb, over); ++} ++ ++static void ++settask(dns_db_t *db, isc_task_t *task) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_settask(sampledb->rbtdb, task); ++} ++ ++static isc_result_t ++getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_getoriginnode(sampledb->rbtdb, nodep)); ++} ++ ++static void ++transfernode(dns_db_t *db, dns_dbnode_t **sourcep, dns_dbnode_t **targetp) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_transfernode(sampledb->rbtdb, sourcep, targetp); ++ ++} ++ ++static isc_result_t ++getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, ++ dns_hash_t *hash, isc_uint8_t *flags, ++ isc_uint16_t *iterations, ++ unsigned char *salt, size_t *salt_length) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_getnsec3parameters(sampledb->rbtdb, version, ++ hash, flags, iterations, ++ salt, salt_length)); ++ ++} ++ ++static isc_result_t ++findnsec3node(dns_db_t *db, dns_name_t *name, isc_boolean_t create, ++ dns_dbnode_t **nodep) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_findnsec3node(sampledb->rbtdb, name, create, nodep)); ++} ++ ++static isc_result_t ++setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_setsigningtime(sampledb->rbtdb, rdataset, resign)); ++} ++ ++static isc_result_t ++getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_getsigningtime(sampledb->rbtdb, rdataset, name)); ++} ++ ++static void ++resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_resigned(sampledb->rbtdb, rdataset, version); ++} ++ ++static isc_boolean_t ++isdnssec(dns_db_t *db) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_isdnssec(sampledb->rbtdb)); ++} ++ ++static dns_stats_t * ++getrrsetstats(dns_db_t *db) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_getrrsetstats(sampledb->rbtdb)); ++ ++} ++ ++static isc_result_t ++rpz_enabled(dns_db_t *db, dns_rpz_st_t *st) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return dns_db_rpz_enabled(sampledb->rbtdb, st); ++} ++ ++static void ++rpz_findips(dns_rpz_zone_t *rpz, dns_rpz_type_t rpz_type, ++ dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, ++ dns_rdataset_t *ardataset, dns_rpz_st_t *st, ++ dns_name_t *query_qname) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_rpz_findips(rpz, rpz_type, zone, db, version, ardataset, st, query_qname); ++} ++ ++#if 0 ++static void ++rpz_attach(dns_db_t *db, dns_rpz_zones_t *rpzs, dns_rpz_num_t rpz_num) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ dns_db_rpz_attach(sampledb->rbtdb, rpzs, rpz_num); ++} ++ ++static isc_result_t ++rpz_ready(dns_db_t *db) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_rpz_ready(sampledb->rbtdb)); ++} ++#endif ++ ++static isc_result_t ++findnodeext(dns_db_t *db, dns_name_t *name, ++ isc_boolean_t create, dns_clientinfomethods_t *methods, ++ dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_findnodeext(sampledb->rbtdb, name, create, ++ methods, clientinfo, nodep)); ++} ++ ++static isc_result_t ++findext(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version, ++ dns_rdatatype_t type, unsigned int options, isc_stdtime_t now, ++ dns_dbnode_t **nodep, dns_name_t *foundname, ++ dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo, ++ dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) ++{ ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_findext(sampledb->rbtdb, name, version, type, ++ options, now, nodep, foundname, methods, ++ clientinfo, rdataset, sigrdataset)); ++} ++ ++#if 0 ++static isc_result_t ++setcachestats(dns_db_t *db, isc_stats_t *stats) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_setcachestats(sampledb->rbtdb, stats)); ++} ++ ++static unsigned int ++hashsize(dns_db_t *db) { ++ sampledb_t *sampledb = (sampledb_t *) db; ++ ++ REQUIRE(VALID_SAMPLEDB(sampledb)); ++ ++ return (dns_db_hashsize(sampledb->rbtdb)); ++} ++#endif ++ ++/* ++ * DB interface definition. Database driver uses this structure to ++ * determine which implementation of dns_db_*() function to call. ++ */ ++static dns_dbmethods_t sampledb_methods = { ++ attach, ++ detach, ++ beginload, ++ endload, ++// serialize, ++ dump, ++ currentversion, ++ newversion, ++ attachversion, ++ closeversion, ++ findnode, ++ find, ++ findzonecut, ++ attachnode, ++ detachnode, ++ expirenode, ++ printnode, ++ createiterator, ++ findrdataset, ++ allrdatasets, ++ addrdataset, ++ subtractrdataset, ++ deleterdataset, ++ issecure, ++ nodecount, ++ ispersistent, ++ overmem, ++ settask, ++ getoriginnode, ++ transfernode, ++ getnsec3parameters, ++ findnsec3node, ++ setsigningtime, ++ getsigningtime, ++ resigned, ++ isdnssec, ++ getrrsetstats, ++ rpz_enabled, ++ rpz_findips, ++ findnodeext, ++ findext, ++#if 0 ++ setcachestats, ++ hashsize ++#endif ++}; ++ ++/* Auxiliary driver functions. */ ++ ++/* ++ * Auxiliary functions add_*() create minimal database which can be loaded. ++ * This is necessary because this driver create empty 'fake' zone which ++ * is not loaded from disk so there is no way for user to supply SOA, NS and A ++ * records. ++ * ++ * Following functions were copied from BIND 9.10.2rc1 named/server.c, ++ * credit goes to ISC. ++ */ ++static isc_result_t ++add_soa(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, ++ dns_name_t *origin, dns_name_t *contact) ++{ ++ dns_dbnode_t *node = NULL; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ dns_rdatalist_t rdatalist; ++ dns_rdataset_t rdataset; ++ isc_result_t result; ++ unsigned char buf[DNS_SOA_BUFFERSIZE]; ++ ++ dns_rdataset_init(&rdataset); ++ dns_rdatalist_init(&rdatalist); ++ CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db), ++ 0, 28800, 7200, 604800, 86400, buf, &rdata)); ++ rdatalist.type = rdata.type; ++ rdatalist.covers = 0; ++ rdatalist.rdclass = rdata.rdclass; ++ rdatalist.ttl = 86400; ++ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); ++ CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); ++ CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); ++ CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); ++ cleanup: ++ if (node != NULL) ++ dns_db_detachnode(db, &node); ++ return (result); ++} ++ ++ ++static isc_result_t ++add_ns(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, ++ dns_name_t *nsname) ++{ ++ dns_dbnode_t *node = NULL; ++ dns_rdata_ns_t ns; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ dns_rdatalist_t rdatalist; ++ dns_rdataset_t rdataset; ++ isc_result_t result; ++ isc_buffer_t b; ++ unsigned char buf[DNS_NAME_MAXWIRE]; ++ ++ isc_buffer_init(&b, buf, sizeof(buf)); ++ ++ dns_rdataset_init(&rdataset); ++ dns_rdatalist_init(&rdatalist); ++ ns.common.rdtype = dns_rdatatype_ns; ++ ns.common.rdclass = dns_db_class(db); ++ ns.mctx = NULL; ++ dns_name_init(&ns.name, NULL); ++ dns_name_clone(nsname, &ns.name); ++ CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns, ++ &ns, &b)); ++ rdatalist.type = rdata.type; ++ rdatalist.covers = 0; ++ rdatalist.rdclass = rdata.rdclass; ++ rdatalist.ttl = 86400; ++ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); ++ CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); ++ CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); ++ CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); ++ cleanup: ++ if (node != NULL) ++ dns_db_detachnode(db, &node); ++ return (result); ++} ++ ++static isc_result_t ++add_a(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, ++ struct in_addr addr) ++{ ++ dns_dbnode_t *node = NULL; ++ dns_rdata_in_a_t a; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ dns_rdatalist_t rdatalist; ++ dns_rdataset_t rdataset; ++ isc_result_t result; ++ isc_buffer_t b; ++ unsigned char buf[DNS_NAME_MAXWIRE]; ++ ++ isc_buffer_init(&b, buf, sizeof(buf)); ++ ++ dns_rdataset_init(&rdataset); ++ dns_rdatalist_init(&rdatalist); ++ a.common.rdtype = dns_rdatatype_a; ++ a.common.rdclass = dns_db_class(db); ++ a.in_addr = addr; ++ CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_a, ++ &a, &b)); ++ rdatalist.type = rdata.type; ++ rdatalist.covers = 0; ++ rdatalist.rdclass = rdata.rdclass; ++ rdatalist.ttl = 86400; ++ ISC_LIST_APPEND(rdatalist.rdata, &rdata, link); ++ CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset)); ++ CHECK(dns_db_findnode(db, name, ISC_TRUE, &node)); ++ CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL)); ++ cleanup: ++ if (node != NULL) ++ dns_db_detachnode(db, &node); ++ return (result); ++} ++ ++/* ++ * Driver-specific implementation of dns_db_create(). ++ * ++ * @param[in] argv Database-specific parameters from dns_db_create(). ++ * @param[in] driverarg Driver-specific parameter from dns_db_register(). ++ */ ++isc_result_t ++create_db(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type, ++ dns_rdataclass_t rdclass, unsigned int argc, char *argv[], ++ void *driverarg, dns_db_t **dbp) ++{ ++ sampledb_t *sampledb = NULL; ++ isc_result_t result; ++ dns_dbversion_t *version = NULL; ++ struct in_addr a_addr; ++ ++ REQUIRE(type == dns_dbtype_zone); ++ REQUIRE(rdclass == dns_rdataclass_in); ++ REQUIRE(argc == 0); ++ REQUIRE(argv != NULL); ++ REQUIRE(driverarg != NULL); /* pointer to driver instance */ ++ REQUIRE(dbp != NULL && *dbp == NULL); ++ ++ UNUSED(driverarg); /* no driver-specific configuration */ ++ ++ a_addr.s_addr = 0x0100007fU; ++ ++ CHECKED_MEM_GET_PTR(mctx, sampledb); ++ ZERO_PTR(sampledb); ++ ++ isc_mem_attach(mctx, &sampledb->common.mctx); ++ dns_name_init(&sampledb->common.origin, NULL); ++ isc_ondestroy_init(&sampledb->common.ondest); ++ ++ sampledb->common.magic = DNS_DB_MAGIC; ++ sampledb->common.impmagic = SAMPLEDB_MAGIC; ++ ++ sampledb->common.methods = &sampledb_methods; ++ sampledb->common.attributes = 0; ++ sampledb->common.rdclass = rdclass; ++ ++ CHECK(dns_name_dupwithoffsets(origin, mctx, &sampledb->common.origin)); ++ ++ CHECK(isc_refcount_init(&sampledb->refs, 1)); ++ ++ /* Translate instance name to instance pointer. */ ++ sampledb->inst = driverarg; ++ ++ /* Create internal instance of RBT DB implementation from BIND. */ ++ CHECK(dns_db_create(mctx, "rbt", origin, dns_dbtype_zone, ++ dns_rdataclass_in, 0, NULL, &sampledb->rbtdb)); ++ ++ /* Create fake SOA, NS, and A records to make database loadable. */ ++ CHECK(dns_db_newversion(sampledb->rbtdb, &version)); ++ CHECK(add_soa(sampledb->rbtdb, version, origin, origin, origin)); ++ CHECK(add_ns(sampledb->rbtdb, version, origin, origin)); ++ CHECK(add_a(sampledb->rbtdb, version, origin, a_addr)); ++ dns_db_closeversion(sampledb->rbtdb, &version, ISC_TRUE); ++ ++ *dbp = (dns_db_t *)sampledb; ++ ++ return (ISC_R_SUCCESS); ++ ++cleanup: ++ if (sampledb != NULL) { ++ if (dns_name_dynamic(&sampledb->common.origin)) ++ dns_name_free(&sampledb->common.origin, mctx); ++ ++ isc_mem_putanddetach(&sampledb->common.mctx, sampledb, ++ sizeof(*sampledb)); ++ } ++ ++ return (result); ++} +diff --git a/bin/tests/system/dyndb/driver/db.h b/bin/tests/system/dyndb/driver/db.h +new file mode 100644 +index 0000000..80693a7 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/db.h +@@ -0,0 +1,15 @@ ++/** ++ * Database API implementation. ++ * ++ * Copyright (C) 2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef DB_H_ ++#define DB_H_ ++ ++isc_result_t ++create_db(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type, ++ dns_rdataclass_t rdclass, unsigned int argc, char *argv[], ++ void *driverarg, dns_db_t **dbp); ++ ++#endif /* DB_H_ */ +diff --git a/bin/tests/system/dyndb/driver/driver.c b/bin/tests/system/dyndb/driver/driver.c +new file mode 100644 +index 0000000..11e6743 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/driver.c +@@ -0,0 +1,143 @@ ++/* ++ * Driver API implementation and main entry point for BIND. ++ * ++ * BIND calls dyndb_version() before loading, dyndb_init() during startup ++ * and dyndb_destroy() during shutdown. ++ * ++ * It is completely up to implementation what to do. ++ * ++ * dyndb <name> <driver> {} sections in named.conf are independent so ++ * driver init() and destroy() functions are called independently for ++ * each section even if they reference the same driver/library. It is ++ * up to driver implementation to detect and catch this situation if ++ * it is undesirable. ++ * ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#include <config.h> ++ ++#include <isc/commandline.h> ++#include <isc/hash.h> ++#include <isc/mem.h> ++#include <isc/lib.h> ++#include <isc/util.h> ++#include <isc/log.h> ++ ++#include <dns/db.h> ++#include <dns/dyndb.h> ++#include <dns/lib.h> ++#include <dns/types.h> ++ ++#include "db.h" ++#include "log.h" ++#include "instance.h" ++#include "util.h" ++ ++dns_dyndb_destroy_t dyndb_destroy; ++dns_dyndb_register_t dyndb_init; ++dns_dyndb_version_t dyndb_version; ++ ++/* ++ * Driver init is called for each dyndb section in named.conf ++ * once during startup and then again on every reload. ++ * ++ * @code ++ * dyndb example-name "sample.so" { param1 param2 }; ++ * @endcode ++ * ++ * @param[in] name User-defined string from dyndb "name" {}; definition ++ * in named.conf. ++ * The example above will have name = "example-name". ++ * @param[in] parameters User-defined parameters from dyndb section as one ++ * string. The example above will have ++ * params = "param1 param2"; ++ * @param[in] file The name of the file from which the parameters ++ * were read. ++ * @param[in] line The line number from which the parameters were read. ++ * @param[out] instp Pointer to instance-specific data ++ * (for one dyndb section). ++ */ ++isc_result_t ++dyndb_init(isc_mem_t *mctx, const char *name, const char *parameters, ++ const char *file, unsigned long line, ++ const dns_dyndbctx_t *dctx, void **instp) ++{ ++ isc_result_t result; ++ unsigned int argc; ++ char **argv = NULL; ++ char *s = NULL; ++ sample_instance_t *sample_inst = NULL; ++ ++ REQUIRE(name != NULL); ++ REQUIRE(dctx != NULL); ++ ++ /* ++ * Depending on how dlopen() was called, we may not have ++ * access to named's global namespace, in which case we need ++ * to initialize libisc/libdns ++ */ ++ if (dctx->refvar != &isc_lctx) { ++ isc_log_setcontext(dctx->lctx); ++ dns_log_setcontext(dctx->lctx); ++ } ++ ++ if (isc_hashctx != NULL && isc_hashctx != dctx->hctx) ++ isc_hash_ctxdetach(&isc_hashctx); ++ isc_hashctx = dctx->hctx; ++ ++ s = isc_mem_strdup(mctx, parameters); ++ if (s == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto cleanup; ++ } ++ ++ result = isc_commandline_strtoargv(mctx, s, &argc, &argv, 0); ++ if (result != ISC_R_SUCCESS) ++ goto cleanup; ++ ++ log_write(ISC_LOG_DEBUG(9), ++ "loading params for dyndb '%s' from %s:%lu", ++ name, file, line); ++ ++ /* Finally, create the instance. */ ++ CHECK(new_sample_instance(mctx, name, argc, argv, dctx, &sample_inst)); ++ ++ /* ++ * This is an example so we create and load zones ++ * right now. This step can be arbitrarily postponed. ++ */ ++ CHECK(load_sample_instance_zones(sample_inst)); ++ ++ *instp = sample_inst; ++ ++ cleanup: ++ if (s != NULL) ++ isc_mem_free(mctx, s); ++ if (argv != NULL) ++ isc_mem_put(mctx, argv, argc * sizeof(*argv)); ++ ++ return (result); ++} ++ ++/* ++ * Driver destroy is called for every instance on every reload and then once ++ * during shutdown. ++ * ++ * @param[out] instp Pointer to instance-specific data (for one dyndb section). ++ */ ++void ++dyndb_destroy(void **instp) { ++ destroy_sample_instance((sample_instance_t **)instp); ++} ++ ++/* ++ * Driver version is called when loading the driver to ensure there ++ * is no API mismatch betwen the driver and the caller. ++ */ ++int ++dyndb_version(unsigned int *flags) { ++ UNUSED(flags); ++ ++ return (DNS_DYNDB_VERSION); ++} +diff --git a/bin/tests/system/dyndb/driver/instance.c b/bin/tests/system/dyndb/driver/instance.c +new file mode 100644 +index 0000000..f2207b9 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/instance.c +@@ -0,0 +1,161 @@ ++/* ++ * Driver instance object. ++ * ++ * One instance is equivalent to dynamic-db section in named.conf. ++ * This module parses arguments and provide high-level operations ++ * instance init/zone load/instance destroy. ++ * ++ * Copyright (C) 2008-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#include <config.h> ++ ++#include <isc/task.h> ++#include <isc/util.h> ++ ++#include <dns/db.h> ++#include <dns/dyndb.h> ++#include <dns/fixedname.h> ++#include <dns/name.h> ++#include <dns/view.h> ++#include <dns/zone.h> ++ ++#include "db.h" ++#include "util.h" ++#include "instance.h" ++#include "log.h" ++#include "zone.h" ++ ++/* ++ * Parse parameters and convert them to zone names. Caller has to deallocate ++ * resulting DNS names. ++ * ++ * @param[in] argv NULL-terminated string array of length 2 (excluding NULL) ++ * Each string has to be a valid DNS name. ++ * @param[out] z1 Zone name from argv[0] ++ * @param[out] z2 Zone name from argv[1] ++ */ ++static isc_result_t ++parse_params(isc_mem_t *mctx, int argc, char **argv, ++ dns_name_t *z1, dns_name_t *z2) ++{ ++ isc_result_t result; ++ int i; ++ ++ REQUIRE(argv != NULL); ++ REQUIRE(z1 != NULL); ++ REQUIRE(z2 != NULL); ++ ++ for (i = 0; i < argc; i++) { ++ log_info("param: '%s'", argv[i]); ++ } ++ log_info("number of params: %d", i); ++ ++ if (argc != 2) { ++ log_error("exactly two parameters " ++ "(absolute zone names) are required"); ++ result = ISC_R_FAILURE; ++ goto cleanup; ++ } ++ CHECK(dns_name_fromstring2(z1, argv[0], dns_rootname, 0, mctx)); ++ CHECK(dns_name_fromstring2(z2, argv[1], dns_rootname, 0, mctx)); ++ ++ result = ISC_R_SUCCESS; ++ ++cleanup: ++ return (result); ++} ++ ++/* ++ * Initialize new driver instance. It will not create zones until ++ * load_sample_instance_zones() is called. ++ */ ++isc_result_t ++new_sample_instance(isc_mem_t *mctx, const char *db_name, ++ int argc, char **argv, const dns_dyndbctx_t *dctx, ++ sample_instance_t **sample_instp) ++{ ++ isc_result_t result; ++ sample_instance_t *inst = NULL; ++ ++ REQUIRE(sample_instp != NULL && *sample_instp == NULL); ++ ++ CHECKED_MEM_GET_PTR(mctx, inst); ++ ZERO_PTR(inst); ++ isc_mem_attach(mctx, &inst->mctx); ++ ++ inst->db_name = isc_mem_strdup(mctx, db_name); ++ if (inst->db_name == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto cleanup; ++ } ++ ++ dns_fixedname_init(&inst->zone1_fn); ++ inst->zone1_name = dns_fixedname_name(&inst->zone1_fn); ++ ++ dns_fixedname_init(&inst->zone2_fn); ++ inst->zone2_name = dns_fixedname_name(&inst->zone2_fn); ++ ++ CHECK(parse_params(mctx, argc, argv, ++ inst->zone1_name, inst->zone2_name)); ++ ++ dns_view_attach(dctx->view, &inst->view); ++ dns_zonemgr_attach(dctx->zmgr, &inst->zmgr); ++ isc_task_attach(dctx->task, &inst->task); ++ ++ /* Register new DNS DB implementation. */ ++ CHECK(dns_db_register(db_name, create_db, inst, mctx, &inst->db_imp)); ++ ++ *sample_instp = inst; ++ result = ISC_R_SUCCESS; ++ ++cleanup: ++ if (result != ISC_R_SUCCESS) ++ destroy_sample_instance(&inst); ++ return (result); ++} ++ ++/* ++ * Create empty zones, add fake SOA, NS, and A records, load fake zones ++ * and add them to inst->view. ++ */ ++isc_result_t ++load_sample_instance_zones(sample_instance_t *inst) { ++ isc_result_t result; ++ ++ CHECK(create_zone(inst, inst->zone1_name, &inst->zone1)); ++ CHECK(activate_zone(inst, inst->zone1)); ++ ++ CHECK(create_zone(inst, inst->zone2_name, &inst->zone2)); ++ CHECK(activate_zone(inst, inst->zone2)); ++ ++cleanup: ++ return (result); ++} ++ ++void ++destroy_sample_instance(sample_instance_t **instp) { ++ sample_instance_t *inst; ++ REQUIRE(instp != NULL); ++ ++ inst = *instp; ++ if (inst == NULL) ++ return; ++ ++ if (inst->db_name != NULL) ++ isc_mem_free(inst->mctx, inst->db_name); ++ if (inst->zone1 != NULL) ++ dns_zone_detach(&inst->zone1); ++ if (inst->zone2 != NULL) ++ dns_zone_detach(&inst->zone2); ++ if (inst->db_imp != NULL) ++ dns_db_unregister(&inst->db_imp); ++ ++ dns_view_detach(&inst->view); ++ dns_zonemgr_detach(&inst->zmgr); ++ isc_task_detach(&inst->task); ++ ++ MEM_PUT_AND_DETACH(inst); ++ ++ *instp = NULL; ++} +diff --git a/bin/tests/system/dyndb/driver/instance.h b/bin/tests/system/dyndb/driver/instance.h +new file mode 100644 +index 0000000..ff0f5c3 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/instance.h +@@ -0,0 +1,47 @@ ++/** ++ * Driver instance object. ++ * ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef _LD_INSTANCE_H_ ++#define _LD_INSTANCE_H_ ++ ++#include <dns/fixedname.h> ++#include <dns/name.h> ++#include <dns/types.h> ++ ++struct sample_instance { ++ isc_mem_t *mctx; ++ char *db_name; ++ dns_dbimplementation_t *db_imp; ++ ++ /* These are needed for zone creation. */ ++ dns_view_t *view; ++ dns_zonemgr_t *zmgr; ++ isc_task_t *task; ++ isc_boolean_t exiting; ++ ++ dns_zone_t *zone1; ++ dns_fixedname_t zone1_fn; ++ dns_name_t *zone1_name; ++ ++ dns_zone_t *zone2; ++ dns_fixedname_t zone2_fn; ++ dns_name_t *zone2_name; ++}; ++ ++typedef struct sample_instance sample_instance_t; ++ ++isc_result_t ++new_sample_instance(isc_mem_t *mctx, const char *db_name, ++ int argc, char **argv, const dns_dyndbctx_t *dctx, ++ sample_instance_t **sample_instp); ++ ++isc_result_t ++load_sample_instance_zones(sample_instance_t *inst); ++ ++void ++destroy_sample_instance(sample_instance_t **sample_instp); ++ ++#endif /* !_LD_INSTANCE_H_ */ +diff --git a/bin/tests/system/dyndb/driver/lock.c b/bin/tests/system/dyndb/driver/lock.c +new file mode 100644 +index 0000000..c97c490 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/lock.c +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2014-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#include <config.h> ++ ++#include <isc/task.h> ++#include <isc/util.h> ++ ++#include "lock.h" ++ ++/* ++ * Lock BIND dispatcher and allow only single task to run. ++ * ++ * @warning ++ * All calls to isc_task_beginexclusive() have to operate on the same task ++ * otherwise it would not be possible to distinguish recursive locking ++ * from real conflict on the dispatcher lock. ++ * For this reason this wrapper function always works with inst->task. ++ * As a result, this function have to be be called only from inst->task. ++ * ++ * Recursive locking is allowed. Auxiliary variable pointed to by "statep" ++ * stores information if last run_exclusive_enter() operation really locked ++ * something or if the lock was called recursively and was no-op. ++ * ++ * The pair (inst, state) used for run_exclusive_enter() has to be ++ * used for run_exclusive_exit(). ++ * ++ * @param[in] inst The instance with the only task which is allowed to run. ++ * @param[in,out] statep Lock state: ISC_R_SUCCESS or ISC_R_LOCKBUSY ++ */ ++void ++run_exclusive_enter(sample_instance_t *inst, isc_result_t *statep) { ++ REQUIRE(statep != NULL); ++ REQUIRE(*statep == ISC_R_IGNORE); ++ ++ *statep = isc_task_beginexclusive(inst->task); ++ RUNTIME_CHECK(*statep == ISC_R_SUCCESS || *statep == ISC_R_LOCKBUSY); ++} ++ ++/* ++ * Exit task-exclusive mode. ++ * ++ * @param[in] inst The instance used for previous run_exclusive_enter() call. ++ * @param[in] state Lock state as returned by run_exclusive_enter(). ++ */ ++void ++run_exclusive_exit(sample_instance_t *inst, isc_result_t state) { ++ if (state == ISC_R_SUCCESS) ++ isc_task_endexclusive(inst->task); ++ else ++ /* Unlocking recursive lock or the lock was never locked. */ ++ INSIST(state == ISC_R_LOCKBUSY || state == ISC_R_IGNORE); ++ ++ return; ++} +diff --git a/bin/tests/system/dyndb/driver/lock.h b/bin/tests/system/dyndb/driver/lock.h +new file mode 100644 +index 0000000..35c9c84 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/lock.h +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (C) 2014-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef LOCK_H_ ++#define LOCK_H_ ++ ++#include "instance.h" ++#include "util.h" ++ ++void ++run_exclusive_enter(sample_instance_t *inst, isc_result_t *statep); ++ ++void ++run_exclusive_exit(sample_instance_t *inst, isc_result_t state); ++ ++#endif /* LOCK_H_ */ +diff --git a/bin/tests/system/dyndb/driver/log.c b/bin/tests/system/dyndb/driver/log.c +new file mode 100644 +index 0000000..2238c7e +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/log.c +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#include <config.h> ++ ++#include <isc/util.h> ++ ++#include <dns/log.h> ++ ++#include "log.h" ++ ++void ++log_write(int level, const char *format, ...) { ++ va_list args; ++ ++ va_start(args, format); ++ isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB, ++ level, format, args); ++ va_end(args); ++} +diff --git a/bin/tests/system/dyndb/driver/log.h b/bin/tests/system/dyndb/driver/log.h +new file mode 100644 +index 0000000..27b38c8 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/log.h +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2009--2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef _LD_LOG_H_ ++#define _LD_LOG_H_ ++ ++#include <isc/error.h> ++#include <dns/log.h> ++#include <dns/result.h> ++ ++#define fatal_error(...) \ ++ isc_error_fatal(__FILE__, __LINE__, __VA_ARGS__) ++ ++#define log_error_r(fmt, ...) \ ++ log_error(fmt ": %s", ##__VA_ARGS__, dns_result_totext(result)) ++ ++#define log_error(format, ...) \ ++ log_write(ISC_LOG_ERROR, format, ##__VA_ARGS__) ++ ++#define log_info(format, ...) \ ++ log_write(ISC_LOG_INFO, format, ##__VA_ARGS__) ++ ++void ++log_write(int level, const char *format, ...) ISC_FORMAT_PRINTF(2, 3); ++ ++#endif /* !_LD_LOG_H_ */ +diff --git a/bin/tests/system/dyndb/driver/syncptr.c b/bin/tests/system/dyndb/driver/syncptr.c +new file mode 100644 +index 0000000..2191bae +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/syncptr.c +@@ -0,0 +1,265 @@ ++/* ++ * Automatic A/AAAA/PTR record synchronization. ++ * ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#include <config.h> ++ ++#include <isc/event.h> ++#include <isc/eventclass.h> ++#include <isc/netaddr.h> ++#include <isc/task.h> ++ ++#include <dns/byaddr.h> ++#include <dns/db.h> ++#include <dns/name.h> ++#include <dns/view.h> ++#include <dns/zone.h> ++ ++#include "instance.h" ++#include "syncptr.h" ++#include "util.h" ++ ++/* Almost random value. See eventclass.h */ ++#define SYNCPTR_WRITE_EVENT (ISC_EVENTCLASS(1025) + 1) ++ ++/* ++ * Event used for making changes to reverse zones. ++ */ ++typedef struct syncptrevent syncptrevent_t; ++struct syncptrevent { ++ ISC_EVENT_COMMON(syncptrevent_t); ++ isc_mem_t *mctx; ++ dns_zone_t *zone; ++ dns_diff_t diff; ++ dns_fixedname_t ptr_target_name; /* referenced by owner name in tuple */ ++ isc_buffer_t b; /* referenced by target name in tuple */ ++ unsigned char buf[DNS_NAME_MAXWIRE]; ++}; ++ ++/* ++ * Write diff generated in syncptr() to reverse zone. ++ * ++ * This function will be called asynchronously and syncptr() will not get ++ * any result from it. ++ * ++ */ ++static void ++syncptr_write(isc_task_t *task, isc_event_t *event) { ++ syncptrevent_t *pevent = (syncptrevent_t *)event; ++ dns_dbversion_t *version = NULL; ++ dns_db_t *db = NULL; ++ isc_result_t result; ++ ++ REQUIRE(event->ev_type == SYNCPTR_WRITE_EVENT); ++ ++ UNUSED(task); ++ ++ CHECK(dns_zone_getdb(pevent->zone, &db)); ++ CHECK(dns_db_newversion(db, &version)); ++ CHECK(dns_diff_apply(&pevent->diff, db, version)); ++ ++cleanup: ++ if (db != NULL) { ++ if (version != NULL) ++ dns_db_closeversion(db, &version, ISC_TRUE); ++ dns_db_detach(&db); ++ } ++ dns_zone_detach(&pevent->zone); ++ dns_diff_clear(&pevent->diff); ++ isc_event_free(&event); ++} ++ ++/* ++ * Find a reverse zone for given IP address. ++ * ++ * @param[in] rdata IP address as A/AAAA record ++ * @param[out] name Owner name for the PTR record ++ * @param[out] zone DNS zone for reverse record matching the IP address ++ * ++ * @retval ISC_R_SUCCESS DNS name derived from given IP address belongs to an ++ * reverse zone managed by this driver instance. ++ * PTR record synchronization can continue. ++ * @retval ISC_R_NOTFOUND Suitable reverse zone was not found because it ++ * does not exist or is not managed by this driver. ++ */ ++static isc_result_t ++syncptr_find_zone(sample_instance_t *inst, dns_rdata_t *rdata, ++ dns_name_t *name, dns_zone_t **zone) ++{ ++ isc_result_t result; ++ isc_netaddr_t isc_ip; /* internal net address representation */ ++ dns_rdata_in_a_t ipv4; ++ dns_rdata_in_aaaa_t ipv6; ++ ++ REQUIRE(inst != NULL); ++ REQUIRE(zone != NULL && *zone == NULL); ++ ++ switch (rdata->type) { ++ case dns_rdatatype_a: ++ CHECK(dns_rdata_tostruct(rdata, &ipv4, inst->mctx)); ++ isc_netaddr_fromin(&isc_ip, &ipv4.in_addr); ++ break; ++ ++ case dns_rdatatype_aaaa: ++ CHECK(dns_rdata_tostruct(rdata, &ipv6, inst->mctx)); ++ isc_netaddr_fromin6(&isc_ip, &ipv6.in6_addr); ++ break; ++ ++ default: ++ fatal_error("unsupported address type 0x%x", rdata->type); ++ break; ++ } ++ ++ /* ++ * Convert IP address to PTR owner name. ++ * ++ * @example ++ * 192.168.0.1 -> 1.0.168.192.in-addr.arpa ++ */ ++ CHECK(dns_byaddr_createptrname2(&isc_ip, 0, name)); ++ ++ /* Find a zone containing owner name of the PTR record. */ ++ result = dns_zt_find(inst->view->zonetable, name, 0, NULL, zone); ++ if (result == DNS_R_PARTIALMATCH) ++ result = ISC_R_SUCCESS; ++ else if (result != ISC_R_SUCCESS) ++ goto cleanup; ++ ++ /* Make sure that the zone is managed by this driver. */ ++ if (*zone != inst->zone1 && *zone != inst->zone2) { ++ dns_zone_detach(zone); ++ result = ISC_R_NOTFOUND; ++ } ++ ++cleanup: ++ if (rdata->type == dns_rdatatype_a) ++ dns_rdata_freestruct(&ipv4); ++ else ++ dns_rdata_freestruct(&ipv6); ++ ++ return (result); ++} ++ ++/* ++ * Generate update event for PTR record to reflect change in A/AAAA record. ++ * ++ * @pre Reverse zone is managed by this driver. ++ * ++ * @param[in] a_name DNS domain of modified A/AAAA record ++ * @param[in] af Address family ++ * @param[in] ip_str IP address as a string (IPv4 or IPv6) ++ * @param[in] mod_op LDAP_MOD_DELETE if A/AAAA record is being deleted ++ * or LDAP_MOD_ADD if A/AAAA record is being added. ++ * ++ * @retval ISC_R_SUCCESS Event for PTR record update was generated and send. ++ * Change to reverse zone will be done asynchronously. ++ * @retval other Synchronization failed - reverse doesn't exist, ++ * is not managed by this driver instance, ++ * memory allocation error, etc. ++ */ ++static isc_result_t ++syncptr(sample_instance_t *inst, dns_name_t *name, ++ dns_rdata_t *addr_rdata, dns_ttl_t ttl, dns_diffop_t op) ++{ ++ isc_result_t result; ++ isc_mem_t *mctx = inst->mctx; ++ dns_fixedname_t ptr_name; ++ dns_zone_t *ptr_zone = NULL; ++ dns_rdata_ptr_t ptr_struct; ++ dns_rdata_t ptr_rdata = DNS_RDATA_INIT; ++ dns_difftuple_t *tp = NULL; ++ isc_task_t *task = NULL; ++ syncptrevent_t *pevent = NULL; ++ ++ dns_fixedname_init(&ptr_name); ++ DNS_RDATACOMMON_INIT(&ptr_struct, dns_rdatatype_ptr, dns_rdataclass_in); ++ dns_name_init(&ptr_struct.ptr, NULL); ++ ++ pevent = (syncptrevent_t *)isc_event_allocate(inst->mctx, inst, ++ SYNCPTR_WRITE_EVENT, ++ syncptr_write, NULL, ++ sizeof(syncptrevent_t)); ++ if (pevent == NULL) { ++ result = ISC_R_NOMEMORY; ++ goto cleanup; ++ } ++ isc_buffer_init(&pevent->b, pevent->buf, sizeof(pevent->buf)); ++ dns_fixedname_init(&pevent->ptr_target_name); ++ ++ /* Check if reverse zone is managed by this driver */ ++ result = syncptr_find_zone(inst, addr_rdata, ++ dns_fixedname_name(&ptr_name), &ptr_zone); ++ if (result != ISC_R_SUCCESS) { ++ log_error_r("PTR record synchonization skipped: reverse zone " ++ "is not managed by driver instance '%s'", ++ inst->db_name); ++ goto cleanup; ++ } ++ ++ /* Reverse zone is managed by this driver, prepare PTR record */ ++ pevent->zone = NULL; ++ dns_zone_attach(ptr_zone, &pevent->zone); ++ CHECK(dns_name_copy(name, dns_fixedname_name(&pevent->ptr_target_name), ++ NULL)); ++ dns_name_clone(dns_fixedname_name(&pevent->ptr_target_name), ++ &ptr_struct.ptr); ++ dns_diff_init(inst->mctx, &pevent->diff); ++ CHECK(dns_rdata_fromstruct(&ptr_rdata, dns_rdataclass_in, ++ dns_rdatatype_ptr, &ptr_struct, &pevent->b)); ++ ++ /* Create diff */ ++ CHECK(dns_difftuple_create(mctx, op, dns_fixedname_name(&ptr_name), ++ ttl, &ptr_rdata, &tp)); ++ dns_diff_append(&pevent->diff, &tp); ++ ++ /* ++ * Send update event to the reverse zone. ++ * It will be processed asynchronously. ++ */ ++ dns_zone_gettask(ptr_zone, &task); ++ isc_task_send(task, (isc_event_t **)&pevent); ++ ++cleanup: ++ if (ptr_zone != NULL) ++ dns_zone_detach(&ptr_zone); ++ if (tp != NULL) ++ dns_difftuple_free(&tp); ++ if (task != NULL) ++ isc_task_detach(&task); ++ if (pevent != NULL) ++ isc_event_free((isc_event_t **)&pevent); ++ ++ return (result); ++} ++ ++/* ++ * Generate update event for every rdata in rdataset. ++ * ++ * @param[in] name Owner name for A/AAAA records in rdataset. ++ * @param[in] rdataset A/AAAA records. ++ * @param[in] op DNS_DIFFOP_ADD / DNS_DIFFOP_DEL for adding / deleting ++ * the rdata ++ */ ++isc_result_t ++syncptrs(sample_instance_t *inst, dns_name_t *name, ++ dns_rdataset_t *rdataset, dns_diffop_t op) ++{ ++ isc_result_t result; ++ dns_rdata_t rdata = DNS_RDATA_INIT; ++ ++ for (result = dns_rdataset_first(rdataset); ++ result == ISC_R_SUCCESS; ++ result = dns_rdataset_next(rdataset)) { ++ dns_rdataset_current(rdataset, &rdata); ++ result = syncptr(inst, name, &rdata, rdataset->ttl, op); ++ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) ++ goto cleanup; ++ } ++ if (result == ISC_R_NOMORE) ++ result = ISC_R_SUCCESS; ++ ++cleanup: ++ return (result); ++} +diff --git a/bin/tests/system/dyndb/driver/syncptr.h b/bin/tests/system/dyndb/driver/syncptr.h +new file mode 100644 +index 0000000..2f9b3a6 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/syncptr.h +@@ -0,0 +1,15 @@ ++/* ++ * Sync PTR records ++ * ++ * Copyright (C) 2014-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef SYNCPTR_H_ ++#define SYNCPTR_H_ ++ ++#include <dns/diff.h> ++isc_result_t ++syncptrs(sample_instance_t *inst, dns_name_t *name, dns_rdataset_t *rdataset, ++ dns_diffop_t op); ++ ++#endif /* SYNCPTR_H_ */ +diff --git a/bin/tests/system/dyndb/driver/util.h b/bin/tests/system/dyndb/driver/util.h +new file mode 100644 +index 0000000..2a00fe3 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/util.h +@@ -0,0 +1,57 @@ ++/* ++ * Memory allocation and error handling utilities. ++ * ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef _LD_UTIL_H_ ++#define _LD_UTIL_H_ ++ ++#include <isc/mem.h> ++#include <dns/types.h> ++ ++#include "log.h" ++ ++#define CLEANUP_WITH(result_code) \ ++ do { \ ++ result = (result_code); \ ++ goto cleanup; \ ++ } while(0) ++ ++#define CHECK(op) \ ++ do { \ ++ result = (op); \ ++ if (result != ISC_R_SUCCESS) \ ++ goto cleanup; \ ++ } while (0) ++ ++#define CHECKED_MEM_GET(m, target_ptr, s) \ ++ do { \ ++ (target_ptr) = isc_mem_get((m), (s)); \ ++ if ((target_ptr) == NULL) { \ ++ result = ISC_R_NOMEMORY; \ ++ log_error("Memory allocation failed"); \ ++ goto cleanup; \ ++ } \ ++ } while (0) ++ ++#define CHECKED_MEM_GET_PTR(m, target_ptr) \ ++ CHECKED_MEM_GET(m, target_ptr, sizeof(*(target_ptr))) ++ ++#define CHECKED_MEM_STRDUP(m, source, target) \ ++ do { \ ++ (target) = isc_mem_strdup((m), (source)); \ ++ if ((target) == NULL) { \ ++ result = ISC_R_NOMEMORY; \ ++ log_error("Memory allocation failed"); \ ++ goto cleanup; \ ++ } \ ++ } while (0) ++ ++#define ZERO_PTR(ptr) memset((ptr), 0, sizeof(*(ptr))) ++ ++#define MEM_PUT_AND_DETACH(target_ptr) \ ++ isc_mem_putanddetach(&(target_ptr)->mctx, target_ptr, \ ++ sizeof(*(target_ptr))) ++ ++#endif /* !_LD_UTIL_H_ */ +diff --git a/bin/tests/system/dyndb/driver/zone.c b/bin/tests/system/dyndb/driver/zone.c +new file mode 100644 +index 0000000..88bd967 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/zone.c +@@ -0,0 +1,192 @@ ++/* ++ * Zone management. ++ * ++ * Copyright (C) 2009-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#include <config.h> ++ ++#include <isc/util.h> ++ ++#include <dns/dyndb.h> ++#include <dns/view.h> ++#include <dns/zone.h> ++ ++#include "util.h" ++#include "instance.h" ++#include "lock.h" ++#include "log.h" ++#include "zone.h" ++ ++extern const char *impname; ++ ++/* ++ * Create a new zone with origin 'name'. The zone stay invisible to clients ++ * until it is explicitly added to a view. ++ */ ++isc_result_t ++create_zone(sample_instance_t * const inst, dns_name_t * const name, ++ dns_zone_t ** const rawp) ++{ ++ isc_result_t result; ++ dns_zone_t *raw = NULL; ++ const char *zone_argv[1]; ++ char zone_name[DNS_NAME_FORMATSIZE]; ++ dns_acl_t *acl_any = NULL; ++ ++ REQUIRE(inst != NULL); ++ REQUIRE(name != NULL); ++ REQUIRE(rawp != NULL && *rawp == NULL); ++ ++ zone_argv[0] = inst->db_name; ++ ++ log_info("debug isc_mem_debugging(%p)=%X", &isc_mem_debugging, isc_mem_debugging); ++ CHECK(dns_zone_create(&raw, inst->mctx)); ++ CHECK(dns_zone_setorigin(raw, name)); ++ dns_zone_setclass(raw, dns_rdataclass_in); ++ dns_zone_settype(raw, dns_zone_master); ++ CHECK(dns_zone_setdbtype(raw, 1, zone_argv)); ++ CHECK(dns_zonemgr_managezone(inst->zmgr, raw)); ++ ++ /* This is completely insecure - use some sensible values instead! */ ++ CHECK(dns_acl_any(inst->mctx, &acl_any)); ++ dns_zone_setupdateacl(raw, acl_any); ++ dns_zone_setqueryacl(raw, acl_any); ++ dns_zone_setxfracl(raw, acl_any); ++ dns_acl_detach(&acl_any); ++ ++ *rawp = raw; ++ return (ISC_R_SUCCESS); ++ ++cleanup: ++ dns_name_format(name, zone_name, DNS_NAME_FORMATSIZE); ++ log_error_r("failed to create new zone '%s'", zone_name); ++ ++ if (raw != NULL) { ++ if (dns_zone_getmgr(raw) != NULL) ++ dns_zonemgr_releasezone(inst->zmgr, raw); ++ dns_zone_detach(&raw); ++ } ++ if (acl_any != NULL) ++ dns_acl_detach(&acl_any); ++ ++ return (result); ++} ++ ++/* ++ * Add zone to the view defined in inst->view. This will make the zone visible ++ * to clients. ++ */ ++static isc_result_t ++publish_zone(sample_instance_t *inst, dns_zone_t *zone) { ++ isc_result_t result; ++ isc_boolean_t freeze = ISC_FALSE; ++ dns_zone_t *zone_in_view = NULL; ++ dns_view_t *view_in_zone = NULL; ++ isc_result_t lock_state = ISC_R_IGNORE; ++ ++ REQUIRE(inst != NULL); ++ REQUIRE(zone != NULL); ++ ++ /* Return success if the zone is already in the view as expected. */ ++ result = dns_view_findzone(inst->view, dns_zone_getorigin(zone), ++ &zone_in_view); ++ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) ++ goto cleanup; ++ ++ view_in_zone = dns_zone_getview(zone); ++ if (view_in_zone != NULL) { ++ /* Zone has a view set -> view should contain the same zone. */ ++ if (zone_in_view == zone) { ++ /* Zone is already published in the right view. */ ++ CLEANUP_WITH(ISC_R_SUCCESS); ++ } else if (view_in_zone != inst->view) { ++ /* ++ * Un-published inactive zone will have ++ * inst->view in zone but will not be present ++ * in the view itself. ++ */ ++ dns_zone_log(zone, ISC_LOG_ERROR, ++ "zone->view doesn't " ++ "match data in the view"); ++ CLEANUP_WITH(ISC_R_UNEXPECTED); ++ } ++ } ++ ++ if (zone_in_view != NULL) { ++ dns_zone_log(zone, ISC_LOG_ERROR, ++ "cannot publish zone: view already " ++ "contains another zone with this name"); ++ CLEANUP_WITH(ISC_R_UNEXPECTED); ++ } ++ ++ run_exclusive_enter(inst, &lock_state); ++ if (inst->view->frozen) { ++ freeze = ISC_TRUE; ++ dns_view_thaw(inst->view); ++ } ++ ++ dns_zone_setview(zone, inst->view); ++ CHECK(dns_view_addzone(inst->view, zone)); ++ ++cleanup: ++ if (zone_in_view != NULL) ++ dns_zone_detach(&zone_in_view); ++ if (freeze) ++ dns_view_freeze(inst->view); ++ run_exclusive_exit(inst, lock_state); ++ ++ return (result); ++} ++ ++/* ++ * @warning Never call this on raw part of in-line secure zone, call it only ++ * on the secure zone! ++ */ ++static isc_result_t ++load_zone(dns_zone_t *zone) { ++ isc_result_t result; ++ isc_boolean_t zone_dynamic; ++ isc_uint32_t serial; ++ ++ result = dns_zone_load(zone); ++ if (result != ISC_R_SUCCESS && result != DNS_R_UPTODATE ++ && result != DNS_R_DYNAMIC && result != DNS_R_CONTINUE) ++ goto cleanup; ++ zone_dynamic = (result == DNS_R_DYNAMIC); ++ ++ CHECK(dns_zone_getserial2(zone, &serial)); ++ dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u", serial); ++ ++ if (zone_dynamic) ++ dns_zone_notify(zone); ++ ++cleanup: ++ return (result); ++} ++ ++/* ++ * Add zone to view and call dns_zone_load(). ++ */ ++isc_result_t ++activate_zone(sample_instance_t *inst, dns_zone_t *raw) { ++ isc_result_t result; ++ ++ /* ++ * Zone has to be published *before* zone load ++ * otherwise it will race with zone->view != NULL check ++ * in zone_maintenance() in zone.c. ++ */ ++ result = publish_zone(inst, raw); ++ if (result != ISC_R_SUCCESS) { ++ dns_zone_log(raw, ISC_LOG_ERROR, ++ "cannot add zone to view: %s", ++ dns_result_totext(result)); ++ goto cleanup; ++ } ++ ++ CHECK(load_zone(raw)); ++ ++cleanup: ++ return (result); ++} +diff --git a/bin/tests/system/dyndb/driver/zone.h b/bin/tests/system/dyndb/driver/zone.h +new file mode 100644 +index 0000000..a862691 +--- /dev/null ++++ b/bin/tests/system/dyndb/driver/zone.h +@@ -0,0 +1,15 @@ ++/* ++ * Copyright (C) 2014-2015 Red Hat ; see COPYRIGHT for license ++ */ ++ ++#ifndef ZONE_H_ ++#define ZONE_H_ ++ ++isc_result_t ++create_zone(sample_instance_t * const inst, dns_name_t * const name, ++ dns_zone_t ** const rawp); ++ ++isc_result_t ++activate_zone(sample_instance_t *inst, dns_zone_t *raw); ++ ++#endif /* ZONE_H_ */ +diff --git a/bin/tests/system/dyndb/ns1/named.conf b/bin/tests/system/dyndb/ns1/named.conf +new file mode 100644 +index 0000000..a4f334b +--- /dev/null ++++ b/bin/tests/system/dyndb/ns1/named.conf +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++controls { }; ++ ++options { ++ query-source address 10.53.0.1; ++ notify-source 10.53.0.1; ++ transfer-source 10.53.0.1; ++ port 5300; ++ pid-file "named.pid"; ++ session-keyfile "session.key"; ++ listen-on { 10.53.0.1; 127.0.0.1; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ notify yes; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-sha256; ++}; ++ ++controls { ++ inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++dyndb sample "../driver/lib/sample.so" { ipv4.example.nil. in-addr.arpa. }; ++dyndb sample2 "../driver/lib/sample.so" { ipv6.example.nil. 8.b.d.0.1.0.0.2.ip6.arpa. }; +diff --git a/bin/tests/system/dyndb/prereq.sh b/bin/tests/system/dyndb/prereq.sh +new file mode 100644 +index 0000000..fe7ef71 +--- /dev/null ++++ b/bin/tests/system/dyndb/prereq.sh +@@ -0,0 +1,21 @@ ++#!/bin/sh ++# ++# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++../dlzexternal/dlopen || { ++ echo "I:dlopen() not supported - skipping dyndb test" ++ exit 255 ++} ++exit 0 +diff --git a/bin/tests/system/dyndb/tests.sh b/bin/tests/system/dyndb/tests.sh +new file mode 100644 +index 0000000..590b70b +--- /dev/null ++++ b/bin/tests/system/dyndb/tests.sh +@@ -0,0 +1,155 @@ ++#!/bin/sh ++# ++# Copyright (C) 2010-2014 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++ ++status=0 ++n=0 ++ ++DIGOPTS="@10.53.0.1 -p 5300" ++ ++newtest() { ++ n=`expr $n + 1` ++ echo "${1} (${n})" ++ ret=0 ++} ++ ++test_add() { ++ host="$1" ++ type="$2" ++ ip="$3" ++ ++ cat <<EOF > ns1/update.txt ++server 10.53.0.1 5300 ++ttl 86400 ++update add $host $type $ip ++send ++EOF ++ ++ newtest "I:adding $host $type $ip" ++ $NSUPDATE ns1/update.txt > /dev/null 2>&1 || { ++ [ "$should_fail" ] || \ ++ echo "I:update failed for $host $type $ip" ++ return 1 ++ } ++ ++ out=`$DIG $DIGOPTS +noall +answer -t $type -q $host` ++ echo $out > added.a.out.$n ++ lines=`echo "$out" | grep "$ip" | wc -l` ++ [ $lines -eq 1 ] || { ++ [ "$should_fail" ] || \ ++ echo "I:dig output incorrect for $host $type $cmd: $out" ++ return 1 ++ } ++ ++ out=`$DIG $DIGOPTS +noall +answer -x $ip` ++ echo $out > added.ptr.out.$n ++ lines=`echo "$out" | grep "$host" | wc -l` ++ [ $lines -eq 1 ] || { ++ [ "$should_fail" ] || \ ++ echo "I:dig reverse output incorrect for $host $type $cmd: $out" ++ return 1 ++ } ++ ++ return 0 ++} ++ ++test_del() { ++ host="$1" ++ type="$2" ++ ++ ip=`$DIG $DIGOPTS +short $host $type` ++ ++ cat <<EOF > ns1/update.txt ++server 10.53.0.1 5300 ++update del $host $type ++send ++EOF ++ ++ newtest "I:deleting $host $type (was $ip)" ++ $NSUPDATE ns1/update.txt > /dev/null 2>&1 || { ++ [ "$should_fail" ] || \ ++ echo "I:update failed deleting $host $type" ++ return 1 ++ } ++ ++ out=`$DIG $DIGOPTS +noall +answer -t $type -q $host` ++ echo $out > deleted.a.out.$n ++ lines=`echo "$out" | grep "$ip" | wc -l` ++ [ $lines -eq 0 ] || { ++ [ "$should_fail" ] || \ ++ echo "I:dig output incorrect for $host $type $cmd: $out" ++ return 1 ++ } ++ ++ out=`$DIG $DIGOPTS +noall +answer -x $ip` ++ echo $out > deleted.ptr.out.$n ++ lines=`echo "$out" | grep "$host" | wc -l` ++ [ $lines -eq 0 ] || { ++ [ "$should_fail" ] || \ ++ echo "I:dig reverse output incorrect for $host $type $cmd: $out" ++ return 1 ++ } ++ ++ return 0 ++} ++ ++test_add test1.ipv4.example.nil. A "10.53.0.10" || ret=1 ++status=`expr $status + $ret` ++ ++test_add test2.ipv4.example.nil. A "10.53.0.11" || ret=1 ++status=`expr $status + $ret` ++ ++test_add test3.ipv4.example.nil. A "10.53.0.12" || ret=1 ++status=`expr $status + $ret` ++ ++test_add test4.ipv6.example.nil. AAAA "2001:db8::1" || ret=1 ++status=`expr $status + $ret` ++ ++test_del test1.ipv4.example.nil. A || ret=1 ++status=`expr $status + $ret` ++ ++test_del test2.ipv4.example.nil. A || ret=1 ++status=`expr $status + $ret` ++ ++test_del test3.ipv4.example.nil. A || ret=1 ++status=`expr $status + $ret` ++ ++test_del test4.ipv6.example.nil. AAAA || ret=1 ++status=`expr $status + $ret` ++ ++newtest "I:checking parameter logging" ++grep "loading params for dyndb 'sample' from .*named.conf:41" ns1/named.run > /dev/null || ret=1 ++grep "loading params for dyndb 'sample2' from .*named.conf:42" ns1/named.run > /dev/null || ret=1 ++status=`expr $status + $ret` ++ ++echo "I:checking dyndb still works after reload" ++$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 reload 2>&1 | sed 's/^/I:ns1 /' ++ ++test_add test5.ipv4.example.nil. A "10.53.0.10" || ret=1 ++status=`expr $status + $ret` ++ ++test_add test6.ipv6.example.nil. AAAA "2001:db8::1" || ret=1 ++status=`expr $status + $ret` ++ ++test_del test5.ipv4.example.nil. A || ret=1 ++status=`expr $status + $ret` ++ ++test_del test6.ipv6.example.nil. AAAA || ret=1 ++status=`expr $status + $ret` ++ ++exit $status +diff --git a/configure b/configure +index 2a53adf..c62da63 100755 +--- a/configure ++++ b/configure +@@ -162,7 +162,7 @@ + # + # ----------------------------------------------------------------------------- + # +-# Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan ++# Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan + # (Royal Institute of Technology, Stockholm, Sweden). + # All rights reserved. + # +@@ -19784,6 +19784,7 @@ $as_echo "#define ISC_DLZ_DLOPEN 1" >>confdefs.h + + fi + fi ++CFLAGS="$CFLAGS $SO_CFLAGS" + + + +@@ -20594,7 +20595,7 @@ ac_config_commands="$ac_config_commands chmod" + # elsewhere if there's a good reason for doing so. + # + +-ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/ecdsa/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/gost/prereq.sh bin/tests/system/lwresd/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rrl/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/check-secure-delegation.pl contrib/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/export/Makefile lib/export/dns/Makefile lib/export/dns/include/Makefile lib/export/dns/include/dns/Makefile lib/export/dns/include/dst/Makefile lib/export/irs/Makefile lib/export/irs/include/Makefile lib/export/irs/include/irs/Makefile lib/export/isc/$thread_dir/Makefile lib/export/isc/$thread_dir/include/Makefile lib/export/isc/$thread_dir/include/isc/Makefile lib/export/isc/Makefile lib/export/isc/include/Makefile lib/export/isc/include/isc/Makefile lib/export/isc/nls/Makefile lib/export/isc/unix/Makefile lib/export/isc/unix/include/Makefile lib/export/isc/unix/include/isc/Makefile lib/export/isccfg/Makefile lib/export/isccfg/include/Makefile lib/export/isccfg/include/isccfg/Makefile lib/export/samples/Makefile lib/export/samples/Makefile-postinstall lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile unit/Makefile unit/unittest.sh" ++ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/ecdsa/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/gost/prereq.sh bin/tests/system/lwresd/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rrl/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/check-secure-delegation.pl contrib/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/export/Makefile lib/export/dns/Makefile lib/export/dns/include/Makefile lib/export/dns/include/dns/Makefile lib/export/dns/include/dst/Makefile lib/export/irs/Makefile lib/export/irs/include/Makefile lib/export/irs/include/irs/Makefile lib/export/isc/$thread_dir/Makefile lib/export/isc/$thread_dir/include/Makefile lib/export/isc/$thread_dir/include/isc/Makefile lib/export/isc/Makefile lib/export/isc/include/Makefile lib/export/isc/include/isc/Makefile lib/export/isc/nls/Makefile lib/export/isc/unix/Makefile lib/export/isc/unix/include/Makefile lib/export/isc/unix/include/isc/Makefile lib/export/isccfg/Makefile lib/export/isccfg/include/Makefile lib/export/isccfg/include/isccfg/Makefile lib/export/samples/Makefile lib/export/samples/Makefile-postinstall lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile unit/Makefile unit/unittest.sh" + + + # +@@ -21637,6 +21638,8 @@ do + "bin/tests/system/dlz/prereq.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/dlz/prereq.sh" ;; + "bin/tests/system/dlzexternal/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/dlzexternal/Makefile" ;; + "bin/tests/system/dlzexternal/ns1/named.conf") CONFIG_FILES="$CONFIG_FILES bin/tests/system/dlzexternal/ns1/named.conf" ;; ++ "bin/tests/system/dyndb/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/dyndb/Makefile" ;; ++ "bin/tests/system/dyndb/driver/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/dyndb/driver/Makefile" ;; + "bin/tests/system/ecdsa/prereq.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/ecdsa/prereq.sh" ;; + "bin/tests/system/filter-aaaa/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/system/filter-aaaa/Makefile" ;; + "bin/tests/system/gost/prereq.sh") CONFIG_FILES="$CONFIG_FILES bin/tests/system/gost/prereq.sh" ;; +diff --git a/configure.in b/configure.in +index 24eafb7..e8c68fc 100644 +--- a/configure.in ++++ b/configure.in +@@ -3755,6 +3755,7 @@ if test "$dlopen" = "yes"; then + [Define to allow building of objects for dlopen().]) + fi + fi ++CFLAGS="$CFLAGS $SO_CFLAGS" + + AC_SUBST(SO) + AC_SUBST(SO_CFLAGS) +@@ -3960,6 +3961,8 @@ AC_CONFIG_FILES([ + bin/tests/system/dlz/prereq.sh + bin/tests/system/dlzexternal/Makefile + bin/tests/system/dlzexternal/ns1/named.conf ++ bin/tests/system/dyndb/Makefile ++ bin/tests/system/dyndb/driver/Makefile + bin/tests/system/ecdsa/prereq.sh + bin/tests/system/filter-aaaa/Makefile + bin/tests/system/gost/prereq.sh +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index bd42e11..16b50a3 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -2384,6 +2384,8 @@ options { + + <xi:include href="pkcs11.xml"/> + ++ <xi:include href="dyndb.xml"/> ++ + <sect1> + <title>IPv6 Support in <acronym>BIND</acronym> 9</title> + +diff --git a/doc/arm/dyndb.xml b/doc/arm/dyndb.xml +new file mode 100644 +index 0000000..4d92b22 +--- /dev/null ++++ b/doc/arm/dyndb.xml +@@ -0,0 +1,105 @@ ++<?xml version="1.0" encoding="utf-8"?> ++<!-- ++ - Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++ - ++ - Permission to use, copy, modify, and/or distribute this software for any ++ - purpose with or without fee is hereby granted, provided that the above ++ - copyright notice and this permission notice appear in all copies. ++ - ++ - THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ - REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ - AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ - INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ - LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ - OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ - PERFORMANCE OF THIS SOFTWARE. ++--> ++ ++<sect1 id="dyndb-info"> ++ <title>DynDB (Dynamic Database)</title> ++ <para> ++ DynDB is an extension to BIND 9 which, like DLZ ++ (see <xref linkend="dlz-info"/>), allows zone data to be ++ retrieved from an external database. Unlike DLZ, a DynDB module ++ provides a full-featured BIND zone database interface. Where ++ DLZ translates DNS queries into real-time database lookups, ++ resulting in relatively poor query performance, and is unable ++ to handle DNSSEC-signed data due to its limited API, a DynDB ++ module can pre-load an in-memory database from the external ++ data source, providing the same performance and functionality ++ as zones served natively by BIND. ++ </para> ++ <para> ++ A DynDB module supporting LDAP has been created by Red Hat ++ and is available from ++ <ulink url="https://fedorahosted.org/bind-dyndb-ldap/" ++ >https://fedorahosted.org/bind-dyndb-ldap/</ulink>. ++ </para> ++ <para> ++ A sample DynDB module for testing and developer guidance ++ is included with the BIND source code, in the directory ++ <filename>bin/tests/system/dyndb/driver</filename>. ++ </para> ++ ++ <sect2> ++ <title>Configuring DynDB</title> ++ <para> ++ A DynDB database is configured with a <command>dyndb</command> ++ statement in <filename>named.conf</filename>: ++ </para> ++ <screen> ++ dyndb example "driver.so" { ++ <replaceable>parameters</replaceable> ++ }; ++ </screen> ++ <para> ++ The file <filename>driver.so</filename> is a DynDB module which ++ implements the full DNS database API. Multiple ++ <command>dyndb</command> statements can be specified, to load ++ different drivers or multiple instances of the same driver. ++ Zones provided by a DynDB module are added to the view's zone ++ table, and are treated as normal authoritative zones when BIND ++ is responding to queries. Zone configuration is handled internally ++ by the DynDB module. ++ </para> ++ <para> ++ The <replaceable>parameters</replaceable> are passed as an opaque ++ string to the DynDB module's initialization routine. Configuration ++ syntax will differ depending on the driver. ++ </para> ++ </sect2> ++ <sect2> ++ <title>Sample DynDB Module</title> ++ <para> ++ For guidance in implementation of DynDB modules, the directory ++ <filename>bin/tests/system/dyndb/driver</filename>. ++ contains a basic DynDB module. ++ The example sets up two zones, whose names are passed ++ to the module as arguments in the <command>dyndb</command> ++ statement: ++ </para> ++ <screen> ++ dyndb sample "sample.so" { example.nil. arpa. }; ++ </screen> ++ <para> ++ In the above example, the module is configured to create a zone ++ "example.nil", which can answer queries and AXFR requests, and ++ accept DDNS updates. At runtime, prior to any updates, the zone ++ contains an SOA, NS, and a single A record at the apex: ++ </para> ++ <screen> ++ example.nil. 86400 IN SOA example.nil. example.nil. ( ++ 0 28800 7200 604800 86400 ++ ) ++ example.nil. 86400 IN NS example.nil. ++ example.nil. 86400 IN A 127.0.0.1 ++ </screen> ++ <para> ++ When the zone is updated dynamically, the DynDB module will determine ++ whether the updated RR is an address (i.e., type A or AAAA) and if ++ so, it will automatically update the corresponding PTR record in a ++ reverse zone. (Updates are not stored permanently; all updates are ++ lost when the server is restarted.) ++ </para> ++ </sect2> ++</sect1> +diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in +index 909250f..2efcc5a 100644 +--- a/lib/dns/Makefile.in ++++ b/lib/dns/Makefile.in +@@ -60,8 +60,8 @@ RRLOBJS = rrl.@O@ + DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ + cache.@O@ callbacks.@O@ clientinfo.@O@ compress.@O@ \ + db.@O@ dbiterator.@O@ dbtable.@O@ diff.@O@ dispatch.@O@ \ +- dlz.@O@ dns64.@O@ dnssec.@O@ ds.@O@ forward.@O@ iptable.@O@ \ +- journal.@O@ keydata.@O@ keytable.@O@ \ ++ dlz.@O@ dns64.@O@ dnssec.@O@ ds.@O@ dyndb.@O@ forward.@O@ \ ++ iptable.@O@ journal.@O@ keydata.@O@ keytable.@O@ \ + lib.@O@ log.@O@ lookup.@O@ \ + master.@O@ masterdump.@O@ message.@O@ \ + name.@O@ ncache.@O@ nsec.@O@ nsec3.@O@ order.@O@ peer.@O@ \ +@@ -93,8 +93,8 @@ DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ @PKCS11LINKSRCS@ \ + DNSSRCS = acache.c acl.c adb.c byaddr.c \ + cache.c callbacks.c clientinfo.c compress.c \ + db.c dbiterator.c dbtable.c diff.c dispatch.c \ +- dlz.c dns64.c dnssec.c ds.c forward.c iptable.c journal.c \ +- keydata.c keytable.c lib.c log.c lookup.c \ ++ dlz.c dns64.c dnssec.c ds.c dyndb.c forward.c iptable.c \ ++ journal.c keydata.c keytable.c lib.c log.c lookup.c \ + master.c masterdump.c message.c \ + name.c ncache.c nsec.c nsec3.c order.c peer.c portlist.c \ + rbt.c rbtdb.c rbtdb64.c rcode.c rdata.c rdatalist.c \ +diff --git a/lib/dns/dlz.c b/lib/dns/dlz.c +index 19c600c..ffcd23f 100644 +--- a/lib/dns/dlz.c ++++ b/lib/dns/dlz.c +@@ -69,6 +69,7 @@ + + + #include <isc/buffer.h> ++#include <isc/commandline.h> + #include <isc/magic.h> + #include <isc/mem.h> + #include <isc/once.h> +@@ -400,67 +401,6 @@ dns_dlzregister(const char *drivername, const dns_dlzmethods_t *methods, + } + + /*% +- * Helper function for dns_dlzstrtoargv(). +- * Pardon the gratuitous recursion. +- */ +-static isc_result_t +-dns_dlzstrtoargvsub(isc_mem_t *mctx, char *s, unsigned int *argcp, +- char ***argvp, unsigned int n) +-{ +- isc_result_t result; +- +- restart: +- /* Discard leading whitespace. */ +- while (*s == ' ' || *s == '\t') +- s++; +- +- if (*s == '\0') { +- /* We have reached the end of the string. */ +- *argcp = n; +- *argvp = isc_mem_get(mctx, n * sizeof(char *)); +- if (*argvp == NULL) +- return (ISC_R_NOMEMORY); +- } else { +- char *p = s; +- while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') { +- if (*p == '\n') { +- *p = ' '; +- goto restart; +- } +- p++; +- } +- +- /* do "grouping", items between { and } are one arg */ +- if (*p == '{') { +- char *t = p; +- /* +- * shift all characters to left by 1 to get rid of '{' +- */ +- while (*t != '\0') { +- t++; +- *(t-1) = *t; +- } +- while (*p != '\0' && *p != '}') { +- p++; +- } +- /* get rid of '}' character */ +- if (*p == '}') { +- *p = '\0'; +- p++; +- } +- /* normal case, no "grouping" */ +- } else if (*p != '\0') +- *p++ = '\0'; +- +- result = dns_dlzstrtoargvsub(mctx, p, argcp, argvp, n + 1); +- if (result != ISC_R_SUCCESS) +- return (result); +- (*argvp)[n] = s; +- } +- return (ISC_R_SUCCESS); +-} +- +-/*% + * Tokenize the string "s" into whitespace-separated words, + * return the number of words in '*argcp' and an array + * of pointers to the words in '*argvp'. The caller +@@ -471,7 +411,7 @@ isc_result_t + dns_dlzstrtoargv(isc_mem_t *mctx, char *s, + unsigned int *argcp, char ***argvp) + { +- return(dns_dlzstrtoargvsub(mctx, s, argcp, argvp, 0)); ++ return(isc_commandline_strtoargv(mctx, s, argcp, argvp, 0)); + } + + /*% +diff --git a/lib/dns/dyndb.c b/lib/dns/dyndb.c +new file mode 100644 +index 0000000..76b77f0 +--- /dev/null ++++ b/lib/dns/dyndb.c +@@ -0,0 +1,486 @@ ++/* ++ * Copyright (C) 2008-2011 Red Hat, Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND Red Hat DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL Red Hat BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++ ++#include <config.h> ++ ++#if HAVE_DLFCN_H ++#include <dlfcn.h> ++#elif _WIN32 ++#include <windows.h> ++#endif ++ ++#include <isc/buffer.h> ++#include <isc/mem.h> ++#include <isc/mutex.h> ++#include <isc/once.h> ++#include <isc/result.h> ++#include <isc/region.h> ++#include <isc/task.h> ++#include <isc/types.h> ++#include <isc/util.h> ++ ++#include <dns/dyndb.h> ++#include <dns/log.h> ++#include <dns/types.h> ++#include <dns/view.h> ++#include <dns/zone.h> ++ ++#include <string.h> ++ ++#define CHECK(op) \ ++ do { result = (op); \ ++ if (result != ISC_R_SUCCESS) goto cleanup; \ ++ } while (0) ++ ++ ++typedef struct dyndb_implementation dyndb_implementation_t; ++struct dyndb_implementation { ++ isc_mem_t *mctx; ++ void *handle; ++ dns_dyndb_register_t *register_func; ++ dns_dyndb_destroy_t *destroy_func; ++ char *name; ++ void *inst; ++ LINK(dyndb_implementation_t) link; ++}; ++ ++/* ++ * List of dyndb implementations. Locked by dyndb_lock. ++ * ++ * These are stored here so they can be cleaned up on shutdown. ++ * (The order in which they are stored is not important.) ++ */ ++static LIST(dyndb_implementation_t) dyndb_implementations; ++ ++/* Locks dyndb_implementations. */ ++static isc_mutex_t dyndb_lock; ++static isc_once_t once = ISC_ONCE_INIT; ++ ++static void ++dyndb_initialize(void) { ++ RUNTIME_CHECK(isc_mutex_init(&dyndb_lock) == ISC_R_SUCCESS); ++ INIT_LIST(dyndb_implementations); ++} ++ ++static dyndb_implementation_t * ++impfind(const char *name) { ++ dyndb_implementation_t *imp; ++ ++ for (imp = ISC_LIST_HEAD(dyndb_implementations); ++ imp != NULL; ++ imp = ISC_LIST_NEXT(imp, link)) ++ if (strcasecmp(name, imp->name) == 0) ++ return (imp); ++ return (NULL); ++} ++ ++#if HAVE_DLFCN_H ++static isc_result_t ++load_symbol(void *handle, const char *filename, ++ const char *symbol_name, void **symbolp) ++{ ++ const char *errmsg; ++ void *symbol; ++ ++ REQUIRE(handle != NULL); ++ REQUIRE(symbolp != NULL && *symbolp == NULL); ++ ++ symbol = dlsym(handle, symbol_name); ++ if (symbol == NULL) { ++ errmsg = dlerror(); ++ if (errmsg == NULL) ++ errmsg = "returned function pointer is NULL"; ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR, ++ "failed to lookup symbol %s in " ++ "dyndb module '%s': %s", ++ symbol_name, filename, errmsg); ++ return (ISC_R_FAILURE); ++ } ++ dlerror(); ++ ++ *symbolp = symbol; ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++load_library(isc_mem_t *mctx, const char *filename, const char *instname, ++ dyndb_implementation_t **impp) ++{ ++ isc_result_t result; ++ void *handle = NULL; ++ dyndb_implementation_t *imp = NULL; ++ dns_dyndb_register_t *register_func = NULL; ++ dns_dyndb_destroy_t *destroy_func = NULL; ++ dns_dyndb_version_t *version_func = NULL; ++ int version, flags; ++ ++ REQUIRE(impp != NULL && *impp == NULL); ++ ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_INFO, ++ "loading DynDB instance '%s' driver '%s'", ++ instname, filename); ++ ++ flags = RTLD_NOW|RTLD_LOCAL; ++#if 0 ++ // Need to access the daemon variables from the plugin, not local copies ++#ifdef RTLD_DEEPBIND ++ flags |= RTLD_DEEPBIND; ++#endif ++#endif ++ ++ handle = dlopen(filename, flags); ++ if (handle == NULL) ++ CHECK(ISC_R_FAILURE); ++ ++ /* Clear dlerror */ ++ dlerror(); ++ ++ CHECK(load_symbol(handle, filename, "dyndb_version", ++ (void **)&version_func)); ++ ++ version = version_func(NULL); ++ if (version < (DNS_DYNDB_VERSION - DNS_DYNDB_AGE) || ++ version > DNS_DYNDB_VERSION) ++ { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR, ++ "driver API version mismatch: %d/%d", ++ version, DNS_DYNDB_VERSION); ++ CHECK(ISC_R_FAILURE); ++ } ++ ++ CHECK(load_symbol(handle, filename, "dyndb_init", ++ (void **)®ister_func)); ++ CHECK(load_symbol(handle, filename, "dyndb_destroy", ++ (void **)&destroy_func)); ++ ++ imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t)); ++ if (imp == NULL) ++ CHECK(ISC_R_NOMEMORY); ++ ++ imp->mctx = NULL; ++ isc_mem_attach(mctx, &imp->mctx); ++ imp->handle = handle; ++ imp->register_func = register_func; ++ imp->destroy_func = destroy_func; ++ imp->name = isc_mem_strdup(mctx, instname); ++ if (imp->name == NULL) ++ CHECK(ISC_R_NOMEMORY); ++ ++ imp->inst = NULL; ++ INIT_LINK(imp, link); ++ ++ *impp = imp; ++ imp = NULL; ++ ++cleanup: ++ if (result != ISC_R_SUCCESS) ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR, ++ "failed to dynamically load instance '%s' " ++ "driver '%s': %s (%s)", instname, filename, ++ dlerror(), isc_result_totext(result)); ++ if (imp != NULL) ++ isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); ++ if (result != ISC_R_SUCCESS && handle != NULL) ++ dlclose(handle); ++ ++ return (result); ++} ++ ++static void ++unload_library(dyndb_implementation_t **impp) { ++ dyndb_implementation_t *imp; ++ ++ REQUIRE(impp != NULL && *impp != NULL); ++ ++ imp = *impp; ++ ++ isc_mem_free(imp->mctx, imp->name); ++ isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); ++ ++ *impp = NULL; ++} ++#elif _WIN32 ++static isc_result_t ++load_symbol(HMODULE handle, const char *filename, ++ const char *symbol_name, void **symbolp) ++{ ++ void *symbol; ++ ++ REQUIRE(handle != NULL); ++ REQUIRE(symbolp != NULL && *symbolp == NULL); ++ ++ symbol = GetProcAddress(handle, symbol_name); ++ if (symbol == NULL) { ++ int errstatus = GetLastError(); ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR, ++ "failed to lookup symbol %s in " ++ "dyndb module '%s': %d", ++ symbol_name, filename, errstatus); ++ return (ISC_R_FAILURE); ++ } ++ ++ *symbolp = symbol; ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static isc_result_t ++load_library(isc_mem_t *mctx, const char *filename, const char *instname, ++ dyndb_implementation_t **impp) ++{ ++ isc_result_t result; ++ HMODULE handle; ++ dyndb_implementation_t *imp = NULL; ++ dns_dyndb_register_t *register_func = NULL; ++ dns_dyndb_destroy_t *destroy_func = NULL; ++ dns_dyndb_version_t *version_func = NULL; ++ int version; ++ ++ REQUIRE(impp != NULL && *impp == NULL); ++ ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_INFO, ++ "loading DynDB instance '%s' driver '%s'", ++ instname, filename); ++ ++ handle = LoadLibraryA(filename); ++ if (handle == NULL) ++ CHECK(ISC_R_FAILURE); ++ ++ CHECK(load_symbol(handle, filename, "dyndb_version", ++ (void **)&version_func)); ++ ++ version = version_func(NULL); ++ if (version < (DNS_DYNDB_VERSION - DNS_DYNDB_AGE) || ++ version > DNS_DYNDB_VERSION) ++ { ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR, ++ "driver API version mismatch: %d/%d", ++ version, DNS_DYNDB_VERSION); ++ CHECK(ISC_R_FAILURE); ++ } ++ ++ CHECK(load_symbol(handle, filename, "dyndb_init", ++ (void **)®ister_func)); ++ CHECK(load_symbol(handle, filename, "dyndb_destroy", ++ (void **)&destroy_func)); ++ ++ imp = isc_mem_get(mctx, sizeof(dyndb_implementation_t)); ++ if (imp == NULL) ++ CHECK(ISC_R_NOMEMORY); ++ ++ imp->mctx = NULL; ++ isc_mem_attach(mctx, &imp->mctx); ++ imp->handle = handle; ++ imp->register_func = register_func; ++ imp->destroy_func = destroy_func; ++ imp->name = isc_mem_strdup(mctx, instname); ++ if (imp->name == NULL) ++ CHECK(ISC_R_NOMEMORY); ++ ++ imp->inst = NULL; ++ INIT_LINK(imp, link); ++ ++ *impp = imp; ++ imp = NULL; ++ ++cleanup: ++ if (result != ISC_R_SUCCESS) ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_ERROR, ++ "failed to dynamically load instance '%s' " ++ "driver '%s': %d (%s)", instname, filename, ++ GetLastError(), isc_result_totext(result)); ++ if (imp != NULL) ++ isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); ++ if (result != ISC_R_SUCCESS && handle != NULL) ++ FreeLibrary(handle); ++ ++ return (result); ++} ++ ++static void ++unload_library(dyndb_implementation_t **impp) { ++ dyndb_implementation_t *imp; ++ ++ REQUIRE(impp != NULL && *impp != NULL); ++ ++ imp = *impp; ++ ++ isc_mem_free(imp->mctx, imp->name); ++ isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); ++ ++ *impp = NULL; ++} ++#else /* HAVE_DLFCN_H || _WIN32 */ ++static isc_result_t ++load_library(isc_mem_t *mctx, const char *filename, const char *instname, ++ dyndb_implementation_t **impp) ++{ ++ UNUSED(mctx); ++ UNUSED(filename); ++ UNUSED(instname); ++ UNUSED(impp); ++ ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DYNDB, ++ ISC_LOG_ERROR, ++ "dynamic database support is not implemented") ++ ++ return (ISC_R_NOTIMPLEMENTED); ++} ++ ++static void ++unload_library(dyndb_implementation_t **impp) ++{ ++ dyndb_implementation_t *imp; ++ ++ REQUIRE(impp != NULL && *impp != NULL); ++ ++ imp = *impp; ++ ++ if (imp->handle != NULL) ++ dlclose(imp->handle); ++ ++ isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); ++ ++ *impp = NULL; ++} ++#endif /* HAVE_DLFCN_H */ ++ ++isc_result_t ++dns_dyndb_load(const char *libname, const char *name, const char *parameters, ++ const char *file, unsigned long line, isc_mem_t *mctx, ++ const dns_dyndbctx_t *dctx) ++{ ++ isc_result_t result; ++ dyndb_implementation_t *implementation = NULL; ++ ++ REQUIRE(DNS_DYNDBCTX_VALID(dctx)); ++ REQUIRE(name != NULL); ++ ++ RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS); ++ ++ LOCK(&dyndb_lock); ++ ++ /* duplicate instance names are not allowed */ ++ if (impfind(name) != NULL) ++ CHECK(ISC_R_EXISTS); ++ ++ CHECK(load_library(mctx, libname, name, &implementation)); ++ CHECK(implementation->register_func(mctx, name, parameters, file, line, ++ dctx, &implementation->inst)); ++ ++ APPEND(dyndb_implementations, implementation, link); ++ result = ISC_R_SUCCESS; ++ ++cleanup: ++ if (result != ISC_R_SUCCESS) ++ if (implementation != NULL) ++ unload_library(&implementation); ++ ++ UNLOCK(&dyndb_lock); ++ return (result); ++} ++ ++void ++dns_dyndb_cleanup(isc_boolean_t exiting) { ++ dyndb_implementation_t *elem; ++ dyndb_implementation_t *prev; ++ ++ RUNTIME_CHECK(isc_once_do(&once, dyndb_initialize) == ISC_R_SUCCESS); ++ ++ LOCK(&dyndb_lock); ++ elem = TAIL(dyndb_implementations); ++ while (elem != NULL) { ++ prev = PREV(elem, link); ++ UNLINK(dyndb_implementations, elem, link); ++ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, ++ DNS_LOGMODULE_DYNDB, ISC_LOG_INFO, ++ "unloading DynDB instance '%s'", elem->name); ++ elem->destroy_func(&elem->inst); ++ ENSURE(elem->inst == NULL); ++ unload_library(&elem); ++ elem = prev; ++ } ++ UNLOCK(&dyndb_lock); ++ ++ if (exiting == ISC_TRUE) ++ isc_mutex_destroy(&dyndb_lock); ++} ++ ++isc_result_t ++dns_dyndb_createctx(isc_mem_t *mctx, isc_hash_t *hctx, isc_log_t *lctx, ++ dns_view_t *view, dns_zonemgr_t *zmgr, ++ isc_task_t *task, isc_timermgr_t *tmgr, ++ dns_dyndbctx_t **dctxp) { ++ dns_dyndbctx_t *dctx; ++ ++ REQUIRE(dctxp != NULL && *dctxp == NULL); ++ ++ dctx = isc_mem_get(mctx, sizeof(*dctx)); ++ if (dctx == NULL) ++ return (ISC_R_NOMEMORY); ++ ++ memset(dctx, 0, sizeof(*dctx)); ++ if (view != NULL) ++ dns_view_attach(view, &dctx->view); ++ if (zmgr != NULL) ++ dns_zonemgr_attach(zmgr, &dctx->zmgr); ++ if (task != NULL) ++ isc_task_attach(task, &dctx->task); ++ dctx->timermgr = tmgr; ++ dctx->hctx = hctx; ++ dctx->lctx = lctx; ++ dctx->refvar = &isc_lctx; ++ ++ isc_mem_attach(mctx, &dctx->mctx); ++ dctx->magic = DNS_DYNDBCTX_MAGIC; ++ ++ *dctxp = dctx; ++ ++ return (ISC_R_SUCCESS); ++} ++ ++void ++dns_dyndb_destroyctx(dns_dyndbctx_t **dctxp) { ++ dns_dyndbctx_t *dctx; ++ ++ REQUIRE(dctxp != NULL && DNS_DYNDBCTX_VALID(*dctxp)); ++ ++ dctx = *dctxp; ++ *dctxp = NULL; ++ ++ dctx->magic = 0; ++ ++ if (dctx->view != NULL) ++ dns_view_detach(&dctx->view); ++ if (dctx->zmgr != NULL) ++ dns_zonemgr_detach(&dctx->zmgr); ++ if (dctx->task != NULL) ++ isc_task_detach(&dctx->task); ++ dctx->timermgr = NULL; ++ dctx->lctx = NULL; ++ ++ isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx)); ++} +diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in +index 832db46..a37b35e 100644 +--- a/lib/dns/include/dns/Makefile.in ++++ b/lib/dns/include/dns/Makefile.in +@@ -23,8 +23,8 @@ top_srcdir = @top_srcdir@ + + HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \ + clientinfo.h db.h dbiterator.h dbtable.h diff.h dispatch.h \ +- dlz.h dnssec.h ds.h events.h fixedname.h iptable.h journal.h \ +- keyflags.h keytable.h keyvalues.h lib.h log.h \ ++ dlz.h dyndb.h dnssec.h ds.h events.h fixedname.h iptable.h \ ++ journal.h keyflags.h keytable.h keyvalues.h lib.h log.h \ + master.h masterdump.h message.h name.h ncache.h nsec.h \ + peer.h portlist.h private.h rbt.h rcode.h \ + rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ +diff --git a/lib/dns/include/dns/dyndb.h b/lib/dns/include/dns/dyndb.h +new file mode 100644 +index 0000000..832ff27 +--- /dev/null ++++ b/lib/dns/include/dns/dyndb.h +@@ -0,0 +1,166 @@ ++/* ++ * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++ * Copyright (C) 2008-2011 Red Hat, Inc. ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND AUTHORS DISCLAIM ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef DNS_DYNDB_H ++#define DNS_DYNDB_H ++ ++#include <isc/types.h> ++ ++#include <dns/types.h> ++ ++ISC_LANG_BEGINDECLS ++ ++/*! ++ * \brief ++ * Context for intializing a dyndb module. ++ * ++ * This structure passes pointers to globals to which a dyndb ++ * module will need access -- the server memory context, hash ++ * context, log context, etc. The structure doesn't persist ++ * beyond configuring the dyndb module. The module's register function ++ * should attach to all reference-counted variables and its destroy ++ * function should detach from them. ++ */ ++struct dns_dyndbctx { ++ unsigned int magic; ++ isc_mem_t *mctx; ++ isc_hash_t *hctx; ++ isc_log_t *lctx; ++ dns_view_t *view; ++ dns_zonemgr_t *zmgr; ++ isc_task_t *task; ++ isc_timermgr_t *timermgr; ++ void *refvar; ++}; ++ ++#define DNS_DYNDBCTX_MAGIC ISC_MAGIC('D', 'd', 'b', 'c') ++#define DNS_DYNDBCTX_VALID(d) ISC_MAGIC_VALID(d, DNS_DYNDBCTX_MAGIC) ++ ++/* ++ * API version ++ * ++ * When the API changes, increment DNS_DYNDB_VERSION. If the ++ * change is backward-compatible (e.g., adding a new function call ++ * but not changing or removing an old one), increment DNS_DYNDB_AGE; ++ * if not, set DNS_DYNDB_AGE to 0. ++ */ ++#ifndef DNS_DYNDB_VERSION ++#define DNS_DYNDB_VERSION 1 ++#define DNS_DYNDB_AGE 0 ++#endif ++ ++typedef isc_result_t dns_dyndb_register_t(isc_mem_t *mctx, ++ const char *name, ++ const char *parameters, ++ const char *file, ++ unsigned long line, ++ const dns_dyndbctx_t *dctx, ++ void **instp); ++/*% ++ * Called when registering a new driver instance. 'name' must be unique. ++ * 'parameters' contains the driver configuration text. 'dctx' is the ++ * initialization context set up in dns_dyndb_createctx(). ++ * ++ * '*instp' must be set to the driver instance handle if the functino ++ * is successful. ++ * ++ * Returns: ++ *\li #ISC_R_SUCCESS ++ *\li #ISC_R_NOMEMORY ++ *\li Other errors are possible ++ */ ++ ++typedef void dns_dyndb_destroy_t(void **instp); ++/*% ++ * Destroy a driver instance. Dereference any reference-counted ++ * variables passed in 'dctx' and 'inst' in the register function. ++ * ++ * \c *instp must be set to \c NULL by the function before it returns. ++ */ ++ ++typedef int dns_dyndb_version_t(unsigned int *flags); ++/*% ++ * Return the API version number a dyndb module was compiled with. ++ * ++ * If the returned version number is no greater than than ++ * DNS_DYNDB_VERSION, and no less than DNS_DYNDB_VERSION - DNS_DYNDB_AGE, ++ * then the module is API-compatible with named. ++ * ++ * 'flags' is currently unused and may be NULL, but could be used in ++ * the future to pass back driver capabilities or other information. ++ */ ++ ++isc_result_t ++dns_dyndb_load(const char *libname, const char *name, const char *parameters, ++ const char *file, unsigned long line, isc_mem_t *mctx, ++ const dns_dyndbctx_t *dctx); ++/*% ++ * Load a dyndb module. ++ * ++ * This loads a dyndb module using dlopen() or equivalent, calls its register ++ * function (see dns_dyndb_register_t above), and if successful, adds ++ * the instance handle to a list of dyndb instances so it can be cleaned ++ * up later. ++ * ++ * 'file' and 'line' can be used to indicate the name of the file and ++ * the line number from which the parameters were taken, so that logged ++ * error messages, if any, will display the correct locations. ++ * ++ * Returns: ++ *\li #ISC_R_SUCCESS ++ *\li #ISC_R_NOMEMORY ++ *\li Other errors are possible ++ */ ++ ++void ++dns_dyndb_cleanup(isc_boolean_t exiting); ++/*% ++ * Shut down and destroy all running dyndb modules. ++ * ++ * 'exiting' indicates whether the server is shutting down, ++ * as opposed to merely being reconfigured. ++ */ ++ ++isc_result_t ++dns_dyndb_createctx(isc_mem_t *mctx, isc_hash_t *hctx, isc_log_t *lctx, ++ dns_view_t *view, dns_zonemgr_t *zmgr, ++ isc_task_t *task, isc_timermgr_t *tmgr, ++ dns_dyndbctx_t **dctxp); ++/*% ++ * Create a dyndb initialization context structure, with ++ * pointers to structures in the server that the dyndb module will ++ * need to access (view, zone manager, memory context, hash context, ++ * etc). This structure is expected to last only until all dyndb ++ * modules have been loaded and initialized; after that it will be ++ * destroyed with dns_dyndb_destroyctx(). ++ * ++ * Returns: ++ *\li #ISC_R_SUCCESS ++ *\li #ISC_R_NOMEMORY ++ *\li Other errors are possible ++ */ ++ ++void ++dns_dyndb_destroyctx(dns_dyndbctx_t **dctxp); ++/*% ++ * Destroys a dyndb initialization context structure; all ++ * reference-counted members are detached and the structure is freed. ++ */ ++ ++ISC_LANG_ENDDECLS ++ ++#endif /* DNS_DYNDB_H */ +diff --git a/lib/dns/include/dns/log.h b/lib/dns/include/dns/log.h +index e8c8c10..a3b7e5a 100644 +--- a/lib/dns/include/dns/log.h ++++ b/lib/dns/include/dns/log.h +@@ -77,6 +77,7 @@ LIBDNS_EXTERNAL_DATA extern isc_logmodule_t dns_modules[]; + #define DNS_LOGMODULE_DLZ (&dns_modules[26]) + #define DNS_LOGMODULE_DNSSEC (&dns_modules[27]) + #define DNS_LOGMODULE_CRYPTO (&dns_modules[28]) ++#define DNS_LOGMODULE_DYNDB (&dns_modules[29]) + + ISC_LANG_BEGINDECLS + +diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h +index 76167c2..5dc03de 100644 +--- a/lib/dns/include/dns/types.h ++++ b/lib/dns/include/dns/types.h +@@ -60,6 +60,7 @@ typedef struct dns_dbtable dns_dbtable_t; + typedef void dns_dbversion_t; + typedef struct dns_dlzimplementation dns_dlzimplementation_t; + typedef struct dns_dlzdb dns_dlzdb_t; ++typedef struct dns_dyndbctx dns_dyndbctx_t; + typedef struct dns_sdlzimplementation dns_sdlzimplementation_t; + typedef struct dns_decompress dns_decompress_t; + typedef struct dns_dispatch dns_dispatch_t; +diff --git a/lib/dns/lib.c b/lib/dns/lib.c +index df16fa2..da86efd 100644 +--- a/lib/dns/lib.c ++++ b/lib/dns/lib.c +@@ -160,7 +160,9 @@ dns_lib_shutdown(void) { + return; + + dst_lib_destroy(); +- isc_hash_destroy(); ++ ++ if (isc_hashctx != NULL) ++ isc_hash_destroy(); + #ifndef BIND9 + dns_ecdb_unregister(&dbimp); + #endif +diff --git a/lib/dns/log.c b/lib/dns/log.c +index 75e0d79..ff9ca65 100644 +--- a/lib/dns/log.c ++++ b/lib/dns/log.c +@@ -83,6 +83,7 @@ LIBDNS_EXTERNAL_DATA isc_logmodule_t dns_modules[] = { + { "dns/dlz", 0 }, + { "dns/dnssec", 0 }, + { "dns/crypto", 0 }, ++ { "dns/dyndb", 0 }, + { NULL, 0 } + }; + +diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def +index 7661f80..5e20491 100644 +--- a/lib/dns/win32/libdns.def ++++ b/lib/dns/win32/libdns.def +@@ -230,6 +230,10 @@ dns_dnsseckey_destroy + dns_ds_buildrdata + dns_ds_digest_supported + dns_dumpctx_detach ++dns_dyndb_load ++dns_dyndb_cleanup ++dns_dyndb_createctx ++dns_dyndb_destroyctx + dns_fwdtable_add + dns_fwdtable_create + dns_fwdtable_destroy +diff --git a/lib/export/isc/Makefile.in b/lib/export/isc/Makefile.in +index a5f8bd0..4f4a9f7 100644 +--- a/lib/export/isc/Makefile.in ++++ b/lib/export/isc/Makefile.in +@@ -64,8 +64,8 @@ WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ + # Alphabetically + OBJS = @ISC_EXTRA_OBJS@ \ + assertions.@O@ backtrace.@O@ backtrace-emptytbl.@O@ base32.@O@ \ +- base64.@O@ buffer.@O@ bufferlist.@O@ counter.@O@ \ +- error.@O@ event.@O@ \ ++ base64.@O@ buffer.@O@ bufferlist.@O@ commandline.@O@ \ ++ counter.@O@ error.@O@ event.@O@ \ + hash.@O@ hex.@O@ hmacmd5.@O@ hmacsha.@O@ \ + inet_aton.@O@ iterated_hash.@O@ lex.@O@ lfsr.@O@ log.@O@ \ + md5.@O@ mutexblock.@O@ netaddr.@O@ netscope.@O@ \ +@@ -86,7 +86,7 @@ ISCDRIVERSRCS = mem.c task.c lib.c timer.c heap.c + + SRCS = @ISC_EXTRA_SRCS@ \ + assertions.c backtrace.c backtrace-emptytbl.c base32.c \ +- base64.c buffer.c bufferlist.c counter.c \ ++ base64.c buffer.c bufferlist.c counter.c commandline.c \ + error.c event.c \ + hash.c hex.c hmacmd5.c hmacsha.c \ + inet_aton.c iterated_hash.c lex.c log.c lfsr.c \ +diff --git a/lib/isc/Makefile.in b/lib/isc/Makefile.in +index df62ec9..4d3a0af 100644 +--- a/lib/isc/Makefile.in ++++ b/lib/isc/Makefile.in +@@ -37,7 +37,7 @@ CWARNINGS = + + # Alphabetically + UNIXOBJS = @ISC_ISCIPV6_O@ @ISC_ISCPK11_API_O@ \ +- unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ \ ++ unix/app.@O@ unix/dir.@O@ unix/entropy.@O@ unix/errno.@O@ \ + unix/errno2result.@O@ unix/file.@O@ unix/fsaccess.@O@ \ + unix/interfaceiter.@O@ unix/keyboard.@O@ unix/net.@O@ \ + unix/os.@O@ unix/resource.@O@ unix/socket.@O@ unix/stdio.@O@ \ +@@ -49,9 +49,9 @@ THREADOPTOBJS = @ISC_THREAD_DIR@/condition.@O@ @ISC_THREAD_DIR@/mutex.@O@ + + THREADOBJS = @THREADOPTOBJS@ @ISC_THREAD_DIR@/thread.@O@ + +-WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/file.@O@ \ +- win32/fsaccess.@O@ win32/once.@O@ win32/stdtime.@O@ \ +- win32/thread.@O@ win32/time.@O@ ++WIN32OBJS = win32/condition.@O@ win32/dir.@O@ win32/errno.@O@ \ ++ win32/file.@O@ win32/fsaccess.@O@ win32/once.@O@ \ ++ win32/stdtime.@O@ win32/thread.@O@ win32/time.@O@ + + # Alphabetically + OBJS = @ISC_EXTRA_OBJS@ @ISC_PK11_O@ @ISC_PK11_RESULT_O@ \ +diff --git a/lib/isc/commandline.c b/lib/isc/commandline.c +index aca1203..26ad23c 100644 +--- a/lib/isc/commandline.c ++++ b/lib/isc/commandline.c +@@ -68,6 +68,7 @@ + #include <stdio.h> + + #include <isc/commandline.h> ++#include <isc/mem.h> + #include <isc/msgs.h> + #include <isc/string.h> + #include <isc/util.h> +@@ -223,3 +224,62 @@ isc_commandline_parse(int argc, char * const *argv, const char *options) { + + return (isc_commandline_option); + } ++ ++isc_result_t ++isc_commandline_strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, ++ char ***argvp, unsigned int n) ++{ ++ isc_result_t result; ++ ++ restart: ++ /* Discard leading whitespace. */ ++ while (*s == ' ' || *s == '\t') ++ s++; ++ ++ if (*s == '\0') { ++ /* We have reached the end of the string. */ ++ *argcp = n; ++ *argvp = isc_mem_get(mctx, n * sizeof(char *)); ++ if (*argvp == NULL) ++ return (ISC_R_NOMEMORY); ++ } else { ++ char *p = s; ++ while (*p != ' ' && *p != '\t' && *p != '\0' && *p != '{') { ++ if (*p == '\n') { ++ *p = ' '; ++ goto restart; ++ } ++ p++; ++ } ++ ++ /* do "grouping", items between { and } are one arg */ ++ if (*p == '{') { ++ char *t = p; ++ /* ++ * shift all characters to left by 1 to get rid of '{' ++ */ ++ while (*t != '\0') { ++ t++; ++ *(t-1) = *t; ++ } ++ while (*p != '\0' && *p != '}') { ++ p++; ++ } ++ /* get rid of '}' character */ ++ if (*p == '}') { ++ *p = '\0'; ++ p++; ++ } ++ /* normal case, no "grouping" */ ++ } else if (*p != '\0') ++ *p++ = '\0'; ++ ++ result = isc_commandline_strtoargv(mctx, p, ++ argcp, argvp, n + 1); ++ if (result != ISC_R_SUCCESS) ++ return (result); ++ (*argvp)[n] = s; ++ } ++ ++ return (ISC_R_SUCCESS); ++} +diff --git a/lib/isc/hash.c b/lib/isc/hash.c +index f1d68c7..c3712e6 100644 +--- a/lib/isc/hash.c ++++ b/lib/isc/hash.c +@@ -15,8 +15,6 @@ + * PERFORMANCE OF THIS SOFTWARE. + */ + +-/* $Id: hash.c,v 1.16 2009/09/01 00:22:28 jinmei Exp $ */ +- + /*! \file + * Some portion of this code was derived from universal hash function + * libraries of Rice University. +@@ -101,7 +99,8 @@ struct isc_hash { + + static isc_mutex_t createlock; + static isc_once_t once = ISC_ONCE_INIT; +-static isc_hash_t *hash = NULL; ++ ++LIBISC_EXTERNAL_DATA isc_hash_t *isc_hashctx = NULL; + + static unsigned char maptolower[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +@@ -224,14 +223,15 @@ isc_hash_create(isc_mem_t *mctx, isc_entropy_t *entropy, size_t limit) { + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(mctx != NULL); +- INSIST(hash == NULL); ++ INSIST(isc_hashctx == NULL); + + RUNTIME_CHECK(isc_once_do(&once, initialize_lock) == ISC_R_SUCCESS); + + LOCK(&createlock); + +- if (hash == NULL) +- result = isc_hash_ctxcreate(mctx, entropy, limit, &hash); ++ if (isc_hashctx == NULL) ++ result = isc_hash_ctxcreate(mctx, entropy, limit, ++ &isc_hashctx); + + UNLOCK(&createlock); + +@@ -283,9 +283,9 @@ isc_hash_ctxinit(isc_hash_t *hctx) { + + void + isc_hash_init() { +- INSIST(hash != NULL && VALID_HASH(hash)); ++ INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx)); + +- isc_hash_ctxinit(hash); ++ isc_hash_ctxinit(isc_hashctx); + } + + void +@@ -350,12 +350,12 @@ void + isc_hash_destroy() { + unsigned int refs; + +- INSIST(hash != NULL && VALID_HASH(hash)); ++ INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx)); + +- isc_refcount_decrement(&hash->refcnt, &refs); ++ isc_refcount_decrement(&isc_hashctx->refcnt, &refs); + INSIST(refs == 0); + +- destroy(&hash); ++ destroy(&isc_hashctx); + } + + static inline unsigned int +@@ -397,8 +397,8 @@ unsigned int + isc_hash_calc(const unsigned char *key, unsigned int keylen, + isc_boolean_t case_sensitive) + { +- INSIST(hash != NULL && VALID_HASH(hash)); +- REQUIRE(keylen <= hash->limit); ++ INSIST(isc_hashctx != NULL && VALID_HASH(isc_hashctx)); ++ REQUIRE(keylen <= isc_hashctx->limit); + +- return (hash_calc(hash, key, keylen, case_sensitive)); ++ return (hash_calc(isc_hashctx, key, keylen, case_sensitive)); + } +diff --git a/lib/isc/include/isc/Makefile.in b/lib/isc/include/isc/Makefile.in +index 38af3f9..7ca1170 100644 +--- a/lib/isc/include/isc/Makefile.in ++++ b/lib/isc/include/isc/Makefile.in +@@ -27,8 +27,8 @@ top_srcdir = @top_srcdir@ + # install target below. + # + HEADERS = app.h assertions.h base64.h bind9.h bitstring.h boolean.h \ +- buffer.h bufferlist.h commandline.h counter.h entropy.h error.h event.h \ +- eventclass.h file.h formatcheck.h fsaccess.h \ ++ buffer.h bufferlist.h commandline.h counter.h entropy.h errno.h \ ++ error.h event.h eventclass.h file.h formatcheck.h fsaccess.h \ + hash.h heap.h hex.h hmacmd5.h hmacsha.h \ + httpd.h \ + interfaceiter.h @ISC_IPV6_H@ iterated_hash.h lang.h lex.h \ +diff --git a/lib/isc/include/isc/commandline.h b/lib/isc/include/isc/commandline.h +index 384640a..d35ccbf 100644 +--- a/lib/isc/include/isc/commandline.h ++++ b/lib/isc/include/isc/commandline.h +@@ -15,8 +15,6 @@ + * PERFORMANCE OF THIS SOFTWARE. + */ + +-/* $Id: commandline.h,v 1.16 2007/06/19 23:47:18 tbox Exp $ */ +- + #ifndef ISC_COMMANDLINE_H + #define ISC_COMMANDLINE_H 1 + +@@ -25,6 +23,7 @@ + #include <isc/boolean.h> + #include <isc/lang.h> + #include <isc/platform.h> ++#include <isc/result.h> + + /*% Index into parent argv vector. */ + LIBISC_EXTERNAL_DATA extern int isc_commandline_index; +@@ -41,9 +40,22 @@ LIBISC_EXTERNAL_DATA extern isc_boolean_t isc_commandline_reset; + + ISC_LANG_BEGINDECLS + +-/*% parse command line */ + int + isc_commandline_parse(int argc, char * const *argv, const char *options); ++/*%< ++ * Parse a command line (similar to getopt()) ++ */ ++ ++isc_result_t ++isc_commandline_strtoargv(isc_mem_t *mctx, char *s, unsigned int *argcp, ++ char ***argvp, unsigned int n); ++/*%< ++ * Tokenize the string "s" into whitespace-separated words, ++ * returning the number of words in '*argcp' and an array ++ * of pointers to the words in '*argvp'. The caller ++ * must free the array using isc_mem_free(). The string ++ * is modified in-place. ++ */ + + ISC_LANG_ENDDECLS + +diff --git a/lib/isc/include/isc/errno.h b/lib/isc/include/isc/errno.h +new file mode 100644 +index 0000000..47ec90f +--- /dev/null ++++ b/lib/isc/include/isc/errno.h +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ */ ++ ++#ifndef ISC_ERRNO_H ++#define ISC_ERRNO_H 1 ++ ++/*! \file isc/file.h */ ++ ++#include <isc/types.h> ++ ++ISC_LANG_BEGINDECLS ++ ++isc_result_t ++isc_errno_toresult(int err); ++/*!< ++ * \brief Convert a POSIX errno value to an ISC result code. ++ */ ++ISC_LANG_ENDDECLS ++ ++#endif /* ISC_ERRNO_H */ +diff --git a/lib/isc/include/isc/hash.h b/lib/isc/include/isc/hash.h +index ca04b4e..5ef1e4c 100644 +--- a/lib/isc/include/isc/hash.h ++++ b/lib/isc/include/isc/hash.h +@@ -15,8 +15,6 @@ + * PERFORMANCE OF THIS SOFTWARE. + */ + +-/* $Id: hash.h,v 1.12 2009/01/17 23:47:43 tbox Exp $ */ +- + #ifndef ISC_HASH_H + #define ISC_HASH_H 1 + +@@ -81,6 +79,8 @@ + ***/ + ISC_LANG_BEGINDECLS + ++LIBDNS_EXTERNAL_DATA extern isc_hash_t *isc_hashctx; ++ + isc_result_t + isc_hash_ctxcreate(isc_mem_t *mctx, isc_entropy_t *entropy, unsigned int limit, + isc_hash_t **hctx); +diff --git a/lib/isc/include/isc/lex.h b/lib/isc/include/isc/lex.h +index 8612150..6ce1465 100644 +--- a/lib/isc/include/isc/lex.h ++++ b/lib/isc/include/isc/lex.h +@@ -90,6 +90,7 @@ ISC_LANG_BEGINDECLS + #define ISC_LEXOPT_ESCAPE 0x100 /*%< Recognize escapes. */ + #define ISC_LEXOPT_QSTRINGMULTILINE 0x200 /*%< Allow multiline "" strings */ + #define ISC_LEXOPT_OCTAL 0x400 /*%< Expect a octal number. */ ++#define ISC_LEXOPT_BTEXT 0x800 /*%< Bracketed text. */ + /*@}*/ + /*@{*/ + /*! +@@ -122,7 +123,8 @@ typedef enum { + isc_tokentype_eof = 5, + isc_tokentype_initialws = 6, + isc_tokentype_special = 7, +- isc_tokentype_nomore = 8 ++ isc_tokentype_nomore = 8, ++ isc_tokentype_btext = 8 + } isc_tokentype_t; + + typedef union { +@@ -412,6 +414,23 @@ isc_lex_setsourcename(isc_lex_t *lex, const char *name); + * \li #ISC_R_NOTFOUND - there are no sources. + */ + ++isc_result_t ++isc_lex_setsourceline(isc_lex_t *lex, unsigned long line); ++/*%< ++ * Assigns a new line number to the input source. This can be used ++ * when parsing a buffer that's been excerpted from the middle a file, ++ * allowing logged messages to display the correct line number, ++ * rather than the line number within the buffer. ++ * ++ * Requires: ++ * ++ * \li 'lex' is a valid lexer. ++ * ++ * Returns: ++ * \li #ISC_R_SUCCESS ++ * \li #ISC_R_NOTFOUND - there are no sources. ++ */ ++ + isc_boolean_t + isc_lex_isfile(isc_lex_t *lex); + /*%< +diff --git a/lib/isc/lex.c b/lib/isc/lex.c +index 1dc2332..46fec84 100644 +--- a/lib/isc/lex.c ++++ b/lib/isc/lex.c +@@ -62,6 +62,7 @@ struct isc_lex { + unsigned int comments; + isc_boolean_t comment_ok; + isc_boolean_t last_was_eol; ++ unsigned int brace_count; + unsigned int paren_count; + unsigned int saved_paren_count; + isc_lexspecials_t specials; +@@ -110,6 +111,7 @@ isc_lex_create(isc_mem_t *mctx, size_t max_token, isc_lex_t **lexp) { + lex->comments = 0; + lex->comment_ok = ISC_TRUE; + lex->last_was_eol = ISC_TRUE; ++ lex->brace_count = 0; + lex->paren_count = 0; + lex->saved_paren_count = 0; + memset(lex->specials, 0, 256); +@@ -309,7 +311,8 @@ typedef enum { + lexstate_ccomment, + lexstate_ccommentend, + lexstate_eatline, +- lexstate_qstring ++ lexstate_qstring, ++ lexstate_btext + } lexstate; + + #define IWSEOL (ISC_LEXOPT_INITIALWS | ISC_LEXOPT_EOL) +@@ -392,10 +395,17 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { + source->at_eof) + { + if ((options & ISC_LEXOPT_DNSMULTILINE) != 0 && +- lex->paren_count != 0) { ++ lex->paren_count != 0) ++ { + lex->paren_count = 0; + return (ISC_R_UNBALANCED); + } ++ if ((options & ISC_LEXOPT_BTEXT) != 0 && ++ lex->brace_count != 0) ++ { ++ lex->brace_count = 0; ++ return (ISC_R_UNBALANCED); ++ } + if ((options & ISC_LEXOPT_EOF) != 0) { + tokenp->type = isc_tokentype_eof; + return (ISC_R_SUCCESS); +@@ -507,6 +517,12 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { + result = ISC_R_UNBALANCED; + goto done; + } ++ if ((options & ISC_LEXOPT_BTEXT) != 0 && ++ lex->brace_count != 0) { ++ lex->brace_count = 0; ++ result = ISC_R_UNBALANCED; ++ goto done; ++ } + if ((options & ISC_LEXOPT_EOF) == 0) { + result = ISC_R_EOF; + goto done; +@@ -539,21 +555,34 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { + } else if (lex->specials[c]) { + lex->last_was_eol = ISC_FALSE; + if ((c == '(' || c == ')') && +- (options & ISC_LEXOPT_DNSMULTILINE) != 0) { ++ (options & ISC_LEXOPT_DNSMULTILINE) != 0) ++ { + if (c == '(') { + if (lex->paren_count == 0) + options &= ~IWSEOL; + lex->paren_count++; + } else { + if (lex->paren_count == 0) { +- result = ISC_R_UNBALANCED; +- goto done; ++ result = ++ ISC_R_UNBALANCED; ++ goto done; + } + lex->paren_count--; + if (lex->paren_count == 0) +- options = +- saved_options; ++ options = saved_options; ++ } ++ continue; ++ } else if (c == '{' && ++ (options & ISC_LEXOPT_BTEXT) != 0) ++ { ++ if (lex->brace_count != 0) { ++ result = ISC_R_UNBALANCED; ++ goto done; + } ++ lex->brace_count++; ++ options &= ~IWSEOL; ++ state = lexstate_btext; ++ no_comments = ISC_TRUE; + continue; + } + tokenp->type = isc_tokentype_special; +@@ -769,6 +798,55 @@ isc_lex_gettoken(isc_lex_t *lex, unsigned int options, isc_token_t *tokenp) { + remaining--; + } + break; ++ case lexstate_btext: ++ if (c == EOF) { ++ result = ISC_R_UNEXPECTEDEND; ++ goto done; ++ } ++ if (c == '{') { ++ if (escaped) { ++ escaped = ISC_FALSE; ++ } else { ++ lex->brace_count++; ++ } ++ } else if (c == '}') { ++ if (escaped) { ++ escaped = ISC_FALSE; ++ } else { ++ INSIST(lex->brace_count > 0); ++ lex->brace_count--; ++ } ++ ++ if (lex->brace_count == 0) { ++ tokenp->type = isc_tokentype_btext; ++ tokenp->value.as_textregion.base = ++ lex->data; ++ tokenp->value.as_textregion.length = ++ (unsigned int) (lex->max_token - ++ remaining); ++ no_comments = ISC_FALSE; ++ done = ISC_TRUE; ++ break; ++ } ++ } ++ ++ if (c == '\\' && !escaped) ++ escaped = ISC_TRUE; ++ else ++ escaped = ISC_FALSE; ++ ++ if (remaining == 0U) { ++ result = grow_data(lex, &remaining, ++ &curr, &prev); ++ if (result != ISC_R_SUCCESS) ++ goto done; ++ } ++ INSIST(remaining > 0U); ++ prev = curr; ++ *curr++ = c; ++ *curr = '\0'; ++ remaining--; ++ break; + default: + FATAL_ERROR(__FILE__, __LINE__, + isc_msgcat_get(isc_msgcat, ISC_MSGSET_LEX, +@@ -895,7 +973,6 @@ isc_lex_getlasttokentext(isc_lex_t *lex, isc_token_t *tokenp, isc_region_t *r) + source->ignored; + } + +- + char * + isc_lex_getsourcename(isc_lex_t *lex) { + inputsource *source; +@@ -922,7 +999,6 @@ isc_lex_getsourceline(isc_lex_t *lex) { + return (source->line); + } + +- + isc_result_t + isc_lex_setsourcename(isc_lex_t *lex, const char *name) { + inputsource *source; +@@ -932,7 +1008,7 @@ isc_lex_setsourcename(isc_lex_t *lex, const char *name) { + source = HEAD(lex->sources); + + if (source == NULL) +- return(ISC_R_NOTFOUND); ++ return (ISC_R_NOTFOUND); + newname = isc_mem_strdup(lex->mctx, name); + if (newname == NULL) + return (ISC_R_NOMEMORY); +@@ -941,6 +1017,20 @@ isc_lex_setsourcename(isc_lex_t *lex, const char *name) { + return (ISC_R_SUCCESS); + } + ++isc_result_t ++isc_lex_setsourceline(isc_lex_t *lex, unsigned long line) { ++ inputsource *source; ++ ++ REQUIRE(VALID_LEX(lex)); ++ source = HEAD(lex->sources); ++ ++ if (source == NULL) ++ return (ISC_R_NOTFOUND); ++ ++ source->line = line; ++ return (ISC_R_SUCCESS); ++} ++ + isc_boolean_t + isc_lex_isfile(isc_lex_t *lex) { + inputsource *source; +diff --git a/lib/isc/tests/Makefile.in b/lib/isc/tests/Makefile.in +index 564d3cd..f04396e 100644 +--- a/lib/isc/tests/Makefile.in ++++ b/lib/isc/tests/Makefile.in +@@ -12,8 +12,6 @@ + # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + # PERFORMANCE OF THIS SOFTWARE. + +-# $Id$ +- + srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ +@@ -37,13 +35,14 @@ LIBS = @LIBS@ @ATFLIBS@ + OBJS = isctest.@O@ + SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c \ + sockaddr_test.c symtab_test.c task_test.c queue_test.c \ +- parse_test.c pool_test.c regex_test.c safe_test.c ++ parse_test.c pool_test.c regex_test.c safe_test.c \ ++ errno_test.c + + SUBDIRS = + TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \ + sockaddr_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \ + queue_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \ +- regex_test@EXEEXT@ safe_test@EXEEXT@ ++ regex_test@EXEEXT@ safe_test@EXEEXT@ errno_test@EXEEXT@ + + @BIND9_MAKE_RULES@ + +@@ -91,6 +90,10 @@ safe_test@EXEEXT@: safe_test.@O@ ${ISCDEPLIBS} + ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ + safe_test.@O@ ${ISCLIBS} ${LIBS} + ++ ++errno_test@EXEEXT@: errno_test.@O@ ${ISCDEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ ++ errno_test.@O@ ${ISCLIBS} ${LIBS} + unit:: + sh ${top_srcdir}/unit/unittest.sh + +diff --git a/lib/isc/tests/errno_test.c b/lib/isc/tests/errno_test.c +new file mode 100644 +index 0000000..253a857 +--- /dev/null ++++ b/lib/isc/tests/errno_test.c +@@ -0,0 +1,102 @@ ++/* ++ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ */ ++ ++#include <config.h> ++ ++#include <stdio.h> ++#include <sys/errno.h> ++ ++#include <atf-c.h> ++ ++#include <isc/errno.h> ++#include <isc/result.h> ++ ++typedef struct { ++ int err; ++ isc_result_t result; ++} testpair_t; ++ ++testpair_t testpair[] = { ++ { EPERM, ISC_R_NOPERM }, ++ { ENOENT, ISC_R_FILENOTFOUND }, ++ { EIO, ISC_R_IOERROR }, ++ { EBADF, ISC_R_INVALIDFILE }, ++ { ENOMEM, ISC_R_NOMEMORY }, ++ { EACCES, ISC_R_NOPERM }, ++ { EEXIST, ISC_R_FILEEXISTS }, ++ { ENOTDIR, ISC_R_INVALIDFILE }, ++ { EINVAL, ISC_R_INVALIDFILE }, ++ { ENFILE, ISC_R_TOOMANYOPENFILES }, ++ { EMFILE, ISC_R_TOOMANYOPENFILES }, ++ { EPIPE, ISC_R_CONNECTIONRESET }, ++ { ENAMETOOLONG, ISC_R_INVALIDFILE }, ++ { ELOOP, ISC_R_INVALIDFILE }, ++#ifdef EOVERFLOW ++ { EOVERFLOW, ISC_R_RANGE }, ++#endif ++#ifdef EAFNOSUPPORT ++ { EAFNOSUPPORT, ISC_R_FAMILYNOSUPPORT }, ++#endif ++#ifdef EADDRINUSE ++ { EADDRINUSE, ISC_R_ADDRINUSE }, ++#endif ++ { EADDRNOTAVAIL, ISC_R_ADDRNOTAVAIL }, ++#ifdef ENETDOWN ++ { ENETDOWN, ISC_R_NETDOWN }, ++#endif ++#ifdef ENETUNREACH ++ { ENETUNREACH, ISC_R_NETUNREACH }, ++#endif ++#ifdef ECONNABORTED ++ { ECONNABORTED, ISC_R_CONNECTIONRESET }, ++#endif ++#ifdef ECONNRESET ++ { ECONNRESET, ISC_R_CONNECTIONRESET }, ++#endif ++#ifdef ENOBUFS ++ { ENOBUFS, ISC_R_NORESOURCES }, ++#endif ++#ifdef ENOTCONN ++ { ENOTCONN, ISC_R_NOTCONNECTED }, ++#endif ++#ifdef ETIMEDOUT ++ { ETIMEDOUT, ISC_R_TIMEDOUT }, ++#endif ++ { ECONNREFUSED, ISC_R_CONNREFUSED }, ++#ifdef EHOSTDOWN ++ { EHOSTDOWN, ISC_R_HOSTDOWN }, ++#endif ++#ifdef EHOSTUNREACH ++ { EHOSTUNREACH, ISC_R_HOSTUNREACH }, ++#endif ++ { 0, ISC_R_UNEXPECTED } ++}; ++ ++ATF_TC(isc_errno_toresult); ++ATF_TC_HEAD(isc_errno_toresult, tc) { ++ atf_tc_set_md_var(tc, "descr", "convert errno to ISC result"); ++} ++ATF_TC_BODY(isc_errno_toresult, tc) { ++ isc_result_t result, expect; ++ size_t i; ++ ++ for (i = 0; i < sizeof(testpair)/sizeof(testpair[0]); i++) { ++ result = isc_errno_toresult(testpair[i].err); ++ expect = testpair[i].result; ++ ATF_CHECK(result == expect); ++ } ++} ++ ++/* ++ * Main ++ */ ++ATF_TP_ADD_TCS(tp) { ++ ATF_TP_ADD_TC(tp, isc_errno_toresult); ++ return (atf_no_error()); ++} ++ +diff --git a/lib/isc/unix/Makefile.in b/lib/isc/unix/Makefile.in +index 0595fa2..8f32119 100644 +--- a/lib/isc/unix/Makefile.in ++++ b/lib/isc/unix/Makefile.in +@@ -13,8 +13,6 @@ + # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + # PERFORMANCE OF THIS SOFTWARE. + +-# $Id: Makefile.in,v 1.44 2009/12/05 23:31:41 each Exp $ +- + srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ +@@ -30,14 +28,14 @@ CWARNINGS = + + # Alphabetically + OBJS = @ISC_IPV6_O@ @ISC_PK11_API_O@ \ +- app.@O@ dir.@O@ entropy.@O@ errno2result.@O@ file.@O@ \ +- fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \ ++ app.@O@ dir.@O@ entropy.@O@ errno.@O@ errno2result.@O@ \ ++ file.@O@ fsaccess.@O@ interfaceiter.@O@ keyboard.@O@ net.@O@ \ + os.@O@ resource.@O@ socket.@O@ stdio.@O@ stdtime.@O@ \ + strerror.@O@ syslog.@O@ time.@O@ + + # Alphabetically + SRCS = @ISC_IPV6_C@ @ISC_PK11_API_C@ \ +- app.c dir.c entropy.c errno2result.c file.c \ ++ app.c dir.c entropy.c errno.c errno2result.c file.c \ + fsaccess.c interfaceiter.c keyboard.c net.c \ + os.c resource.c socket.c stdio.c stdtime.c \ + strerror.c syslog.c time.c +diff --git a/lib/isc/unix/errno.c b/lib/isc/unix/errno.c +new file mode 100644 +index 0000000..c5f1c56 +--- /dev/null ++++ b/lib/isc/unix/errno.c +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <isc/errno.h> ++#include <isc/util.h> ++ ++#include "errno2result.h" ++ ++isc_result_t ++isc_errno_toresult(int err) { ++ return (isc___errno2result(err, ISC_FALSE, 0, 0)); ++} +diff --git a/lib/isc/unix/errno2result.c b/lib/isc/unix/errno2result.c +index 2951ef8..2309794 100644 +--- a/lib/isc/unix/errno2result.c ++++ b/lib/isc/unix/errno2result.c +@@ -34,7 +34,9 @@ + * not already there. + */ + isc_result_t +-isc___errno2result(int posixerrno, const char *file, unsigned int line) { ++isc___errno2result(int posixerrno, isc_boolean_t dolog, ++ const char *file, unsigned int line) ++{ + char strbuf[ISC_STRERRORSIZE]; + + switch (posixerrno) { +@@ -108,10 +110,12 @@ isc___errno2result(int posixerrno, const char *file, unsigned int line) { + case ECONNREFUSED: + return (ISC_R_CONNREFUSED); + default: +- isc__strerror(posixerrno, strbuf, sizeof(strbuf)); +- UNEXPECTED_ERROR(file, line, "unable to convert errno " +- "to isc_result: %d: %s", +- posixerrno, strbuf); ++ if (dolog) { ++ isc__strerror(posixerrno, strbuf, sizeof(strbuf)); ++ UNEXPECTED_ERROR(file, line, "unable to convert errno " ++ "to isc_result: %d: %s", ++ posixerrno, strbuf); ++ } + /* + * XXXDCL would be nice if perhaps this function could + * return the system's error string, so the caller +diff --git a/lib/isc/unix/errno2result.h b/lib/isc/unix/errno2result.h +index 1e49ed1..9c6b052 100644 +--- a/lib/isc/unix/errno2result.h ++++ b/lib/isc/unix/errno2result.h +@@ -15,8 +15,6 @@ + * PERFORMANCE OF THIS SOFTWARE. + */ + +-/* $Id$ */ +- + #ifndef UNIX_ERRNO2RESULT_H + #define UNIX_ERRNO2RESULT_H 1 + +@@ -31,10 +29,11 @@ + + ISC_LANG_BEGINDECLS + +-#define isc__errno2result(x) isc___errno2result(x, __FILE__, __LINE__) ++#define isc__errno2result(x) isc___errno2result(x, ISC_TRUE, __FILE__, __LINE__) + + isc_result_t +-isc___errno2result(int posixerrno, const char *file, unsigned int line); ++isc___errno2result(int posixerrno, isc_boolean_t dolog, ++ const char *file, unsigned int line); + + ISC_LANG_ENDDECLS + +diff --git a/lib/isc/win32/Makefile.in b/lib/isc/win32/Makefile.in +index c129e31..9cd717d 100644 +--- a/lib/isc/win32/Makefile.in ++++ b/lib/isc/win32/Makefile.in +@@ -13,8 +13,6 @@ + # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + # PERFORMANCE OF THIS SOFTWARE. + +-# $Id: Makefile.in,v 1.14 2009/12/05 23:31:41 each Exp $ +- + srcdir = @srcdir@ + VPATH = @srcdir@ + top_srcdir = @top_srcdir@ +@@ -27,11 +25,11 @@ CDEFINES = + CWARNINGS = + + # Alphabetically +-OBJS = condition.@O@ dir.@O@ file.@O@ fsaccess.@O@ once.@O@ \ +- stdtime.@O@ thread.@O@ time.@O@ ++OBJS = condition.@O@ dir.@O@ errno.@O@ file.@O@ fsaccess.@O@ \ ++ once.@O@ stdtime.@O@ thread.@O@ time.@O@ + + # Alphabetically +-SRCS = condition.c dir.c file.c once.c fsaccess.c \ ++SRCS = condition.c dir.c errno.c file.c once.c fsaccess.c \ + stdtime.c thread.c time.c + + SUBDIRS = include +diff --git a/lib/isc/win32/errno.c b/lib/isc/win32/errno.c +new file mode 100644 +index 0000000..5c45496 +--- /dev/null ++++ b/lib/isc/win32/errno.c +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * This Source Code Form is subject to the terms of the Mozilla Public ++ * License, v. 2.0. If a copy of the MPL was not distributed with this ++ * file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include "errno2result.h" ++ ++isc_result_t ++isc_errno_toresult(int err) { ++ return (isc__errno2resultx(err, ISC_FALSE, 0, 0)); ++} +diff --git a/lib/isc/win32/errno2result.c b/lib/isc/win32/errno2result.c +index c3d54d6..c9a3ab5 100644 +--- a/lib/isc/win32/errno2result.c ++++ b/lib/isc/win32/errno2result.c +@@ -32,7 +32,9 @@ + * not already there. + */ + isc_result_t +-isc__errno2resultx(int posixerrno, const char *file, int line) { ++isc__errno2resultx(int posixerrno, isc_boolean_t dolog, ++ const char *file, int line) ++{ + char strbuf[ISC_STRERRORSIZE]; + + switch (posixerrno) { +@@ -99,9 +101,13 @@ isc__errno2resultx(int posixerrno, const char *file, int line) { + case WSAENOBUFS: + return (ISC_R_NORESOURCES); + default: +- isc__strerror(posixerrno, strbuf, sizeof(strbuf)); +- UNEXPECTED_ERROR(file, line, "unable to convert errno " +- "to isc_result: %d: %s", posixerrno, strbuf); ++ if (dolog) { ++ isc__strerror(posixerrno, strbuf, sizeof(strbuf)); ++ UNEXPECTED_ERROR(file, line, ++ "unable to convert errno " ++ "to isc_result: %d: %s", ++ posixerrno, strbuf); ++ } + /* + * XXXDCL would be nice if perhaps this function could + * return the system's error string, so the caller +diff --git a/lib/isc/win32/errno2result.h b/lib/isc/win32/errno2result.h +index 41682db..cc9115e 100644 +--- a/lib/isc/win32/errno2result.h ++++ b/lib/isc/win32/errno2result.h +@@ -30,10 +30,11 @@ + ISC_LANG_BEGINDECLS + + #define isc__errno2result(posixerrno) \ +- isc__errno2resultx(posixerrno, __FILE__, __LINE__) ++ isc__errno2resultx(posixerrno, ISC_TRUE, __FILE__, __LINE__) + + isc_result_t +-isc__errno2resultx(int posixerrno, const char *file, int line); ++isc__errno2resultx(int posixerrno, isc_boolean_t dolog, ++ const char *file, int line); + + ISC_LANG_ENDDECLS + +diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def +index 0c7a829..d7d2243 100644 +--- a/lib/isc/win32/libisc.def ++++ b/lib/isc/win32/libisc.def +@@ -183,6 +183,7 @@ isc_buffer_reinit + isc_bufferlist_availablecount + isc_bufferlist_usedcount + isc_commandline_parse ++isc_commandline_strtoargv + isc_condition_broadcast + isc_condition_destroy + isc_condition_init +@@ -258,6 +259,7 @@ isc_hash_ctxdetach + isc_hash_ctxinit + isc_hash_destroy + isc_hash_init ++isc_hashctx + isc_heap_create + isc_heap_decreased + isc_heap_delete +diff --git a/lib/isc/win32/libisc.dsp b/lib/isc/win32/libisc.dsp +index 0f14a89..156e23b 100644 +--- a/lib/isc/win32/libisc.dsp ++++ b/lib/isc/win32/libisc.dsp +@@ -115,6 +115,10 @@ SOURCE=.\entropy.c + # End Source File + # Begin Source File + ++SOURCE=.\errno.c ++# End Source File ++# Begin Source File ++ + SOURCE=.\errno2result.c + # End Source File + # Begin Source File +@@ -267,6 +271,10 @@ SOURCE=..\include\isc\entropy.h + # End Source File + # Begin Source File + ++SOURCE=..\include\isc\errno.h ++# End Source File ++# Begin Source File ++ + SOURCE=.\errno2result.h + # End Source File + # Begin Source File +diff --git a/lib/isc/win32/libisc.mak b/lib/isc/win32/libisc.mak +index 96e44e4..5923693 100644 +--- a/lib/isc/win32/libisc.mak ++++ b/lib/isc/win32/libisc.mak +@@ -128,6 +128,7 @@ CLEAN : + -@erase "$(INTDIR)\dir.obj" + -@erase "$(INTDIR)\DLLMain.obj" + -@erase "$(INTDIR)\entropy.obj" ++ -@erase "$(INTDIR)\errno.obj" + -@erase "$(INTDIR)\errno2result.obj" + -@erase "$(INTDIR)\error.obj" + -@erase "$(INTDIR)\event.obj" +@@ -219,6 +220,7 @@ LINK32_OBJS= \ + "$(INTDIR)\dir.obj" \ + "$(INTDIR)\DLLMain.obj" \ + "$(INTDIR)\entropy.obj" \ ++ "$(INTDIR)\errno.obj" \ + "$(INTDIR)\errno2result.obj" \ + "$(INTDIR)\file.obj" \ + "$(INTDIR)\fsaccess.obj" \ +@@ -341,6 +343,8 @@ CLEAN : + -@erase "$(INTDIR)\DLLMain.sbr" + -@erase "$(INTDIR)\entropy.obj" + -@erase "$(INTDIR)\entropy.sbr" ++ -@erase "$(INTDIR)\errno.obj" ++ -@erase "$(INTDIR)\errno.sbr" + -@erase "$(INTDIR)\errno2result.obj" + -@erase "$(INTDIR)\errno2result.sbr" + -@erase "$(INTDIR)\error.obj" +@@ -497,6 +501,7 @@ BSC32_SBRS= \ + "$(INTDIR)\dir.sbr" \ + "$(INTDIR)\DLLMain.sbr" \ + "$(INTDIR)\entropy.sbr" \ ++ "$(INTDIR)\errno.sbr" \ + "$(INTDIR)\errno2result.sbr" \ + "$(INTDIR)\file.sbr" \ + "$(INTDIR)\fsaccess.sbr" \ +@@ -588,6 +593,7 @@ LINK32_OBJS= \ + "$(INTDIR)\dir.obj" \ + "$(INTDIR)\DLLMain.obj" \ + "$(INTDIR)\entropy.obj" \ ++ "$(INTDIR)\errno.obj" \ + "$(INTDIR)\errno2result.obj" \ + "$(INTDIR)\file.obj" \ + "$(INTDIR)\fsaccess.obj" \ +@@ -793,6 +799,23 @@ SOURCE=.\entropy.c + + !ENDIF + ++SOURCE=.\errno.c ++ ++!IF "$(CFG)" == "libisc - @PLATFORM@ Release" ++ ++ ++"$(INTDIR)\errno.obj" : $(SOURCE) "$(INTDIR)" ++ ++ ++!ELSEIF "$(CFG)" == "libisc - @PLATFORM@ Debug" ++ ++ ++"$(INTDIR)\errno.obj" "$(INTDIR)\errno.sbr" : $(SOURCE) "$(INTDIR)" ++ ++ ++!ENDIF ++ ++ + SOURCE=.\errno2result.c + + !IF "$(CFG)" == "libisc - Win32 Release" +diff --git a/lib/isc/win32/socket.c b/lib/isc/win32/socket.c +index f015974..5455dbf 100644 +--- a/lib/isc/win32/socket.c ++++ b/lib/isc/win32/socket.c +@@ -2480,7 +2480,7 @@ SocketIoThread(LPVOID ThreadContext) { + * Did the I/O operation complete? + */ + errstatus = GetLastError(); +- isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__); ++ isc_result = isc__errno2result(errstatus); + + LOCK(&sock->lock); + CONSISTENT(sock); +@@ -2532,7 +2532,7 @@ SocketIoThread(LPVOID ThreadContext) { + goto wait_again; + } else { + errstatus = GetLastError(); +- isc_result = isc__errno2resultx(errstatus, __FILE__, __LINE__); ++ isc_result = isc__errno2result(errstatus); + socket_log(__LINE__, sock, NULL, EVENT, NULL, 0, 0, + "restart_accept() failed: errstatus=%d isc_result=%d", + errstatus, isc_result); +diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h +index 2d7080c..7df760a 100644 +--- a/lib/isccfg/include/isccfg/grammar.h ++++ b/lib/isccfg/include/isccfg/grammar.h +@@ -266,6 +266,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_uint64; + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_qstring; + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring; + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring; ++LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_text; + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr; + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr; + LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr4; +diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c +index 1527575..62fcc96 100644 +--- a/lib/isccfg/namedconf.c ++++ b/lib/isccfg/namedconf.c +@@ -126,6 +126,7 @@ static cfg_type_t cfg_type_zoneopts; + static cfg_type_t cfg_type_dynamically_loadable_zones; + static cfg_type_t cfg_type_dynamically_loadable_zones_opts; + static cfg_type_t cfg_type_v4_aaaa; ++static cfg_type_t cfg_type_dyndb; + + /* + * Clauses that can be found in a 'dynamically loadable zones' statement +@@ -897,6 +898,7 @@ namedconf_or_view_clauses[] = { + { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, + /* only 1 DLZ per view allowed */ + { "dlz", &cfg_type_dynamically_loadable_zones, 0 }, ++ { "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI }, + { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, + { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, + { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, +@@ -1706,6 +1708,22 @@ static cfg_type_t cfg_type_dynamically_loadable_zones_opts = { + }; + + /*% ++ * The "dyndb" statement syntax. ++ */ ++ ++static cfg_tuplefielddef_t dyndb_fields[] = { ++ { "name", &cfg_type_astring, 0 }, ++ { "library", &cfg_type_qstring, 0 }, ++ { "parameters", &cfg_type_bracketed_text, 0 }, ++ { NULL, NULL, 0 } ++}; ++ ++static cfg_type_t cfg_type_dyndb = { ++ "dyndb", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, ++ &cfg_rep_tuple, dyndb_fields ++}; ++ ++/*% + * Clauses that can be found within the 'key' statement. + */ + static cfg_clausedef_t +diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c +index de0fa31..5dc1653 100644 +--- a/lib/isccfg/parser.c ++++ b/lib/isccfg/parser.c +@@ -762,6 +762,42 @@ cfg_parse_astring(cfg_parser_t *pctx, const cfg_type_t *type, + return (result); + } + ++static isc_result_t ++parse_btext(cfg_parser_t *pctx, const cfg_type_t *type, ++ cfg_obj_t **ret) ++{ ++ isc_result_t result; ++ UNUSED(type); ++ ++ CHECK(cfg_gettoken(pctx, ISC_LEXOPT_BTEXT)); ++ if (pctx->token.type != isc_tokentype_btext) { ++ cfg_parser_error(pctx, CFG_LOG_NEAR, ++ "expected bracketed text"); ++ return (ISC_R_UNEXPECTEDTOKEN); ++ } ++ return (create_string(pctx, ++ TOKEN_STRING(pctx), ++ &cfg_type_bracketed_text, ++ ret)); ++ cleanup: ++ return (result); ++} ++ ++static void ++print_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) { ++ cfg_print_cstr(pctx, "{"); ++ cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); ++ print_close(pctx); ++} ++ ++static void ++doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) { ++ UNUSED(type); ++ ++ cfg_print_cstr(pctx, "{ <unspecified text> }"); ++} ++ ++ + isc_boolean_t + cfg_is_enum(const char *s, const char *const *enums) { + const char * const *p; +@@ -855,6 +891,16 @@ cfg_type_t cfg_type_astring = { + }; + + /* ++ * Text enclosed in brackets. Used to pass a block of configuration ++ * text to dynamic library or external application. Checked for ++ * bracket balance, but not otherwise parsed. ++ */ ++cfg_type_t cfg_type_bracketed_text = { ++ "bracketed_text", parse_btext, print_btext, doc_btext, ++ &cfg_rep_string, NULL ++}; ++ ++/* + * Booleans + */ + +-- +2.9.3 + diff --git a/SOURCES/bind99-forward.patch b/SOURCES/bind99-forward.patch new file mode 100644 index 0000000..0392103 --- /dev/null +++ b/SOURCES/bind99-forward.patch @@ -0,0 +1,13 @@ +diff -up bind-9.9.0b2/lib/dns/include/dns/Makefile.in.forward bind-9.9.0b2/lib/dns/include/dns/Makefile.in +--- bind-9.9.0b2/lib/dns/include/dns/Makefile.in.forward 2011-12-07 16:17:50.822438237 +0100 ++++ bind-9.9.0b2/lib/dns/include/dns/Makefile.in 2011-12-07 16:18:00.374455261 +0100 +@@ -31,7 +31,8 @@ HEADERS = acl.h adb.h byaddr.h cache.h c + rdataslab.h rdatatype.h request.h resolver.h result.h \ + rootns.h rpz.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \ + tcpmsg.h time.h tkey.h tsig.h ttl.h types.h \ +- validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h ++ validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h \ ++ forward.h + + GENHEADERS = enumclass.h enumtype.h rdatastruct.h + diff --git a/SOURCES/bind99-libidn4.patch b/SOURCES/bind99-libidn4.patch new file mode 100644 index 0000000..99c1f13 --- /dev/null +++ b/SOURCES/bind99-libidn4.patch @@ -0,0 +1,14 @@ +diff -up bind-9.7.0-P2/bin/dig/dig.docbook.rh811566 bind-9.7.0-P2/bin/dig/dig.docbook +--- bind-9.7.0-P2/bin/dig/dig.docbook.rh811566 2012-06-20 15:50:03.206839118 +0200 ++++ bind-9.7.0-P2/bin/dig/dig.docbook 2012-06-20 15:50:28.368558830 +0200 +@@ -912,8 +912,8 @@ dig +qr www.isc.org any -x 127.0.0.1 isc + <command>dig</command> appropriately converts character encoding of + domain name before sending a request to DNS server or displaying a + reply from the server. +- If you'd like to turn off the IDN support for some reason, defines +- the <envar>IDN_DISABLE</envar> environment variable. ++ If you'd like to turn off the IDN support for some reason, define ++ the <envar>CHARSET=ASCII</envar> environment variable. + The IDN support is disabled if the variable is set when + <command>dig</command> runs. + </para> diff --git a/SOURCES/bind99-rh1067424.patch b/SOURCES/bind99-rh1067424.patch new file mode 100644 index 0000000..9f5faf8 --- /dev/null +++ b/SOURCES/bind99-rh1067424.patch @@ -0,0 +1,41 @@ +From 09f1a6e812c02bd8bf1644e2253e21c26d25613a Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Thu, 20 Feb 2014 11:01:00 +0100 +Subject: [PATCH] check TSIG key ID when receiving NOTIFY + +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + lib/dns/zone.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/lib/dns/zone.c b/lib/dns/zone.c +index 01ff97b..54b7896 100644 +--- a/lib/dns/zone.c ++++ b/lib/dns/zone.c +@@ -11846,6 +11846,8 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, + int match = 0; + isc_netaddr_t netaddr; + isc_sockaddr_t local, remote; ++ dns_tsigkey_t *tsigkey; ++ dns_name_t *tsig; + + REQUIRE(DNS_ZONE_VALID(zone)); + +@@ -11928,10 +11930,12 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from, + + /* + * Accept notify requests from non masters if they are on +- * 'zone->notify_acl'. ++ * 'zone->notify_acl' or if used key ID match the ACLs. + */ ++ tsigkey = dns_message_gettsigkey(msg); ++ tsig = dns_tsigkey_identity(tsigkey); + if (i >= zone->masterscnt && zone->notify_acl != NULL && +- dns_acl_match(&netaddr, NULL, zone->notify_acl, ++ dns_acl_match(&netaddr, tsig, zone->notify_acl, + &zone->view->aclenv, + &match, NULL) == ISC_R_SUCCESS && + match > 0) +-- +1.8.5.3 + diff --git a/SOURCES/bind99-rh1072379.patch b/SOURCES/bind99-rh1072379.patch new file mode 100644 index 0000000..2eb0cc2 --- /dev/null +++ b/SOURCES/bind99-rh1072379.patch @@ -0,0 +1,53 @@ +From 7f5bdf7f4063c2fefb18900468d2c851f8de7816 Mon Sep 17 00:00:00 2001 +From: Evan Hunt <each@isc.org> +Date: Tue, 18 Feb 2014 23:32:02 -0800 +Subject: [PATCH] [master] fix dns_resolver_destroyfetch race + +3747. [bug] A race condition could lead to a core dump when + destroying a resolver fetch object. [RT #35385] +--- + lib/dns/resolver.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index fa188c1..66ab41f 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -357,6 +357,7 @@ typedef struct { + + struct dns_fetch { + unsigned int magic; ++ isc_mem_t * mctx; + fetchctx_t * private; + }; + +@@ -8561,6 +8562,8 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, + fetch = isc_mem_get(res->mctx, sizeof(*fetch)); + if (fetch == NULL) + return (ISC_R_NOMEMORY); ++ fetch->mctx = NULL; ++ isc_mem_attach(res->mctx, &fetch->mctx); + + bucketnum = dns_name_fullhash(name, ISC_FALSE) % res->nbuckets; + +@@ -8651,7 +8654,7 @@ dns_resolver_createfetch2(dns_resolver_t *res, dns_name_t *name, + FTRACE("created"); + *fetchp = fetch; + } else +- isc_mem_put(res->mctx, fetch, sizeof(*fetch)); ++ isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch)); + + return (result); + } +@@ -8742,7 +8745,7 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { + + UNLOCK(&res->buckets[bucketnum].lock); + +- isc_mem_put(res->mctx, fetch, sizeof(*fetch)); ++ isc_mem_putanddetach(&fetch->mctx, fetch, sizeof(*fetch)); + *fetchp = NULL; + + if (bucket_empty) +-- +1.9.0 + diff --git a/SOURCES/bind99-rh1098959.patch b/SOURCES/bind99-rh1098959.patch new file mode 100644 index 0000000..ef4ce0a --- /dev/null +++ b/SOURCES/bind99-rh1098959.patch @@ -0,0 +1,164 @@ +diff -up bind-9.8.2rc1/bin/named/include/named/lwresd.h.lwres_tasks_clients bind-9.8.2rc1/bin/named/include/named/lwresd.h +--- bind-9.8.2rc1/bin/named/include/named/lwresd.h.lwres_tasks_clients 2007-06-20 01:46:59.000000000 +0200 ++++ bind-9.8.2rc1/bin/named/include/named/lwresd.h 2014-05-19 09:41:56.792427201 +0200 +@@ -36,6 +36,8 @@ struct ns_lwresd { + dns_view_t *view; + ns_lwsearchlist_t *search; + unsigned int ndots; ++ unsigned int ntasks; ++ unsigned int nclients; + isc_mem_t *mctx; + isc_boolean_t shutting_down; + unsigned int refs; +diff -up bind-9.8.2rc1/bin/named/lwresd.c.lwres_tasks_clients bind-9.8.2rc1/bin/named/lwresd.c +--- bind-9.8.2rc1/bin/named/lwresd.c.lwres_tasks_clients 2009-09-03 01:48:01.000000000 +0200 ++++ bind-9.8.2rc1/bin/named/lwresd.c 2014-05-19 09:41:56.793427201 +0200 +@@ -60,11 +60,7 @@ + #define LWRESLISTENER_MAGIC ISC_MAGIC('L', 'W', 'R', 'L') + #define VALID_LWRESLISTENER(l) ISC_MAGIC_VALID(l, LWRESLISTENER_MAGIC) + +-/*! +- * The total number of clients we can handle will be NTASKS * NRECVS. +- */ +-#define NTASKS 2 /*%< tasks to create to handle lwres queries */ +-#define NRECVS 2 /*%< max clients per task */ ++#define LWRESD_NCLIENTS_MAX 32768 /*%< max clients per task */ + + typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t; + +@@ -395,6 +391,24 @@ ns_lwdmanager_create(isc_mem_t *mctx, co + } + } + ++ obj = NULL; ++ (void)cfg_map_get(lwres, "lwres-tasks", &obj); ++ if (obj != NULL) ++ lwresd->ntasks = cfg_obj_asuint32(obj); ++ else ++ lwresd->ntasks = ns_g_cpus; ++ ++ obj = NULL; ++ (void)cfg_map_get(lwres, "lwres-clients", &obj); ++ if (obj != NULL) { ++ lwresd->nclients = cfg_obj_asuint32(obj); ++ if (lwresd->nclients > LWRESD_NCLIENTS_MAX) ++ lwresd->nclients = LWRESD_NCLIENTS_MAX; ++ } else if (ns_g_lwresdonly) ++ lwresd->nclients = 1024; ++ else ++ lwresd->nclients = 256; ++ + lwresd->magic = LWRESD_MAGIC; + + *lwresdp = lwresd; +@@ -604,15 +618,24 @@ static isc_result_t + listener_startclients(ns_lwreslistener_t *listener) { + ns_lwdclientmgr_t *cm; + unsigned int i; +- isc_result_t result; ++ isc_result_t result = ISC_R_SUCCESS; ++ ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_LWRESD, ISC_LOG_DEBUG(6), ++ "listener_startclients: creating %d " ++ "managers with %d clients each", ++ listener->manager->ntasks, listener->manager->nclients); + + /* + * Create the client managers. + */ +- result = ISC_R_SUCCESS; +- for (i = 0; i < NTASKS && result == ISC_R_SUCCESS; i++) +- result = ns_lwdclientmgr_create(listener, NRECVS, ++ for (i = 0; i < listener->manager->ntasks; i++) { ++ result = ns_lwdclientmgr_create(listener, ++ listener->manager->nclients, + ns_g_taskmgr); ++ if (result != ISC_R_SUCCESS) ++ break; ++ } + + /* + * Ensure that we have created at least one. +diff -up bind-9.8.2rc1/bin/named/named.conf.docbook.lwres_tasks_clients bind-9.8.2rc1/bin/named/named.conf.docbook +--- bind-9.8.2rc1/bin/named/named.conf.docbook.lwres_tasks_clients 2011-11-07 01:31:47.000000000 +0100 ++++ bind-9.8.2rc1/bin/named/named.conf.docbook 2014-05-19 09:41:56.793427201 +0200 +@@ -185,6 +185,8 @@ lwres { + view <replaceable>string</replaceable> <replaceable>optional_class</replaceable>; + search { <replaceable>string</replaceable>; ... }; + ndots <replaceable>integer</replaceable>; ++ lwres-tasks <replaceable>integer</replaceable>; ++ lwres-clients <replaceable>integer</replaceable>; + }; + </literallayout> + </refsect1> +diff -up bind-9.8.2rc1/doc/arm/Bv9ARM-book.xml.lwres_tasks_clients bind-9.8.2rc1/doc/arm/Bv9ARM-book.xml +--- bind-9.8.2rc1/doc/arm/Bv9ARM-book.xml.lwres_tasks_clients 2014-05-19 09:41:56.770427201 +0200 ++++ bind-9.8.2rc1/doc/arm/Bv9ARM-book.xml 2014-05-19 10:26:40.147380836 +0200 +@@ -2964,7 +2964,12 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2. + be configured to act as a lightweight resolver daemon using the + <command>lwres</command> statement in <filename>named.conf</filename>. + </para> +- ++ <para> ++ The number of client queries that the <command>lwresd</command> ++ daemon is able to serve can be set using the ++ <option>lwres-tasks</option> and <option>lwres-clients</option> ++ statements in the configuration. ++ </para> + </sect1> + </chapter> + +@@ -4959,6 +4964,8 @@ badresp:1,adberr:0,findfail:0,valfail:0] + <optional> view <replaceable>view_name</replaceable>; </optional> + <optional> search { <replaceable>domain_name</replaceable> ; <optional> <replaceable>domain_name</replaceable> ; ... </optional> }; </optional> + <optional> ndots <replaceable>number</replaceable>; </optional> ++ <optional> lwres-tasks <replaceable>number</replaceable>; </optional> ++ <optional> lwres-clients <replaceable>number</replaceable>; </optional> + }; + </programlisting> + +@@ -5017,6 +5024,31 @@ badresp:1,adberr:0,findfail:0,valfail:0] + number of dots in a relative domain name that should result in an + exact match lookup before search path elements are appended. + </para> ++ <para> ++ The <option>lwres-tasks</option> statement specifies the number ++ of worker threads the lightweight resolver will dedicate to serving ++ clients. By default the number is the same as the number of CPUs on ++ the system; this can be overridden using the <option>-n</option> ++ command line option when starting the server. ++ </para> ++ <para> ++ The <option>lwres-clients</option> specifies ++ the number of client objects per thread the lightweight ++ resolver should create to serve client queries. ++ By default, if the lightweight resolver runs as a part ++ of <command>named</command>, 256 client objects are ++ created for each task; if it runs as <command>lwresd</command>, ++ 1024 client objects are created for each thread. The maximum ++ value is 32768; higher values will be silently ignored and ++ the maximum will be used instead. ++ Note that setting too high a value may overconsume ++ system resources. ++ </para> ++ <para> ++ The maximum number of client queries that the lightweight ++ resolver can handle at any one time equals ++ <option>lwres-tasks</option> times <option>lwres-clients</option>. ++ </para> + </sect2> + <sect2> + <title><command>masters</command> Statement Grammar</title> +diff -up bind-9.8.2rc1/lib/isccfg/namedconf.c.lwres_tasks_clients bind-9.8.2rc1/lib/isccfg/namedconf.c +--- bind-9.8.2rc1/lib/isccfg/namedconf.c.lwres_tasks_clients 2014-05-19 09:41:56.771427201 +0200 ++++ bind-9.8.2rc1/lib/isccfg/namedconf.c 2014-05-19 09:41:56.797427201 +0200 +@@ -2563,6 +2563,8 @@ lwres_clauses[] = { + { "view", &cfg_type_lwres_view, 0 }, + { "search", &cfg_type_lwres_searchlist, 0 }, + { "ndots", &cfg_type_uint32, 0 }, ++ { "lwres-tasks", &cfg_type_uint32, 0}, ++ { "lwres-clients", &cfg_type_uint32, 0}, + { NULL, NULL, 0 } + }; + diff --git a/SOURCES/bind99-rh1214827.patch b/SOURCES/bind99-rh1214827.patch new file mode 100644 index 0000000..19c35ac --- /dev/null +++ b/SOURCES/bind99-rh1214827.patch @@ -0,0 +1,408 @@ +From c8cd2cd7f21ce56f93532a6d5f26239e60657acb Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Thu, 25 Jun 2015 14:53:31 +0200 +Subject: [PATCH] nsupdate: Don't extract REAML from ticket, but leave it up to + GSSAPI + +The current implementation of nsupdate does not work correctly with +GSSAPI in cross realm trust scenarios. The realm is currently +extracted from local kerberos ticket instead of letting GSSAPI to +figure out the realm based on the remote nameserver hostname. + +RFC 4752 section 3.1 states that the client should use +GSS_C_NT_HOSTBASED_SERVICE when calling gss_import_name(). + +nsupdate now leaves the realm detection up to GSSAPI, if the realm is +not specified explicitly using the 'realm' option. If the option is +used, the old behavior is preserved. + +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + bin/nsupdate/nsupdate.1 | 3 +- + bin/nsupdate/nsupdate.c | 72 ++++++++----------------------------------- + bin/nsupdate/nsupdate.docbook | 2 +- + bin/nsupdate/nsupdate.html | 2 +- + bin/tests/dst/gsstest.c | 4 +-- + lib/dns/gssapictx.c | 16 +++++++--- + lib/dns/include/dns/tkey.h | 24 +++++++++------ + lib/dns/include/dst/gssapi.h | 8 +++-- + lib/dns/tkey.c | 28 +++++++++-------- + 9 files changed, 65 insertions(+), 94 deletions(-) + +diff --git a/bin/nsupdate/nsupdate.1 b/bin/nsupdate/nsupdate.1 +index 1e2dcaf..c847fb8 100644 +--- a/bin/nsupdate/nsupdate.1 ++++ b/bin/nsupdate/nsupdate.1 +@@ -259,8 +259,7 @@ on the commandline. + .RS 4 + When using GSS\-TSIG use + \fIrealm_name\fR +-rather than the default realm in +-\fIkrb5.conf\fR. If no realm is specified the saved realm is cleared. ++rather than leaving the realm detection up to GSSAPI. If no realm is specified the saved realm is cleared. + .RE + .PP + \fB[prereq]\fR\fB nxdomain\fR {domain\-name} +diff --git a/bin/nsupdate/nsupdate.c b/bin/nsupdate/nsupdate.c +index b901e03..644e3d9 100644 +--- a/bin/nsupdate/nsupdate.c ++++ b/bin/nsupdate/nsupdate.c +@@ -2489,57 +2489,6 @@ sendrequest(isc_sockaddr_t *srcaddr, isc_sockaddr_t *destaddr, + + #ifdef GSSAPI + +-/* +- * Get the realm from the users kerberos ticket if possible +- */ +-static void +-get_ticket_realm(isc_mem_t *mctx) +-{ +- krb5_context ctx; +- krb5_error_code rc; +- krb5_ccache ccache; +- krb5_principal princ; +- char *name, *ticket_realm; +- +- rc = krb5_init_context(&ctx); +- if (rc != 0) +- return; +- +- rc = krb5_cc_default(ctx, &ccache); +- if (rc != 0) { +- krb5_free_context(ctx); +- return; +- } +- +- rc = krb5_cc_get_principal(ctx, ccache, &princ); +- if (rc != 0) { +- krb5_cc_close(ctx, ccache); +- krb5_free_context(ctx); +- return; +- } +- +- rc = krb5_unparse_name(ctx, princ, &name); +- if (rc != 0) { +- krb5_free_principal(ctx, princ); +- krb5_cc_close(ctx, ccache); +- krb5_free_context(ctx); +- return; +- } +- +- ticket_realm = strrchr(name, '@'); +- if (ticket_realm != NULL) { +- realm = isc_mem_strdup(mctx, ticket_realm); +- } +- +- free(name); +- krb5_free_principal(ctx, princ); +- krb5_cc_close(ctx, ccache); +- krb5_free_context(ctx); +- if (realm != NULL && debugging) +- fprintf(stderr, "Found realm from ticket: %s\n", realm+1); +-} +- +- + static void + start_gssrequest(dns_name_t *master) { + gss_ctx_id_t context; +@@ -2580,11 +2529,15 @@ start_gssrequest(dns_name_t *master) { + dns_fixedname_init(&fname); + servname = dns_fixedname_name(&fname); + +- if (realm == NULL) +- get_ticket_realm(mctx); +- +- result = isc_string_printf(servicename, sizeof(servicename), +- "DNS/%s%s", namestr, realm ? realm : ""); ++ if (realm != NULL) { ++ /* Use explicit REALM passed as argument */ ++ result = isc_string_printf(servicename, sizeof(servicename), ++ "DNS/%s%s", namestr, realm); ++ } else { ++ /* Use service@host as advised in RFC4752 section 3.1 */ ++ result = isc_string_printf(servicename, sizeof(servicename), ++ "DNS@%s", namestr); ++ } + if (result != ISC_R_SUCCESS) + fatal("isc_string_printf(servicename) failed: %s", + isc_result_totext(result)); +@@ -2623,9 +2576,9 @@ start_gssrequest(dns_name_t *master) { + + /* Build first request. */ + context = GSS_C_NO_CONTEXT; +- result = dns_tkey_buildgssquery(rmsg, keyname, servname, NULL, 0, +- &context, use_win2k_gsstsig, +- mctx, &err_message); ++ result = dns_tkey_buildgssquery(rmsg, keyname, servname, ++ realm != NULL ? ISC_TRUE : ISC_FALSE, NULL, 0, ++ &context, use_win2k_gsstsig, mctx, &err_message); + if (result == ISC_R_FAILURE) + fatal("tkey query failed: %s", + err_message != NULL ? err_message : "unknown error"); +@@ -2765,6 +2718,7 @@ recvgss(isc_task_t *task, isc_event_t *event) { + + tsigkey = NULL; + result = dns_tkey_gssnegotiate(tsigquery, rcvmsg, servname, ++ realm != NULL ? ISC_TRUE : ISC_FALSE, + &context, &tsigkey, gssring, + use_win2k_gsstsig, + &err_message); +diff --git a/bin/nsupdate/nsupdate.docbook b/bin/nsupdate/nsupdate.docbook +index c54211c..bbcc681 100644 +--- a/bin/nsupdate/nsupdate.docbook ++++ b/bin/nsupdate/nsupdate.docbook +@@ -418,7 +418,7 @@ + <listitem> + <para> + When using GSS-TSIG use <parameter>realm_name</parameter> rather +- than the default realm in <filename>krb5.conf</filename>. If no ++ than leaving the realm detection up to GSSAPI. If no + realm is specified the saved realm is cleared. + </para> + </listitem> +diff --git a/bin/nsupdate/nsupdate.html b/bin/nsupdate/nsupdate.html +index 276d4af..9c0eba0 100644 +--- a/bin/nsupdate/nsupdate.html ++++ b/bin/nsupdate/nsupdate.html +@@ -327,7 +327,7 @@ + </span></dt> + <dd><p> + When using GSS-TSIG use <em class="parameter"><code>realm_name</code></em> rather +- than the default realm in <code class="filename">krb5.conf</code>. If no ++ than leaving the realm detection up to GSSAPI. If no + realm is specified the saved realm is cleared. + </p></dd> + <dt><span class="term"> +diff --git a/bin/tests/dst/gsstest.c b/bin/tests/dst/gsstest.c +index c1296f7..7c85d0b 100755 +--- a/bin/tests/dst/gsstest.c ++++ b/bin/tests/dst/gsstest.c +@@ -309,7 +309,7 @@ initctx2(isc_task_t *task, isc_event_t *event) { + printf("Received token from server, calling gss_init_sec_context()\n"); + isc_buffer_init(&outtoken, array, DNS_NAME_MAXTEXT + 1); + result = dns_tkey_processgssresponse(query, response, +- dns_fixedname_name(&gssname), ++ dns_fixedname_name(&gssname), ISC_FALSE, + &gssctx, &outtoken, + &tsigkey, ring, NULL); + gssctx = *gssctxp; +@@ -396,7 +396,7 @@ initctx1(isc_task_t *task, isc_event_t *event) { + printf("Calling gss_init_sec_context()\n"); + gssctx = GSS_C_NO_CONTEXT; + result = dns_tkey_buildgssquery(query, dns_fixedname_name(&servername), +- dns_fixedname_name(&gssname), ++ dns_fixedname_name(&gssname), ISC_FALSE, + NULL, 36000, &gssctx, ISC_TRUE, + mctx, NULL); + CHECK("dns_tkey_buildgssquery", result); +diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c +index aeaeb85..21222e0 100644 +--- a/lib/dns/gssapictx.c ++++ b/lib/dns/gssapictx.c +@@ -558,14 +558,15 @@ gss_err_message(isc_mem_t *mctx, isc_uint32_t major, isc_uint32_t minor, + #endif + + isc_result_t +-dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, +- isc_buffer_t *outtoken, gss_ctx_id_t *gssctx, +- isc_mem_t *mctx, char **err_message) ++dst_gssapi_initctx(dns_name_t *name, isc_boolean_t explicit_realm, ++ isc_buffer_t *intoken, isc_buffer_t *outtoken, ++ gss_ctx_id_t *gssctx, isc_mem_t *mctx, char **err_message) + { + #ifdef GSSAPI + isc_region_t r; + isc_buffer_t namebuf; + gss_name_t gname; ++ gss_OID gname_type; + OM_uint32 gret, minor, ret_flags, flags; + gss_buffer_desc gintoken, *gintokenp, gouttoken = GSS_C_EMPTY_BUFFER; + isc_result_t result; +@@ -580,7 +581,13 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, + name_to_gbuffer(name, &namebuf, &gnamebuf); + + /* Get the name as a GSS name */ +- gret = gss_import_name(&minor, &gnamebuf, GSS_C_NO_OID, &gname); ++ if (explicit_realm == ISC_TRUE) { ++ gname_type = GSS_C_NO_OID; ++ } else { ++ gname_type = GSS_C_NT_HOSTBASED_SERVICE; ++ } ++ ++ gret = gss_import_name(&minor, &gnamebuf, gname_type, &gname); + if (gret != GSS_S_COMPLETE) { + gss_err_message(mctx, gret, minor, err_message); + result = ISC_R_FAILURE; +@@ -642,6 +649,7 @@ dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, + return (result); + #else + UNUSED(name); ++ UNUSED(explicit_realm); + UNUSED(intoken); + UNUSED(outtoken); + UNUSED(gssctx); +diff --git a/lib/dns/include/dns/tkey.h b/lib/dns/include/dns/tkey.h +index 0dcec1e..a0e6c2a 100644 +--- a/lib/dns/include/dns/tkey.h ++++ b/lib/dns/include/dns/tkey.h +@@ -123,9 +123,9 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, + + isc_result_t + dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, +- isc_buffer_t *intoken, isc_uint32_t lifetime, +- gss_ctx_id_t *context, isc_boolean_t win2k, +- isc_mem_t *mctx, char **err_message); ++ isc_boolean_t explicit_realm, isc_buffer_t *intoken, ++ isc_uint32_t lifetime, gss_ctx_id_t *context, ++ isc_boolean_t win2k, isc_mem_t *mctx, char **err_message); + /*%< + * Builds a query containing a TKEY that will generate a GSSAPI context. + * The key is requested to have the specified lifetime (in seconds). +@@ -134,6 +134,8 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, + *\li 'msg' is a valid message + *\li 'name' is a valid name + *\li 'gname' is a valid name ++ *\li 'explicit_realm' ISC_TRUE if an explicit realm is used, ++ * ISC_FALSE if the realm detection is left up to GSSAPI. + *\li 'context' is a pointer to a valid gss_ctx_id_t + * (which may have the value GSS_C_NO_CONTEXT) + *\li 'win2k' when true says to turn on some hacks to work +@@ -188,9 +190,10 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, + + isc_result_t + dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, +- dns_name_t *gname, gss_ctx_id_t *context, +- isc_buffer_t *outtoken, dns_tsigkey_t **outkey, +- dns_tsig_keyring_t *ring, char **err_message); ++ dns_name_t *gname, isc_boolean_t explicit_realm, ++ gss_ctx_id_t *context, isc_buffer_t *outtoken, ++ dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, ++ char **err_message); + /*%< + * XXX + */ +@@ -216,9 +219,10 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, + + isc_result_t + dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, +- dns_name_t *server, gss_ctx_id_t *context, +- dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, +- isc_boolean_t win2k, char **err_message); ++ dns_name_t *server, isc_boolean_t explicit_realm, ++ gss_ctx_id_t *context, dns_tsigkey_t **outkey, ++ dns_tsig_keyring_t *ring, isc_boolean_t win2k, ++ char **err_message); + + /* + * Client side negotiation of GSS-TSIG. Process the response +@@ -231,6 +235,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, + * it will be filled with the new message to send + * 'rmsg' is a valid message, the incoming TKEY message + * 'server' is the server name ++ * 'explicit_realm' ISC_TRUE if an explicit realm is used, ++ * ISC_FALSE if the realm detection is left up to GSSAPI. + * 'context' is the input context handle + * 'outkey' receives the established key, if non-NULL; + * if non-NULL must point to NULL +diff --git a/lib/dns/include/dst/gssapi.h b/lib/dns/include/dst/gssapi.h +index 1e81a55..d093fa3 100644 +--- a/lib/dns/include/dst/gssapi.h ++++ b/lib/dns/include/dst/gssapi.h +@@ -93,15 +93,17 @@ dst_gssapi_releasecred(gss_cred_id_t *cred); + */ + + isc_result_t +-dst_gssapi_initctx(dns_name_t *name, isc_buffer_t *intoken, +- isc_buffer_t *outtoken, gss_ctx_id_t *gssctx, +- isc_mem_t *mctx, char **err_message); ++dst_gssapi_initctx(dns_name_t *name, isc_boolean_t explicit_realm, ++ isc_buffer_t *intoken, isc_buffer_t *outtoken, ++ gss_ctx_id_t *gssctx, isc_mem_t *mctx, char **err_message); + /* + * Initiates a GSS context. + * + * Requires: + * 'name' is a valid name, preferably one known by the GSS + * provider ++ * 'explicit_realm' True if the REALM is explicitly included in the 'name', ++ * otherwise leave the REALM detection up to GSSAPI + * 'intoken' is a token received from the acceptor, or NULL if + * there isn't one + * 'outtoken' is a buffer to receive the token generated by +diff --git a/lib/dns/tkey.c b/lib/dns/tkey.c +index 20c98e5..3463d3a 100644 +--- a/lib/dns/tkey.c ++++ b/lib/dns/tkey.c +@@ -1016,9 +1016,9 @@ dns_tkey_builddhquery(dns_message_t *msg, dst_key_t *key, dns_name_t *name, + + isc_result_t + dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, +- isc_buffer_t *intoken, isc_uint32_t lifetime, +- gss_ctx_id_t *context, isc_boolean_t win2k, +- isc_mem_t *mctx, char **err_message) ++ isc_boolean_t explicit_realm, isc_buffer_t *intoken, ++ isc_uint32_t lifetime, gss_ctx_id_t *context, ++ isc_boolean_t win2k, isc_mem_t *mctx, char **err_message) + { + dns_rdata_tkey_t tkey; + isc_result_t result; +@@ -1035,7 +1035,7 @@ dns_tkey_buildgssquery(dns_message_t *msg, dns_name_t *name, dns_name_t *gname, + REQUIRE(mctx != NULL); + + isc_buffer_init(&token, array, sizeof(array)); +- result = dst_gssapi_initctx(gname, NULL, &token, context, ++ result = dst_gssapi_initctx(gname, explicit_realm, NULL, &token, context, + mctx, err_message); + if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) + return (result); +@@ -1251,9 +1251,10 @@ dns_tkey_processdhresponse(dns_message_t *qmsg, dns_message_t *rmsg, + + isc_result_t + dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, +- dns_name_t *gname, gss_ctx_id_t *context, +- isc_buffer_t *outtoken, dns_tsigkey_t **outkey, +- dns_tsig_keyring_t *ring, char **err_message) ++ dns_name_t *gname, isc_boolean_t explicit_realm, ++ gss_ctx_id_t *context, isc_buffer_t *outtoken, ++ dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, ++ char **err_message) + { + dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; + dns_name_t *tkeyname; +@@ -1304,7 +1305,7 @@ dns_tkey_processgssresponse(dns_message_t *qmsg, dns_message_t *rmsg, + + isc_buffer_init(outtoken, array, sizeof(array)); + isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); +- RETERR(dst_gssapi_initctx(gname, &intoken, outtoken, context, ++ RETERR(dst_gssapi_initctx(gname, explicit_realm, &intoken, outtoken, context, + ring->mctx, err_message)); + + RETERR(dst_key_fromgssapi(dns_rootname, *context, rmsg->mctx, +@@ -1384,9 +1385,10 @@ dns_tkey_processdeleteresponse(dns_message_t *qmsg, dns_message_t *rmsg, + + isc_result_t + dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, +- dns_name_t *server, gss_ctx_id_t *context, +- dns_tsigkey_t **outkey, dns_tsig_keyring_t *ring, +- isc_boolean_t win2k, char **err_message) ++ dns_name_t *server, isc_boolean_t explicit_realm, ++ gss_ctx_id_t *context, dns_tsigkey_t **outkey, ++ dns_tsig_keyring_t *ring, isc_boolean_t win2k, ++ char **err_message) + { + dns_rdata_t rtkeyrdata = DNS_RDATA_INIT, qtkeyrdata = DNS_RDATA_INIT; + dns_name_t *tkeyname; +@@ -1430,8 +1432,8 @@ dns_tkey_gssnegotiate(dns_message_t *qmsg, dns_message_t *rmsg, + isc_buffer_init(&intoken, rtkey.key, rtkey.keylen); + isc_buffer_init(&outtoken, array, sizeof(array)); + +- result = dst_gssapi_initctx(server, &intoken, &outtoken, context, +- ring->mctx, err_message); ++ result = dst_gssapi_initctx(server, explicit_realm, &intoken, &outtoken, ++ context, ring->mctx, err_message); + if (result != DNS_R_CONTINUE && result != ISC_R_SUCCESS) + return (result); + +-- +2.4.3 + diff --git a/SOURCES/bind99-rh1215164.patch b/SOURCES/bind99-rh1215164.patch new file mode 100644 index 0000000..80bef02 --- /dev/null +++ b/SOURCES/bind99-rh1215164.patch @@ -0,0 +1,178 @@ +diff --git a/bin/check/named-checkzone.8 b/bin/check/named-checkzone.8 +index 8538ca8..0ab0049 100644 +--- a/bin/check/named-checkzone.8 ++++ b/bin/check/named-checkzone.8 +@@ -251,7 +251,7 @@ so that include directives in the configuration file are processed as if run by + .PP + \-T \fImode\fR + .RS 4 +-Check if Sender Policy Framework records (TXT and SPF) both exist or both don't exist. A warning is issued if they don't match. Possible modes are ++Check if Sender Policy Framework (SPF) records exist and issues a warning if an SPF-formatted TXT record is not also present. Possible modes are + \fB"warn"\fR + (default), + \fB"ignore"\fR. +diff --git a/bin/check/named-checkzone.docbook b/bin/check/named-checkzone.docbook +index ea37fa2..e78d574 100644 +--- a/bin/check/named-checkzone.docbook ++++ b/bin/check/named-checkzone.docbook +@@ -408,10 +408,10 @@ + <term>-T <replaceable class="parameter">mode</replaceable></term> + <listitem> + <para> +- Check if Sender Policy Framework records (TXT and SPF) +- both exist or both don't exist. A warning is issued +- if they don't match. Possible modes are +- <command>"warn"</command> (default), <command>"ignore"</command>. ++ Check if Sender Policy Framework (SPF) records exist ++ and issues a warning if an SPF-formatted TXT record is ++ not also present. Possible modes are <command>"warn"</command> ++ (default), <command>"ignore"</command>. + </para> + </listitem> + </varlistentry> +diff --git a/bin/tests/system/checkzone/tests.sh b/bin/tests/system/checkzone/tests.sh +index 2353c14..7d9192e 100644 +--- a/bin/tests/system/checkzone/tests.sh ++++ b/bin/tests/system/checkzone/tests.sh +@@ -44,12 +44,12 @@ echo "I:checking with spf warnings ($n)" + ret=0 + $CHECKZONE example zones/spf.db > test.out1.$n 2>&1 || ret=1 + $CHECKZONE -T ignore example zones/spf.db > test.out2.$n 2>&1 || ret=1 +-grep "'x.example' found SPF/TXT" test.out1.$n > /dev/null || ret=1 +-grep "'y.example' found SPF/SPF" test.out1.$n > /dev/null || ret=1 +-grep "'example' found SPF/" test.out1.$n > /dev/null && ret=1 +-grep "'x.example' found SPF/" test.out2.$n > /dev/null && ret=1 +-grep "'y.example' found SPF/" test.out2.$n > /dev/null && ret=1 +-grep "'example' found SPF/" test.out2.$n > /dev/null && ret=1 ++grep "'x.example' found type SPF" test.out1.$n > /dev/null && ret=1 ++grep "'y.example' found type SPF" test.out1.$n > /dev/null || ret=1 ++grep "'example' found type SPF" test.out1.$n > /dev/null && ret=1 ++grep "'x.example' found type SPF" test.out2.$n > /dev/null && ret=1 ++grep "'y.example' found type SPF" test.out2.$n > /dev/null && ret=1 ++grep "'example' found type SPF" test.out2.$n > /dev/null && ret=1 + n=`expr $n + 1` + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` +diff --git a/bin/tests/system/spf/tests.sh b/bin/tests/system/spf/tests.sh +index 6acd283..3da6e2e 100644 +--- a/bin/tests/system/spf/tests.sh ++++ b/bin/tests/system/spf/tests.sh +@@ -24,19 +24,16 @@ echo "I:checking that SPF warnings have been correctly generated ($n)" + ret=0 + + grep "zone spf/IN: loaded serial 0" ns1/named.run > /dev/null || ret=1 +-grep "'x.spf' found SPF/TXT" ns1/named.run > /dev/null || ret=1 +-grep "'y.spf' found SPF/SPF" ns1/named.run > /dev/null || ret=1 +-grep "'spf' found SPF/" ns1/named.run > /dev/null && ret=1 ++grep "'y.spf' found type SPF" ns1/named.run > /dev/null || ret=1 ++grep "'spf' found type SPF" ns1/named.run > /dev/null && ret=1 + + grep "zone warn/IN: loaded serial 0" ns1/named.run > /dev/null || ret=1 +-grep "'x.warn' found SPF/TXT" ns1/named.run > /dev/null || ret=1 +-grep "'y.warn' found SPF/SPF" ns1/named.run > /dev/null || ret=1 +-grep "'warn' found SPF/" ns1/named.run > /dev/null && ret=1 ++grep "'y.warn' found type SPF" ns1/named.run > /dev/null || ret=1 ++grep "'warn' found type SPF" ns1/named.run > /dev/null && ret=1 + + grep "zone nowarn/IN: loaded serial 0" ns1/named.run > /dev/null || ret=1 +-grep "'x.nowarn' found SPF/" ns1/named.run > /dev/null && ret=1 +-grep "'y.nowarn' found SPF/" ns1/named.run > /dev/null && ret=1 +-grep "'nowarn' found SPF/" ns1/named.run > /dev/null && ret=1 ++grep "'y.nowarn' found type SPF" ns1/named.run > /dev/null && ret=1 ++grep "'nowarn' found type SPF" ns1/named.run > /dev/null && ret=1 + n=`expr $n + 1` + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index 96c9faf..bd42e11 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -4750,7 +4750,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] + <optional> check-mx-cname ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional> + <optional> check-srv-cname ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional> + <optional> check-sibling <replaceable>yes_or_no</replaceable>; </optional> +- <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional> ++ <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>ignore</replaceable> ); </optional> + <optional> allow-new-zones { <replaceable>yes_or_no</replaceable> }; </optional> + <optional> allow-notify { <replaceable>address_match_list</replaceable> }; </optional> + <optional> allow-query { <replaceable>address_match_list</replaceable> }; </optional> +@@ -6573,10 +6573,13 @@ options { + The default is <command>yes</command>. + </para> + <para> +- Check that the two forms of Sender Policy Framework +- records (TXT records starting with "v=spf1" and SPF) either +- both exist or both don't exist. Warnings are +- emitted it they don't and be suppressed with ++ The use of the SPF record for publishing Sender ++ Policy Framework is deprecated as the migration ++ from using TXT records to SPF records was abandoned. ++ Enabling this option also checks that a TXT Sender ++ Policy Framework record exists (starts with "v=spf1") ++ if there is an SPF record. Warnings are emitted if the ++ TXT record does not exist and can be suppressed with + <command>check-spf</command>. + </para> + </listitem> +@@ -6618,11 +6621,11 @@ options { + <term><command>check-spf</command></term> + <listitem> + <para> +- When performing integrity checks, check that the +- two forms of Sender Policy Framwork records (TXT +- records starting with "v=spf1" and SPF) both exist +- or both don't exist and issue a warning if not +- met. The default is <command>warn</command>. ++ If <command>check-integrity</command> is set then ++ check that there is a TXT Sender Policy Framework ++ record present (starts with "v=spf1") if there is an ++ SPF record present. The default is ++ <command>warn</command>. + </para> + </listitem> + </varlistentry> +@@ -10372,7 +10375,7 @@ view "external" { + <optional> check-names (<constant>warn</constant>|<constant>fail</constant>|<constant>ignore</constant>) ; </optional> + <optional> check-mx (<constant>warn</constant>|<constant>fail</constant>|<constant>ignore</constant>) ; </optional> + <optional> check-wildcard <replaceable>yes_or_no</replaceable>; </optional> +- <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>fail</replaceable> | <replaceable>ignore</replaceable> ); </optional> ++ <optional> check-spf ( <replaceable>warn</replaceable> | <replaceable>ignore</replaceable> ); </optional> + <optional> check-integrity <replaceable>yes_or_no</replaceable> ; </optional> + <optional> dialup <replaceable>dialup_option</replaceable> ; </optional> + <optional> file <replaceable>string</replaceable> ; </optional> +diff --git a/lib/dns/zone.c b/lib/dns/zone.c +index 86fad98..08c6d10 100644 +--- a/lib/dns/zone.c ++++ b/lib/dns/zone.c +@@ -2612,8 +2612,8 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) { + + checkspf: + /* +- * Check if there is a type TXT spf record without a type SPF +- * RRset being present. ++ * Check if there is a type SPF record without an ++ * SPF-formatted type TXT record also being present. + */ + if (!DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKSPF)) + goto next; +@@ -2642,16 +2642,13 @@ integrity_checks(dns_zone_t *zone, dns_db_t *db) { + dns_rdataset_disassociate(&rdataset); + + notxt: +- if (have_spf != have_txt) { ++ if (have_spf && !have_txt) { + char namebuf[DNS_NAME_FORMATSIZE]; +- const char *found = have_txt ? "TXT" : "SPF"; +- const char *need = have_txt ? "SPF" : "TXT"; + + dns_name_format(name, namebuf, sizeof(namebuf)); +- dns_zone_log(zone, ISC_LOG_WARNING, "'%s' found SPF/%s " +- "record but no SPF/%s record found, add " +- "matching type %s record", namebuf, found, +- need, need); ++ dns_zone_log(zone, ISC_LOG_WARNING, "'%s' found type " ++ "SPF record but no SPF TXT record found, " ++ "add matching type TXT record", namebuf); + } + + next: diff --git a/SOURCES/bind99-rh1215687-limits.patch b/SOURCES/bind99-rh1215687-limits.patch new file mode 100644 index 0000000..7922b7e --- /dev/null +++ b/SOURCES/bind99-rh1215687-limits.patch @@ -0,0 +1,67 @@ +diff -up bind-9.9.4/bin/named/interfacemgr.c.rh1215687-limits bind-9.9.4/bin/named/interfacemgr.c +--- bind-9.9.4/bin/named/interfacemgr.c.rh1215687-limits 2015-05-20 16:08:21.286007013 +0200 ++++ bind-9.9.4/bin/named/interfacemgr.c 2015-05-20 16:21:49.227001713 +0200 +@@ -275,7 +275,7 @@ ns_interface_listenudp(ns_interface_t *i + result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr, + ns_g_socketmgr, + ns_g_taskmgr, &ifp->addr, +- 4096, 1000, 32768, 8219, 8237, ++ 4096, 32768, 32768, 8219, 8237, + attrs, attrmask, + &ifp->udpdispatch[disp], + disp == 0 +diff -up bind-9.9.4/bin/named/server.c.rh1215687-limits bind-9.9.4/bin/named/server.c +--- bind-9.9.4/bin/named/server.c.rh1215687-limits 2015-05-20 16:08:21.272006979 +0200 ++++ bind-9.9.4/bin/named/server.c 2015-05-20 16:08:21.288007018 +0200 +@@ -992,7 +992,7 @@ get_view_querysource_dispatch(const cfg_ + } + if (isc_sockaddr_getport(&sa) == 0) { + attrs |= DNS_DISPATCHATTR_EXCLUSIVE; +- maxdispatchbuffers = 4096; ++ maxdispatchbuffers = 32768; + } else { + INSIST(obj != NULL); + if (is_firstview) { +@@ -1001,7 +1001,7 @@ get_view_querysource_dispatch(const cfg_ + "suppresses port randomization and can be " + "insecure."); + } +- maxdispatchbuffers = 1000; ++ maxdispatchbuffers = 32768; + } + + attrmask = 0; +@@ -6491,7 +6491,7 @@ ns_add_reserved_dispatch(ns_server_t *se + + result = dns_dispatch_getudp(ns_g_dispatchmgr, ns_g_socketmgr, + ns_g_taskmgr, &dispatch->addr, 4096, +- 1000, 32768, 16411, 16433, ++ 32768, 32768, 16411, 16433, + attrs, attrmask, &dispatch->dispatch); + if (result != ISC_R_SUCCESS) + goto cleanup; +diff -up bind-9.9.4/lib/dns/dispatch.c.rh1215687-limits bind-9.9.4/lib/dns/dispatch.c +diff -up bind-9.9.4/lib/dns/request.c.rh1215687-limits bind-9.9.4/lib/dns/request.c +--- bind-9.9.4/lib/dns/request.c.rh1215687-limits 2013-09-05 07:09:08.000000000 +0200 ++++ bind-9.9.4/lib/dns/request.c 2015-05-20 16:08:21.286007013 +0200 +@@ -601,7 +601,7 @@ find_udp_dispatch(dns_requestmgr_t *requ + requestmgr->socketmgr, + requestmgr->taskmgr, + srcaddr, 4096, +- 1000, 32768, 16411, 16433, ++ 32768, 32768, 16411, 16433, + attrs, attrmask, + dispatchp)); + } +diff -up bind-9.9.4/lib/dns/resolver.c.rh1215687-limits bind-9.9.4/lib/dns/resolver.c +--- bind-9.9.4/lib/dns/resolver.c.rh1215687-limits 2015-05-20 16:08:21.277006991 +0200 ++++ bind-9.9.4/lib/dns/resolver.c 2015-05-20 16:08:21.285007010 +0200 +@@ -1489,7 +1489,7 @@ fctx_query(fetchctx_t *fctx, dns_adbaddr + result = dns_dispatch_getudp(res->dispatchmgr, + res->socketmgr, + res->taskmgr, &addr, +- 4096, 1000, 32768, 16411, ++ 4096, 20000, 32768, 16411, + 16433, attrs, attrmask, + &query->dispatch); + if (result != ISC_R_SUCCESS) diff --git a/SOURCES/bind99-rh1220594-geoip.patch b/SOURCES/bind99-rh1220594-geoip.patch new file mode 100644 index 0000000..3e65b99 --- /dev/null +++ b/SOURCES/bind99-rh1220594-geoip.patch @@ -0,0 +1,5539 @@ +From 34c87ea385ff013ca2f2058b884f53886065a4a3 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Wed, 13 Apr 2016 09:57:31 +0200 +Subject: [PATCH] Added support for GeoIP + +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + bin/named/Makefile.in | 8 +- + bin/named/geoip.c | 148 +++++ + bin/named/include/named/geoip.h | 31 + + bin/named/include/named/globals.h | 5 + + bin/named/interfacemgr.c | 3 + + bin/named/server.c | 38 +- + bin/tests/system/Makefile.in | 2 +- + bin/tests/system/conf.sh.in | 2 +- + bin/tests/system/geoip/Makefile.in | 55 ++ + bin/tests/system/geoip/clean.sh | 23 + + bin/tests/system/geoip/data/GeoIP.csv | 7 + + bin/tests/system/geoip/data/GeoIPASNum.csv | 7 + + bin/tests/system/geoip/data/GeoIPASNumv6.csv | 7 + + bin/tests/system/geoip/data/GeoIPCity.csv | 7 + + bin/tests/system/geoip/data/GeoIPCityv6.csv | 7 + + bin/tests/system/geoip/data/GeoIPDomain.csv | 7 + + bin/tests/system/geoip/data/GeoIPISP.csv | 7 + + bin/tests/system/geoip/data/GeoIPNetSpeed.csv | 7 + + bin/tests/system/geoip/data/GeoIPOrg.csv | 7 + + bin/tests/system/geoip/data/GeoIPRegion.csv | 7 + + bin/tests/system/geoip/data/GeoIPv6.csv | 7 + + bin/tests/system/geoip/data/README | 29 + + bin/tests/system/geoip/geoip.c | 31 + + bin/tests/system/geoip/ns2/example.db.in | 24 + + bin/tests/system/geoip/ns2/named1.conf | 104 ++++ + bin/tests/system/geoip/ns2/named10.conf | 104 ++++ + bin/tests/system/geoip/ns2/named11.conf | 104 ++++ + bin/tests/system/geoip/ns2/named12.conf | 80 +++ + bin/tests/system/geoip/ns2/named13.conf | 45 ++ + bin/tests/system/geoip/ns2/named14.conf | 112 ++++ + bin/tests/system/geoip/ns2/named15.conf | 55 ++ + bin/tests/system/geoip/ns2/named2.conf | 104 ++++ + bin/tests/system/geoip/ns2/named3.conf | 104 ++++ + bin/tests/system/geoip/ns2/named4.conf | 96 +++ + bin/tests/system/geoip/ns2/named5.conf | 104 ++++ + bin/tests/system/geoip/ns2/named6.conf | 104 ++++ + bin/tests/system/geoip/ns2/named7.conf | 104 ++++ + bin/tests/system/geoip/ns2/named8.conf | 104 ++++ + bin/tests/system/geoip/ns2/named9.conf | 104 ++++ + bin/tests/system/geoip/options.conf | 42 ++ + bin/tests/system/geoip/prereq.sh | 23 + + bin/tests/system/geoip/setup.sh | 27 + + bin/tests/system/geoip/tests.sh | 328 +++++++++++ + config.h.in | 9 + + configure.in | 94 +++ + doc/arm/Bv9ARM-book.xml | 72 +++ + lib/dns/Makefile.in | 8 +- + lib/dns/acl.c | 23 +- + lib/dns/geoip.c | 820 ++++++++++++++++++++++++++ + lib/dns/include/dns/Makefile.in | 6 +- + lib/dns/include/dns/acl.h | 24 +- + lib/dns/include/dns/geoip.h | 119 ++++ + lib/dns/tests/Makefile.in | 9 +- + lib/dns/tests/geoip_test.c | 694 ++++++++++++++++++++++ + lib/export/dns/Makefile.in | 6 +- + lib/isccfg/aclconf.c | 361 +++++++++++- + lib/isccfg/include/isccfg/aclconf.h | 6 + + lib/isccfg/namedconf.c | 129 +++- + 58 files changed, 4671 insertions(+), 33 deletions(-) + create mode 100644 bin/named/geoip.c + create mode 100644 bin/named/include/named/geoip.h + create mode 100644 bin/tests/system/geoip/Makefile.in + create mode 100644 bin/tests/system/geoip/clean.sh + create mode 100644 bin/tests/system/geoip/data/GeoIP.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPASNum.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPASNumv6.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPCity.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPCityv6.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPDomain.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPISP.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPNetSpeed.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPOrg.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPRegion.csv + create mode 100644 bin/tests/system/geoip/data/GeoIPv6.csv + create mode 100644 bin/tests/system/geoip/data/README + create mode 100644 bin/tests/system/geoip/geoip.c + create mode 100644 bin/tests/system/geoip/ns2/example.db.in + create mode 100644 bin/tests/system/geoip/ns2/named1.conf + create mode 100644 bin/tests/system/geoip/ns2/named10.conf + create mode 100644 bin/tests/system/geoip/ns2/named11.conf + create mode 100644 bin/tests/system/geoip/ns2/named12.conf + create mode 100644 bin/tests/system/geoip/ns2/named13.conf + create mode 100644 bin/tests/system/geoip/ns2/named14.conf + create mode 100644 bin/tests/system/geoip/ns2/named15.conf + create mode 100644 bin/tests/system/geoip/ns2/named2.conf + create mode 100644 bin/tests/system/geoip/ns2/named3.conf + create mode 100644 bin/tests/system/geoip/ns2/named4.conf + create mode 100644 bin/tests/system/geoip/ns2/named5.conf + create mode 100644 bin/tests/system/geoip/ns2/named6.conf + create mode 100644 bin/tests/system/geoip/ns2/named7.conf + create mode 100644 bin/tests/system/geoip/ns2/named8.conf + create mode 100644 bin/tests/system/geoip/ns2/named9.conf + create mode 100644 bin/tests/system/geoip/options.conf + create mode 100644 bin/tests/system/geoip/prereq.sh + create mode 100644 bin/tests/system/geoip/setup.sh + create mode 100644 bin/tests/system/geoip/tests.sh + create mode 100644 lib/dns/geoip.c + create mode 100644 lib/dns/include/dns/geoip.h + create mode 100644 lib/dns/tests/geoip_test.c + +diff --git a/bin/named/Makefile.in b/bin/named/Makefile.in +index 8ec9ad7..8b9e87a 100644 +--- a/bin/named/Makefile.in ++++ b/bin/named/Makefile.in +@@ -83,8 +83,10 @@ SUBDIRS = unix + + TARGETS = named@EXEEXT@ lwresd@EXEEXT@ + ++GEOIPLINKOBJS = geoip.@O@ ++ + OBJS = builtin.@O@ client.@O@ config.@O@ control.@O@ \ +- controlconf.@O@ interfacemgr.@O@ \ ++ controlconf.@O@ @GEOIPLINKOBJS@ interfacemgr.@O@ \ + listenlist.@O@ log.@O@ logconf.@O@ main.@O@ notify.@O@ \ + query.@O@ server.@O@ sortlist.@O@ statschannel.@O@ \ + tkeyconf.@O@ tsigconf.@O@ update.@O@ xfrout.@O@ \ +@@ -97,8 +99,10 @@ UOBJS = unix/os.@O@ unix/dlz_dlopen_driver.@O@ + + SYMOBJS = symtbl.@O@ + ++GEOIPLINKSRCS = geoip.c ++ + SRCS = builtin.c client.c config.c control.c \ +- controlconf.c interfacemgr.c \ ++ controlconf.c @GEOIPLINKSRCS@ interfacemgr.c \ + listenlist.c log.c logconf.c main.c notify.c \ + query.c server.c sortlist.c statschannel.c symtbl.c symtbl-empty.c \ + tkeyconf.c tsigconf.c update.c xfrout.c \ +diff --git a/bin/named/geoip.c b/bin/named/geoip.c +new file mode 100644 +index 0000000..c8f0c62 +--- /dev/null ++++ b/bin/named/geoip.c +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <isc/util.h> ++ ++#include <named/log.h> ++#include <named/geoip.h> ++ ++#include <dns/geoip.h> ++ ++#ifdef HAVE_GEOIP ++static dns_geoip_databases_t geoip_table = { ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ++}; ++ ++static void ++init_geoip_db(GeoIP **dbp, GeoIPDBTypes edition, GeoIPDBTypes fallback, ++ GeoIPOptions method, const char *name) ++{ ++ char *info; ++ GeoIP *db; ++ ++ REQUIRE(dbp != NULL); ++ ++ db = *dbp; ++ ++ if (db != NULL) { ++ GeoIP_delete(db); ++ db = *dbp = NULL; ++ } ++ ++ if (! GeoIP_db_avail(edition)) { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_INFO, ++ "GeoIP %s (type %d) DB not available", name, edition); ++ goto fail; ++ } ++ ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_INFO, ++ "initializing GeoIP %s (type %d) DB", name, edition); ++ ++ db = GeoIP_open_type(edition, method); ++ if (db == NULL) { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_ERROR, ++ "failed to initialize GeoIP %s (type %d) DB%s", ++ name, edition, fallback == 0 ++ ? "geoip matches using this database will fail" : ""); ++ goto fail; ++ } ++ ++ info = GeoIP_database_info(db); ++ if (info != NULL) ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_INFO, ++ "%s", info); ++ ++ *dbp = db; ++ return; ++ fail: ++ if (fallback != 0) ++ init_geoip_db(dbp, fallback, 0, method, name); ++ ++} ++#endif /* HAVE_GEOIP */ ++ ++void ++ns_geoip_init(void) { ++#ifndef HAVE_GEOIP ++ return; ++#else ++ GeoIP_cleanup(); ++ if (ns_g_geoip == NULL) ++ ns_g_geoip = &geoip_table; ++#endif ++} ++ ++void ++ns_geoip_load(char *dir) { ++#ifndef HAVE_GEOIP ++ ++ UNUSED(dir); ++ ++ return; ++#else ++ GeoIPOptions method; ++ ++#ifdef _WIN32 ++ method = GEOIP_STANDARD; ++#else ++ method = GEOIP_MMAP_CACHE; ++#endif ++ ++ ns_geoip_init(); ++ if (dir != NULL) { ++ isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, ++ NS_LOGMODULE_SERVER, ISC_LOG_INFO, ++ "using \"%s\" as GeoIP directory", dir); ++ GeoIP_setup_custom_directory(dir); ++ } ++ ++ init_geoip_db(&ns_g_geoip->country_v4, GEOIP_COUNTRY_EDITION, 0, ++ method, "Country (IPv4)"); ++#ifdef HAVE_GEOIP_V6 ++ init_geoip_db(&ns_g_geoip->country_v6, GEOIP_COUNTRY_EDITION_V6, 0, ++ method, "Country (IPv6)"); ++#endif ++ ++ init_geoip_db(&ns_g_geoip->city_v4, GEOIP_CITY_EDITION_REV1, ++ GEOIP_CITY_EDITION_REV0, method, "City (IPv4)"); ++#if defined(HAVE_GEOIP_V6) && defined(HAVE_GEOIP_CITY_V6) ++ init_geoip_db(&ns_g_geoip->city_v6, GEOIP_CITY_EDITION_REV1_V6, ++ GEOIP_CITY_EDITION_REV0_V6, method, "City (IPv6)"); ++#endif ++ ++ init_geoip_db(&ns_g_geoip->region, GEOIP_REGION_EDITION_REV1, ++ GEOIP_REGION_EDITION_REV0, method, "Region"); ++ ++ init_geoip_db(&ns_g_geoip->isp, GEOIP_ISP_EDITION, 0, ++ method, "ISP"); ++ init_geoip_db(&ns_g_geoip->org, GEOIP_ORG_EDITION, 0, ++ method, "Org"); ++ init_geoip_db(&ns_g_geoip->as, GEOIP_ASNUM_EDITION, 0, ++ method, "AS"); ++ init_geoip_db(&ns_g_geoip->domain, GEOIP_DOMAIN_EDITION, 0, ++ method, "Domain"); ++ init_geoip_db(&ns_g_geoip->netspeed, GEOIP_NETSPEED_EDITION, 0, ++ method, "NetSpeed"); ++#endif /* HAVE_GEOIP */ ++} +diff --git a/bin/named/include/named/geoip.h b/bin/named/include/named/geoip.h +new file mode 100644 +index 0000000..e1a66a7 +--- /dev/null ++++ b/bin/named/include/named/geoip.h +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef _GEOIP_H ++#define _GEOIP_H ++ ++#ifdef HAVE_GEOIP ++#include <GeoIP.h> ++#include <GeoIPCity.h> ++#endif /* HAVE_GEOIP */ ++ ++void ns_geoip_init(void); ++void ns_geoip_load(char *dir); ++ ++#ifdef HAVE_GEOIP ++extern dns_geoip_databases_t *ns_g_geoip; ++#endif /* HAVE_GEOIP */ ++#endif +diff --git a/bin/named/include/named/globals.h b/bin/named/include/named/globals.h +index aad462d..412b3a7 100644 +--- a/bin/named/include/named/globals.h ++++ b/bin/named/include/named/globals.h +@@ -29,6 +29,7 @@ + #include <isccfg/aclconf.h> + #include <isccfg/cfg.h> + ++#include <dns/acl.h> + #include <dns/zone.h> + + #include <dst/dst.h> +@@ -160,6 +161,10 @@ EXTERN isc_boolean_t ns_g_nosoa INIT(ISC_FALSE); + EXTERN isc_boolean_t ns_g_noaa INIT(ISC_FALSE); + EXTERN isc_boolean_t ns_g_nonearest INIT(ISC_FALSE); + ++#ifdef HAVE_GEOIP ++EXTERN dns_geoip_databases_t *ns_g_geoip INIT(NULL); ++#endif ++ + #undef EXTERN + #undef INIT + +diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c +index 9206ebb..4f6b0f3 100644 +--- a/bin/named/interfacemgr.c ++++ b/bin/named/interfacemgr.c +@@ -108,6 +108,9 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, + result = dns_aclenv_init(mctx, &mgr->aclenv); + if (result != ISC_R_SUCCESS) + goto cleanup_listenon; ++#ifdef HAVE_GEOIP ++ mgr->aclenv.geoip = ns_g_geoip; ++#endif + + mgr->references = 1; + mgr->magic = IFMGR_MAGIC; +diff --git a/bin/named/server.c b/bin/named/server.c +index 6260f8f..e3ffc2e 100644 +--- a/bin/named/server.c ++++ b/bin/named/server.c +@@ -99,6 +99,7 @@ + #include <named/client.h> + #include <named/config.h> + #include <named/control.h> ++#include <named/geoip.h> + #include <named/interfacemgr.h> + #include <named/log.h> + #include <named/logconf.h> +@@ -114,6 +115,9 @@ + #include <named/ns_smf_globals.h> + #include <stdlib.h> + #endif ++#ifdef HAVE_GEOIP ++#include <named/geoip.h> ++#endif /* HAVE_GEOIP */ + + #ifndef PATH_MAX + #define PATH_MAX 1024 +@@ -3795,6 +3799,10 @@ create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist, + if (result != ISC_R_SUCCESS) + return (result); + ++#ifdef HAVE_GEOIP ++ view->aclenv.geoip = ns_g_geoip; ++#endif ++ + ISC_LIST_APPEND(*viewlist, view, link); + dns_view_attach(view, viewp); + return (ISC_R_SUCCESS); +@@ -5122,6 +5130,24 @@ load_configuration(const char *filename, ns_server_t *server, + } + isc__socketmgr_setreserved(ns_g_socketmgr, reserved); + ++#ifdef HAVE_GEOIP ++ /* ++ * Initialize GeoIP databases from the configured location. ++ * This should happen before configuring any ACLs, so that we ++ * know what databases are available and can reject any GeoIP ++ * ACLs that can't work. ++ */ ++ obj = NULL; ++ result = ns_config_get(maps, "geoip-directory", &obj); ++ if (result == ISC_R_SUCCESS && cfg_obj_isstring(obj)) { ++ char *dir; ++ DE_CONST(cfg_obj_asstring(obj), dir); ++ ns_geoip_load(dir); ++ } else ++ ns_geoip_load(NULL); ++ ns_g_aclconfctx->geoip = ns_g_geoip; ++#endif /* HAVE_GEOIP */ ++ + /* + * Configure various server options. + */ +@@ -6134,6 +6160,10 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { + if (server->blackholeacl != NULL) + dns_acl_detach(&server->blackholeacl); + ++#ifdef HAVE_GEOIP ++ dns_geoip_shutdown(); ++#endif ++ + dns_db_detach(&server->in_roothints); + + isc_task_endexclusive(server->task); +@@ -6155,7 +6185,6 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { + server->task = NULL; + + /* Initialize configuration data with default values. */ +- + result = isc_quota_init(&server->xfroutquota, 10); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + result = isc_quota_init(&server->tcpquota, 10); +@@ -6163,9 +6192,16 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) { + result = isc_quota_init(&server->recursionquota, 100); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ++ + result = dns_aclenv_init(mctx, &server->aclenv); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + ++#ifdef HAVE_GEOIP ++ /* Initialize GeoIP before using ACL environment */ ++ ns_geoip_init(); ++ server->aclenv.geoip = ns_g_geoip; ++#endif ++ + /* Initialize server data structures. */ + server->zonemgr = NULL; + server->interfacemgr = NULL; +diff --git a/bin/tests/system/Makefile.in b/bin/tests/system/Makefile.in +index af8b82c..0c7fdff 100644 +--- a/bin/tests/system/Makefile.in ++++ b/bin/tests/system/Makefile.in +@@ -21,7 +21,7 @@ top_srcdir = @top_srcdir@ + + @BIND9_MAKE_INCLUDES@ + +-SUBDIRS = dlzexternal dyndb filter-aaaa lwresd rpz rrl \ ++SUBDIRS = dlzexternal dyndb filter-aaaa geoip lwresd rpz rrl \ + rsabigexponent tkey tsiggss + TARGETS = + +diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in +index eb02236..6df4734 100644 +--- a/bin/tests/system/conf.sh.in ++++ b/bin/tests/system/conf.sh.in +@@ -65,7 +65,7 @@ SUBDIRS="acl additional allow_query addzone autosign builtin + lwresd masterfile masterformat metadata notify nsupdate pending + @PKCS11_TEST@ redirect resolver rndc rpz rrl rrsetorder rsabigexponent + smartsign sortlist spf staticstub stub tkey tsig tsiggss unknown +- upforwd verify views wildcard xfer xferquota zero zonechecks" ++ upforwd verify views wildcard xfer xferquota zero zonechecks geoip filter-aaaa" + + # PERL will be an empty string if no perl interpreter was found. + PERL=@PERL@ +diff --git a/bin/tests/system/geoip/Makefile.in b/bin/tests/system/geoip/Makefile.in +new file mode 100644 +index 0000000..ab48003 +--- /dev/null ++++ b/bin/tests/system/geoip/Makefile.in +@@ -0,0 +1,55 @@ ++# Copyright (C) 2010-2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++# $Id: Makefile.in,v 1.4 2011/07/28 23:47:58 tbox Exp $ ++ ++srcdir = @srcdir@ ++VPATH = @srcdir@ ++top_srcdir = @top_srcdir@ ++ ++@BIND9_VERSION@ ++ ++@BIND9_MAKE_INCLUDES@ ++ ++CINCLUDES = ${ISC_INCLUDES} ++ ++CDEFINES = ++CWARNINGS = ++ ++DNSLIBS = ++ISCLIBS = . ++ ++DNSDEPLIBS = ++ISCDEPLIBS = ++ ++DEPLIBS = ++ ++LIBS = @LIBS@ ++ ++TARGETS = geoip@EXEEXT@ ++ ++FILTEROBJS = geoip.@O@ ++ ++SRCS = geoip.c ++ ++@BIND9_MAKE_RULES@ ++ ++all: geoip@EXEEXT@ ++ ++geoip@EXEEXT@: ${FILTEROBJS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${FILTEROBJS} ${LIBS} ++ ++clean distclean:: ++ rm -f ${TARGETS} ++ +diff --git a/bin/tests/system/geoip/clean.sh b/bin/tests/system/geoip/clean.sh +new file mode 100644 +index 0000000..b04ca2d +--- /dev/null ++++ b/bin/tests/system/geoip/clean.sh +@@ -0,0 +1,23 @@ ++#!/bin/sh ++# ++# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++rm -f ns2/named.conf ++rm -f ns2/example*.db ++rm -f dig.out.* rndc.out.* ++rm -f data2/*dat ++[ -d data2 ] && rmdir data2 ++rm -f ns?/named.run ++rm -f ns?/named.memstats +diff --git a/bin/tests/system/geoip/data/GeoIP.csv b/bin/tests/system/geoip/data/GeoIP.csv +new file mode 100644 +index 0000000..f158a5b +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIP.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 AU ++10.53.0.2/32 US ++10.53.0.3/32 GB ++10.53.0.4/32 CA ++10.53.0.5/32 CL ++10.53.0.6/32 DE ++10.53.0.7/32 EH +diff --git a/bin/tests/system/geoip/data/GeoIPASNum.csv b/bin/tests/system/geoip/data/GeoIPASNum.csv +new file mode 100644 +index 0000000..774edd1 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPASNum.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 AS100001 One Systems, Inc. ++10.53.0.2/32 AS100002 Two Technology Ltd. ++10.53.0.3/32 AS100003 Three Network Labs ++10.53.0.4/32 AS100004 Four University ++10.53.0.5/32 AS100005 Five Telecom ++10.53.0.6/32 AS100006 Six Company ++10.53.0.7/32 AS100007 Seven Communications +diff --git a/bin/tests/system/geoip/data/GeoIPASNumv6.csv b/bin/tests/system/geoip/data/GeoIPASNumv6.csv +new file mode 100644 +index 0000000..4074289 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPASNumv6.csv +@@ -0,0 +1,7 @@ ++fd92:7065:b8e:ffff::1/128,AS100001 One Systems, Inc. ++fd92:7065:b8e:ffff::2/128,AS100002 Two Technology Ltd. ++fd92:7065:b8e:ffff::3/128,AS100003 Three Network Labs ++fd92:7065:b8e:ffff::4/128,AS100004 Four University ++fd92:7065:b8e:ffff::5/128,AS100005 Five Telecom ++fd92:7065:b8e:ffff::6/128,AS100006 Six Company ++fd92:7065:b8e:ffff::7/128,AS100007 Seven Communications +diff --git a/bin/tests/system/geoip/data/GeoIPCity.csv b/bin/tests/system/geoip/data/GeoIPCity.csv +new file mode 100644 +index 0000000..14900d5 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPCity.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32,US,CA,"Redwood City",94063,37.4914,-122.2110,807,650 ++10.53.0.2/32,US,CA,"Santa Cruz",95060,37.0448,-122.1021,828,831 ++10.53.0.3/32,US,OK,"Oklahoma City",73120,35.5798,-97.5731,650,405 ++10.53.0.4/32,US,VA,Ashland,23005,37.7563,-77.4888,556,804 ++10.53.0.5/32,US,GA,Atlanta,30345,33.8477,-84.2814,524,404 ++10.53.0.6/32,US,CO,Morrison,80465,39.6081,-105.2072,751,303 ++10.53.0.7/32,US,AK,Ketchikan,99901,55.6153,-131.5848,747,907 +diff --git a/bin/tests/system/geoip/data/GeoIPCityv6.csv b/bin/tests/system/geoip/data/GeoIPCityv6.csv +new file mode 100644 +index 0000000..5f09e62 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPCityv6.csv +@@ -0,0 +1,7 @@ ++"fd92:7065:b8e:ffff::1","fd92:7065:b8e:ffff::1","US","CA","Redwood City","94063",37.4914,-122.2110,807,650 ++"fd92:7065:b8e:ffff::2","fd92:7065:b8e:ffff::2","US","CA","Santa Cruz","95060",37.0448,-122.1021,828,831 ++"fd92:7065:b8e:ffff::3","fd92:7065:b8e:ffff::3","US","OK","Oklahoma City","73120",35.5798,-97.5731,650,405 ++"fd92:7065:b8e:ffff::4","fd92:7065:b8e:ffff::4","DE","07","Lotte","",52.2833,7.9167,0,0 ++"fd92:7065:b8e:ffff::5","fd92:7065:b8e:ffff::5","US","GA","Atlanta","30345",33.8477,-84.2814,524,404 ++"fd92:7065:b8e:ffff::6","fd92:7065:b8e:ffff::6","US","CO","Morrison","80465",39.6081,-105.2072,751,303 ++"fd92:7065:b8e:ffff::7","fd92:7065:b8e:ffff::7","US","AK","Ketchikan","99901",55.6153,-131.5848,747,907 +diff --git a/bin/tests/system/geoip/data/GeoIPDomain.csv b/bin/tests/system/geoip/data/GeoIPDomain.csv +new file mode 100644 +index 0000000..8611d65 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPDomain.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 one.de ++10.53.0.2/32 two.com ++10.53.0.3/32 three.com ++10.53.0.4/32 four.com ++10.53.0.5/32 five.es ++10.53.0.6/32 six.it ++10.53.0.7/32 seven.org +diff --git a/bin/tests/system/geoip/data/GeoIPISP.csv b/bin/tests/system/geoip/data/GeoIPISP.csv +new file mode 100644 +index 0000000..3d5b4fa +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPISP.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 One Systems, Inc. ++10.53.0.2/32 Two Technology Ltd. ++10.53.0.3/32 Three Network Labs ++10.53.0.4/32 Four University ++10.53.0.5/32 Five Telecom ++10.53.0.6/32 Six Company ++10.53.0.7/32 Seven Communications +diff --git a/bin/tests/system/geoip/data/GeoIPNetSpeed.csv b/bin/tests/system/geoip/data/GeoIPNetSpeed.csv +new file mode 100644 +index 0000000..4ede137 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPNetSpeed.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 0 ++10.53.0.2/32 1 ++10.53.0.3/32 2 ++10.53.0.4/32 3 ++10.53.0.5/32 0 ++10.53.0.6/32 1 ++10.53.0.7/32 2 +diff --git a/bin/tests/system/geoip/data/GeoIPOrg.csv b/bin/tests/system/geoip/data/GeoIPOrg.csv +new file mode 100644 +index 0000000..3d5b4fa +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPOrg.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 One Systems, Inc. ++10.53.0.2/32 Two Technology Ltd. ++10.53.0.3/32 Three Network Labs ++10.53.0.4/32 Four University ++10.53.0.5/32 Five Telecom ++10.53.0.6/32 Six Company ++10.53.0.7/32 Seven Communications +diff --git a/bin/tests/system/geoip/data/GeoIPRegion.csv b/bin/tests/system/geoip/data/GeoIPRegion.csv +new file mode 100644 +index 0000000..0bcd872 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPRegion.csv +@@ -0,0 +1,7 @@ ++10.53.0.1/32 US CA ++10.53.0.2/32 CA BC ++10.53.0.3/32 US OK ++10.53.0.4/32 AU ++10.53.0.5/32 US CO ++10.53.0.6/32 CA ON ++10.53.0.7/32 NL +diff --git a/bin/tests/system/geoip/data/GeoIPv6.csv b/bin/tests/system/geoip/data/GeoIPv6.csv +new file mode 100644 +index 0000000..919bf86 +--- /dev/null ++++ b/bin/tests/system/geoip/data/GeoIPv6.csv +@@ -0,0 +1,7 @@ ++"fd92:7065:b8e:ffff::1/128",AU ++"fd92:7065:b8e:ffff::2/128",US ++"fd92:7065:b8e:ffff::3/128",GB ++"fd92:7065:b8e:ffff::4/128",CA ++"fd92:7065:b8e:ffff::5/128",CL ++"fd92:7065:b8e:ffff::6/128",DE ++"fd92:7065:b8e:ffff::7/128",EH +diff --git a/bin/tests/system/geoip/data/README b/bin/tests/system/geoip/data/README +new file mode 100644 +index 0000000..0711cde +--- /dev/null ++++ b/bin/tests/system/geoip/data/README +@@ -0,0 +1,29 @@ ++The data data files in this directory are sample GeoIP databases, ++generated from the corresponding CSV files. Thanks to MaxMind, Inc. ++for assistance with producing these files. ++ ++Unless otherwise noted, the databases only support IPv4: ++ ++GeoIP.dat: Country (IPv4) ++GeoIPv6.dat: Country (IPv6) ++GeoIPCity.dat: City (IPv4) ++GeoIPCityv6.dat: City (IPv6) ++GeoIPRegion.dat: Region ++GeoIPISP.dat: ISP ++GeoIPOrg.dat: Organization ++GeoIPDoain.dat: Domain Name ++GeoIPASNum.dat: AS Number ++GeoIPNetSpeed.dat: Net Speed ++ ++GeoIP.dat can also be generated using the open source 'geoip-csv-to-dat' ++utility: ++ ++$ geoip-csv-to-dat -i "BIND9 geoip test data v1" -o GeoIP.dat << EOF ++"10.53.0.1","10.53.0.1","171245569","171245569","AU","Australia" ++"10.53.0.2","10.53.0.2","171245570","171245570","US","United States" ++"10.53.0.3","10.53.0.3","171245571","171245571","GB","United Kingdom" ++"10.53.0.4","10.53.0.4","171245572","171245572","CA","Canada" ++"10.53.0.5","10.53.0.5","171245573","171245573","CL","Chile" ++"10.53.0.6","10.53.0.6","171245574","171245574","DE","Germany" ++"10.53.0.7","10.53.0.7","171245575","171245575","EH","Western Sahara" ++EOF +diff --git a/bin/tests/system/geoip/geoip.c b/bin/tests/system/geoip/geoip.c +new file mode 100644 +index 0000000..e0dadad +--- /dev/null ++++ b/bin/tests/system/geoip/geoip.c +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#include <config.h> ++#include <isc/util.h> ++ ++int ++main(int argc, char **argv) { ++ ++ UNUSED(argc); ++ UNUSED(argv); ++ ++#ifdef HAVE_GEOIP ++ return (0); ++#else ++ return (1); ++#endif ++} +diff --git a/bin/tests/system/geoip/ns2/example.db.in b/bin/tests/system/geoip/ns2/example.db.in +new file mode 100644 +index 0000000..52a233b +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/example.db.in +@@ -0,0 +1,24 @@ ++; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC") ++; ++; Permission to use, copy, modify, and/or distribute this software for any ++; purpose with or without fee is hereby granted, provided that the above ++; copyright notice and this permission notice appear in all copies. ++; ++; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++; PERFORMANCE OF THIS SOFTWARE. ++ ++$TTL 300 ; 5 minutes ++@ IN SOA mname1. . ( ++ 2000042407 ; serial ++ 20 ; refresh (20 seconds) ++ 20 ; retry (20 seconds) ++ 1814400 ; expire (3 weeks) ++ 3600 ; minimum (1 hour) ++ ) ++ NS ns2 ++ns2 A 10.53.0.2 +diff --git a/bin/tests/system/geoip/ns2/named1.conf b/bin/tests/system/geoip/ns2/named1.conf +new file mode 100644 +index 0000000..66aca6f +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named1.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip db country country AU; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip db country country US; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip db country country GB; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip db country country CA; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip db country country CL; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip db country country DE; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip db country country EH; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named10.conf b/bin/tests/system/geoip/ns2/named10.conf +new file mode 100644 +index 0000000..2dd52ae +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named10.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip asnum "AS100001"; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip asnum "AS100002"; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip asnum "AS100003"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip asnum "AS100004"; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip asnum "AS100005"; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip asnum "AS100006"; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip asnum "AS100007"; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named11.conf b/bin/tests/system/geoip/ns2/named11.conf +new file mode 100644 +index 0000000..af87edf +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named11.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip domain one.de; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip domain two.com; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip domain three.com; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip domain four.com; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip domain five.es; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip domain six.it; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip domain seven.org; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named12.conf b/bin/tests/system/geoip/ns2/named12.conf +new file mode 100644 +index 0000000..85c0d32 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named12.conf +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-sha256; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip netspeed 0; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip netspeed 1; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip netspeed 2; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip netspeed 3; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named13.conf b/bin/tests/system/geoip/ns2/named13.conf +new file mode 100644 +index 0000000..a650a63 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named13.conf +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++acl blocking { ++ geoip db country country AU; ++}; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++ blackhole { blocking; }; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-sha256; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named14.conf b/bin/tests/system/geoip/ns2/named14.conf +new file mode 100644 +index 0000000..f92d252 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named14.conf +@@ -0,0 +1,112 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-sha256; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++acl gAU { geoip db country country AU; }; ++acl gUS { geoip db country country US; }; ++acl gGB { geoip db country country GB; }; ++acl gCA { geoip db country country CA; }; ++acl gCL { geoip db country country CL; }; ++acl gDE { geoip db country country DE; }; ++acl gEH { geoip db country country EH; }; ++ ++view one { ++ match-clients { gAU; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { gUS; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { gGB; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { gCA; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { gCL; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { gDE; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { gEH; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named15.conf b/bin/tests/system/geoip/ns2/named15.conf +new file mode 100644 +index 0000000..6ac837b +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named15.conf +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { fd92:7065:b8e:ffff::2; }; ++ recursion no; ++ geoip-directory "../data2"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-sha256; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view two { ++ match-clients { geoip country US; }; ++ zone "example" { ++ type master; ++ file "../ns2/example2.db"; ++ }; ++}; ++ ++view none { ++ zone "example" { ++ type master; ++ file "examplebogus.db"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named2.conf b/bin/tests/system/geoip/ns2/named2.conf +new file mode 100644 +index 0000000..67a5155 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named2.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip db country country AUS; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip db country country USA; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip db country country GBR; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip db country country CAN; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip db country country CHL; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip db country country DEU; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip db country country ESH; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named3.conf b/bin/tests/system/geoip/ns2/named3.conf +new file mode 100644 +index 0000000..65113a6 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named3.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip db country country Australia; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip db country country "United States"; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip db country country "United Kingdom"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip db country country Canada; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip db country country Chile; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip db country country Germany; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip db country country "Western Sahara"; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named4.conf b/bin/tests/system/geoip/ns2/named4.conf +new file mode 100644 +index 0000000..d2393d5 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named4.conf +@@ -0,0 +1,96 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip region CA; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip region OK; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip region VA; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip region GA; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip region CO; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip region AK; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named5.conf b/bin/tests/system/geoip/ns2/named5.conf +new file mode 100644 +index 0000000..011e310 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named5.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip db region region "California"; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip db region region "British Columbia"; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip db region region "Oklahoma"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip db region country AU; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip db region region "Colorado"; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip db region region "Ontario"; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip db region country NL; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named6.conf b/bin/tests/system/geoip/ns2/named6.conf +new file mode 100644 +index 0000000..7ef7b19 +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named6.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { fd92:7065:b8e:ffff::1; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip city "Redwood City"; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip city "Santa Cruz"; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip city "Oklahoma City"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip city "Ashland"; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip city "Atlanta"; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip city "Morrison"; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip city "Ketchikan"; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named7.conf b/bin/tests/system/geoip/ns2/named7.conf +new file mode 100644 +index 0000000..118bdbe +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named7.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip isp "One Systems, Inc."; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip isp "Two Technology Ltd."; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip isp "Three Network Labs"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip isp "Four University"; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip isp "Five Telecom"; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip isp "Six Company"; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip isp "Seven Communications"; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named8.conf b/bin/tests/system/geoip/ns2/named8.conf +new file mode 100644 +index 0000000..9cb5c0a +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named8.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip org "One Systems, Inc."; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip org "Two Technology Ltd."; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip org "Three Network Labs"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip org "Four University"; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip org "Five Telecom"; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip org "Six Company"; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip org "Seven Communications"; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/ns2/named9.conf b/bin/tests/system/geoip/ns2/named9.conf +new file mode 100644 +index 0000000..af2f7ff +--- /dev/null ++++ b/bin/tests/system/geoip/ns2/named9.conf +@@ -0,0 +1,104 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "../data"; ++}; ++ ++key rndc_key { ++ secret "1234abcd8765"; ++ algorithm hmac-md5; ++}; ++ ++controls { ++ inet 10.53.0.2 port 9953 allow { any; } keys { rndc_key; }; ++}; ++ ++view one { ++ match-clients { geoip asnum "AS100001 One Systems, Inc."; }; ++ zone "example" { ++ type master; ++ file "example1.db"; ++ }; ++}; ++ ++view two { ++ match-clients { geoip asnum "AS100002 Two Technology Ltd."; }; ++ zone "example" { ++ type master; ++ file "example2.db"; ++ }; ++}; ++ ++view three { ++ match-clients { geoip asnum "AS100003 Three Network Labs"; }; ++ zone "example" { ++ type master; ++ file "example3.db"; ++ }; ++}; ++ ++view four { ++ match-clients { geoip asnum "AS100004 Four University"; }; ++ zone "example" { ++ type master; ++ file "example4.db"; ++ }; ++}; ++ ++view five { ++ match-clients { geoip asnum "AS100005 Five Telecom"; }; ++ zone "example" { ++ type master; ++ file "example5.db"; ++ }; ++}; ++ ++view six { ++ match-clients { geoip asnum "AS100006 Six Company"; }; ++ zone "example" { ++ type master; ++ file "example6.db"; ++ }; ++}; ++ ++view seven { ++ match-clients { geoip asnum "AS100007 Seven Communications"; }; ++ zone "example" { ++ type master; ++ file "example7.db"; ++ }; ++}; ++ ++view none { ++ match-clients { any; }; ++ zone "example" { ++ type master; ++ file "example.db.in"; ++ }; ++}; +diff --git a/bin/tests/system/geoip/options.conf b/bin/tests/system/geoip/options.conf +new file mode 100644 +index 0000000..b4d46cb +--- /dev/null ++++ b/bin/tests/system/geoip/options.conf +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++// NS2 ++ ++controls { /* empty */ }; ++ ++options { ++ query-source address 10.53.0.2; ++ notify-source 10.53.0.2; ++ transfer-source 10.53.0.2; ++ port 5300; ++ pid-file "named.pid"; ++ listen-on { 10.53.0.2; }; ++ listen-on-v6 { none; }; ++ recursion no; ++ geoip-directory "data"; ++ allow-query { ++ geoip area 831; ++ geoip areacode 831; ++ geoip metro 828; ++ geoip metrocode 828; ++ geoip tz PST; ++ geoip timezone PST; ++ geoip postal 95060; ++ geoip postalcode 95060; ++ }; ++}; ++ +diff --git a/bin/tests/system/geoip/prereq.sh b/bin/tests/system/geoip/prereq.sh +new file mode 100644 +index 0000000..b78be41 +--- /dev/null ++++ b/bin/tests/system/geoip/prereq.sh +@@ -0,0 +1,23 @@ ++#!/bin/sh ++# ++# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++if ./geoip ++then ++ : ++else ++ echo "I:This test requires GeoIP support." >&2 ++ exit 1 ++fi +diff --git a/bin/tests/system/geoip/setup.sh b/bin/tests/system/geoip/setup.sh +new file mode 100644 +index 0000000..5c5e2ca +--- /dev/null ++++ b/bin/tests/system/geoip/setup.sh +@@ -0,0 +1,27 @@ ++#!/bin/sh ++# ++# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++sh clean.sh ++ ++cp ns2/named1.conf ns2/named.conf ++ ++for i in 1 2 3 4 5 6 7 other bogus; do ++ cp ns2/example.db.in ns2/example${i}.db ++ echo "@ IN TXT \"$i\"" >> ns2/example$i.db ++done ++ ++mkdir -p data2 ++cp data/GeoIPv6.dat data2/ +diff --git a/bin/tests/system/geoip/tests.sh b/bin/tests/system/geoip/tests.sh +new file mode 100644 +index 0000000..07635b1 +--- /dev/null ++++ b/bin/tests/system/geoip/tests.sh +@@ -0,0 +1,328 @@ ++#!/bin/sh ++# ++# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++# ++# Permission to use, copy, modify, and/or distribute this software for any ++# purpose with or without fee is hereby granted, provided that the above ++# copyright notice and this permission notice appear in all copies. ++# ++# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++# PERFORMANCE OF THIS SOFTWARE. ++ ++SYSTEMTESTTOP=.. ++. $SYSTEMTESTTOP/conf.sh ++ ++status=0 ++n=0 ++ ++rm -f dig.out.* ++ ++DIGOPTS="+tcp +short -p 5300 @10.53.0.2" ++DIGOPTS6="+tcp +short -p 5300 @fd92:7065:b8e:ffff::2" ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP country database by code ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named2.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP country database by three-letter code ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named3.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP country database by name ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named4.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP region code, no specified database ($n)" ++ret=0 ++lret=0 ++# skipping 2 on purpose here; it has the same region code as 1 ++for i in 1 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named5.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP region database by region name and country code ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named6.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++if $TESTSOCK6 fd92:7065:b8e:ffff::3 ++then ++ n=`expr $n + 1` ++ echo "I:checking GeoIP city database by city name using IPv6 ($n)" ++ ret=0 ++ $DIG +tcp +short -p 5300 @fd92:7065:b8e:ffff::1 -6 txt example -b fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 ++ [ $ret -eq 0 ] || echo "I:failed" ++ status=`expr $status + $ret` ++else ++ echo "I:IPv6 unavailable; skipping" ++fi ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP city database by city name ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named7.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP isp database ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named8.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP org database ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named9.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP asnum database ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named10.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP asnum database - ASNNNN only ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named11.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP domain database ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named12.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP netspeed database ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named13.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP blackhole ACL ($n)" ++ret=0 ++$DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n || ret=1 ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 status 2>&1 > rndc.out.ns2.test$n || ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:reloading server" ++cp -f ns2/named14.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP country database by code (using nested ACLs) ($n)" ++ret=0 ++lret=0 ++for i in 1 2 3 4 5 6 7; do ++ $DIG $DIGOPTS txt example -b 10.53.0.$i > dig.out.ns2.test$n.$i || lret=1 ++ j=`cat dig.out.ns2.test$n.$i | tr -d '"'` ++ [ "$i" = "$j" ] || lret=1 ++ [ $lret -eq 1 ] && break ++done ++[ $lret -eq 1 ] && ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++n=`expr $n + 1` ++echo "I:reloading server with different geoip-directory ($n)" ++ret=0 ++cp -f ns2/named15.conf ns2/named.conf ++$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 reload 2>&1 | sed 's/^/I:ns2 /' ++sleep 3 ++awk '/using "..\/data2" as GeoIP directory/ {m=1} ; { if (m>0) { print } }' ns2/named.run | grep "GeoIP City .* DB not available" > /dev/null || ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++n=`expr $n + 1` ++echo "I:checking GeoIP v4/v6 when only IPv6 database is available ($n)" ++ret=0 ++$DIG $DIGOPTS -4 txt example -b 10.53.0.2 > dig.out.ns2.test$n.1 || ret=1 ++j=`cat dig.out.ns2.test$n.1 | tr -d '"'` ++[ "$j" = "bogus" ] || ret=1 ++if $TESTSOCK6 fd92:7065:b8e:ffff::2; then ++ $DIG $DIGOPTS6 txt example -b fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n.2 || ret=1 ++ j=`cat dig.out.ns2.test$n.2 | tr -d '"'` ++ [ "$j" = "2" ] || ret=1 ++fi ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++n=`expr $n + 1` ++echo "I:checking other GeoIP options are parsed correctly ($n)" ++ret=0 ++$CHECKCONF options.conf || ret=1 ++[ $ret -eq 0 ] || echo "I:failed" ++status=`expr $status + $ret` ++ ++echo "I:exit status: $status" ++exit $status +diff --git a/config.h.in b/config.h.in +index f2eb59a..6ed8381 100644 +--- a/config.h.in ++++ b/config.h.in +@@ -214,6 +214,15 @@ int sigwait(const unsigned int *set, int *sig); + /* Define to 1 if you have the <fcntl.h> header file. */ + #undef HAVE_FCNTL_H + ++/* Build with GeoIP support */ ++#undef HAVE_GEOIP ++ ++/* Build with GeoIP City IPv6 support */ ++#undef HAVE_GEOIP_CITY_V6 ++ ++/* Build with GeoIP Country IPv6 support */ ++#undef HAVE_GEOIP_V6 ++ + /* Define to 1 if you have the <gssapi/gssapi.h> header file. */ + #undef HAVE_GSSAPI_GSSAPI_H + +diff --git a/configure.in b/configure.in +index e8c68fc..71e90c1 100644 +--- a/configure.in ++++ b/configure.in +@@ -1252,6 +1252,99 @@ if test "$have_clock_gt" = "yes"; then + fi + + ++GEOIPLINKSRCS= ++GEOIPLINKOBJS= ++AC_ARG_WITH(geoip, ++[ --with-geoip=PATH Build with GeoIP support (yes|no|path)], ++ use_geoip="$withval", use_geoip="no") ++ ++if test "$use_geoip" = "yes" ++then ++ for d in /usr /usr/local /opt/local ++ do ++ if test -f $d/include/GeoIP.h ++ then ++ use_geoip=$d ++ break ++ fi ++ done ++fi ++ ++case "$use_geoip" in ++ no|'') ++ AC_MSG_CHECKING([for GeoIP support]) ++ AC_MSG_RESULT([disabled]) ++ ;; ++ *) ++ if test -d "$use_geoip" -o -L "$use_geoip" ++ then ++ CFLAGS="$CFLAGS -I$use_geoip/include" ++ CPPFLAGS="$CPPFLAGS -I$use_geoip/include" ++ LIBS="$LIBS -L$use_geoip/lib" ++ case "$host_os" in ++ netbsd*|openbsd*|solaris*) ++ LIBS="$LIBS -Wl,-rpath=$use_geoip/lib" ++ ;; ++ esac ++ elif test "$use_geoip" = "yes" ++ then ++ AC_MSG_ERROR([GeoIP path not found]) ++ else ++ AC_MSG_ERROR([GeoIP path $use_geoip does not exist]) ++ fi ++ AC_CHECK_HEADER(GeoIP.h, [], ++ [AC_MSG_ERROR([GeoIP header file not found])] ++ ) ++ AC_SEARCH_LIBS(GeoIP_open, GeoIP, [], ++ [AC_MSG_ERROR([GeoIP library not found])] ++ ) ++ AC_SEARCH_LIBS(fabsf, m, [], ++ [AC_MSG_ERROR([Math library not found])] ++ ) ++ AC_DEFINE(HAVE_GEOIP, 1, Build with GeoIP support) ++ GEOIPLINKSRCS='${GEOIPLINKSRCS}' ++ GEOIPLINKOBJS='${GEOIPLINKOBJS}' ++ AC_MSG_CHECKING([for GeoIP support]) ++ AC_MSG_RESULT([yes]) ++ ++ AC_MSG_CHECKING([for GeoIP Country IPv6 support]) ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM([ ++ #include <GeoIP.h> ++ #include <netinet/in.h> ++ ], [ ++ struct in6_addr in6; ++ GeoIP_country_name_by_ipnum_v6(NULL, in6); ++ ])], ++ [ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE(HAVE_GEOIP_V6, 1, Build with GeoIP Country IPv6 support) ++ ], ++ [AC_MSG_RESULT([no])] ++ ) ++ ++ AC_MSG_CHECKING([for GeoIP City IPv6 support]) ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM([ ++ #include <GeoIP.h> ++ #include <GeoIPCity.h> ++ #include <netinet/in.h> ++ ], [ ++ struct in6_addr in6; ++ int i = GEOIP_CITY_EDITION_REV0_V6; ++ GeoIP_record_by_ipnum_v6(NULL, in6); ++ ])], ++ [ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE(HAVE_GEOIP_CITY_V6, 1, Build with GeoIP City IPv6 support) ++ ], ++ [AC_MSG_RESULT([no])] ++ ) ++ ;; ++esac ++AC_SUBST(GEOIPLINKSRCS) ++AC_SUBST(GEOIPLINKOBJS) ++ + AC_MSG_CHECKING(for GSSAPI library) + AC_ARG_WITH(gssapi, + [ --with-gssapi=PATH Specify path for system-supplied GSSAPI [[default=yes]]], +@@ -3965,6 +4058,7 @@ AC_CONFIG_FILES([ + bin/tests/system/dyndb/driver/Makefile + bin/tests/system/ecdsa/prereq.sh + bin/tests/system/filter-aaaa/Makefile ++ bin/tests/system/geoip/Makefile + bin/tests/system/gost/prereq.sh + bin/tests/system/lwresd/Makefile + bin/tests/system/rpz/Makefile +diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml +index 16b50a3..b79bfa0 100644 +--- a/doc/arm/Bv9ARM-book.xml ++++ b/doc/arm/Bv9ARM-book.xml +@@ -3412,6 +3412,62 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa. + </tgroup> + </informaltable> + ++ <para> ++ When <acronym>BIND</acronym> 9 is built with GeoIP support, ++ ACLs can also be used for geographic access restrictions. ++ This is done by specifying an ACL element of the form: ++ <command>geoip <optional>db <replaceable>database</replaceable></optional> <replaceable>field</replaceable> <replaceable>value</replaceable></command> ++ </para> ++ <para> ++ The <replaceable>field</replaceable> indicates which field ++ to search for a match. Available fields are "country", ++ "region", "city", "continent", "postal" (postal code), ++ "metro" (metro code), "area" (area code), "tz" (timezone), ++ "isp", "org", "asnum", "domain" and "netspeed". ++ </para> ++ <para> ++ <replaceable>value</replaceable> is the value to searched for ++ within the database. A string may be quoted if it contains ++ spaces or other special characters. If this is a "country" ++ search and the string is two characters long, then it must be a ++ standard ISO-3166-1 two-letter country code, and if it is three ++ characters long then it must be an ISO-3166-1 three-letter ++ country code; otherwise it is the full name of the country. ++ Similarly, if this is a "region" search and the string is ++ two characters long, then it must be a standard two-letter state ++ or province abbreviation; otherwise it is the full name of the ++ state or province. ++ </para> ++ <para> ++ The <replaceable>database</replaceable> field indicates which ++ GeoIP database to search for a match. In most cases this is ++ unnecessary, because most search fields can only be found in ++ a single database. However, searches for country can be ++ answered from the "city", "region", or "country" databases, ++ and searches for region (i.e., state or provice) can be ++ answered from the "city" or "region" databases. For these ++ search types, specifying a <replaceable>database</replaceable> ++ will force the query to be answered from that database and no ++ other. If <replaceable>database</replaceable> is not ++ specified, then these queries will be answered from the "city", ++ database if it is installed, or the "region" database if it is ++ installed, or the "country" database, in that order. ++ </para> ++ <para> ++ Some example GeoIP ACLs: ++ </para> ++ <programlisting>geoip country US; ++geoip country JAP; ++geoip db country country Canada; ++geoip db region region WA; ++geoip city "San Francisco"; ++geoip region Oklahoma; ++geoip postal 95062; ++geoip tz "America/Los_Angeles"; ++geoip org "Internet Systems Consortium"; ++</programlisting> ++ ++ + </sect2> + <sect2> + <title><command>controls</command> Statement Grammar</title> +@@ -4692,6 +4748,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] + <optional> hostname <replaceable>hostname_string</replaceable>; </optional> + <optional> server-id <replaceable>server_id_string</replaceable>; </optional> + <optional> directory <replaceable>path_name</replaceable>; </optional> ++ <optional> geoip-directory <replaceable>path_name</replaceable>; </optional> + <optional> key-directory <replaceable>path_name</replaceable>; </optional> + <optional> managed-keys-directory <replaceable>path_name</replaceable>; </optional> + <optional> named-xfer <replaceable>path_name</replaceable>; </optional> +@@ -5048,6 +5105,21 @@ badresp:1,adberr:0,findfail:0,valfail:0] + </varlistentry> + + <varlistentry> ++ <term><command>geoip-directory</command></term> ++ <listitem> ++ <para> ++ Specifies the directory containing GeoIP ++ <filename>.dat</filename> database files for GeoIP ++ initialization. By default, this option is unset ++ and the GeoIP support will use libGeoIP's ++ built-in directory. ++ (For details, see <xref linkend="acl"/> about the ++ <command>geoip</command> ACL.) ++ </para> ++ </listitem> ++ </varlistentry> ++ ++ <varlistentry> + <term><command>key-directory</command></term> + <listitem> + <para> +diff --git a/lib/dns/Makefile.in b/lib/dns/Makefile.in +index 2efcc5a..ae316c5 100644 +--- a/lib/dns/Makefile.in ++++ b/lib/dns/Makefile.in +@@ -56,6 +56,8 @@ DSTOBJS = @DST_EXTRA_OBJS@ @OPENSSLLINKOBJS@ @PKCS11LINKOBJS@ \ + + RRLOBJS = rrl.@O@ + ++GEOIPLINKOBJS = geoip.@O@ ++ + # Alphabetically + DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ + cache.@O@ callbacks.@O@ clientinfo.@O@ compress.@O@ \ +@@ -75,7 +77,7 @@ DNSOBJS = acache.@O@ acl.@O@ adb.@O@ byaddr.@O@ \ + tsec.@O@ tsig.@O@ ttl.@O@ update.@O@ validator.@O@ \ + version.@O@ view.@O@ xfrin.@O@ zone.@O@ zonekey.@O@ zt.@O@ + +-OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} @RRLLINKOBJS@ ++OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} @RRLLINKOBJS@ @GEOIPLINKOBJS@ + + # Alphabetically + OPENSSLGOSTLINKSRCS = opensslgost_link.c +@@ -90,6 +92,8 @@ DSTSRCS = @DST_EXTRA_SRCS@ @OPENSSLLINKSRCS@ @PKCS11LINKSRCS@ \ + dst_result.c gssapi_link.c gssapictx.c \ + hmac_link.c key.c + ++GEOIOLINKSRCS = geoip.c ++ + DNSSRCS = acache.c acl.c adb.c byaddr.c \ + cache.c callbacks.c clientinfo.c compress.c \ + db.c dbiterator.c dbtable.c diff.c dispatch.c \ +@@ -107,7 +111,7 @@ DNSSRCS = acache.c acl.c adb.c byaddr.c \ + + RRLSRCS = rrl.c + +-SRCS = ${DSTSRCS} ${DNSSRCS} @RRLLINKSRCS@ ++SRCS = ${DSTSRCS} ${DNSSRCS} @RRLLINKSRCS@ @GEOIPLINKSRCS@ + + SUBDIRS = include + TARGETS = include/dns/enumtype.h include/dns/enumclass.h \ +diff --git a/lib/dns/acl.c b/lib/dns/acl.c +index 3221d30..aad9aa5 100644 +--- a/lib/dns/acl.c ++++ b/lib/dns/acl.c +@@ -29,6 +29,7 @@ + #include <dns/acl.h> + #include <dns/iptable.h> + ++ + /* + * Create a new ACL, including an IP table and an array with room + * for 'n' ACL elements. The elements are uninitialized and the +@@ -336,6 +337,14 @@ dns_acl_merge(dns_acl_t *dest, dns_acl_t *source, isc_boolean_t pos) + return result; + } + ++#ifdef HAVE_GEOIP ++ /* Duplicate GeoIP data */ ++ if (source->elements[i].type == dns_aclelementtype_geoip) { ++ dest->elements[nelem + i].geoip_elem = ++ source->elements[i].geoip_elem; ++ } ++#endif ++ + /* reverse sense of positives if this is a negative acl */ + if (!pos && source->elements[i].negative == ISC_FALSE) { + dest->elements[nelem + i].negative = ISC_TRUE; +@@ -386,9 +395,8 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, + if (matchelt != NULL) + *matchelt = e; + return (ISC_TRUE); +- } else { ++ } else + return (ISC_FALSE); +- } + + case dns_aclelementtype_nestedacl: + inner = e->nestedacl; +@@ -406,6 +414,12 @@ dns_aclelement_match(const isc_netaddr_t *reqaddr, + inner = env->localnets; + break; + ++#ifdef HAVE_GEOIP ++ case dns_aclelementtype_geoip: ++ if (env == NULL || env->geoip == NULL) ++ return (ISC_FALSE); ++ return (dns_geoip_match(reqaddr, env->geoip, &e->geoip_elem)); ++#endif + default: + /* Should be impossible. */ + INSIST(0); +@@ -560,7 +574,7 @@ dns_acl_isinsecure(const dns_acl_t *a) { + insecure = insecure_prefix_found; + UNLOCK(&insecure_prefix_lock); + if (insecure) +- return(ISC_TRUE); ++ return (ISC_TRUE); + + /* Now check non-radix elements */ + for (i = 0; i < a->length; i++) { +@@ -609,6 +623,9 @@ dns_aclenv_init(isc_mem_t *mctx, dns_aclenv_t *env) { + if (result != ISC_R_SUCCESS) + goto cleanup_localhost; + env->match_mapped = ISC_FALSE; ++#ifdef HAVE_GEOIP ++ env->geoip = NULL; ++#endif + return (ISC_R_SUCCESS); + + cleanup_localhost: +diff --git a/lib/dns/geoip.c b/lib/dns/geoip.c +new file mode 100644 +index 0000000..5387ebb +--- /dev/null ++++ b/lib/dns/geoip.c +@@ -0,0 +1,820 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <isc/util.h> ++ ++#include <isc/mem.h> ++#include <isc/once.h> ++#include <isc/string.h> ++ ++#include <dns/acl.h> ++#include <dns/geoip.h> ++ ++#include <isc/thread.h> ++#include <math.h> ++#include <netinet/in.h> ++#include <dns/log.h> ++ ++#ifdef HAVE_GEOIP ++#include <GeoIP.h> ++#include <GeoIPCity.h> ++ ++/* ++ * This structure preserves state from the previous GeoIP lookup, ++ * so that successive lookups for the same data from the same IP ++ * address will not require repeated calls into the GeoIP library ++ * to look up data in the database. This should improve performance ++ * somewhat. ++ * ++ * For lookups in the City and Region databases, we preserve pointers ++ * to the GeoIPRecord and GeoIPregion structures; these will need to be ++ * freed by GeoIPRecord_delete() and GeoIPRegion_delete(). ++ * ++ * for lookups in ISP, AS, Org and Domain we prserve a pointer to ++ * the returned name; these must be freed by free(). ++ * ++ * For lookups in Country we preserve a pointer to the text of ++ * the country code, name, etc (we use a different pointer for this ++ * than for the names returned by Org, ISP, etc, because those need ++ * to be freed but country lookups do not). ++ * ++ * For lookups in Netspeed we preserve the returned ID. ++ * ++ * XXX: Currently this mechanism is only used for IPv4 lookups; the ++ * family and addr6 fields are to be used IPv6 is added. ++ */ ++typedef struct geoip_state { ++ isc_uint16_t subtype; ++ unsigned int family; ++ isc_uint32_t ipnum; ++ geoipv6_t ipnum6; ++ GeoIPRecord *record; ++ GeoIPRegion *region; ++ const char *text; ++ char *name; ++ int id; ++ isc_mem_t *mctx; ++} geoip_state_t; ++ ++#ifdef ISC_PLATFORM_USETHREADS ++static isc_mutex_t key_mutex; ++static isc_boolean_t state_key_initialized = ISC_FALSE; ++static isc_thread_key_t state_key; ++static isc_once_t mutex_once = ISC_ONCE_INIT; ++static isc_mem_t *state_mctx = NULL; ++ ++static void ++key_mutex_init(void) { ++ RUNTIME_CHECK(isc_mutex_init(&key_mutex) == ISC_R_SUCCESS); ++} ++ ++static void ++free_state(void *arg) { ++ geoip_state_t *state = arg; ++ if (state != NULL && state->record != NULL) ++ GeoIPRecord_delete(state->record); ++ if (state != NULL) ++ isc_mem_putanddetach(&state->mctx, ++ state, sizeof(geoip_state_t)); ++ isc_thread_key_setspecific(state_key, NULL); ++} ++ ++static isc_result_t ++state_key_init(void) { ++ isc_result_t result; ++ ++ result = isc_once_do(&mutex_once, key_mutex_init); ++ if (result != ISC_R_SUCCESS) ++ return (result); ++ ++ if (!state_key_initialized) { ++ LOCK(&key_mutex); ++ if (!state_key_initialized) { ++ int ret; ++ ++ if (state_mctx == NULL) ++ result = isc_mem_create2(0, 0, &state_mctx, 0); ++ if (result != ISC_R_SUCCESS) ++ goto unlock; ++ isc_mem_setname(state_mctx, "geoip_state", NULL); ++ isc_mem_setdestroycheck(state_mctx, ISC_FALSE); ++ ++ ret = isc_thread_key_create(&state_key, free_state); ++ if (ret == 0) ++ state_key_initialized = ISC_TRUE; ++ else ++ result = ISC_R_FAILURE; ++ } ++ unlock: ++ UNLOCK(&key_mutex); ++ } ++ ++ return (result); ++} ++#else ++static geoip_state_t saved_state; ++#endif ++ ++static void ++clean_state(geoip_state_t *state) { ++ if (state == NULL) ++ return; ++ ++ if (state->record != NULL) { ++ GeoIPRecord_delete(state->record); ++ state->record = NULL; ++ } ++ if (state->region != NULL) { ++ GeoIPRegion_delete(state->region); ++ state->region = NULL; ++ } ++ if (state->name != NULL) { ++ free (state->name); ++ state->name = NULL; ++ } ++ state->ipnum = 0; ++ state->text = NULL; ++ state->id = 0; ++} ++ ++static isc_result_t ++set_state(unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6, ++ dns_geoip_subtype_t subtype, GeoIPRecord *record, ++ GeoIPRegion *region, char *name, const char *text, int id) ++{ ++ geoip_state_t *state = NULL; ++#ifdef ISC_PLATFORM_USETHREADS ++ isc_result_t result; ++ ++ result = state_key_init(); ++ if (result != ISC_R_SUCCESS) ++ return (result); ++ ++ state = (geoip_state_t *) isc_thread_key_getspecific(state_key); ++ if (state == NULL) { ++ state = (geoip_state_t *) isc_mem_get(state_mctx, ++ sizeof(geoip_state_t)); ++ if (state == NULL) ++ return (ISC_R_NOMEMORY); ++ memset(state, 0, sizeof(*state)); ++ ++ result = isc_thread_key_setspecific(state_key, state); ++ if (result != ISC_R_SUCCESS) { ++ isc_mem_put(state_mctx, state, sizeof(geoip_state_t)); ++ return (result); ++ } ++ ++ isc_mem_attach(state_mctx, &state->mctx); ++ } else ++ clean_state(state); ++#else ++ state = &saved_state; ++ clean_state(state); ++#endif ++ ++ if (family == AF_INET) ++ state->ipnum = ipnum; ++ else ++ state->ipnum6 = *ipnum6; ++ ++ state->family = family; ++ state->subtype = subtype; ++ state->record = record; ++ state->region = region; ++ state->name = name; ++ state->text = text; ++ state->id = id; ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static geoip_state_t * ++get_state_for(unsigned int family, isc_uint32_t ipnum, ++ const geoipv6_t *ipnum6) ++{ ++ geoip_state_t *state; ++ ++#ifdef ISC_PLATFORM_USETHREADS ++ isc_result_t result; ++ ++ result = state_key_init(); ++ if (result != ISC_R_SUCCESS) ++ return (NULL); ++ ++ state = (geoip_state_t *) isc_thread_key_getspecific(state_key); ++ if (state == NULL) ++ return (NULL); ++#else ++ state = &saved_state; ++#endif ++ ++ if (state->family == family && ++ ((state->family == AF_INET && state->ipnum == ipnum) || ++ (state->family == AF_INET6 && ipnum6 != NULL && ++ memcmp(state->ipnum6.s6_addr, ipnum6->s6_addr, 16) == 0))) ++ return (state); ++ ++ return (NULL); ++} ++ ++/* ++ * Country lookups are performed if the previous lookup was from a ++ * different IP address than the current, or was for a search of a ++ * different subtype. ++ */ ++static const char * ++country_lookup(GeoIP *db, dns_geoip_subtype_t subtype, ++ unsigned int family, ++ isc_uint32_t ipnum, const geoipv6_t *ipnum6) ++{ ++ geoip_state_t *prev_state = NULL; ++ const char *text = NULL; ++ ++ REQUIRE(db != NULL); ++ ++#ifndef HAVE_GEOIP_V6 ++ /* no IPv6 support? give up now */ ++ if (family == AF_INET6) ++ return (NULL); ++#endif ++ ++ prev_state = get_state_for(family, ipnum, ipnum6); ++ if (prev_state != NULL && prev_state->subtype == subtype) ++ text = prev_state->text; ++ ++ if (text == NULL) { ++ switch (subtype) { ++ case dns_geoip_country_code: ++ if (family == AF_INET) ++ text = GeoIP_country_code_by_ipnum(db, ipnum); ++#ifdef HAVE_GEOIP_V6 ++ else ++ text = GeoIP_country_code_by_ipnum_v6(db, ++ *ipnum6); ++#endif ++ break; ++ case dns_geoip_country_code3: ++ if (family == AF_INET) ++ text = GeoIP_country_code3_by_ipnum(db, ipnum); ++#ifdef HAVE_GEOIP_V6 ++ else ++ text = GeoIP_country_code3_by_ipnum_v6(db, ++ *ipnum6); ++#endif ++ break; ++ case dns_geoip_country_name: ++ if (family == AF_INET) ++ text = GeoIP_country_name_by_ipnum(db, ipnum); ++#ifdef HAVE_GEOIP_V6 ++ else ++ text = GeoIP_country_name_by_ipnum_v6(db, ++ *ipnum6); ++#endif ++ break; ++ default: ++ INSIST(0); ++ } ++ ++ set_state(family, ipnum, ipnum6, subtype, ++ NULL, NULL, NULL, text, 0); ++ } ++ ++ return (text); ++} ++ ++static char * ++city_string(GeoIPRecord *record, dns_geoip_subtype_t subtype, int *maxlen) { ++ const char *s; ++ char *deconst; ++ ++ REQUIRE(record != NULL); ++ REQUIRE(maxlen != NULL); ++ ++ /* Set '*maxlen' to the maximum length of this subtype, if any */ ++ switch (subtype) { ++ case dns_geoip_city_countrycode: ++ case dns_geoip_city_region: ++ case dns_geoip_city_continentcode: ++ *maxlen = 2; ++ break; ++ ++ case dns_geoip_city_countrycode3: ++ *maxlen = 3; ++ break; ++ ++ default: ++ /* No fixed length; just use strcasecmp() for comparison */ ++ *maxlen = 255; ++ } ++ ++ switch (subtype) { ++ case dns_geoip_city_countrycode: ++ return (record->country_code); ++ case dns_geoip_city_countrycode3: ++ return (record->country_code3); ++ case dns_geoip_city_countryname: ++ return (record->country_name); ++ case dns_geoip_city_region: ++ return (record->region); ++ case dns_geoip_city_regionname: ++ s = GeoIP_region_name_by_code(record->country_code, ++ record->region); ++ DE_CONST(s, deconst); ++ return (deconst); ++ case dns_geoip_city_name: ++ return (record->city); ++ case dns_geoip_city_postalcode: ++ return (record->postal_code); ++ case dns_geoip_city_continentcode: ++ return (record->continent_code); ++ case dns_geoip_city_timezonecode: ++ s = GeoIP_time_zone_by_country_and_region(record->country_code, ++ record->region); ++ DE_CONST(s, deconst); ++ return (deconst); ++ default: ++ INSIST(0); ++ } ++} ++ ++static isc_boolean_t ++is_city(dns_geoip_subtype_t subtype) { ++ switch (subtype) { ++ case dns_geoip_city_countrycode: ++ case dns_geoip_city_countrycode3: ++ case dns_geoip_city_countryname: ++ case dns_geoip_city_region: ++ case dns_geoip_city_regionname: ++ case dns_geoip_city_name: ++ case dns_geoip_city_postalcode: ++ case dns_geoip_city_continentcode: ++ case dns_geoip_city_timezonecode: ++ case dns_geoip_city_metrocode: ++ case dns_geoip_city_areacode: ++ return (ISC_TRUE); ++ default: ++ return (ISC_FALSE); ++ } ++} ++ ++/* ++ * GeoIPRecord lookups are performed if the previous lookup was ++ * from a different IP address than the current, or was for a search ++ * outside the City database. ++ */ ++static GeoIPRecord * ++city_lookup(GeoIP *db, dns_geoip_subtype_t subtype, ++ unsigned int family, isc_uint32_t ipnum, const geoipv6_t *ipnum6) ++{ ++ GeoIPRecord *record = NULL; ++ geoip_state_t *prev_state = NULL; ++ ++ REQUIRE(db != NULL); ++ ++#ifndef HAVE_GEOIP_V6 ++ /* no IPv6 support? give up now */ ++ if (family == AF_INET6) ++ return (NULL); ++#endif ++ ++ prev_state = get_state_for(family, ipnum, ipnum6); ++ if (prev_state != NULL && is_city(prev_state->subtype)) ++ record = prev_state->record; ++ ++ if (record == NULL) { ++ if (family == AF_INET) ++ record = GeoIP_record_by_ipnum(db, ipnum); ++#ifdef HAVE_GEOIP_V6 ++ else ++ record = GeoIP_record_by_ipnum_v6(db, *ipnum6); ++#endif ++ if (record == NULL) ++ return (NULL); ++ ++ set_state(family, ipnum, ipnum6, subtype, ++ record, NULL, NULL, NULL, 0); ++ } ++ ++ return (record); ++} ++ ++static char * ++region_string(GeoIPRegion *region, dns_geoip_subtype_t subtype, int *maxlen) { ++ const char *s; ++ char *deconst; ++ ++ REQUIRE(region != NULL); ++ REQUIRE(maxlen != NULL); ++ ++ switch (subtype) { ++ case dns_geoip_region_countrycode: ++ *maxlen = 2; ++ return (region->country_code); ++ case dns_geoip_region_code: ++ *maxlen = 2; ++ return (region->region); ++ case dns_geoip_region_name: ++ *maxlen = 255; ++ s = GeoIP_region_name_by_code(region->country_code, ++ region->region); ++ DE_CONST(s, deconst); ++ return (deconst); ++ default: ++ INSIST(0); ++ } ++} ++ ++static isc_boolean_t ++is_region(dns_geoip_subtype_t subtype) { ++ switch (subtype) { ++ case dns_geoip_region_countrycode: ++ case dns_geoip_region_code: ++ return (ISC_TRUE); ++ default: ++ return (ISC_FALSE); ++ } ++} ++ ++/* ++ * GeoIPRegion lookups are performed if the previous lookup was ++ * from a different IP address than the current, or was for a search ++ * outside the Region database. ++ */ ++static GeoIPRegion * ++region_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { ++ GeoIPRegion *region = NULL; ++ geoip_state_t *prev_state = NULL; ++ ++ REQUIRE(db != NULL); ++ ++ prev_state = get_state_for(AF_INET, ipnum, NULL); ++ if (prev_state != NULL && is_region(prev_state->subtype)) ++ region = prev_state->region; ++ ++ if (region == NULL) { ++ region = GeoIP_region_by_ipnum(db, ipnum); ++ if (region == NULL) ++ return (NULL); ++ ++ set_state(AF_INET, ipnum, NULL, ++ subtype, NULL, region, NULL, NULL, 0); ++ } ++ ++ return (region); ++} ++ ++/* ++ * ISP, Organization, AS Number and Domain lookups are performed if ++ * the previous lookup was from a different IP address than the current, ++ * or was for a search of a different subtype. ++ */ ++static char * ++name_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { ++ char *name = NULL; ++ geoip_state_t *prev_state = NULL; ++ ++ REQUIRE(db != NULL); ++ ++ prev_state = get_state_for(AF_INET, ipnum, NULL); ++ if (prev_state != NULL && prev_state->subtype == subtype) ++ name = prev_state->name; ++ ++ if (name == NULL) { ++ name = GeoIP_name_by_ipnum(db, ipnum); ++ if (name == NULL) ++ return (NULL); ++ ++ set_state(AF_INET, ipnum, NULL, ++ subtype, NULL, NULL, name, NULL, 0); ++ } ++ ++ return (name); ++} ++ ++/* ++ * Netspeed lookups are performed if the previous lookup was from a ++ * different IP address than the current, or was for a search of a ++ * different subtype. ++ */ ++static int ++netspeed_lookup(GeoIP *db, dns_geoip_subtype_t subtype, isc_uint32_t ipnum) { ++ geoip_state_t *prev_state = NULL; ++ isc_boolean_t found = ISC_FALSE; ++ int id = -1; ++ ++ REQUIRE(db != NULL); ++ ++ prev_state = get_state_for(AF_INET, ipnum, NULL); ++ if (prev_state != NULL && prev_state->subtype == subtype) { ++ id = prev_state->id; ++ found = ISC_TRUE; ++ } ++ ++ if (!found) { ++ id = GeoIP_id_by_ipnum(db, ipnum); ++ set_state(AF_INET, ipnum, NULL, ++ subtype, NULL, NULL, NULL, NULL, id); ++ } ++ ++ return (id); ++} ++#endif /* HAVE_GEOIP */ ++ ++#define DB46(addr, geoip, name) \ ++ ((addr->family == AF_INET) ? (geoip->name##_v4) : (geoip->name##_v6)) ++ ++#ifdef HAVE_GEOIP ++/* ++ * Find the best database to answer a generic subtype ++ */ ++static dns_geoip_subtype_t ++fix_subtype(const isc_netaddr_t *reqaddr, const dns_geoip_databases_t *geoip, ++ dns_geoip_subtype_t subtype) ++{ ++ dns_geoip_subtype_t ret = subtype; ++ ++ switch (subtype) { ++ case dns_geoip_countrycode: ++ if (DB46(reqaddr, geoip, city) != NULL) ++ ret = dns_geoip_city_countrycode; ++ else if (reqaddr->family == AF_INET && geoip->region != NULL) ++ ret = dns_geoip_region_countrycode; ++ else if (DB46(reqaddr, geoip, country) != NULL) ++ ret = dns_geoip_country_code; ++ break; ++ case dns_geoip_countrycode3: ++ if (DB46(reqaddr, geoip, city) != NULL) ++ ret = dns_geoip_city_countrycode3; ++ else if (DB46(reqaddr, geoip, country) != NULL) ++ ret = dns_geoip_country_code3; ++ break; ++ case dns_geoip_countryname: ++ if (DB46(reqaddr, geoip, city) != NULL) ++ ret = dns_geoip_city_countryname; ++ else if (DB46(reqaddr, geoip, country) != NULL) ++ ret = dns_geoip_country_name; ++ break; ++ case dns_geoip_region: ++ if (DB46(reqaddr, geoip, city) != NULL) ++ ret = dns_geoip_city_region; ++ else if (reqaddr->family == AF_INET && geoip->region != NULL) ++ ret = dns_geoip_region_code; ++ break; ++ case dns_geoip_regionname: ++ if (DB46(reqaddr, geoip, city) != NULL) ++ ret = dns_geoip_city_regionname; ++ else if (reqaddr->family == AF_INET && geoip->region != NULL) ++ ret = dns_geoip_region_name; ++ break; ++ default: ++ break; ++ } ++ ++ return (ret); ++} ++#endif /* HAVE_GEOIP */ ++ ++isc_boolean_t ++dns_geoip_match(const isc_netaddr_t *reqaddr, ++ const dns_geoip_databases_t *geoip, ++ const dns_geoip_elem_t *elt) ++{ ++#ifndef HAVE_GEOIP ++ UNUSED(reqaddr); ++ UNUSED(geoip); ++ UNUSED(elt); ++ ++ return (ISC_FALSE); ++#else ++ GeoIP *db; ++ GeoIPRecord *record; ++ GeoIPRegion *region; ++ dns_geoip_subtype_t subtype; ++ isc_uint32_t ipnum = 0; ++ int maxlen = 0, id, family; ++ const char *cs; ++ char *s; ++#ifdef HAVE_GEOIP_V6 ++ const geoipv6_t *ipnum6 = NULL; ++#else ++ const void *ipnum6 = NULL; ++#endif ++ ++ INSIST(geoip != NULL); ++ ++ family = reqaddr->family; ++ switch (family) { ++ case AF_INET: ++ ipnum = ntohl(reqaddr->type.in.s_addr); ++ break; ++ case AF_INET6: ++#ifdef HAVE_GEOIP_V6 ++ ipnum6 = &reqaddr->type.in6; ++ break; ++#else ++ return (ISC_FALSE); ++#endif ++ default: ++ return (ISC_FALSE); ++ } ++ ++ subtype = fix_subtype(reqaddr, geoip, elt->subtype); ++ ++ switch (subtype) { ++ case dns_geoip_country_code: ++ maxlen = 2; ++ goto getcountry; ++ ++ case dns_geoip_country_code3: ++ maxlen = 3; ++ goto getcountry; ++ ++ case dns_geoip_country_name: ++ maxlen = 255; ++ getcountry: ++ db = DB46(reqaddr, geoip, country); ++ if (db == NULL) ++ return (ISC_FALSE); ++ ++ INSIST(elt->as_string != NULL); ++ ++ cs = country_lookup(db, subtype, family, ipnum, ipnum6); ++ if (cs != NULL && strncasecmp(elt->as_string, cs, maxlen) == 0) ++ return (ISC_TRUE); ++ break; ++ ++ case dns_geoip_city_countrycode: ++ case dns_geoip_city_countrycode3: ++ case dns_geoip_city_countryname: ++ case dns_geoip_city_region: ++ case dns_geoip_city_regionname: ++ case dns_geoip_city_name: ++ case dns_geoip_city_postalcode: ++ case dns_geoip_city_continentcode: ++ case dns_geoip_city_timezonecode: ++ INSIST(elt->as_string != NULL); ++ ++ db = DB46(reqaddr, geoip, city); ++ if (db == NULL) ++ return (ISC_FALSE); ++ ++ record = city_lookup(db, subtype, family, ipnum, ipnum6); ++ if (record == NULL) ++ break; ++ ++ s = city_string(record, subtype, &maxlen); ++ INSIST(maxlen != 0); ++ if (s != NULL && strncasecmp(elt->as_string, s, maxlen) == 0) ++ return (ISC_TRUE); ++ break; ++ ++ case dns_geoip_city_metrocode: ++ db = DB46(reqaddr, geoip, city); ++ if (db == NULL) ++ return (ISC_FALSE); ++ ++ record = city_lookup(db, subtype, family, ipnum, ipnum6); ++ if (record == NULL) ++ break; ++ ++ if (elt->as_int == record->metro_code) ++ return (ISC_TRUE); ++ break; ++ ++ case dns_geoip_city_areacode: ++ db = DB46(reqaddr, geoip, city); ++ if (db == NULL) ++ return (ISC_FALSE); ++ ++ record = city_lookup(db, subtype, family, ipnum, ipnum6); ++ if (record == NULL) ++ break; ++ ++ if (elt->as_int == record->area_code) ++ return (ISC_TRUE); ++ break; ++ ++ case dns_geoip_region_countrycode: ++ case dns_geoip_region_code: ++ case dns_geoip_region_name: ++ case dns_geoip_region: ++ if (geoip->region == NULL) ++ return (ISC_FALSE); ++ ++ INSIST(elt->as_string != NULL); ++ ++ /* Region DB is not supported for IPv6 */ ++ if (family == AF_INET6) ++ return (ISC_FALSE); ++ ++ region = region_lookup(geoip->region, subtype, ipnum); ++ if (region == NULL) ++ break; ++ ++ s = region_string(region, subtype, &maxlen); ++ INSIST(maxlen != 0); ++ if (s != NULL && strncasecmp(elt->as_string, s, maxlen) == 0) ++ return (ISC_TRUE); ++ break; ++ ++ case dns_geoip_isp_name: ++ db = geoip->isp; ++ goto getname; ++ ++ case dns_geoip_org_name: ++ db = geoip->org; ++ goto getname; ++ ++ case dns_geoip_as_asnum: ++ db = geoip->as; ++ goto getname; ++ ++ case dns_geoip_domain_name: ++ db = geoip->domain; ++ ++ getname: ++ if (db == NULL) ++ return (ISC_FALSE); ++ ++ INSIST(elt->as_string != NULL); ++ /* ISP, Org, AS, and Domain are not supported for IPv6 */ ++ if (family == AF_INET6) ++ return (ISC_FALSE); ++ ++ s = name_lookup(db, subtype, ipnum); ++ if (s != NULL) { ++ size_t l; ++ if (strcasecmp(elt->as_string, s) == 0) ++ return (ISC_TRUE); ++ if (subtype != dns_geoip_as_asnum) ++ break; ++ /* ++ * Just check if the ASNNNN value matches. ++ */ ++ l = strlen(elt->as_string); ++ if (l > 0U && strchr(elt->as_string, ' ') == NULL && ++ strncasecmp(elt->as_string, s, l) == 0 && ++ s[l] == ' ') ++ return (ISC_TRUE); ++ } ++ break; ++ ++ case dns_geoip_netspeed_id: ++ INSIST(geoip->netspeed != NULL); ++ ++ /* Netspeed DB is not supported for IPv6 */ ++ if (family == AF_INET6) ++ return (ISC_FALSE); ++ ++ id = netspeed_lookup(geoip->netspeed, subtype, ipnum); ++ if (id == elt->as_int) ++ return (ISC_TRUE); ++ break; ++ ++ case dns_geoip_countrycode: ++ case dns_geoip_countrycode3: ++ case dns_geoip_countryname: ++ case dns_geoip_regionname: ++ /* ++ * If these were not remapped by fix_subtype(), ++ * the database was unavailable. Always return false. ++ */ ++ break; ++ ++ default: ++ INSIST(0); ++ } ++ ++ return (ISC_FALSE); ++#endif ++} ++ ++void ++dns_geoip_shutdown(void) { ++#ifdef HAVE_GEOIP ++ GeoIP_cleanup(); ++#ifdef ISC_PLATFORM_USETHREADS ++ if (state_mctx != NULL) ++ isc_mem_detach(&state_mctx); ++#endif ++#else ++ return; ++#endif ++} +diff --git a/lib/dns/include/dns/Makefile.in b/lib/dns/include/dns/Makefile.in +index a37b35e..2fcbd1e 100644 +--- a/lib/dns/include/dns/Makefile.in ++++ b/lib/dns/include/dns/Makefile.in +@@ -23,9 +23,9 @@ top_srcdir = @top_srcdir@ + + HEADERS = acl.h adb.h byaddr.h cache.h callbacks.h cert.h compress.h \ + clientinfo.h db.h dbiterator.h dbtable.h diff.h dispatch.h \ +- dlz.h dyndb.h dnssec.h ds.h events.h fixedname.h iptable.h \ +- journal.h keyflags.h keytable.h keyvalues.h lib.h log.h \ +- master.h masterdump.h message.h name.h ncache.h nsec.h \ ++ dlz.h dyndb.h dnssec.h ds.h events.h fixedname.h geoip.h \ ++ iptable.h journal.h keyflags.h keytable.h keyvalues.h lib.h \ ++ log.h master.h masterdump.h message.h name.h ncache.h nsec.h \ + peer.h portlist.h private.h rbt.h rcode.h \ + rdata.h rdataclass.h rdatalist.h rdataset.h rdatasetiter.h \ + rdataslab.h rdatatype.h request.h resolver.h result.h \ +diff --git a/lib/dns/include/dns/acl.h b/lib/dns/include/dns/acl.h +index f4fc4a3..2c3bb37 100644 +--- a/lib/dns/include/dns/acl.h ++++ b/lib/dns/include/dns/acl.h +@@ -38,10 +38,17 @@ + #include <isc/netaddr.h> + #include <isc/refcount.h> + ++#ifdef HAVE_GEOIP ++#include <dns/geoip.h> ++#endif + #include <dns/name.h> + #include <dns/types.h> + #include <dns/iptable.h> + ++#ifdef HAVE_GEOIP ++#include <GeoIP.h> ++#endif ++ + /*** + *** Types + ***/ +@@ -52,8 +59,11 @@ typedef enum { + dns_aclelementtype_nestedacl, + dns_aclelementtype_localhost, + dns_aclelementtype_localnets, ++#ifdef HAVE_GEOIP ++ dns_aclelementtype_geoip, ++#endif /* HAVE_GEOIP */ + dns_aclelementtype_any +-} dns_aclelemettype_t; ++} dns_aclelementtype_t; + + typedef struct dns_aclipprefix dns_aclipprefix_t; + +@@ -63,9 +73,12 @@ struct dns_aclipprefix { + }; + + struct dns_aclelement { +- dns_aclelemettype_t type; ++ dns_aclelementtype_t type; + isc_boolean_t negative; + dns_name_t keyname; ++#ifdef HAVE_GEOIP ++ dns_geoip_elem_t geoip_elem; ++#endif /* HAVE_GEOIP */ + dns_acl_t *nestedacl; + int node_num; + }; +@@ -88,6 +101,9 @@ struct dns_aclenv { + dns_acl_t *localhost; + dns_acl_t *localnets; + isc_boolean_t match_mapped; ++#ifdef HAVE_GEOIP ++ dns_geoip_databases_t *geoip; ++#endif + }; + + #define DNS_ACL_MAGIC ISC_MAGIC('D','a','c','l') +@@ -214,6 +230,10 @@ dns_acl_match(const isc_netaddr_t *reqaddr, + * and 'matchelt' is non-NULL, *matchelt will be pointed to the matching + * element. + * ++ * 'env' points to the current ACL environment, including the ++ * current values of localhost and localnets and (if applicable) ++ * the GeoIP context. ++ * + * Returns: + *\li #ISC_R_SUCCESS Always succeeds. + */ +diff --git a/lib/dns/include/dns/geoip.h b/lib/dns/include/dns/geoip.h +new file mode 100644 +index 0000000..bad9485 +--- /dev/null ++++ b/lib/dns/include/dns/geoip.h +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef DNS_GEOIP_H ++#define DNS_GEOIP_H 1 ++ ++/***** ++ ***** Module Info ++ *****/ ++ ++/*! \file dns/acl.h ++ * \brief ++ * Address match list handling. ++ */ ++ ++/*** ++ *** Imports ++ ***/ ++ ++#include <isc/lang.h> ++#include <isc/magic.h> ++#include <isc/netaddr.h> ++#include <isc/refcount.h> ++ ++#include <dns/name.h> ++#include <dns/types.h> ++#include <dns/iptable.h> ++ ++#ifdef HAVE_GEOIP ++#include <GeoIP.h> ++#else ++typedef void GeoIP; ++#endif ++ ++/*** ++ *** Types ++ ***/ ++ ++typedef enum { ++ dns_geoip_countrycode, ++ dns_geoip_countrycode3, ++ dns_geoip_countryname, ++ dns_geoip_region, ++ dns_geoip_regionname, ++ dns_geoip_country_code, ++ dns_geoip_country_code3, ++ dns_geoip_country_name, ++ dns_geoip_region_countrycode, ++ dns_geoip_region_code, ++ dns_geoip_region_name, ++ dns_geoip_city_countrycode, ++ dns_geoip_city_countrycode3, ++ dns_geoip_city_countryname, ++ dns_geoip_city_region, ++ dns_geoip_city_regionname, ++ dns_geoip_city_name, ++ dns_geoip_city_postalcode, ++ dns_geoip_city_metrocode, ++ dns_geoip_city_areacode, ++ dns_geoip_city_continentcode, ++ dns_geoip_city_timezonecode, ++ dns_geoip_isp_name, ++ dns_geoip_org_name, ++ dns_geoip_as_asnum, ++ dns_geoip_domain_name, ++ dns_geoip_netspeed_id ++} dns_geoip_subtype_t; ++ ++typedef struct dns_geoip_elem { ++ dns_geoip_subtype_t subtype; ++ GeoIP *db; ++ union { ++ char as_string[256]; ++ int as_int; ++ }; ++} dns_geoip_elem_t; ++ ++typedef struct dns_geoip_databases { ++ GeoIP *country_v4; /* DB 1 */ ++ GeoIP *city_v4; /* DB 2 or 6 */ ++ GeoIP *region; /* DB 3 or 7 */ ++ GeoIP *isp; /* DB 4 */ ++ GeoIP *org; /* DB 5 */ ++ GeoIP *as; /* DB 9 */ ++ GeoIP *netspeed; /* DB 10 */ ++ GeoIP *domain; /* DB 11 */ ++ GeoIP *country_v6; /* DB 12 */ ++ GeoIP *city_v6; /* DB 30 or 31 */ ++} dns_geoip_databases_t; ++ ++/*** ++ *** Functions ++ ***/ ++ ++ISC_LANG_BEGINDECLS ++ ++isc_boolean_t ++dns_geoip_match(const isc_netaddr_t *reqaddr, ++ const dns_geoip_databases_t *geoip, ++ const dns_geoip_elem_t *elt); ++ ++void ++dns_geoip_shutdown(void); ++ ++ISC_LANG_ENDDECLS ++#endif /* DNS_GEOIP_H */ +diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in +index 3b19784..8d1b83e 100644 +--- a/lib/dns/tests/Makefile.in ++++ b/lib/dns/tests/Makefile.in +@@ -40,13 +40,13 @@ LIBS = @LIBS@ @ATFLIBS@ + OBJS = dnstest.@O@ + SRCS = dnstest.c gost_test.c master_test.c dbiterator_test.c time_test.c \ + private_test.c update_test.c zonemgr_test.c zt_test.c \ +- dbdiff_test.c dispatch_test.c nsec3_test.c \ ++ dbdiff_test.c geoip_test.c dispatch_test.c nsec3_test.c \ + rdataset_test.c rdata_test.c + + SUBDIRS = + TARGETS = gost_test@EXEEXT@ master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \ + private_test@EXEEXT@ update_test@EXEEXT@ zonemgr_test@EXEEXT@ \ +- zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ \ ++ zt_test@EXEEXT@ dbversion_test@EXEEXT@ dbdiff_test@EXEEXT@ geoip_test@EXEEXT@ \ + dispatch_test@EXEEXT@ nsec3_test@EXEEXT@ \ + rdataset_test@EXEEXT@ rdata_test@EXEEXT@ + +@@ -129,6 +129,11 @@ gost_test@EXEEXT@: gost_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} + gost_test.@O@ dnstest.@O@ ${DNSLIBS} \ + ${ISCLIBS} ${LIBS} + ++geoip_test@EXEEXT@: geoip_test.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS} ++ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \ ++ geoip_test.@O@ dnstest.@O@ ${DNSLIBS} \ ++ ${ISCLIBS} ${LIBS} ++ + unit:: + sh ${top_srcdir}/unit/unittest.sh + +diff --git a/lib/dns/tests/geoip_test.c b/lib/dns/tests/geoip_test.c +new file mode 100644 +index 0000000..ad983b0 +--- /dev/null ++++ b/lib/dns/tests/geoip_test.c +@@ -0,0 +1,694 @@ ++/* ++ * Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++/* $Id$ */ ++ ++/*! \file */ ++ ++#include <config.h> ++ ++#include <atf-c.h> ++ ++#include <unistd.h> ++ ++#include <isc/types.h> ++ ++#include <dns/geoip.h> ++ ++#include "dnstest.h" ++ ++#ifdef HAVE_GEOIP ++#include <GeoIP.h> ++ ++/* We use GeoIP databases from the 'geoip' system test */ ++#define TEST_GEOIP_DATA "../../../bin/tests/system/geoip/data" ++ ++/* ++ * Helper functions ++ * (Mostly copied from bin/named/geoip.c) ++ */ ++static dns_geoip_databases_t geoip = { ++ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ++}; ++ ++static void ++init_geoip_db(GeoIP **dbp, GeoIPDBTypes edition, GeoIPDBTypes fallback, ++ GeoIPOptions method, const char *name) ++{ ++ char *info; ++ GeoIP *db; ++ ++ REQUIRE(dbp != NULL); ++ ++ db = *dbp; ++ ++ if (db != NULL) { ++ GeoIP_delete(db); ++ db = *dbp = NULL; ++ } ++ ++ if (! GeoIP_db_avail(edition)) { ++ fprintf(stderr, "GeoIP %s (type %d) DB not available\n", ++ name, edition); ++ goto fail; ++ } ++ ++ fprintf(stderr, "initializing GeoIP %s (type %d) DB\n", ++ name, edition); ++ ++ db = GeoIP_open_type(edition, method); ++ if (db == NULL) { ++ fprintf(stderr, ++ "failed to initialize GeoIP %s (type %d) DB%s\n", ++ name, edition, fallback == 0 ++ ? "; geoip matches using this database will fail" ++ : ""); ++ goto fail; ++ } ++ ++ info = GeoIP_database_info(db); ++ if (info != NULL) ++ fprintf(stderr, "%s\n", info); ++ ++ *dbp = db; ++ return; ++ ++ fail: ++ if (fallback != 0) ++ init_geoip_db(dbp, fallback, 0, method, name); ++} ++ ++static void ++load_geoip(const char *dir) { ++ GeoIPOptions method; ++ ++#ifdef _WIN32 ++ method = GEOIP_STANDARD; ++#else ++ method = GEOIP_MMAP_CACHE; ++#endif ++ ++ if (dir != NULL) { ++ char *p; ++ DE_CONST(dir, p); ++ GeoIP_setup_custom_directory(p); ++ } ++ ++ init_geoip_db(&geoip.country_v4, GEOIP_COUNTRY_EDITION, 0, ++ method, "Country (IPv4)"); ++#ifdef HAVE_GEOIP_V6 ++ init_geoip_db(&geoip.country_v6, GEOIP_COUNTRY_EDITION_V6, 0, ++ method, "Country (IPv6)"); ++#endif ++ ++ init_geoip_db(&geoip.city_v4, GEOIP_CITY_EDITION_REV1, ++ GEOIP_CITY_EDITION_REV0, method, "City (IPv4)"); ++#if defined(HAVE_GEOIP_V6) && defined(HAVE_GEOIP_CITY_V6) ++ init_geoip_db(&geoip.city_v6, GEOIP_CITY_EDITION_REV1_V6, ++ GEOIP_CITY_EDITION_REV0_V6, method, "City (IPv6)"); ++#endif ++ ++ init_geoip_db(&geoip.region, GEOIP_REGION_EDITION_REV1, ++ GEOIP_REGION_EDITION_REV0, method, "Region"); ++ init_geoip_db(&geoip.isp, GEOIP_ISP_EDITION, 0, ++ method, "ISP"); ++ init_geoip_db(&geoip.org, GEOIP_ORG_EDITION, 0, ++ method, "Org"); ++ init_geoip_db(&geoip.as, GEOIP_ASNUM_EDITION, 0, ++ method, "AS"); ++ init_geoip_db(&geoip.domain, GEOIP_DOMAIN_EDITION, 0, ++ method, "Domain"); ++ init_geoip_db(&geoip.netspeed, GEOIP_NETSPEED_EDITION, 0, ++ method, "NetSpeed"); ++} ++ ++static isc_boolean_t ++do_lookup_string(const char *addr, dns_geoip_subtype_t subtype, ++ const char *string) ++{ ++ dns_geoip_elem_t elt; ++ struct in_addr in4; ++ isc_netaddr_t na; ++ ++ inet_pton(AF_INET, addr, &in4); ++ isc_netaddr_fromin(&na, &in4); ++ ++ elt.subtype = subtype; ++ strcpy(elt.as_string, string); ++ ++ return (dns_geoip_match(&na, &geoip, &elt)); ++} ++ ++static isc_boolean_t ++do_lookup_string_v6(const char *addr, dns_geoip_subtype_t subtype, ++ const char *string) ++{ ++ dns_geoip_elem_t elt; ++ struct in6_addr in6; ++ isc_netaddr_t na; ++ ++ inet_pton(AF_INET6, addr, &in6); ++ isc_netaddr_fromin6(&na, &in6); ++ ++ elt.subtype = subtype; ++ strcpy(elt.as_string, string); ++ ++ return (dns_geoip_match(&na, &geoip, &elt)); ++} ++ ++static isc_boolean_t ++do_lookup_int(const char *addr, dns_geoip_subtype_t subtype, int id) { ++ dns_geoip_elem_t elt; ++ struct in_addr in4; ++ isc_netaddr_t na; ++ ++ inet_pton(AF_INET, addr, &in4); ++ isc_netaddr_fromin(&na, &in4); ++ ++ elt.subtype = subtype; ++ elt.as_int = id; ++ ++ return (dns_geoip_match(&na, &geoip, &elt)); ++} ++ ++/* ++ * Individual unit tests ++ */ ++ ++/* GeoIP country matching */ ++ATF_TC(country); ++ATF_TC_HEAD(country, tc) { ++ atf_tc_set_md_var(tc, "descr", "test country database matching"); ++} ++ATF_TC_BODY(country, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.country_v4 == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.1", dns_geoip_country_code, "AU"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_country_code3, "AUS"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_country_name, "Australia"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP country (ipv6) matching */ ++ATF_TC(country_v6); ++ATF_TC_HEAD(country_v6, tc) { ++ atf_tc_set_md_var(tc, "descr", "test country (ipv6) database matching"); ++} ++ATF_TC_BODY(country_v6, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.country_v6 == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_country_code, "AU"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_country_code3, "AUS"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_country_name, "Australia"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP city (ipv4) matching */ ++ATF_TC(city); ++ATF_TC_HEAD(city, tc) { ++ atf_tc_set_md_var(tc, "descr", "test city database matching"); ++} ++ATF_TC_BODY(city, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.city_v4 == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_continentcode, "NA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_countrycode, "US"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_countrycode3, "USA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_countryname, "United States"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_region, "CA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_regionname, "California"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_name, "Redwood City"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_city_postalcode, "94063"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_int("10.53.0.1", dns_geoip_city_areacode, 650); ++ ATF_CHECK(match); ++ ++ match = do_lookup_int("10.53.0.1", dns_geoip_city_metrocode, 807); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP city (ipv6) matching */ ++ATF_TC(city_v6); ++ATF_TC_HEAD(city_v6, tc) { ++ atf_tc_set_md_var(tc, "descr", "test city (ipv6) database matching"); ++} ++ATF_TC_BODY(city_v6, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.city_v6 == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_continentcode, "NA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_countrycode, "US"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_countrycode3, "USA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_countryname, ++ "United States"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_region, "CA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_regionname, "California"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_name, "Redwood City"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string_v6("fd92:7065:b8e:ffff::1", ++ dns_geoip_city_postalcode, "94063"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++ ++/* GeoIP region matching */ ++ATF_TC(region); ++ATF_TC_HEAD(region, tc) { ++ atf_tc_set_md_var(tc, "descr", "test region database matching"); ++} ++ATF_TC_BODY(region, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.region == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_region_code, "CA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_region_name, "California"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.1", ++ dns_geoip_region_countrycode, "US"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* ++ * GeoIP best-database matching ++ * (With no specified databse and a city database available, answers ++ * should come from city database. With city database unavailable, region ++ * database. Region database unavailable, country database.) ++ */ ++ATF_TC(best); ++ATF_TC_HEAD(best, tc) { ++ atf_tc_set_md_var(tc, "descr", "test best database matching"); ++} ++ATF_TC_BODY(best, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.region == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countrycode, "US"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countrycode3, "USA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countryname, "United States"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_regionname, "Virginia"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_region, "VA"); ++ ATF_CHECK(match); ++ ++ GeoIP_delete(geoip.city_v4); ++ geoip.city_v4 = NULL; ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countrycode, "AU"); ++ ATF_CHECK(match); ++ ++ /* ++ * Note, region doesn't support code3 or countryname, so ++ * the next two would be answered from the country database instead ++ */ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countrycode3, "CAN"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countryname, "Canada"); ++ ATF_CHECK(match); ++ ++ GeoIP_delete(geoip.region); ++ geoip.region = NULL; ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countrycode, "CA"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countrycode3, "CAN"); ++ ATF_CHECK(match); ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_countryname, "Canada"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++ ++/* GeoIP asnum matching */ ++ATF_TC(asnum); ++ATF_TC_HEAD(asnum, tc) { ++ atf_tc_set_md_var(tc, "descr", "test asnum database matching"); ++} ++ATF_TC_BODY(asnum, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.as == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ ++ match = do_lookup_string("10.53.0.3", dns_geoip_as_asnum, ++ "AS100003 Three Network Labs"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP isp matching */ ++ATF_TC(isp); ++ATF_TC_HEAD(isp, tc) { ++ atf_tc_set_md_var(tc, "descr", "test isp database matching"); ++} ++ATF_TC_BODY(isp, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.isp == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.1", dns_geoip_isp_name, ++ "One Systems, Inc."); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP org matching */ ++ATF_TC(org); ++ATF_TC_HEAD(org, tc) { ++ atf_tc_set_md_var(tc, "descr", "test org database matching"); ++} ++ATF_TC_BODY(org, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.org == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.2", dns_geoip_org_name, ++ "Two Technology Ltd."); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP domain matching */ ++ATF_TC(domain); ++ATF_TC_HEAD(domain, tc) { ++ atf_tc_set_md_var(tc, "descr", "test domain database matching"); ++} ++ATF_TC_BODY(domain, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.domain == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_string("10.53.0.4", ++ dns_geoip_domain_name, "four.com"); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++ ++/* GeoIP netspeed matching */ ++ATF_TC(netspeed); ++ATF_TC_HEAD(netspeed, tc) { ++ atf_tc_set_md_var(tc, "descr", "test netspeed database matching"); ++} ++ATF_TC_BODY(netspeed, tc) { ++ isc_result_t result; ++ isc_boolean_t match; ++ ++ UNUSED(tc); ++ ++ result = dns_test_begin(NULL, ISC_TRUE); ++ ATF_REQUIRE(result == ISC_R_SUCCESS); ++ ++ /* Use databases from the geoip system test */ ++ load_geoip(TEST_GEOIP_DATA); ++ ++ if (geoip.netspeed == NULL) { ++ dns_test_end(); ++ atf_tc_skip("Database not available"); ++ } ++ ++ match = do_lookup_int("10.53.0.1", dns_geoip_netspeed_id, 0); ++ ATF_CHECK(match); ++ ++ match = do_lookup_int("10.53.0.2", dns_geoip_netspeed_id, 1); ++ ATF_CHECK(match); ++ ++ match = do_lookup_int("10.53.0.3", dns_geoip_netspeed_id, 2); ++ ATF_CHECK(match); ++ ++ match = do_lookup_int("10.53.0.4", dns_geoip_netspeed_id, 3); ++ ATF_CHECK(match); ++ ++ dns_test_end(); ++} ++#else ++ATF_TC(untested); ++ATF_TC_HEAD(untested, tc) { ++ atf_tc_set_md_var(tc, "descr", "skipping geoip test"); ++} ++ATF_TC_BODY(untested, tc) { ++ UNUSED(tc); ++ atf_tc_skip("GeoIP not available"); ++} ++#endif ++ ++/* ++ * Main ++ */ ++ATF_TP_ADD_TCS(tp) { ++#ifdef HAVE_GEOIP ++ ATF_TP_ADD_TC(tp, country); ++ ATF_TP_ADD_TC(tp, country_v6); ++ ATF_TP_ADD_TC(tp, city); ++ ATF_TP_ADD_TC(tp, city_v6); ++ ATF_TP_ADD_TC(tp, region); ++ ATF_TP_ADD_TC(tp, best); ++ ATF_TP_ADD_TC(tp, asnum); ++ ATF_TP_ADD_TC(tp, isp); ++ ATF_TP_ADD_TC(tp, org); ++ ATF_TP_ADD_TC(tp, domain); ++ ATF_TP_ADD_TC(tp, netspeed); ++#else ++ ATF_TP_ADD_TC(tp, untested); ++#endif ++ ++ return (atf_no_error()); ++} ++ +diff --git a/lib/export/dns/Makefile.in b/lib/export/dns/Makefile.in +index e10bf59..887acb9 100644 +--- a/lib/export/dns/Makefile.in ++++ b/lib/export/dns/Makefile.in +@@ -67,8 +67,9 @@ DNSOBJS = acl.@O@ adb.@O@ byaddr.@O@ \ + tcpmsg.@O@ time.@O@ tsec.@O@ tsig.@O@ ttl.@O@ \ + validator.@O@ version.@O@ view.@O@ + PORTDNSOBJS = ecdb.@O@ ++GEOIPLINKOBJS = geoip.@O@ + +-OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} ${PORTDNSOBJS} ++OBJS= ${DNSOBJS} ${OTHEROBJS} ${DSTOBJS} ${PORTDNSOBJS} @GEOIPLINKOBJS@ + + # Alphabetically + +@@ -96,8 +97,9 @@ DNSSRCS = acl.c adb.c byaddr.c \ + tcpmsg.c time.c tsec.c tsig.c ttl.c \ + validator.c version.c view.c + PORTDNSSRCS = ecdb.c ++GEOIPLINKSRCS = geoip.c + +-SRCS = ${DSTSRCS} ${DNSSRCS} ${PORTDNSSRCS} ++SRCS = ${DSTSRCS} ${DNSSRCS} ${PORTDNSSRCS} @GEOIPLINKSRCS@ + + SUBDIRS = include + TARGETS = include/dns/enumtype.h include/dns/enumclass.h \ +diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c +index af56599..c415a98 100644 +--- a/lib/isccfg/aclconf.c ++++ b/lib/isccfg/aclconf.c +@@ -31,6 +31,11 @@ + #include <dns/fixedname.h> + #include <dns/log.h> + ++#ifdef HAVE_GEOIP ++#include <stdlib.h> ++#include <math.h> ++#endif /* HAVE_GEOIP */ ++ + #define LOOP_MAGIC ISC_MAGIC('L','O','O','P') + + isc_result_t +@@ -53,6 +58,10 @@ cfg_aclconfctx_create(isc_mem_t *mctx, cfg_aclconfctx_t **ret) { + isc_mem_attach(mctx, &actx->mctx); + ISC_LIST_INIT(actx->named_acl_cache); + ++#ifdef HAVE_GEOIP ++ actx->geoip = NULL; ++#endif ++ + *ret = actx; + return (ISC_R_SUCCESS); + +@@ -230,11 +239,15 @@ count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx, + elt = cfg_list_next(elt)) { + const cfg_obj_t *ce = cfg_listelt_value(elt); + +- /* negated element; just get the value. */ ++ /* might be a negated element, in which case get the value. */ + if (cfg_obj_istuple(ce)) { +- ce = cfg_tuple_get(ce, "value"); +- if (has_negative != NULL) +- *has_negative = ISC_TRUE; ++ const cfg_obj_t *negated = ++ cfg_tuple_get(ce, "negated"); ++ if (! cfg_obj_isvoid(negated)) { ++ ce = negated; ++ if (has_negative != NULL) ++ *has_negative = ISC_TRUE; ++ } + } + + if (cfg_obj_istype(ce, &cfg_type_keyref)) { +@@ -244,6 +257,12 @@ count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx, + n += count_acl_elements(ce, cctx, &negative); + if (negative) + n++; ++#ifdef HAVE_GEOIP ++ } else if (cfg_obj_istuple(ce) && ++ cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) ++ { ++ n++; ++#endif /* HAVE_GEOIP */ + } else if (cfg_obj_isstring(ce)) { + const char *name = cfg_obj_asstring(ce); + if (strcasecmp(name, "localhost") == 0 || +@@ -262,6 +281,313 @@ count_acl_elements(const cfg_obj_t *caml, const cfg_obj_t *cctx, + return n; + } + ++#ifdef HAVE_GEOIP ++static dns_geoip_subtype_t ++get_subtype(const cfg_obj_t *obj, isc_log_t *lctx, ++ dns_geoip_subtype_t subtype, const char *dbname) ++{ ++ if (dbname == NULL) ++ return (subtype); ++ ++ switch (subtype) { ++ case dns_geoip_countrycode: ++ if (strcasecmp(dbname, "city") == 0) ++ return (dns_geoip_city_countrycode); ++ else if (strcasecmp(dbname, "region") == 0) ++ return (dns_geoip_region_countrycode); ++ else if (strcasecmp(dbname, "country") == 0) ++ return (dns_geoip_country_code); ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "invalid GeoIP DB specified for " ++ "country search: ignored"); ++ return (subtype); ++ case dns_geoip_countrycode3: ++ if (strcasecmp(dbname, "city") == 0) ++ return (dns_geoip_city_countrycode3); ++ else if (strcasecmp(dbname, "country") == 0) ++ return (dns_geoip_country_code3); ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "invalid GeoIP DB specified for " ++ "country search: ignored"); ++ return (subtype); ++ case dns_geoip_countryname: ++ if (strcasecmp(dbname, "city") == 0) ++ return (dns_geoip_city_countryname); ++ else if (strcasecmp(dbname, "country") == 0) ++ return (dns_geoip_country_name); ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "invalid GeoIP DB specified for " ++ "country search: ignored"); ++ return (subtype); ++ case dns_geoip_region: ++ if (strcasecmp(dbname, "city") == 0) ++ return (dns_geoip_city_region); ++ else if (strcasecmp(dbname, "region") == 0) ++ return (dns_geoip_region_code); ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "invalid GeoIP DB specified for " ++ "region search: ignored"); ++ return (subtype); ++ case dns_geoip_regionname: ++ if (strcasecmp(dbname, "city") == 0) ++ return (dns_geoip_city_region); ++ else if (strcasecmp(dbname, "region") == 0) ++ return (dns_geoip_region_name); ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "invalid GeoIP DB specified for " ++ "region search: ignored"); ++ return (subtype); ++ ++ /* ++ * Log a warning if the wrong database was specified ++ * on an unambiguous query ++ */ ++ case dns_geoip_city_name: ++ case dns_geoip_city_postalcode: ++ case dns_geoip_city_metrocode: ++ case dns_geoip_city_areacode: ++ case dns_geoip_city_continentcode: ++ case dns_geoip_city_timezonecode: ++ if (strcasecmp(dbname, "city") != 0) ++ cfg_obj_log(obj, lctx, ISC_LOG_WARNING, ++ "invalid GeoIP DB specified for " ++ "a 'city'-only search type: ignoring"); ++ return (subtype); ++ case dns_geoip_isp_name: ++ if (strcasecmp(dbname, "isp") != 0) ++ cfg_obj_log(obj, lctx, ISC_LOG_WARNING, ++ "invalid GeoIP DB specified for " ++ "an 'isp' search: ignoring"); ++ return (subtype); ++ case dns_geoip_org_name: ++ if (strcasecmp(dbname, "org") != 0) ++ cfg_obj_log(obj, lctx, ISC_LOG_WARNING, ++ "invalid GeoIP DB specified for " ++ "an 'org' search: ignoring"); ++ return (subtype); ++ case dns_geoip_as_asnum: ++ if (strcasecmp(dbname, "asnum") != 0) ++ cfg_obj_log(obj, lctx, ISC_LOG_WARNING, ++ "invalid GeoIP DB specified for " ++ "an 'asnum' search: ignoring"); ++ return (subtype); ++ case dns_geoip_domain_name: ++ if (strcasecmp(dbname, "domain") != 0) ++ cfg_obj_log(obj, lctx, ISC_LOG_WARNING, ++ "invalid GeoIP DB specified for " ++ "a 'domain' search: ignoring"); ++ return (subtype); ++ case dns_geoip_netspeed_id: ++ if (strcasecmp(dbname, "netspeed") != 0) ++ cfg_obj_log(obj, lctx, ISC_LOG_WARNING, ++ "invalid GeoIP DB specified for " ++ "a 'netspeed' search: ignoring"); ++ return (subtype); ++ default: ++ INSIST(0); ++ } ++} ++ ++static isc_boolean_t ++geoip_can_answer(dns_aclelement_t *elt, cfg_aclconfctx_t *ctx) { ++ if (ctx->geoip == NULL) ++ return (ISC_TRUE); ++ ++ switch (elt->geoip_elem.subtype) { ++ case dns_geoip_countrycode: ++ case dns_geoip_countrycode3: ++ case dns_geoip_countryname: ++ if (ctx->geoip->city_v4 != NULL || ++ ctx->geoip->city_v6 != NULL || ++ ctx->geoip->country_v4 != NULL || ++ ctx->geoip->country_v6 != NULL || ++ ctx->geoip->region != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_region: ++ case dns_geoip_regionname: ++ if (ctx->geoip->city_v4 != NULL || ++ ctx->geoip->city_v6 != NULL || ++ ctx->geoip->region != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_country_code: ++ case dns_geoip_country_code3: ++ case dns_geoip_country_name: ++ if (ctx->geoip->country_v4 != NULL || ++ ctx->geoip->country_v6 != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_region_countrycode: ++ case dns_geoip_region_code: ++ case dns_geoip_region_name: ++ if (ctx->geoip->region != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_city_countrycode: ++ case dns_geoip_city_countrycode3: ++ case dns_geoip_city_countryname: ++ case dns_geoip_city_region: ++ case dns_geoip_city_regionname: ++ case dns_geoip_city_name: ++ case dns_geoip_city_postalcode: ++ case dns_geoip_city_metrocode: ++ case dns_geoip_city_areacode: ++ case dns_geoip_city_continentcode: ++ case dns_geoip_city_timezonecode: ++ if (ctx->geoip->city_v4 != NULL || ++ ctx->geoip->city_v6 != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_isp_name: ++ if (ctx->geoip->isp != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_org_name: ++ if (ctx->geoip->org != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_as_asnum: ++ if (ctx->geoip->as != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_domain_name: ++ if (ctx->geoip->domain != NULL) ++ return (ISC_TRUE); ++ case dns_geoip_netspeed_id: ++ if (ctx->geoip->netspeed != NULL) ++ return (ISC_TRUE); ++ } ++ ++ return (ISC_FALSE); ++} ++ ++static isc_result_t ++parse_geoip_element(const cfg_obj_t *obj, isc_log_t *lctx, ++ cfg_aclconfctx_t *ctx, dns_aclelement_t *dep) ++{ ++ const cfg_obj_t *ge; ++ const char *dbname = NULL; ++ const char *stype, *search; ++ dns_geoip_subtype_t subtype; ++ dns_aclelement_t de; ++ size_t len; ++ ++ REQUIRE(dep != NULL); ++ ++ de = *dep; ++ ++ ge = cfg_tuple_get(obj, "db"); ++ if (!cfg_obj_isvoid(ge)) ++ dbname = cfg_obj_asstring(ge); ++ ++ stype = cfg_obj_asstring(cfg_tuple_get(obj, "subtype")); ++ search = cfg_obj_asstring(cfg_tuple_get(obj, "search")); ++ len = strlen(search); ++ ++ if (len == 0) { ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "zero-length geoip search field"); ++ return (ISC_R_FAILURE); ++ } ++ ++ if (strcasecmp(stype, "country") == 0 && len == 2) { ++ /* Two-letter country code */ ++ subtype = dns_geoip_countrycode; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "country") == 0 && len == 3) { ++ /* Three-letter country code */ ++ subtype = dns_geoip_countrycode3; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "country") == 0) { ++ /* Country name */ ++ subtype = dns_geoip_countryname; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "region") == 0 && len == 2) { ++ /* Two-letter region code */ ++ subtype = dns_geoip_region; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "region") == 0) { ++ /* Region name */ ++ subtype = dns_geoip_regionname; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "city") == 0) { ++ /* City name */ ++ subtype = dns_geoip_city_name; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "postal") == 0 || ++ strcasecmp(stype, "postalcode") == 0) ++ { ++ if (len < 7) { ++ subtype = dns_geoip_city_postalcode; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else { ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "geoiop postal code (%s) too long", ++ search); ++ return (ISC_R_FAILURE); ++ } ++ } else if (strcasecmp(stype, "metro") == 0 || ++ strcasecmp(stype, "metrocode") == 0) ++ { ++ subtype = dns_geoip_city_metrocode; ++ de.geoip_elem.as_int = atoi(search); ++ } else if (strcasecmp(stype, "area") == 0 || ++ strcasecmp(stype, "areacode") == 0) ++ { ++ subtype = dns_geoip_city_areacode; ++ de.geoip_elem.as_int = atoi(search); ++ } else if (strcasecmp(stype, "tz") == 0 || ++ strcasecmp(stype, "timezone") == 0) ++ { ++ subtype = dns_geoip_city_timezonecode; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "continent") == 0 && len == 2) { ++ /* Two-letter continent code */ ++ subtype = dns_geoip_city_continentcode; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "continent") == 0) { ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "geoiop continent code (%s) too long", search); ++ return (ISC_R_FAILURE); ++ } else if (strcasecmp(stype, "isp") == 0) { ++ subtype = dns_geoip_isp_name; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "asnum") == 0) { ++ subtype = dns_geoip_as_asnum; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "org") == 0) { ++ subtype = dns_geoip_org_name; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "domain") == 0) { ++ subtype = dns_geoip_domain_name; ++ strlcpy(de.geoip_elem.as_string, search, ++ sizeof(de.geoip_elem.as_string)); ++ } else if (strcasecmp(stype, "netspeed") == 0) { ++ subtype = dns_geoip_netspeed_id; ++ de.geoip_elem.as_int = atoi(search); ++ } else ++ INSIST(0); ++ ++ de.geoip_elem.subtype = get_subtype(obj, lctx, subtype, dbname); ++ ++ if (! geoip_can_answer(&de, ctx)) { ++ cfg_obj_log(obj, lctx, ISC_LOG_ERROR, ++ "no GeoIP database installed which can answer " ++ "queries of type '%s'", stype); ++ return (ISC_R_FAILURE); ++ } ++ ++ *dep = de; ++ ++ return (ISC_R_SUCCESS); ++} ++#endif ++ + isc_result_t + cfg_acl_fromconfig(const cfg_obj_t *caml, + const cfg_obj_t *cctx, +@@ -317,15 +643,18 @@ cfg_acl_fromconfig(const cfg_obj_t *caml, + elt != NULL; + elt = cfg_list_next(elt)) { + const cfg_obj_t *ce = cfg_listelt_value(elt); +- isc_boolean_t neg; ++ isc_boolean_t neg = ISC_FALSE; + + if (cfg_obj_istuple(ce)) { +- /* This must be a negated element. */ +- ce = cfg_tuple_get(ce, "value"); +- neg = ISC_TRUE; +- dacl->has_negatives = ISC_TRUE; +- } else +- neg = ISC_FALSE; ++ /* Might be a negated element */ ++ const cfg_obj_t *negated = ++ cfg_tuple_get(ce, "negated"); ++ if (! cfg_obj_isvoid(negated)) { ++ neg = ISC_TRUE; ++ dacl->has_negatives = ISC_TRUE; ++ ce = negated; ++ } ++ } + + /* + * If nest_level is nonzero, then every element is +@@ -405,6 +734,16 @@ nested_acl: + &de->keyname); + if (result != ISC_R_SUCCESS) + goto cleanup; ++#ifdef HAVE_GEOIP ++ } else if (cfg_obj_istuple(ce) && ++ cfg_obj_isvoid(cfg_tuple_get(ce, "negated"))) ++ { ++ result = parse_geoip_element(ce, lctx, ctx, de); ++ if (result != ISC_R_SUCCESS) ++ goto cleanup; ++ de->type = dns_aclelementtype_geoip; ++ de->negative = neg; ++#endif /* HAVE_GEOIP */ + } else if (cfg_obj_isstring(ce)) { + /* ACL name. */ + const char *name = cfg_obj_asstring(ce); +diff --git a/lib/isccfg/include/isccfg/aclconf.h b/lib/isccfg/include/isccfg/aclconf.h +index 38ab9f6..3fb66f9 100644 +--- a/lib/isccfg/include/isccfg/aclconf.h ++++ b/lib/isccfg/include/isccfg/aclconf.h +@@ -24,11 +24,17 @@ + + #include <isccfg/cfg.h> + ++#ifdef HAVE_GEOIP ++#include <dns/geoip.h> ++#endif + #include <dns/types.h> + + typedef struct cfg_aclconfctx { + ISC_LIST(dns_acl_t) named_acl_cache; + isc_mem_t *mctx; ++#ifdef HAVE_GEOIP ++ dns_geoip_databases_t *geoip; ++#endif + isc_refcount_t references; + } cfg_aclconfctx_t; + +diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c +index 62fcc96..1867506 100644 +--- a/lib/isccfg/namedconf.c ++++ b/lib/isccfg/namedconf.c +@@ -82,6 +82,17 @@ doc_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); + static void + doc_optional_keyvalue(cfg_printer_t *pctx, const cfg_type_t *type); + ++#ifdef HAVE_GEOIP ++static isc_result_t ++parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); ++ ++static void ++print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj); ++ ++static void ++doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type); ++#endif /* HAVE_GEOIP */ ++ + static cfg_type_t cfg_type_acl; + static cfg_type_t cfg_type_addrmatchelt; + static cfg_type_t cfg_type_bracketed_aml; +@@ -935,6 +946,9 @@ options_clauses[] = { + { "fake-iquery", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, + { "files", &cfg_type_size, 0 }, + { "flush-zones-on-shutdown", &cfg_type_boolean, 0 }, ++#ifdef HAVE_GEOIP ++ { "geoip-directory", &cfg_type_qstringornone, 0 }, ++#endif /* HAVE_GEOIP */ + { "has-old-clients", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, + { "heartbeat-interval", &cfg_type_uint32, 0 }, + { "host-statistics", &cfg_type_boolean, CFG_CLAUSEFLAG_NOTIMP }, +@@ -2108,6 +2122,102 @@ static cfg_type_t cfg_type_optional_keyref = { + doc_optional_keyvalue, &cfg_rep_string, &key_kw + }; + ++#ifdef HAVE_GEOIP ++/* ++ * "geoip" ACL element: ++ * geoip [ db <database> ] search-type <string> ++ */ ++static const char *geoiptype_enums[] = { ++ "country", "country3", "countryname", "region", "regionname", ++ "city", "postalcode", "postal", "metrocode", "metro", ++ "areacode", "area", "timezone", "tz", "continent", "isp", ++ "domain", "asnum", "org", "netspeed", NULL ++}; ++static cfg_type_t cfg_type_geoiptype = { ++ "geoiptype", cfg_parse_enum, cfg_print_ustring, ++ cfg_doc_enum, &cfg_rep_string, &geoiptype_enums ++}; ++ ++static const char *geoipdb_enums[] = { ++ "country", "region", "city", ++ "isp", "domain", "asnum", "org", "netspeed", NULL ++}; ++static cfg_type_t cfg_type_geoipdb = { ++ "geoipdb", cfg_parse_enum, cfg_print_ustring, ++ cfg_doc_enum, &cfg_rep_string, &geoipdb_enums ++}; ++ ++static cfg_tuplefielddef_t geoip_fields[] = { ++ { "negated", &cfg_type_void, 0}, ++ { "db", &cfg_type_geoipdb, 0}, ++ { "subtype", &cfg_type_geoiptype, 0 }, ++ { "search", &cfg_type_astring, 0 }, ++ { NULL, NULL, 0 } ++}; ++ ++static cfg_type_t cfg_type_geoip = { ++ "geoip", parse_geoip, print_geoip, doc_geoip, ++ &cfg_rep_tuple, geoip_fields ++}; ++ ++static isc_result_t ++parse_geoip(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { ++ isc_result_t result; ++ cfg_obj_t *obj = NULL; ++ const cfg_tuplefielddef_t *fields = type->of; ++ ++ CHECK(cfg_create_tuple(pctx, type, &obj)); ++ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[0])); ++ ++ /* Parse the optional "db" field. */ ++ CHECK(cfg_peektoken(pctx, 0)); ++ if (pctx->token.type == isc_tokentype_string) { ++ CHECK(cfg_gettoken(pctx, 0)); ++ if (strcasecmp(TOKEN_STRING(pctx), "db") == 0 && ++ obj->value.tuple[1] == NULL) { ++ CHECK(cfg_parse_obj(pctx, fields[1].type, ++ &obj->value.tuple[1])); ++ } else { ++ CHECK(cfg_parse_void(pctx, NULL, &obj->value.tuple[1])); ++ cfg_ungettoken(pctx); ++ } ++ } ++ ++ CHECK(cfg_parse_obj(pctx, fields[2].type, &obj->value.tuple[2])); ++ CHECK(cfg_parse_obj(pctx, fields[3].type, &obj->value.tuple[3])); ++ ++ *ret = obj; ++ return (ISC_R_SUCCESS); ++ ++ cleanup: ++ CLEANUP_OBJ(obj); ++ return (result); ++} ++ ++static void ++print_geoip(cfg_printer_t *pctx, const cfg_obj_t *obj) { ++ if (obj->value.tuple[1]->type->print != cfg_print_void) { ++ cfg_print_cstr(pctx, " db "); ++ cfg_print_obj(pctx, obj->value.tuple[1]); ++ } ++ cfg_print_obj(pctx, obj->value.tuple[2]); ++ cfg_print_obj(pctx, obj->value.tuple[3]); ++} ++ ++ ++static void ++doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type) { ++ UNUSED(type); ++ cfg_print_cstr(pctx, "[ db "); ++ cfg_doc_enum(pctx, &cfg_type_geoipdb); ++ cfg_print_cstr(pctx, " ]"); ++ cfg_print_chars(pctx, " ", 1); ++ cfg_doc_enum(pctx, &cfg_type_geoiptype); ++ cfg_print_chars(pctx, " ", 1); ++ cfg_print_cstr(pctx, "<quoted_string>"); ++} ++#endif /* HAVE_GEOIP */ ++ + /*% + * A "controls" statement is represented as a map with the multivalued + * "inet" and "unix" clauses. +@@ -2251,7 +2361,9 @@ static cfg_type_t cfg_type_statschannels = { + * An optional class, as used in view and zone statements. + */ + static isc_result_t +-parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { ++parse_optional_class(cfg_parser_t *pctx, const cfg_type_t *type, ++ cfg_obj_t **ret) ++{ + isc_result_t result; + UNUSED(type); + CHECK(cfg_peektoken(pctx, 0)); +@@ -2374,6 +2486,16 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) + if (pctx->token.type == isc_tokentype_string && + (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) { + CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret)); ++ } else if (pctx->token.type == isc_tokentype_string && ++ (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) { ++#ifdef HAVE_GEOIP ++ CHECK(cfg_gettoken(pctx, 0)); ++ CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret)); ++#else ++ cfg_parser_error(pctx, CFG_LOG_NEAR, ++ "'geoip' not supported in this build"); ++ return (ISC_R_UNEXPECTEDTOKEN); ++#endif + } else { + if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | + CFG_ADDR_V4PREFIXOK | +@@ -2387,7 +2509,8 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) + } else if (pctx->token.type == isc_tokentype_special) { + if (pctx->token.value.as_char == '{') { + /* Nested match list. */ +- CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_aml, ret)); ++ CHECK(cfg_parse_obj(pctx, ++ &cfg_type_bracketed_aml, ret)); + } else if (pctx->token.value.as_char == '!') { + CHECK(cfg_gettoken(pctx, 0)); /* read "!" */ + CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret)); +@@ -2411,7 +2534,7 @@ parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) + */ + + static cfg_tuplefielddef_t negated_fields[] = { +- { "value", &cfg_type_addrmatchelt, 0 }, ++ { "negated", &cfg_type_addrmatchelt, 0 }, + { NULL, NULL, 0 } + }; + +-- +2.9.3 + diff --git a/SOURCES/bind99-rh1259514.patch b/SOURCES/bind99-rh1259514.patch new file mode 100644 index 0000000..3b268d0 --- /dev/null +++ b/SOURCES/bind99-rh1259514.patch @@ -0,0 +1,12 @@ +diff --git a/bin/tests/system/tkey/ns1/named.conf.in b/bin/tests/system/tkey/ns1/named.conf.in +index 50600b7..b0f1700 100644 +--- a/bin/tests/system/tkey/ns1/named.conf.in ++++ b/bin/tests/system/tkey/ns1/named.conf.in +@@ -32,6 +32,7 @@ options { + tkey-domain "server"; + tkey-dhkey "server" KEYID; + allow-query-cache { any; }; ++ random-device "/dev/urandom"; + }; + + key rndc_key { diff --git a/SOURCES/bind99-rh1291185.patch b/SOURCES/bind99-rh1291185.patch new file mode 100644 index 0000000..9f7c936 --- /dev/null +++ b/SOURCES/bind99-rh1291185.patch @@ -0,0 +1,58 @@ +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 8696b15..5ef2dd6 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -7373,9 +7373,12 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + * NXDOMAIN, NXRDATASET, or referral. + */ + result = noanswer_response(fctx, NULL, 0); +- if (result == DNS_R_CHASEDSSERVERS) { +- } else if (result == DNS_R_DELEGATION) { +- force_referral: ++ switch (result) { ++ case ISC_R_SUCCESS: ++ case DNS_R_CHASEDSSERVERS: ++ break; ++ case DNS_R_DELEGATION: ++ force_referral: + /* + * We don't have the answer, but we know a better + * place to look. +@@ -7400,7 +7403,8 @@ resquery_response(isc_task_t *task, isc_event_t *event) { + fctx->adberr = 0; + + result = ISC_R_SUCCESS; +- } else if (result != ISC_R_SUCCESS) { ++ break; ++ default: + /* + * Something has gone wrong. + */ +diff --git a/lib/dns/view.c b/lib/dns/view.c +index 142b09e..35900b3 100644 +--- a/lib/dns/view.c ++++ b/lib/dns/view.c +@@ -1216,6 +1216,7 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, + dns_name_t *zfname; + dns_rdataset_t zrdataset, zsigrdataset; + dns_fixedname_t zfixedname; ++ unsigned int ztoptions = 0; + + #ifndef BIND9 + UNUSED(zone); +@@ -1242,9 +1243,12 @@ dns_view_findzonecut2(dns_view_t *view, dns_name_t *name, dns_name_t *fname, + #ifdef BIND9 + zone = NULL; + LOCK(&view->lock); +- if (view->zonetable != NULL) +- result = dns_zt_find(view->zonetable, name, 0, NULL, &zone); +- else ++ if (view->zonetable != NULL) { ++ if ((options & DNS_DBFIND_NOEXACT) != 0) ++ ztoptions |= DNS_ZTFIND_NOEXACT; ++ result = dns_zt_find(view->zonetable, name, ztoptions, ++ NULL, &zone); ++ } else + result = ISC_R_NOTFOUND; + if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) + result = dns_zone_getdb(zone, &db); diff --git a/SOURCES/bind99-rh1306610.patch b/SOURCES/bind99-rh1306610.patch new file mode 100644 index 0000000..cf5c8cc --- /dev/null +++ b/SOURCES/bind99-rh1306610.patch @@ -0,0 +1,1847 @@ +From 620b1c9d90d0a59a0d892fef089ce4f5f6f61742 Mon Sep 17 00:00:00 2001 +From: Tomas Hozza <thozza@redhat.com> +Date: Fri, 1 Apr 2016 15:20:27 +0200 +Subject: [PATCH] Added support for CAA records + +Signed-off-by: Tomas Hozza <thozza@redhat.com> +--- + bin/tests/rdata_test.c | 17 +- + doc/rfc/rfc6844.txt | 1011 ++++++++++++++++++++++++++++++++++++++ + lib/dns/rdata.c | 95 ++-- + lib/dns/rdata/generic/caa_257.c | 370 ++++++++++++++ + lib/dns/rdata/generic/caa_257.h | 32 ++ + lib/dns/rdata/generic/gpos_27.c | 2 +- + lib/dns/rdata/generic/hinfo_13.c | 4 +- + lib/dns/rdata/generic/isdn_20.c | 4 +- + lib/dns/rdata/generic/naptr_35.c | 6 +- + lib/dns/rdata/generic/spf_99.c | 2 +- + lib/dns/rdata/generic/txt_16.c | 2 +- + lib/dns/rdata/generic/uri_256.c | 23 +- + lib/dns/rdata/generic/x25_19.c | 2 +- + 13 files changed, 1478 insertions(+), 92 deletions(-) + create mode 100644 doc/rfc/rfc6844.txt + create mode 100644 lib/dns/rdata/generic/caa_257.c + create mode 100644 lib/dns/rdata/generic/caa_257.h + +diff --git a/bin/tests/rdata_test.c b/bin/tests/rdata_test.c +index 51cc406..0f25364 100644 +--- a/bin/tests/rdata_test.c ++++ b/bin/tests/rdata_test.c +@@ -15,8 +15,6 @@ + * PERFORMANCE OF THIS SOFTWARE. + */ + +-/* $Id: rdata_test.c,v 1.52 2011/08/28 09:10:41 marka Exp $ */ +- + #include <config.h> + + #include <stdlib.h> +@@ -284,6 +282,11 @@ viastruct(dns_rdata_t *rdata, isc_mem_t *mctx, + result = dns_rdata_tostruct(rdata, sp = &uri, NULL); + break; + } ++ case dns_rdatatype_caa: { ++ static dns_rdata_caa_t caa; ++ result = dns_rdata_tostruct(rdata, sp = &caa, NULL); ++ break; ++ } + case dns_rdatatype_wks: { + static dns_rdata_in_wks_t in_wks; + result = dns_rdata_tostruct(rdata, sp = &in_wks, NULL); +@@ -551,6 +554,11 @@ viastruct(dns_rdata_t *rdata, isc_mem_t *mctx, + result = dns_rdata_tostruct(rdata, sp = &uri, mctx); + break; + } ++ case dns_rdatatype_caa: { ++ static dns_rdata_caa_t caa; ++ result = dns_rdata_tostruct(rdata, sp = &caa, mctx); ++ break; ++ } + case dns_rdatatype_wks: { + static dns_rdata_in_wks_t in_wks; + result = dns_rdata_tostruct(rdata, sp = &in_wks, mctx); +@@ -848,6 +856,11 @@ viastruct(dns_rdata_t *rdata, isc_mem_t *mctx, + result = dns_rdata_fromstruct(rdata2, rdc, rdt, &uri, b); + break; + } ++ case dns_rdatatype_caa: { ++ dns_rdata_caa_t caa; ++ result = dns_rdata_fromstruct(rdata2, rdc, rdt, &caa, b); ++ break; ++ } + case dns_rdatatype_wks: { + dns_rdata_in_wks_t in_wks; + result = dns_rdata_fromstruct(rdata2, rdc, rdt, &in_wks, b); +diff --git a/doc/rfc/rfc6844.txt b/doc/rfc/rfc6844.txt +new file mode 100644 +index 0000000..d923649 +--- /dev/null ++++ b/doc/rfc/rfc6844.txt +@@ -0,0 +1,1011 @@ ++ ++ ++ ++ ++ ++ ++Internet Engineering Task Force (IETF) P. Hallam-Baker ++Request for Comments: 6844 Comodo Group, Inc. ++Category: Standards Track R. Stradling ++ISSN: 2070-1721 Comodo CA, Ltd. ++ January 2013 ++ ++ ++ DNS Certification Authority Authorization (CAA) Resource Record ++ ++Abstract ++ ++ The Certification Authority Authorization (CAA) DNS Resource Record ++ allows a DNS domain name holder to specify one or more Certification ++ Authorities (CAs) authorized to issue certificates for that domain. ++ CAA Resource Records allow a public Certification Authority to ++ implement additional controls to reduce the risk of unintended ++ certificate mis-issue. This document defines the syntax of the CAA ++ record and rules for processing CAA records by certificate issuers. ++ ++Status of This Memo ++ ++ This is an Internet Standards Track document. ++ ++ This document is a product of the Internet Engineering Task Force ++ (IETF). It represents the consensus of the IETF community. It has ++ received public review and has been approved for publication by the ++ Internet Engineering Steering Group (IESG). Further information on ++ Internet Standards is available in Section 2 of RFC 5741. ++ ++ Information about the current status of this document, any errata, ++ and how to provide feedback on it may be obtained at ++ http://www.rfc-editor.org/info/rfc6844. ++ ++Copyright Notice ++ ++ Copyright (c) 2013 IETF Trust and the persons identified as the ++ document authors. All rights reserved. ++ ++ This document is subject to BCP 78 and the IETF Trust's Legal ++ Provisions Relating to IETF Documents ++ (http://trustee.ietf.org/license-info) in effect on the date of ++ publication of this document. Please review these documents ++ carefully, as they describe your rights and restrictions with respect ++ to this document. Code Components extracted from this document must ++ include Simplified BSD License text as described in Section 4.e of ++ the Trust Legal Provisions and are provided without warranty as ++ described in the Simplified BSD License. ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 1] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++Table of Contents ++ ++ 1. Introduction ....................................................2 ++ 2. Definitions .....................................................3 ++ 2.1. Requirements Language ......................................3 ++ 2.2. Defined Terms ..............................................3 ++ 3. The CAA RR Type .................................................5 ++ 4. Certification Authority Processing ..............................7 ++ 4.1. Use of DNS Security ........................................8 ++ 5. Mechanism .......................................................8 ++ 5.1. Syntax .....................................................8 ++ 5.1.1. Canonical Presentation Format ......................10 ++ 5.2. CAA issue Property ........................................10 ++ 5.3. CAA issuewild Property ....................................12 ++ 5.4. CAA iodef Property ........................................12 ++ 6. Security Considerations ........................................13 ++ 6.1. Non-Compliance by Certification Authority .................13 ++ 6.2. Mis-Issue by Authorized Certification Authority ...........13 ++ 6.3. Suppression or Spoofing of CAA Records ....................13 ++ 6.4. Denial of Service .........................................14 ++ 6.5. Abuse of the Critical Flag ................................14 ++ 7. IANA Considerations ............................................14 ++ 7.1. Registration of the CAA Resource Record Type ..............14 ++ 7.2. Certification Authority Restriction Properties ............15 ++ 7.3. Certification Authority Restriction Flags .................15 ++ 8. Acknowledgements ...............................................16 ++ 9. References .....................................................16 ++ 9.1. Normative References ......................................16 ++ 9.2. Informative References ....................................17 ++ ++1. Introduction ++ ++ The Certification Authority Authorization (CAA) DNS Resource Record ++ allows a DNS domain name holder to specify the Certification ++ Authorities (CAs) authorized to issue certificates for that domain. ++ Publication of CAA Resource Records allows a public Certification ++ Authority to implement additional controls to reduce the risk of ++ unintended certificate mis-issue. ++ ++ Like the TLSA record defined in DNS-Based Authentication of Named ++ Entities (DANE) [RFC6698], CAA records are used as a part of a ++ mechanism for checking PKIX certificate data. The distinction ++ between the two specifications is that CAA records specify an ++ authorization control to be performed by a certificate issuer before ++ issue of a certificate and TLSA records specify a verification ++ control to be performed by a relying party after the certificate is ++ issued. ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 2] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ Conformance with a published CAA record is a necessary but not ++ sufficient condition for issuance of a certificate. Before issuing a ++ certificate, a PKIX CA is required to validate the request according ++ to the policies set out in its Certificate Policy. In the case of a ++ public CA that validates certificate requests as a third party, the ++ certificate will typically be issued under a public trust anchor ++ certificate embedded in one or more relevant Relying Applications. ++ ++ Criteria for inclusion of embedded trust anchor certificates in ++ applications are outside the scope of this document. Typically, such ++ criteria require the CA to publish a Certificate Practices Statement ++ (CPS) that specifies how the requirements of the Certificate Policy ++ (CP) are achieved. It is also common for a CA to engage an ++ independent third-party auditor to prepare an annual audit statement ++ of its performance against its CPS. ++ ++ A set of CAA records describes only current grants of authority to ++ issue certificates for the corresponding DNS domain. Since a ++ certificate is typically valid for at least a year, it is possible ++ that a certificate that is not conformant with the CAA records ++ currently published was conformant with the CAA records published at ++ the time that the certificate was issued. Relying Applications MUST ++ NOT use CAA records as part of certificate validation. ++ ++ CAA records MAY be used by Certificate Evaluators as a possible ++ indicator of a security policy violation. Such use SHOULD take ++ account of the possibility that published CAA records changed between ++ the time a certificate was issued and the time at which the ++ certificate was observed by the Certificate Evaluator. ++ ++2. Definitions ++ ++2.1. Requirements Language ++ ++ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", ++ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this ++ document are to be interpreted as described in [RFC2119]. ++ ++2.2. Defined Terms ++ ++ The following terms are used in this document: ++ ++ Authorization Entry: An authorization assertion that grants or ++ denies a specific set of permissions to a specific group of ++ entities. ++ ++ Certificate: An X.509 Certificate, as specified in [RFC5280]. ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 3] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ Certificate Evaluator: A party other than a relying party that ++ evaluates the trustworthiness of certificates issued by ++ Certification Authorities. ++ ++ Certification Authority (CA): An issuer that issues certificates in ++ accordance with a specified Certificate Policy. ++ ++ Certificate Policy (CP): Specifies the criteria that a Certification ++ Authority undertakes to meet in its issue of certificates. See ++ [RFC3647]. ++ ++ Certification Practices Statement (CPS): Specifies the means by ++ which the criteria of the Certificate Policy are met. In most ++ cases, this will be the document against which the operations of ++ the Certification Authority are audited. See [RFC3647]. ++ ++ Domain: A DNS Domain Name. ++ ++ Domain Name: A DNS Domain Name as specified in [STD13]. ++ ++ Domain Name System (DNS): The Internet naming system specified in ++ [STD13]. ++ ++ DNS Security (DNSSEC): Extensions to the DNS that provide ++ authentication services as specified in [RFC4033], [RFC4034], ++ [RFC4035], [RFC5155], and revisions. ++ ++ Issuer: An entity that issues certificates. See [RFC5280]. ++ ++ Property: The tag-value portion of a CAA Resource Record. ++ ++ Property Tag: The tag portion of a CAA Resource Record. ++ ++ Property Value: The value portion of a CAA Resource Record. ++ ++ Public Key Infrastructure X.509 (PKIX): Standards and specifications ++ issued by the IETF that apply the [X.509] certificate standards ++ specified by the ITU to Internet applications as specified in ++ [RFC5280] and related documents. ++ ++ Resource Record (RR): A particular entry in the DNS including the ++ owner name, class, type, time to live, and data, as defined in ++ [STD13] and [RFC2181]. ++ ++ Resource Record Set (RRSet): A set of Resource Records or a ++ particular owner name, class, and type. The time to live on all ++ RRs with an RRSet is always the same, but the data may be ++ different among RRs in the RRSet. ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 4] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ Relying Party: A party that makes use of an application whose ++ operation depends on use of a certificate for making a security ++ decision. See [RFC5280]. ++ ++ Relying Application: An application whose operation depends on use ++ of a certificate for making a security decision. ++ ++3. The CAA RR Type ++ ++ A CAA RR consists of a flags byte and a tag-value pair referred to as ++ a property. Multiple properties MAY be associated with the same ++ domain name by publishing multiple CAA RRs at that domain name. The ++ following flag is defined: ++ ++ Issuer Critical: If set to '1', indicates that the corresponding ++ property tag MUST be understood if the semantics of the CAA record ++ are to be correctly interpreted by an issuer. ++ ++ Issuers MUST NOT issue certificates for a domain if the relevant ++ CAA Resource Record set contains unknown property tags that have ++ the Critical bit set. ++ ++ The following property tags are defined: ++ ++ issue <Issuer Domain Name> [; <name>=<value> ]* : The issue property ++ entry authorizes the holder of the domain name <Issuer Domain ++ Name> or a party acting under the explicit authority of the holder ++ of that domain name to issue certificates for the domain in which ++ the property is published. ++ ++ issuewild <Issuer Domain Name> [; <name>=<value> ]* : The issuewild ++ property entry authorizes the holder of the domain name <Issuer ++ Domain Name> or a party acting under the explicit authority of the ++ holder of that domain name to issue wildcard certificates for the ++ domain in which the property is published. ++ ++ iodef <URL> : Specifies a URL to which an issuer MAY report ++ certificate issue requests that are inconsistent with the issuer's ++ Certification Practices or Certificate Policy, or that a ++ Certificate Evaluator may use to report observation of a possible ++ policy violation. The Incident Object Description Exchange Format ++ (IODEF) format is used [RFC5070]. ++ ++ The following example is a DNS zone file (see [RFC1035]) that informs ++ CAs that certificates are not to be issued except by the holder of ++ the domain name 'ca.example.net' or an authorized agent thereof. ++ This policy applies to all subordinate domains under example.com. ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 5] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ $ORIGIN example.com ++ . CAA 0 issue "ca.example.net" ++ ++ If the domain name holder specifies one or more iodef properties, a ++ certificate issuer MAY report invalid certificate requests to that ++ address. In the following example, the domain name holder specifies ++ that reports may be made by means of email with the IODEF data as an ++ attachment, a Web service [RFC6546], or both: ++ ++ $ORIGIN example.com ++ . CAA 0 issue "ca.example.net" ++ . CAA 0 iodef "mailto:security@example.com" ++ . CAA 0 iodef "http://iodef.example.com/" ++ ++ A certificate issuer MAY specify additional parameters that allow ++ customers to specify additional parameters governing certificate ++ issuance. This might be the Certificate Policy under which the ++ certificate is to be issued, the authentication process to be used ++ might be specified, or an account number specified by the CA to ++ enable these parameters to be retrieved. ++ ++ For example, the CA 'ca.example.net' has requested its customer ++ 'example.com' to specify the CA's account number '230123' in each of ++ the customer's CAA records. ++ ++ $ORIGIN example.com ++ . CAA 0 issue "ca.example.net; account=230123" ++ ++ The syntax of additional parameters is a sequence of name-value pairs ++ as defined in Section 5.2. The semantics of such parameters is left ++ to site policy and is outside the scope of this document. ++ ++ The critical flag is intended to permit future versions CAA to ++ introduce new semantics that MUST be understood for correct ++ processing of the record, preventing conforming CAs that do not ++ recognize the new semantics from issuing certificates for the ++ indicated domains. ++ ++ In the following example, the property 'tbs' is flagged as critical. ++ Neither the example.net CA nor any other issuer is authorized to ++ issue under either policy unless the processing rules for the 'tbs' ++ property tag are understood. ++ ++ $ORIGIN example.com ++ . CAA 0 issue "ca.example.net; policy=ev" ++ . CAA 128 tbs "Unknown" ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 6] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ Note that the above restrictions only apply at certificate issue. ++ Since the validity of an end entity certificate is typically a year ++ or more, it is quite possible that the CAA records published at a ++ domain will change between the time a certificate was issued and ++ validation by a relying party. ++ ++4. Certification Authority Processing ++ ++ Before issuing a certificate, a compliant CA MUST check for ++ publication of a relevant CAA Resource Record set. If such a record ++ set exists, a CA MUST NOT issue a certificate unless the CA ++ determines that either (1) the certificate request is consistent with ++ the applicable CAA Resource Record set or (2) an exception specified ++ in the relevant Certificate Policy or Certification Practices ++ Statement applies. ++ ++ A certificate request MAY specify more than one domain name and MAY ++ specify wildcard domains. Issuers MUST verify authorization for all ++ the domains and wildcard domains specified in the request. ++ ++ The search for a CAA record climbs the DNS name tree from the ++ specified label up to but not including the DNS root '.'. ++ ++ Given a request for a specific domain X, or a request for a wildcard ++ domain *.X, the relevant record set R(X) is determined as follows: ++ ++ Let CAA(X) be the record set returned in response to performing a CAA ++ record query on the label X, P(X) be the DNS label immediately above ++ X in the DNS hierarchy, and A(X) be the target of a CNAME or DNAME ++ alias record specified at the label X. ++ ++ o If CAA(X) is not empty, R(X) = CAA (X), otherwise ++ ++ o If A(X) is not null, and R(A(X)) is not empty, then R(X) = ++ R(A(X)), otherwise ++ ++ o If X is not a top-level domain, then R(X) = R(P(X)), otherwise ++ ++ o R(X) is empty. ++ ++ For example, if a certificate is requested for X.Y.Z the issuer will ++ search for the relevant CAA record set in the following order: ++ ++ X.Y.Z ++ ++ Alias (X.Y.Z) ++ ++ Y.Z ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 7] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ Alias (Y.Z) ++ ++ Z ++ ++ Alias (Z) ++ ++ Return Empty ++ ++4.1. Use of DNS Security ++ ++ Use of DNSSEC to authenticate CAA RRs is strongly RECOMMENDED but not ++ required. An issuer MUST NOT issue certificates if doing so would ++ conflict with the relevant CAA Resource Record set, irrespective of ++ whether the corresponding DNS records are signed. ++ ++ DNSSEC provides a proof of non-existence for both DNS domains and RR ++ set within domains. DNSSEC verification thus enables an issuer to ++ determine if the answer to a CAA record query is empty because the RR ++ set is empty or if it is non-empty but the response has been ++ suppressed. ++ ++ Use of DNSSEC allows an issuer to acquire and archive a proof that ++ they were authorized to issue certificates for the domain. ++ Verification of such archives MAY be an audit requirement to verify ++ CAA record processing compliance. Publication of such archives MAY ++ be a transparency requirement to verify CAA record processing ++ compliance. ++ ++5. Mechanism ++ ++5.1. Syntax ++ ++ A CAA RR contains a single property entry consisting of a tag-value ++ pair. Each tag represents a property of the CAA record. The value ++ of a CAA property is that specified in the corresponding value field. ++ ++ A domain name MAY have multiple CAA RRs associated with it and a ++ given property MAY be specified more than once. ++ ++ The CAA data field contains one property entry. A property entry ++ consists of the following data fields: ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 8] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ +0-1-2-3-4-5-6-7-|0-1-2-3-4-5-6-7-| ++ | Flags | Tag Length = n | ++ +----------------+----------------+...+---------------+ ++ | Tag char 0 | Tag char 1 |...| Tag char n-1 | ++ +----------------+----------------+...+---------------+ ++ +----------------+----------------+.....+----------------+ ++ | Value byte 0 | Value byte 1 |.....| Value byte m-1 | ++ +----------------+----------------+.....+----------------+ ++ ++ Where n is the length specified in the Tag length field and m is the ++ remaining octets in the Value field (m = d - n - 2) where d is the ++ length of the RDATA section. ++ ++ The data fields are defined as follows: ++ ++ Flags: One octet containing the following fields: ++ ++ Bit 0, Issuer Critical Flag: If the value is set to '1', the ++ critical flag is asserted and the property MUST be understood ++ if the CAA record is to be correctly processed by a certificate ++ issuer. ++ ++ A Certification Authority MUST NOT issue certificates for any ++ Domain that contains a CAA critical property for an unknown or ++ unsupported property tag that for which the issuer critical ++ flag is set. ++ ++ Note that according to the conventions set out in [RFC1035], bit 0 ++ is the Most Significant Bit and bit 7 is the Least Significant ++ Bit. Thus, the Flags value 1 means that bit 7 is set while a value ++ of 128 means that bit 0 is set according to this convention. ++ ++ All other bit positions are reserved for future use. ++ ++ To ensure compatibility with future extensions to CAA, DNS records ++ compliant with this version of the CAA specification MUST clear ++ (set to "0") all reserved flags bits. Applications that interpret ++ CAA records MUST ignore the value of all reserved flag bits. ++ ++ Tag Length: A single octet containing an unsigned integer specifying ++ the tag length in octets. The tag length MUST be at least 1 and ++ SHOULD be no more than 15. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 9] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ Tag: The property identifier, a sequence of US-ASCII characters. ++ ++ Tag values MAY contain US-ASCII characters 'a' through 'z', 'A' ++ through 'Z', and the numbers 0 through 9. Tag values SHOULD NOT ++ contain any other characters. Matching of tag values is case ++ insensitive. ++ ++ Tag values submitted for registration by IANA MUST NOT contain any ++ characters other than the (lowercase) US-ASCII characters 'a' ++ through 'z' and the numbers 0 through 9. ++ ++ Value: A sequence of octets representing the property value. ++ Property values are encoded as binary values and MAY employ sub- ++ formats. ++ ++ The length of the value field is specified implicitly as the ++ remaining length of the enclosing Resource Record data field. ++ ++5.1.1. Canonical Presentation Format ++ ++ The canonical presentation format of the CAA record is: ++ ++ CAA <flags> <tag> <value> ++ ++ Where: ++ ++ Flags: Is an unsigned integer between 0 and 255. ++ ++ Tag: Is a non-zero sequence of US-ASCII letters and numbers in lower ++ case. ++ ++ Value: Is the <character-string> encoding of the value field as ++ specified in [RFC1035], Section 5.1. ++ ++5.2. CAA issue Property ++ ++ The issue property tag is used to request that certificate issuers ++ perform CAA issue restriction processing for the domain and to grant ++ authorization to specific certificate issuers. ++ ++ The CAA issue property value has the following sub-syntax (specified ++ in ABNF as per [RFC5234]). ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 10] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ issuevalue = space [domain] space [";" *(space parameter) space] ++ ++ domain = label *("." label) ++ label = (ALPHA / DIGIT) *( *("-") (ALPHA / DIGIT)) ++ ++ space = *(SP / HTAB) ++ ++ parameter = tag "=" value ++ ++ tag = 1*(ALPHA / DIGIT) ++ ++ value = *VCHAR ++ ++ For consistency with other aspects of DNS administration, domain name ++ values are specified in letter-digit-hyphen Label (LDH-Label) form. ++ ++ A CAA record with an issue parameter tag that does not specify a ++ domain name is a request that certificate issuers perform CAA issue ++ restriction processing for the corresponding domain without granting ++ authorization to any certificate issuer. ++ ++ This form of issue restriction would be appropriate to specify that ++ no certificates are to be issued for the domain in question. ++ ++ For example, the following CAA record set requests that no ++ certificates be issued for the domain 'nocerts.example.com' by any ++ certificate issuer. ++ ++ nocerts.example.com CAA 0 issue ";" ++ ++ A CAA record with an issue parameter tag that specifies a domain name ++ is a request that certificate issuers perform CAA issue restriction ++ processing for the corresponding domain and grants authorization to ++ the certificate issuer specified by the domain name. ++ ++ For example, the following CAA record set requests that no ++ certificates be issued for the domain 'certs.example.com' by any ++ certificate issuer other than the example.net certificate issuer. ++ ++ certs.example.com CAA 0 issue "example.net" ++ ++ CAA authorizations are additive; thus, the result of specifying both ++ the empty issuer and a specified issuer is the same as specifying ++ just the specified issuer alone. ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 11] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ An issuer MAY choose to specify issuer-parameters that further ++ constrain the issue of certificates by that issuer, for example, ++ specifying that certificates are to be subject to specific validation ++ polices, billed to certain accounts, or issued under specific trust ++ anchors. ++ ++ The semantics of issuer-parameters are determined by the issuer ++ alone. ++ ++5.3. CAA issuewild Property ++ ++ The issuewild property has the same syntax and semantics as the issue ++ property except that issuewild properties only grant authorization to ++ issue certificates that specify a wildcard domain and issuewild ++ properties take precedence over issue properties when specified. ++ Specifically: ++ ++ issuewild properties MUST be ignored when processing a request for ++ a domain that is not a wildcard domain. ++ ++ If at least one issuewild property is specified in the relevant ++ CAA record set, all issue properties MUST be ignored when ++ processing a request for a domain that is a wildcard domain. ++ ++5.4. CAA iodef Property ++ ++ The iodef property specifies a means of reporting certificate issue ++ requests or cases of certificate issue for the corresponding domain ++ that violate the security policy of the issuer or the domain name ++ holder. ++ ++ The Incident Object Description Exchange Format (IODEF) [RFC5070] is ++ used to present the incident report in machine-readable form. ++ ++ The iodef property takes a URL as its parameter. The URL scheme type ++ determines the method used for reporting: ++ ++ mailto: The IODEF incident report is reported as a MIME email ++ attachment to an SMTP email that is submitted to the mail address ++ specified. The mail message sent SHOULD contain a brief text ++ message to alert the recipient to the nature of the attachment. ++ ++ http or https: The IODEF report is submitted as a Web service ++ request to the HTTP address specified using the protocol specified ++ in [RFC6546]. ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 12] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++6. Security Considerations ++ ++ CAA records assert a security policy that the holder of a domain name ++ wishes to be observed by certificate issuers. The effectiveness of ++ CAA records as an access control mechanism is thus dependent on ++ observance of CAA constraints by issuers. ++ ++ The objective of the CAA record properties described in this document ++ is to reduce the risk of certificate mis-issue rather than avoid ++ reliance on a certificate that has been mis-issued. DANE [RFC6698] ++ describes a mechanism for avoiding reliance on mis-issued ++ certificates. ++ ++6.1. Non-Compliance by Certification Authority ++ ++ CAA records offer CAs a cost-effective means of mitigating the risk ++ of certificate mis-issue: the cost of implementing CAA checks is very ++ small and the potential costs of a mis-issue event include the ++ removal of an embedded trust anchor. ++ ++6.2. Mis-Issue by Authorized Certification Authority ++ ++ Use of CAA records does not prevent mis-issue by an authorized ++ Certification Authority, i.e., a CA that is authorized to issue ++ certificates for the domain in question by CAA records. ++ ++ Domain name holders SHOULD verify that the CAs they authorize to ++ issue certificates for their domains employ appropriate controls to ++ ensure that certificates are issued only to authorized parties within ++ their organization. ++ ++ Such controls are most appropriately determined by the domain name ++ holder and the authorized CA(s) directly and are thus out of scope of ++ this document. ++ ++6.3. Suppression or Spoofing of CAA Records ++ ++ Suppression of the CAA record or insertion of a bogus CAA record ++ could enable an attacker to obtain a certificate from an issuer that ++ was not authorized to issue for that domain name. ++ ++ Where possible, issuers SHOULD perform DNSSEC validation to detect ++ missing or modified CAA record sets. ++ ++ In cases where DNSSEC is not deployed in a corresponding domain, an ++ issuer SHOULD attempt to mitigate this risk by employing appropriate ++ DNS security controls. For example, all portions of the DNS lookup ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 13] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ process SHOULD be performed against the authoritative name server. ++ Data cached by third parties MUST NOT be relied on but MAY be used to ++ support additional anti-spoofing or anti-suppression controls. ++ ++6.4. Denial of Service ++ ++ Introduction of a malformed or malicious CAA RR could in theory ++ enable a Denial-of-Service (DoS) attack. ++ ++ This specific threat is not considered to add significantly to the ++ risk of running an insecure DNS service. ++ ++ An attacker could, in principle, perform a DoS attack against an ++ issuer by requesting a certificate with a maliciously long DNS name. ++ In practice, the DNS protocol imposes a maximum name length and CAA ++ processing does not exacerbate the existing need to mitigate DoS ++ attacks to any meaningful degree. ++ ++6.5. Abuse of the Critical Flag ++ ++ A Certification Authority could make use of the critical flag to ++ trick customers into publishing records that prevent competing ++ Certification Authorities from issuing certificates even though the ++ customer intends to authorize multiple providers. ++ ++ In practice, such an attack would be of minimal effect since any ++ competent competitor that found itself unable to issue certificates ++ due to lack of support for a property marked critical SHOULD ++ investigate the cause and report the reason to the customer. The ++ customer will thus discover that they had been deceived. ++ ++7. IANA Considerations ++ ++7.1. Registration of the CAA Resource Record Type ++ ++ IANA has assigned Resource Record Type 257 for the CAA Resource ++ Record Type and added the line depicted below to the registry named ++ "Resource Record (RR) TYPEs" and QTYPEs as defined in BCP 42 ++ [RFC6195] and located at ++ http://www.iana.org/assignments/dns-parameters. ++ ++ RR Name Value and meaning Reference ++ ----------- --------------------------------------------- --------- ++ CAA 257 Certification Authority Restriction [RFC6844] ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 14] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++7.2. Certification Authority Restriction Properties ++ ++ IANA has created the "Certification Authority Restriction Properties" ++ registry with the following initial values: ++ ++ ++ Tag Meaning Reference ++ ----------- -------------------------------------- --------- ++ issue Authorization Entry by Domain [RFC6844] ++ issuewild Authorization Entry by Wildcard Domain [RFC6844] ++ iodef Report incident by IODEF report [RFC6844] ++ auth Reserved [HB2011] ++ path Reserved [HB2011] ++ policy Reserved [HB2011] ++ ++ ++ Although [HB2011] has expired, deployed clients implement the CAA ++ properties specified in the document and reuse of these property tags ++ for a different purpose could cause unexpected behavior. ++ ++ Addition of tag identifiers requires a public specification and ++ Expert Review as set out in [RFC6195], Section 3.1.1. ++ ++ The tag space is designed to be sufficiently large that exhausting ++ the possible tag space need not be a concern. The scope of Expert ++ Review SHOULD be limited to the question of whether the specification ++ provided is sufficiently clear to permit implementation and to avoid ++ unnecessary duplication of functionality. ++ ++7.3. Certification Authority Restriction Flags ++ ++ IANA has created the "Certification Authority Restriction Flags" ++ registry with the following initial values: ++ ++ ++ Flag Meaning Reference ++ ----------- ---------------------------------- --------- ++ 0 Issuer Critical Flag [RFC6844] ++ 1-7 Reserved> [RFC6844] ++ ++ Assignment of new flags follows the RFC Required policy set out in ++ [RFC5226], Section 4.1. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 15] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++8. Acknowledgements ++ ++ The authors would like to thank the following people who contributed ++ to the design and documentation of this work item: Chris Evans, ++ Stephen Farrell, Jeff Hodges, Paul Hoffman, Stephen Kent, Adam ++ Langley, Ben Laurie, James Manager, Chris Palmer, Scott Schmit, Sean ++ Turner, and Ben Wilson. ++ ++9. References ++ ++9.1. Normative References ++ ++ [RFC1035] Mockapetris, P., "Domain names - implementation and ++ specification", STD 13, RFC 1035, November 1987. ++ ++ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate ++ Requirement Levels", BCP 14, RFC 2119, March 1997. ++ ++ [RFC2181] Elz, R. and R. Bush, "Clarifications to the DNS ++ Specification", RFC 2181, July 1997. ++ ++ [RFC4033] Arends, R., Austein, R., Larson, M., Massey, D., and S. ++ Rose, "DNS Security Introduction and Requirements", ++ RFC 4033, March 2005. ++ ++ [RFC4034] Arends, R., Austein, R., Larson, M., Massey, D., and S. ++ Rose, "Resource Records for the DNS Security Extensions", ++ RFC 4034, March 2005. ++ ++ [RFC4035] Arends, R., Austein, R., Larson, M., Massey, D., and S. ++ Rose, "Protocol Modifications for the DNS Security ++ Extensions", RFC 4035, March 2005. ++ ++ [RFC5070] Danyliw, R., Meijer, J., and Y. Demchenko, "The Incident ++ Object Description Exchange Format", RFC 5070, ++ December 2007. ++ ++ [RFC5155] Laurie, B., Sisson, G., Arends, R., and D. Blacka, "DNS ++ Security (DNSSEC) Hashed Authenticated Denial of ++ Existence", RFC 5155, March 2008. ++ ++ [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an ++ IANA Considerations Section in RFCs", BCP 26, RFC 5226, ++ May 2008. ++ ++ [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax ++ Specifications: ABNF", STD 68, RFC 5234, January 2008. ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 16] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++ [RFC5280] Cooper, D., Santesson, S., Farrell, S., Boeyen, S., ++ Housley, R., and W. Polk, "Internet X.509 Public Key ++ Infrastructure Certificate and Certificate Revocation List ++ (CRL) Profile", RFC 5280, May 2008. ++ ++ [RFC6195] Eastlake, D., "Domain Name System (DNS) IANA ++ Considerations", BCP 42, RFC 6195, March 2011. ++ ++ [RFC6546] Trammell, B., "Transport of Real-time Inter-network ++ Defense (RID) Messages over HTTP/TLS", RFC 6546, ++ April 2012. ++ ++ [RFC6698] Hoffman, P. and J. Schlyter, "The DNS-Based Authentication ++ of Named Entities (DANE) Transport Layer Security (TLS) ++ Protocol: TLSA", RFC 6698, August 2012. ++ ++ [STD13] Mockapetris, P., "Domain names - concepts and facilities", ++ STD 13, RFC 1034, November 1987. ++ ++ Mockapetris, P., "Domain names - implementation and ++ specification", STD 13, RFC 1035, November 1987. ++ ++ [X.509] International Telecommunication Union, "ITU-T ++ Recommendation X.509 (11/2008): Information technology - ++ Open systems interconnection - The Directory: Public-key ++ and attribute certificate frameworks", ITU-T ++ Recommendation X.509, November 2008. ++ ++9.2. Informative References ++ ++ [HB2011] Hallam-Baker, P., Stradling, R., and B. Laurie, "DNS ++ Certification Authority Authorization (CAA) Resource ++ Record", Work in Progress, May 2011. ++ ++ [RFC3647] Chokhani, S., Ford, W., Sabett, R., Merrill, C., and S. ++ Wu, "Internet X.509 Public Key Infrastructure Certificate ++ Policy and Certification Practices Framework", RFC 3647, ++ November 2003. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 17] ++ ++RFC 6844 Certification Authority Authorization January 2013 ++ ++ ++Authors' Addresses ++ ++ Phillip Hallam-Baker ++ Comodo Group, Inc. ++ ++ EMail: philliph@comodo.com ++ ++ ++ Rob Stradling ++ Comodo CA, Ltd. ++ ++ EMail: rob.stradling@comodo.com ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++Hallam-Baker & Stradling Standards Track [Page 18] ++ +diff --git a/lib/dns/rdata.c b/lib/dns/rdata.c +index a83dab4..9bf83a4 100644 +--- a/lib/dns/rdata.c ++++ b/lib/dns/rdata.c +@@ -116,7 +116,7 @@ typedef struct dns_rdata_textctx { + } dns_rdata_textctx_t; + + static isc_result_t +-txt_totext(isc_region_t *source, isc_buffer_t *target); ++txt_totext(isc_region_t *source, isc_boolean_t quote, isc_buffer_t *target); + + static isc_result_t + txt_fromtext(isc_textregion_t *source, isc_buffer_t *target); +@@ -130,9 +130,6 @@ multitxt_totext(isc_region_t *source, isc_buffer_t *target); + static isc_result_t + multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target); + +-static isc_result_t +-multitxt_fromwire(isc_buffer_t *source, isc_buffer_t *target); +- + static isc_boolean_t + name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target); + +@@ -1131,7 +1128,7 @@ name_length(dns_name_t *name) { + } + + static isc_result_t +-txt_totext(isc_region_t *source, isc_buffer_t *target) { ++txt_totext(isc_region_t *source, isc_boolean_t quote, isc_buffer_t *target) { + unsigned int tl; + unsigned int n; + unsigned char *sp; +@@ -1146,13 +1143,20 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) { + n = *sp++; + + REQUIRE(n + 1 <= source->length); ++ if (n == 0U) ++ REQUIRE(quote == ISC_TRUE); + +- if (tl < 1) +- return (ISC_R_NOSPACE); +- *tp++ = '"'; +- tl--; ++ if (quote) { ++ if (tl < 1) ++ return (ISC_R_NOSPACE); ++ *tp++ = '"'; ++ tl--; ++ } + while (n--) { +- if (*sp < 0x20 || *sp >= 0x7f) { ++ /* ++ * \DDD space (0x20) if not quoting. ++ */ ++ if (*sp < (quote ? 0x20 : 0x21) || *sp >= 0x7f) { + if (tl < 4) + return (ISC_R_NOSPACE); + *tp++ = 0x5c; +@@ -1163,8 +1167,13 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) { + tl -= 4; + continue; + } +- /* double quote, semi-colon, backslash */ +- if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c) { ++ /* ++ * Escape double quote, semi-colon, backslash. ++ * If we are not enclosing the string in double ++ * quotes also escape at sign. ++ */ ++ if (*sp == 0x22 || *sp == 0x3b || *sp == 0x5c || ++ (!quote && *sp == 0x40)) { + if (tl < 2) + return (ISC_R_NOSPACE); + *tp++ = '\\'; +@@ -1175,10 +1184,12 @@ txt_totext(isc_region_t *source, isc_buffer_t *target) { + *tp++ = *sp++; + tl--; + } +- if (tl < 1) +- return (ISC_R_NOSPACE); +- *tp++ = '"'; +- tl--; ++ if (quote) { ++ if (tl < 1) ++ return (ISC_R_NOSPACE); ++ *tp++ = '"'; ++ tl--; ++ } + isc_buffer_add(target, tp - (char *)region.base); + isc_region_consume(source, *source->base + 1); + return (ISC_R_SUCCESS); +@@ -1274,6 +1285,9 @@ txt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { + return (ISC_R_SUCCESS); + } + ++/* ++ * Conversion of TXT-like rdata fields without length limits. ++ */ + static isc_result_t + multitxt_totext(isc_region_t *source, isc_buffer_t *target) { + unsigned int tl; +@@ -1292,9 +1306,8 @@ multitxt_totext(isc_region_t *source, isc_buffer_t *target) { + *tp++ = '"'; + tl--; + do { +- n0 = n = *sp++; +- +- REQUIRE(n0 + 1 <= source->length); ++ n = source->length; ++ n0 = source->length - 1; + + while (n--) { + if (*sp < 0x20 || *sp >= 0x7f) { +@@ -1346,17 +1359,11 @@ multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { + + do { + isc_buffer_availableregion(target, &tregion); +- t0 = tregion.base; ++ t0 = t = tregion.base; + nrem = tregion.length; + if (nrem < 1) + return (ISC_R_NOSPACE); +- /* length byte */ +- t = t0; +- nrem--; +- t++; +- /* 255 byte character-string slice */ +- if (nrem > 255) +- nrem = 255; ++ + while (n != 0) { + --n; + c = (*s++) & 0xff; +@@ -1390,39 +1397,9 @@ multitxt_fromtext(isc_textregion_t *source, isc_buffer_t *target) { + } + if (escape) + return (DNS_R_SYNTAX); +- *t0 = t - t0 - 1; +- isc_buffer_add(target, *t0 + 1); +- } while (n != 0); +- return (ISC_R_SUCCESS); +-} +- +-static isc_result_t +-multitxt_fromwire(isc_buffer_t *source, isc_buffer_t *target) { +- unsigned int n; +- isc_region_t sregion; +- isc_region_t tregion; +- +- isc_buffer_activeregion(source, &sregion); +- if (sregion.length == 0) +- return(ISC_R_UNEXPECTEDEND); +- n = 256U; +- do { +- if (n != 256U) +- return (DNS_R_SYNTAX); +- n = *sregion.base + 1; +- if (n > sregion.length) +- return (ISC_R_UNEXPECTEDEND); + +- isc_buffer_availableregion(target, &tregion); +- if (n > tregion.length) +- return (ISC_R_NOSPACE); +- +- if (tregion.base != sregion.base) +- memcpy(tregion.base, sregion.base, n); +- isc_buffer_forward(source, n); +- isc_buffer_add(target, n); +- isc_buffer_activeregion(source, &sregion); +- } while (sregion.length != 0); ++ isc_buffer_add(target, t - t0); ++ } while (n != 0); + return (ISC_R_SUCCESS); + } + +diff --git a/lib/dns/rdata/generic/caa_257.c b/lib/dns/rdata/generic/caa_257.c +new file mode 100644 +index 0000000..671f332 +--- /dev/null ++++ b/lib/dns/rdata/generic/caa_257.c +@@ -0,0 +1,370 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef GENERIC_CAA_257_C ++#define GENERIC_CAA_257_C 1 ++ ++#define RRTYPE_CAA_ATTRIBUTES (0) ++ ++static unsigned char const alphanumeric[256] = { ++ /* 0x00-0x0f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0x10-0x1f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0x20-0x2f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0x30-0x3f */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, ++ /* 0x40-0x4f */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ /* 0x50-0x5f */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, ++ /* 0x60-0x6f */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ++ /* 0x70-0x7f */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, ++ /* 0x80-0x8f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0x90-0x9f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0xa0-0xaf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0xb0-0xbf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0xc0-0xcf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0xd0-0xdf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0xe0-0xef */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ /* 0xf0-0xff */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++}; ++ ++static inline isc_result_t ++fromtext_caa(ARGS_FROMTEXT) { ++ isc_token_t token; ++ isc_textregion_t tr; ++ isc_uint8_t flags; ++ unsigned int i; ++ ++ REQUIRE(type == 257); ++ ++ UNUSED(type); ++ UNUSED(rdclass); ++ UNUSED(origin); ++ UNUSED(options); ++ UNUSED(callbacks); ++ ++ /* Flags. */ ++ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, ++ ISC_FALSE)); ++ if (token.value.as_ulong > 255U) ++ RETTOK(ISC_R_RANGE); ++ flags = token.value.as_ulong & 255U; ++ RETERR(uint8_tobuffer(flags, target)); ++ ++ /* ++ * Tag ++ */ ++ RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, ++ ISC_FALSE)); ++ tr = token.value.as_textregion; ++ for (i = 0; i < tr.length; i++) ++ if (!alphanumeric[(unsigned char) tr.base[i]]) ++ RETTOK(DNS_R_SYNTAX); ++ RETERR(uint8_tobuffer(tr.length, target)); ++ RETERR(mem_tobuffer(target, tr.base, tr.length)); ++ ++ /* ++ * Value ++ */ ++ RETERR(isc_lex_getmastertoken(lexer, &token, ++ isc_tokentype_qstring, ISC_FALSE)); ++ if (token.type != isc_tokentype_qstring && ++ token.type != isc_tokentype_string) ++ RETERR(DNS_R_SYNTAX); ++ RETERR(multitxt_fromtext(&token.value.as_textregion, target)); ++ return (ISC_R_SUCCESS); ++} ++ ++static inline isc_result_t ++totext_caa(ARGS_TOTEXT) { ++ isc_region_t region; ++ isc_uint8_t flags; ++ char buf[256]; ++ ++ UNUSED(tctx); ++ ++ REQUIRE(rdata->type == 257); ++ REQUIRE(rdata->length >= 3U); ++ REQUIRE(rdata->data != NULL); ++ ++ dns_rdata_toregion(rdata, ®ion); ++ ++ /* ++ * Flags ++ */ ++ flags = uint8_consume_fromregion(®ion); ++ sprintf(buf, "%u ", flags); ++ RETERR(str_totext(buf, target)); ++ ++ /* ++ * Tag ++ */ ++ RETERR(txt_totext(®ion, ISC_FALSE, target)); ++ RETERR(str_totext(" ", target)); ++ ++ /* ++ * Value ++ */ ++ RETERR(multitxt_totext(®ion, target)); ++ return (ISC_R_SUCCESS); ++} ++ ++static inline isc_result_t ++fromwire_caa(ARGS_FROMWIRE) { ++ isc_region_t sr; ++ unsigned int len, i; ++ ++ REQUIRE(type == 257); ++ ++ UNUSED(type); ++ UNUSED(rdclass); ++ UNUSED(dctx); ++ UNUSED(options); ++ ++ /* ++ * Flags ++ */ ++ isc_buffer_activeregion(source, &sr); ++ if (sr.length < 2) ++ return (ISC_R_UNEXPECTEDEND); ++ ++ /* ++ * Flags, tag length ++ */ ++ RETERR(mem_tobuffer(target, sr.base, 2)); ++ len = sr.base[1]; ++ isc_region_consume(&sr, 2); ++ isc_buffer_forward(source, 2); ++ ++ /* ++ * Zero length tag fields are illegal. ++ */ ++ if (sr.length < len || len == 0) ++ RETERR(DNS_R_FORMERR); ++ ++ /* Check the Tag's value */ ++ for (i = 0; i < len; i++) ++ if (!alphanumeric[sr.base[i]]) ++ RETERR(DNS_R_FORMERR); ++ /* ++ * Tag + Value ++ */ ++ isc_buffer_forward(source, sr.length); ++ return (mem_tobuffer(target, sr.base, sr.length)); ++} ++ ++static inline isc_result_t ++towire_caa(ARGS_TOWIRE) { ++ isc_region_t region; ++ ++ REQUIRE(rdata->type == 257); ++ REQUIRE(rdata->length >= 3U); ++ REQUIRE(rdata->data != NULL); ++ ++ UNUSED(cctx); ++ ++ dns_rdata_toregion(rdata, ®ion); ++ return (mem_tobuffer(target, region.base, region.length)); ++} ++ ++static inline int ++compare_caa(ARGS_COMPARE) { ++ isc_region_t r1, r2; ++ ++ REQUIRE(rdata1->type == rdata2->type); ++ REQUIRE(rdata1->rdclass == rdata2->rdclass); ++ REQUIRE(rdata1->type == 257); ++ REQUIRE(rdata1->length >= 3U); ++ REQUIRE(rdata2->length >= 3U); ++ REQUIRE(rdata1->data != NULL); ++ REQUIRE(rdata2->data != NULL); ++ ++ dns_rdata_toregion(rdata1, &r1); ++ dns_rdata_toregion(rdata2, &r2); ++ return (isc_region_compare(&r1, &r2)); ++} ++ ++static inline isc_result_t ++fromstruct_caa(ARGS_FROMSTRUCT) { ++ dns_rdata_caa_t *caa = source; ++ isc_region_t region; ++ unsigned int i; ++ ++ REQUIRE(type == 257); ++ REQUIRE(source != NULL); ++ REQUIRE(caa->common.rdtype == type); ++ REQUIRE(caa->common.rdclass == rdclass); ++ REQUIRE(caa->tag != NULL && caa->tag_len != 0); ++ REQUIRE(caa->value != NULL); ++ ++ UNUSED(type); ++ UNUSED(rdclass); ++ ++ /* ++ * Flags ++ */ ++ RETERR(uint8_tobuffer(caa->flags, target)); ++ ++ /* ++ * Tag length ++ */ ++ RETERR(uint8_tobuffer(caa->tag_len, target)); ++ ++ /* ++ * Tag ++ */ ++ region.base = caa->tag; ++ region.length = caa->tag_len; ++ for (i = 0; i < region.length; i++) ++ if (!alphanumeric[region.base[i]]) ++ RETERR(DNS_R_SYNTAX); ++ RETERR(isc_buffer_copyregion(target, ®ion)); ++ ++ /* ++ * Value ++ */ ++ region.base = caa->value; ++ region.length = caa->value_len; ++ return (isc_buffer_copyregion(target, ®ion)); ++} ++ ++static inline isc_result_t ++tostruct_caa(ARGS_TOSTRUCT) { ++ dns_rdata_caa_t *caa = target; ++ isc_region_t sr; ++ ++ REQUIRE(rdata->type == 257); ++ REQUIRE(target != NULL); ++ REQUIRE(rdata->length >= 3U); ++ REQUIRE(rdata->data != NULL); ++ ++ caa->common.rdclass = rdata->rdclass; ++ caa->common.rdtype = rdata->type; ++ ISC_LINK_INIT(&caa->common, link); ++ ++ dns_rdata_toregion(rdata, &sr); ++ ++ /* ++ * Flags ++ */ ++ if (sr.length < 1) ++ return (ISC_R_UNEXPECTEDEND); ++ caa->flags = uint8_fromregion(&sr); ++ isc_region_consume(&sr, 1); ++ ++ /* ++ * Tag length ++ */ ++ if (sr.length < 1) ++ return (ISC_R_UNEXPECTEDEND); ++ caa->tag_len = uint8_fromregion(&sr); ++ isc_region_consume(&sr, 1); ++ ++ /* ++ * Tag ++ */ ++ if (sr.length < caa->tag_len) ++ return (ISC_R_UNEXPECTEDEND); ++ caa->tag = mem_maybedup(mctx, sr.base, caa->tag_len); ++ if (caa->tag == NULL) ++ return (ISC_R_NOMEMORY); ++ isc_region_consume(&sr, caa->tag_len); ++ ++ /* ++ * Value ++ */ ++ caa->value_len = sr.length; ++ caa->value = mem_maybedup(mctx, sr.base, sr.length); ++ if (caa->value == NULL) ++ return (ISC_R_NOMEMORY); ++ ++ caa->mctx = mctx; ++ return (ISC_R_SUCCESS); ++} ++ ++static inline void ++freestruct_caa(ARGS_FREESTRUCT) { ++ dns_rdata_caa_t *caa = (dns_rdata_caa_t *) source; ++ ++ REQUIRE(source != NULL); ++ REQUIRE(caa->common.rdtype == 257); ++ ++ if (caa->mctx == NULL) ++ return; ++ ++ if (caa->tag != NULL) ++ isc_mem_free(caa->mctx, caa->tag); ++ if (caa->value != NULL) ++ isc_mem_free(caa->mctx, caa->value); ++ caa->mctx = NULL; ++} ++ ++static inline isc_result_t ++additionaldata_caa(ARGS_ADDLDATA) { ++ REQUIRE(rdata->type == 257); ++ REQUIRE(rdata->data != NULL); ++ REQUIRE(rdata->length >= 3U); ++ ++ UNUSED(rdata); ++ UNUSED(add); ++ UNUSED(arg); ++ ++ return (ISC_R_SUCCESS); ++} ++ ++static inline isc_result_t ++digest_caa(ARGS_DIGEST) { ++ isc_region_t r; ++ ++ REQUIRE(rdata->type == 257); ++ REQUIRE(rdata->data != NULL); ++ REQUIRE(rdata->length >= 3U); ++ ++ dns_rdata_toregion(rdata, &r); ++ ++ return ((digest)(arg, &r)); ++} ++ ++static inline isc_boolean_t ++checkowner_caa(ARGS_CHECKOWNER) { ++ ++ REQUIRE(type == 257); ++ ++ UNUSED(name); ++ UNUSED(type); ++ UNUSED(rdclass); ++ UNUSED(wildcard); ++ ++ return (ISC_TRUE); ++} ++ ++static inline isc_boolean_t ++checknames_caa(ARGS_CHECKNAMES) { ++ ++ REQUIRE(rdata->type == 257); ++ REQUIRE(rdata->data != NULL); ++ REQUIRE(rdata->length >= 3U); ++ ++ UNUSED(rdata); ++ UNUSED(owner); ++ UNUSED(bad); ++ ++ return (ISC_TRUE); ++} ++ ++static inline int ++casecompare_caa(ARGS_COMPARE) { ++ return (compare_caa(rdata1, rdata2)); ++} ++ ++#endif /* GENERIC_CAA_257_C */ +diff --git a/lib/dns/rdata/generic/caa_257.h b/lib/dns/rdata/generic/caa_257.h +new file mode 100644 +index 0000000..79866a5 +--- /dev/null ++++ b/lib/dns/rdata/generic/caa_257.h +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC") ++ * ++ * Permission to use, copy, modify, and/or distribute this software for any ++ * purpose with or without fee is hereby granted, provided that the above ++ * copyright notice and this permission notice appear in all copies. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH ++ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY ++ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, ++ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ++ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE ++ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR ++ * PERFORMANCE OF THIS SOFTWARE. ++ */ ++ ++#ifndef GENERIC_CAA_257_H ++#define GENERIC_CAA_257_H 1 ++ ++/* $Id$ */ ++ ++typedef struct dns_rdata_caa { ++ dns_rdatacommon_t common; ++ isc_mem_t * mctx; ++ isc_uint8_t flags; ++ unsigned char * tag; ++ isc_uint8_t tag_len; ++ unsigned char *value; ++ isc_uint8_t value_len; ++} dns_rdata_caa_t; ++ ++#endif /* GENERIC_CAA_257_H */ +diff --git a/lib/dns/rdata/generic/gpos_27.c b/lib/dns/rdata/generic/gpos_27.c +index ce71822..5a90216 100644 +--- a/lib/dns/rdata/generic/gpos_27.c ++++ b/lib/dns/rdata/generic/gpos_27.c +@@ -61,7 +61,7 @@ totext_gpos(ARGS_TOTEXT) { + dns_rdata_toregion(rdata, ®ion); + + for (i = 0; i < 3; i++) { +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + if (i != 2) + RETERR(str_totext(" ", target)); + } +diff --git a/lib/dns/rdata/generic/hinfo_13.c b/lib/dns/rdata/generic/hinfo_13.c +index 10b4fec..92038b7 100644 +--- a/lib/dns/rdata/generic/hinfo_13.c ++++ b/lib/dns/rdata/generic/hinfo_13.c +@@ -58,9 +58,9 @@ totext_hinfo(ARGS_TOTEXT) { + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, ®ion); +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + RETERR(str_totext(" ", target)); +- return (txt_totext(®ion, target)); ++ return (txt_totext(®ion, ISC_TRUE, target)); + } + + static inline isc_result_t +diff --git a/lib/dns/rdata/generic/isdn_20.c b/lib/dns/rdata/generic/isdn_20.c +index 5aac73f..059c247 100644 +--- a/lib/dns/rdata/generic/isdn_20.c ++++ b/lib/dns/rdata/generic/isdn_20.c +@@ -65,11 +65,11 @@ totext_isdn(ARGS_TOTEXT) { + UNUSED(tctx); + + dns_rdata_toregion(rdata, ®ion); +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + if (region.length == 0) + return (ISC_R_SUCCESS); + RETERR(str_totext(" ", target)); +- return (txt_totext(®ion, target)); ++ return (txt_totext(®ion, ISC_TRUE, target)); + } + + static inline isc_result_t +diff --git a/lib/dns/rdata/generic/naptr_35.c b/lib/dns/rdata/generic/naptr_35.c +index 83439a5..be7d403 100644 +--- a/lib/dns/rdata/generic/naptr_35.c ++++ b/lib/dns/rdata/generic/naptr_35.c +@@ -224,19 +224,19 @@ totext_naptr(ARGS_TOTEXT) { + /* + * Flags. + */ +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + RETERR(str_totext(" ", target)); + + /* + * Service. + */ +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + RETERR(str_totext(" ", target)); + + /* + * Regexp. + */ +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + RETERR(str_totext(" ", target)); + + /* +diff --git a/lib/dns/rdata/generic/spf_99.c b/lib/dns/rdata/generic/spf_99.c +index 492e315..85594fd 100644 +--- a/lib/dns/rdata/generic/spf_99.c ++++ b/lib/dns/rdata/generic/spf_99.c +@@ -64,7 +64,7 @@ totext_spf(ARGS_TOTEXT) { + dns_rdata_toregion(rdata, ®ion); + + while (region.length > 0) { +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + if (region.length > 0) + RETERR(str_totext(" ", target)); + } +diff --git a/lib/dns/rdata/generic/txt_16.c b/lib/dns/rdata/generic/txt_16.c +index e1bce6a..e0e8ea5 100644 +--- a/lib/dns/rdata/generic/txt_16.c ++++ b/lib/dns/rdata/generic/txt_16.c +@@ -71,7 +71,7 @@ totext_txt(ARGS_TOTEXT) { + dns_rdata_toregion(rdata, ®ion); + + while (region.length > 0) { +- RETERR(txt_totext(®ion, target)); ++ RETERR(txt_totext(®ion, ISC_TRUE, target)); + if (region.length > 0) + RETERR(str_totext(" ", target)); + } +diff --git a/lib/dns/rdata/generic/uri_256.c b/lib/dns/rdata/generic/uri_256.c +index 799eb69..62bdd25 100644 +--- a/lib/dns/rdata/generic/uri_256.c ++++ b/lib/dns/rdata/generic/uri_256.c +@@ -115,15 +115,12 @@ fromwire_uri(ARGS_FROMWIRE) { + isc_buffer_activeregion(source, ®ion); + if (region.length < 4) + return (ISC_R_UNEXPECTEDEND); +- RETERR(mem_tobuffer(target, region.base, 4)); +- isc_buffer_forward(source, 4); + + /* +- * Target URI ++ * Priority, weight and target URI + */ +- RETERR(multitxt_fromwire(source, target)); +- +- return (ISC_R_SUCCESS); ++ isc_buffer_forward(source, region.length); ++ return (mem_tobuffer(target, region.base, region.length)); + } + + static inline isc_result_t +@@ -178,8 +175,6 @@ compare_uri(ARGS_COMPARE) { + static inline isc_result_t + fromstruct_uri(ARGS_FROMSTRUCT) { + dns_rdata_uri_t *uri = source; +- isc_region_t region; +- isc_uint8_t len; + + REQUIRE(type == 256); + REQUIRE(source != NULL); +@@ -203,18 +198,6 @@ fromstruct_uri(ARGS_FROMSTRUCT) { + /* + * Target URI + */ +- len = 255U; +- region.base = uri->target; +- region.length = uri->tgt_len; +- while (region.length > 0) { +- REQUIRE(len == 255U); +- len = uint8_fromregion(®ion); +- isc_region_consume(®ion, 1); +- if (region.length < len) +- return (ISC_R_UNEXPECTEDEND); +- isc_region_consume(®ion, len); +- } +- + return (mem_tobuffer(target, uri->target, uri->tgt_len)); + } + +diff --git a/lib/dns/rdata/generic/x25_19.c b/lib/dns/rdata/generic/x25_19.c +index 6867fec..f9dfb8a 100644 +--- a/lib/dns/rdata/generic/x25_19.c ++++ b/lib/dns/rdata/generic/x25_19.c +@@ -60,7 +60,7 @@ totext_x25(ARGS_TOTEXT) { + REQUIRE(rdata->length != 0); + + dns_rdata_toregion(rdata, ®ion); +- return (txt_totext(®ion, target)); ++ return (txt_totext(®ion, ISC_TRUE, target)); + } + + static inline isc_result_t +-- +2.4.3 + diff --git a/SOURCES/bind99-rh1392362.patch b/SOURCES/bind99-rh1392362.patch new file mode 100644 index 0000000..a936c1f --- /dev/null +++ b/SOURCES/bind99-rh1392362.patch @@ -0,0 +1,41 @@ +From 3acf8e092f95233bc3d854e161569487dce83ba2 Mon Sep 17 00:00:00 2001 +From: Mark Andrews <marka@isc.org> +Date: Fri, 3 Feb 2017 14:22:03 +1100 +Subject: [PATCH] 4567. [port] Call getprotobyname and getservbyname prior to + calling chroot so that shared libraries get loaded. [RT #44537] + +--- + lib/isc/unix/dir.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/lib/isc/unix/dir.c b/lib/isc/unix/dir.c +index 0d64778..ee80f41 100644 +--- a/lib/isc/unix/dir.c ++++ b/lib/isc/unix/dir.c +@@ -31,6 +31,7 @@ + + #include <isc/dir.h> + #include <isc/magic.h> ++#include <isc/netdb.h> + #include <isc/string.h> + #include <isc/util.h> + +@@ -172,6 +173,15 @@ isc_dir_chroot(const char *dirname) { + REQUIRE(dirname != NULL); + + #ifdef HAVE_CHROOT ++ /* ++ * Try to use getservbyname and getprotobyname before chroot. ++ * If WKS records are used in a zone under chroot, Name Service Switch ++ * may fail to load library in chroot. ++ * Do not report errors if it fails, we do not need any result now. ++ */ ++ if (getprotobyname("udp")) ++ (void)getservbyname("domain", "udp"); ++ + if (chroot(dirname) < 0 || chdir("/") < 0) + return (isc__errno2result(errno)); + +-- +2.9.3 + diff --git a/SOURCES/bind99-rh1416304.patch b/SOURCES/bind99-rh1416304.patch new file mode 100644 index 0000000..34a9c23 --- /dev/null +++ b/SOURCES/bind99-rh1416304.patch @@ -0,0 +1,139 @@ +From e7a2611c555e03314ac4f7960044b05cce040364 Mon Sep 17 00:00:00 2001 +From: Mark Andrews <marka@isc.org> +Date: Thu, 31 Jul 2014 11:38:11 +1000 +Subject: [PATCH] 3905. [bug] Address deadlock between view.c and adb.c. [RT + #36341] +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Original-commit: 5e746ab61ed8158f784b86111fef95581a08b7dd +Signed-off-by: Petr Menšík <pemensik@redhat.com> +--- + lib/dns/adb.c | 57 +++++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 41 insertions(+), 16 deletions(-) + +diff --git a/lib/dns/adb.c b/lib/dns/adb.c +index a6da94d..ac89e66 100644 +--- a/lib/dns/adb.c ++++ b/lib/dns/adb.c +@@ -15,8 +15,6 @@ + * PERFORMANCE OF THIS SOFTWARE. + */ + +-/* $Id: adb.c,v 1.264 2011/12/05 17:10:51 each Exp $ */ +- + /*! \file + * + * \note +@@ -157,7 +155,7 @@ struct dns_adb { + unsigned int *entry_refcnt; + + isc_event_t cevent; +- isc_boolean_t cevent_sent; ++ isc_boolean_t cevent_out; + isc_boolean_t shutting_down; + isc_eventlist_t whenshutdown; + isc_event_t growentries; +@@ -322,6 +320,7 @@ static inline isc_boolean_t unlink_entry(dns_adb_t *, dns_adbentry_t *); + static isc_boolean_t kill_name(dns_adbname_t **, isc_eventtype_t); + static void water(void *, int); + static void dump_entry(FILE *, dns_adbentry_t *, isc_boolean_t, isc_stdtime_t); ++static void shutdown_task(isc_task_t *task, isc_event_t *ev); + + /* + * MUST NOT overlap DNS_ADBFIND_* flags! +@@ -1499,10 +1498,13 @@ check_exit(dns_adb_t *adb) { + * If there aren't any external references either, we're + * done. Send the control event to initiate shutdown. + */ +- INSIST(!adb->cevent_sent); /* Sanity check. */ ++ INSIST(!adb->cevent_out); /* Sanity check. */ ++ ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, ++ DNS_EVENT_ADBCONTROL, shutdown_task, adb, ++ adb, NULL, NULL); + event = &adb->cevent; + isc_task_send(adb->task, &event); +- adb->cevent_sent = ISC_TRUE; ++ adb->cevent_out = ISC_TRUE; + } + } + +@@ -2431,10 +2433,9 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, + adb->view = view; + adb->taskmgr = taskmgr; + adb->next_cleanbucket = 0; +- ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, +- DNS_EVENT_ADBCONTROL, shutdown_task, adb, +- adb, NULL, NULL); +- adb->cevent_sent = ISC_FALSE; ++ ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), ++ 0, NULL, 0, NULL, NULL, NULL, NULL, NULL); ++ adb->cevent_out = ISC_FALSE; + adb->shutting_down = ISC_FALSE; + ISC_LIST_INIT(adb->whenshutdown); + +@@ -2468,7 +2469,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, + "intializing table sizes to %u\n", + nbuckets[11]); + adb->nentries = nbuckets[11]; +- adb->nnames= nbuckets[11]; ++ adb->nnames = nbuckets[11]; + + } + +@@ -2741,9 +2742,28 @@ dns_adb_whenshutdown(dns_adb_t *adb, isc_task_t *task, isc_event_t **eventp) { + UNLOCK(&adb->lock); + } + ++static void ++shutdown_stage2(isc_task_t *task, isc_event_t *event) { ++ dns_adb_t *adb; ++ ++ UNUSED(task); ++ ++ adb = event->ev_arg; ++ INSIST(DNS_ADB_VALID(adb)); ++ ++ LOCK(&adb->lock); ++ INSIST(adb->shutting_down); ++ adb->cevent_out = ISC_FALSE; ++ (void)shutdown_names(adb); ++ (void)shutdown_entries(adb); ++ if (dec_adb_irefcnt(adb)) ++ check_exit(adb); ++ UNLOCK(&adb->lock); ++} ++ + void + dns_adb_shutdown(dns_adb_t *adb) { +- isc_boolean_t need_check_exit; ++ isc_event_t *event; + + /* + * Shutdown 'adb'. +@@ -2754,11 +2774,16 @@ dns_adb_shutdown(dns_adb_t *adb) { + if (!adb->shutting_down) { + adb->shutting_down = ISC_TRUE; + isc_mem_setwater(adb->mctx, water, adb, 0, 0); +- need_check_exit = shutdown_names(adb); +- if (!need_check_exit) +- need_check_exit = shutdown_entries(adb); +- if (need_check_exit) +- check_exit(adb); ++ /* ++ * Isolate shutdown_names and shutdown_entries calls. ++ */ ++ inc_adb_irefcnt(adb); ++ ISC_EVENT_INIT(&adb->cevent, sizeof(adb->cevent), 0, NULL, ++ DNS_EVENT_ADBCONTROL, shutdown_stage2, adb, ++ adb, NULL, NULL); ++ adb->cevent_out = ISC_TRUE; ++ event = &adb->cevent; ++ isc_task_send(adb->task, &event); + } + + UNLOCK(&adb->lock); +-- +2.9.3 + diff --git a/SOURCES/bind99-rh640538.patch b/SOURCES/bind99-rh640538.patch new file mode 100644 index 0000000..a8e68f2 --- /dev/null +++ b/SOURCES/bind99-rh640538.patch @@ -0,0 +1,44 @@ +diff -up bind-9.9.2/bin/dig/dig.docbook.rh640538 bind-9.9.2/bin/dig/dig.docbook +--- bind-9.9.2/bin/dig/dig.docbook.rh640538 2012-09-27 02:35:19.000000000 +0200 ++++ bind-9.9.2/bin/dig/dig.docbook 2012-11-12 14:47:17.385334972 +0100 +@@ -961,6 +961,40 @@ dig +qr www.isc.org any -x 127.0.0.1 isc + </refsect1> + + <refsect1> ++ <title>RETURN CODES</title> ++ <para> ++ <command>Dig</command> return codes are: ++ <variablelist> ++ <varlistentry> ++ <listitem> ++ <para>0: Everything went well, including things like NXDOMAIN</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <listitem> ++ <para>1: Usage error</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <listitem> ++ <para>8: Couldn't open batch file</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <listitem> ++ <para>9: No reply from server</para> ++ </listitem> ++ </varlistentry> ++ <varlistentry> ++ <listitem> ++ <para>10: Internal error</para> ++ </listitem> ++ </varlistentry> ++ </variablelist> ++ </para> ++ </refsect1> ++ ++ <refsect1> + <title>FILES</title> + <para><filename>/etc/resolv.conf</filename> + </para> diff --git a/SOURCES/bind99-rrl.patch b/SOURCES/bind99-rrl.patch new file mode 100644 index 0000000..3b04e1e --- /dev/null +++ b/SOURCES/bind99-rrl.patch @@ -0,0 +1,12 @@ +diff -up bind-9.9.3rc1/lib/dns/include/dns/Makefile.in.rrl bind-9.9.3rc1/lib/dns/include/dns/Makefile.in +--- bind-9.9.3rc1/lib/dns/include/dns/Makefile.in.rrl 2013-04-16 16:37:00.682186997 +0200 ++++ bind-9.9.3rc1/lib/dns/include/dns/Makefile.in 2013-04-16 16:37:08.387169682 +0200 +@@ -32,7 +32,7 @@ HEADERS = acl.h adb.h byaddr.h cache.h c + rootns.h rpz.h sdb.h sdlz.h secalg.h secproto.h soa.h ssu.h \ + tcpmsg.h time.h tkey.h tsig.h ttl.h types.h \ + validator.h version.h view.h xfrin.h zone.h zonekey.h zt.h \ +- forward.h ++ forward.h rrl.h + + GENHEADERS = enumclass.h enumtype.h rdatastruct.h + diff --git a/SOURCES/bind99-rt43779.patch b/SOURCES/bind99-rt43779.patch new file mode 100644 index 0000000..fa6b6ec --- /dev/null +++ b/SOURCES/bind99-rt43779.patch @@ -0,0 +1,159 @@ +commit 524f5c0d8fa5bd55c98243be889528f48437a2f7 +Author: Mark Andrews <marka@isc.org> +Date: Fri Dec 9 12:50:18 2016 +1100 + + 4530. [bug] Change 4489 broke the handling of CNAME -> DNAME + in responses resulting in SERVFAIL being returned. + [RT #43779] + + (cherry picked from commit 60cb462c56536f307fac4db8bdebf1247e2b5f66) + +diff --git a/bin/tests/system/dname/ns2/example.db b/bin/tests/system/dname/ns2/example.db +index ece3506..4289134 100644 +--- a/bin/tests/system/dname/ns2/example.db ++++ b/bin/tests/system/dname/ns2/example.db +@@ -29,4 +29,6 @@ a.short A 10.0.0.1 + short-dname DNAME short + a.longlonglonglonglonglonglonglonglonglonglonglonglong A 10.0.0.2 + long-dname DNAME longlonglonglonglonglonglonglonglonglonglonglonglong +-; ++cname CNAME a.cnamedname ++cnamedname DNAME target ++a.target A 10.0.0.3 +diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh +index d22f54b..04bfcb2 100644 +--- a/bin/tests/system/dname/tests.sh ++++ b/bin/tests/system/dname/tests.sh +@@ -63,6 +63,24 @@ grep "status: YXDOMAIN" dig.out.ns4.toolong > /dev/null || ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + ++echo "I:checking cname to dname from authoritative" ++ret=0 ++$DIG cname.example @10.53.0.2 a -p 5300 > dig.out.ns2.cname ++grep "status: NOERROR" dig.out.ns2.cname > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ ++echo "I:checking cname to dname from recursive" ++ret=0 ++$DIG cname.example @10.53.0.4 a -p 5300 > dig.out.ns4.cname ++grep "status: NOERROR" dig.out.ns4.cname > /dev/null || ret=1 ++grep '^cname.example.' dig.out.ns4.cname > /dev/null || ret=1 ++grep '^cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 ++grep '^a.cnamedname.example.' dig.out.ns4.cname > /dev/null || ret=1 ++grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ + echo "I:exit status: $status" + + exit $status +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 4bef072..de80928 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -6463,7 +6463,7 @@ static isc_result_t + answer_response(fetchctx_t *fctx) { + isc_result_t result; + dns_message_t *message; +- dns_name_t *name, *dname = NULL, *qname, *dqname, tname, *ns_name; ++ dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; + dns_name_t *cname = NULL; + dns_rdataset_t *rdataset, *ns_rdataset; + isc_boolean_t done, external, chaining, aa, found, want_chaining; +@@ -6471,7 +6471,7 @@ answer_response(fetchctx_t *fctx) { + isc_boolean_t wanted_chaining; + unsigned int aflag; + dns_rdatatype_t type; +- dns_fixedname_t fdname, fqname, fqdname; ++ dns_fixedname_t fdname, fqname; + dns_view_t *view; + + FCTXTRACE("answer_response"); +@@ -6495,13 +6495,12 @@ answer_response(fetchctx_t *fctx) { + aa = ISC_TRUE; + else + aa = ISC_FALSE; +- dqname = qname = &fctx->name; ++ qname = &fctx->name; + type = fctx->type; + view = fctx->res->view; +- dns_fixedname_init(&fqdname); + result = dns_message_firstname(message, DNS_SECTION_ANSWER); + while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln, dnamereln; ++ dns_namereln_t namereln; + int order; + unsigned int nlabels; + +@@ -6509,8 +6508,6 @@ answer_response(fetchctx_t *fctx) { + dns_message_currentname(message, DNS_SECTION_ANSWER, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); + namereln = dns_name_fullcompare(qname, name, &order, &nlabels); +- dnamereln = dns_name_fullcompare(dqname, name, &order, +- &nlabels); + if (namereln == dns_namereln_equal) { + wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); +@@ -6763,11 +6760,24 @@ answer_response(fetchctx_t *fctx) { + return (DNS_R_FORMERR); + } + +- if (dnamereln != dns_namereln_subdomain) { ++ /* ++ * If DNAME + synthetic CNAME then the ++ * namereln is dns_namereln_subdomain. ++ * ++ * If synthetic CNAME + DNAME then the ++ * namereln is dns_namereln_commonancestor ++ * and the number of label must match the ++ * DNAME. This order is not RFC compliant. ++ */ ++ ++ if (namereln != dns_namereln_subdomain && ++ (namereln != dns_namereln_commonancestor || ++ nlabels != dns_name_countlabels(name))) ++ { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; + +- dns_name_format(dqname, qbuf, ++ dns_name_format(qname, qbuf, + sizeof(qbuf)); + dns_name_format(name, obuf, + sizeof(obuf)); +@@ -6782,7 +6792,7 @@ answer_response(fetchctx_t *fctx) { + want_chaining = ISC_TRUE; + POST(want_chaining); + aflag = DNS_RDATASETATTR_ANSWER; +- result = dname_target(rdataset, dqname, ++ result = dname_target(rdataset, qname, + nlabels, &fdname); + if (result == ISC_R_NOSPACE) { + /* +@@ -6799,13 +6809,11 @@ answer_response(fetchctx_t *fctx) { + + dname = dns_fixedname_name(&fdname); + if (!is_answertarget_allowed(view, +- dqname, rdataset->type, ++ qname, rdataset->type, + dname, &fctx->domain)) + { + return (DNS_R_SERVFAIL); + } +- dqname = dns_fixedname_name(&fqdname); +- dns_name_copy(dname, dqname, NULL); + } else { + /* + * We've found a signature that +@@ -6951,7 +6959,8 @@ answer_response(fetchctx_t *fctx) { + rdataset->trust = + dns_trust_additional; + +- if (rdataset->type == dns_rdatatype_ns) { ++ if (rdataset->type == dns_rdatatype_ns) ++ { + ns_name = name; + ns_rdataset = rdataset; + } diff --git a/SOURCES/bind99-rt44318.patch b/SOURCES/bind99-rt44318.patch new file mode 100644 index 0000000..35389fc --- /dev/null +++ b/SOURCES/bind99-rt44318.patch @@ -0,0 +1,482 @@ +From e92ac3b83209ddc46ca9a3facd7edf1f14052edf Mon Sep 17 00:00:00 2001 +From: rpm-build <rpm-build> +Date: Wed, 8 Feb 2017 13:49:47 +0100 +Subject: [PATCH] 4558. [bug] Synthesised CNAME before matching DNAME + was still being cached when it should not have been. [RT + #44318] + +Fixes and tests last case fixed by CVE-2016-9147 +--- + bin/tests/system/dname/ans3/ans.pl | 95 +++++++++++++++++++++++ + bin/tests/system/dname/ns1/root.db | 5 +- + bin/tests/system/dname/tests.sh | 25 ++++++- + lib/dns/resolver.c | 150 +++++++++++++++++++++++++------------ + 4 files changed, 225 insertions(+), 50 deletions(-) + create mode 100644 bin/tests/system/dname/ans3/ans.pl + +diff --git a/bin/tests/system/dname/ans3/ans.pl b/bin/tests/system/dname/ans3/ans.pl +new file mode 100644 +index 0000000..271fc7d +--- /dev/null ++++ b/bin/tests/system/dname/ans3/ans.pl +@@ -0,0 +1,95 @@ ++#!/usr/bin/env perl ++# ++# Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC") ++# ++# This Source Code Form is subject to the terms of the Mozilla Public ++# License, v. 2.0. If a copy of the MPL was not distributed with this ++# file, You can obtain one at http://mozilla.org/MPL/2.0/. ++ ++use strict; ++use warnings; ++ ++use IO::File; ++use Getopt::Long; ++use Net::DNS::Nameserver; ++ ++my $pidf = new IO::File "ans.pid", "w" or die "cannot open pid file: $!"; ++print $pidf "$$\n" or die "cannot write pid file: $!"; ++$pidf->close or die "cannot close pid file: $!"; ++sub rmpid { unlink "ans.pid"; exit 1; }; ++ ++$SIG{INT} = \&rmpid; ++$SIG{TERM} = \&rmpid; ++ ++my $localaddr = "10.53.0.3"; ++my $localport = 5300; ++my $verbose = 0; ++my $ttl = 60; ++my $zone = "example.broken"; ++my $nsname = "ns3.$zone"; ++my $synth = "synth-then-dname.$zone"; ++my $synth2 = "synth2-then-dname.$zone"; ++ ++sub reply_handler { ++ my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_; ++ my ($rcode, @ans, @auth, @add); ++ ++ print ("request: $qname/$qtype\n"); ++ STDOUT->flush(); ++ ++ if ($qname eq "example.broken") { ++ if ($qtype eq "SOA") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass SOA . . 0 0 0 0 0"); ++ push @ans, $rr; ++ } elsif ($qtype eq "NS") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass NS $nsname"); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$nsname $ttl $qclass A $localaddr"); ++ push @add, $rr; ++ } ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "cname-to-$synth2") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name.$synth2"); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("name.$synth2 $ttl $qclass CNAME name"); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "$synth" || $qname eq "$synth2") { ++ if ($qtype eq "DNAME") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ } ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "name.$synth") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name."); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$synth $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ $rcode = "NOERROR"; ++ } elsif ($qname eq "name.$synth2") { ++ my $rr = new Net::DNS::RR("$qname $ttl $qclass CNAME name."); ++ push @ans, $rr; ++ $rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME ."); ++ push @ans, $rr; ++ $rcode = "NOERROR"; ++ } else { ++ $rcode = "REFUSED"; ++ } ++ return ($rcode, \@ans, \@auth, \@add, { aa => 1 }); ++} ++ ++GetOptions( ++ 'port=i' => \$localport, ++ 'verbose!' => \$verbose, ++); ++ ++my $ns = Net::DNS::Nameserver->new( ++ LocalAddr => $localaddr, ++ LocalPort => $localport, ++ ReplyHandler => \&reply_handler, ++ Verbose => $verbose, ++); ++ ++$ns->main_loop; +diff --git a/bin/tests/system/dname/ns1/root.db b/bin/tests/system/dname/ns1/root.db +index 7049e77..2e84ae0 100644 +--- a/bin/tests/system/dname/ns1/root.db ++++ b/bin/tests/system/dname/ns1/root.db +@@ -12,8 +12,6 @@ + ; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + ; PERFORMANCE OF THIS SOFTWARE. + +-; $Id: root.db,v 1.2 2011/03/18 21:14:19 fdupont Exp $ +- + $TTL 300 + . IN SOA gson.nominum.com. a.root.servers.nil. ( + 2000042100 ; serial +@@ -27,3 +25,6 @@ a.root-servers.nil. A 10.53.0.1 + + example. NS ns2.example. + ns2.example. A 10.53.0.2 ++ ++example.broken. NS ns3.example.broken. ++ns3.example.broken. A 10.53.0.3 +diff --git a/bin/tests/system/dname/tests.sh b/bin/tests/system/dname/tests.sh +index 04bfcb2..6dc9e88 100644 +--- a/bin/tests/system/dname/tests.sh ++++ b/bin/tests/system/dname/tests.sh +@@ -20,6 +20,7 @@ SYSTEMTESTTOP=.. + . $SYSTEMTESTTOP/conf.sh + + status=0 ++n=0 + + echo "I:checking short dname from authoritative" + ret=0 +@@ -81,6 +82,26 @@ grep '^a.target.example.' dig.out.ns4.cname > /dev/null || ret=1 + if [ $ret != 0 ]; then echo "I:failed"; fi + status=`expr $status + $ret` + +-echo "I:exit status: $status" ++n=`expr $n + 1` ++echo "I:checking dname is returned with synthesized cname before dname ($n)" ++ret=0 ++$DIG @10.53.0.4 -p 5300 name.synth-then-dname.example.broken A > dig.out.test$n ++grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 ++grep '^name.synth-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 ++grep '^synth-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` + +-exit $status ++n=`expr $n + 1` ++echo "I:checking dname is returned with cname to synthesized cname before dname ($n)" ++ret=0 ++$DIG @10.53.0.4 -p 5300 cname-to-synth2-then-dname.example.broken A > dig.out.test$n ++grep "status: NXDOMAIN" dig.out.test$n > /dev/null || ret=1 ++grep '^cname-to-synth2-then-dname\.example\.broken\..*CNAME.*name\.synth2-then-dname\.example\.broken.$' dig.out.test$n > /dev/null || ret=1 ++grep '^name\.synth2-then-dname\.example\.broken\..*CNAME.*name.$' dig.out.test$n > /dev/null || ret=1 ++grep '^synth2-then-dname\.example\.broken\..*DNAME.*\.$' dig.out.test$n > /dev/null || ret=1 ++if [ $ret != 0 ]; then echo "I:failed"; fi ++status=`expr $status + $ret` ++ ++echo "I:exit status: $status" ++[ $status -eq 0 ] || exit 1 +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index bfd4dcb..c3607fa 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -5406,9 +5406,13 @@ cname_target(dns_rdataset_t *rdataset, dns_name_t *tname) { + return (ISC_R_SUCCESS); + } + ++/*% ++ * Construct the synthesised CNAME from the existing QNAME and ++ * the DNAME RR and store it in 'target'. ++ */ + static inline isc_result_t + dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, +- unsigned int nlabels, dns_fixedname_t *fixeddname) ++ unsigned int nlabels, dns_name_t *target) + { + isc_result_t result; + dns_rdata_t rdata = DNS_RDATA_INIT; +@@ -5428,14 +5432,33 @@ dname_target(dns_rdataset_t *rdataset, dns_name_t *qname, + + dns_fixedname_init(&prefix); + dns_name_split(qname, nlabels, dns_fixedname_name(&prefix), NULL); +- dns_fixedname_init(fixeddname); + result = dns_name_concatenate(dns_fixedname_name(&prefix), +- &dname.dname, +- dns_fixedname_name(fixeddname), NULL); ++ &dname.dname, target, NULL); + dns_rdata_freestruct(&dname); + return (result); + } + ++/*% ++ * Check if it was possible to construct 'qname' from 'lastcname' ++ * and 'rdataset'. ++ */ ++static inline isc_result_t ++fromdname(dns_rdataset_t *rdataset, dns_name_t *lastcname, ++ unsigned int nlabels, const dns_name_t *qname) ++{ ++ dns_fixedname_t fixed; ++ isc_result_t result; ++ dns_name_t *target; ++ ++ dns_fixedname_init(&fixed); ++ target = dns_fixedname_name(&fixed); ++ result = dname_target(rdataset, lastcname, nlabels, target); ++ if (result != ISC_R_SUCCESS || !dns_name_equal(qname, target)) ++ return (ISC_R_NOTFOUND); ++ ++ return (ISC_R_SUCCESS); ++} ++ + static isc_boolean_t + is_answeraddress_allowed(dns_view_t *view, dns_name_t *name, + dns_rdataset_t *rdataset) +@@ -6039,12 +6062,12 @@ answer_response(fetchctx_t *fctx) { + isc_result_t result; + dns_message_t *message; + dns_name_t *name, *dname = NULL, *qname, tname, *ns_name; +- dns_name_t *cname = NULL; ++ dns_name_t *cname = NULL, *lastcname = NULL; + dns_rdataset_t *rdataset, *ns_rdataset; +- isc_boolean_t done, external, chaining, aa, found, want_chaining; ++ isc_boolean_t done, external, aa, found, want_chaining; + isc_boolean_t have_answer, found_cname, found_dname, found_type; + isc_boolean_t wanted_chaining; +- unsigned int aflag; ++ unsigned int aflag, chaining; + dns_rdatatype_t type; + dns_fixedname_t fdname, fqname; + dns_view_t *view; +@@ -6062,9 +6085,9 @@ answer_response(fetchctx_t *fctx) { + found_cname = ISC_FALSE; + found_dname = ISC_FALSE; + found_type = ISC_FALSE; +- chaining = ISC_FALSE; + have_answer = ISC_FALSE; + want_chaining = ISC_FALSE; ++ chaining = 0; + POST(want_chaining); + if ((message->flags & DNS_MESSAGEFLAG_AA) != 0) + aa = ISC_TRUE; +@@ -6075,14 +6098,15 @@ answer_response(fetchctx_t *fctx) { + view = fctx->res->view; + result = dns_message_firstname(message, DNS_SECTION_ANSWER); + while (!done && result == ISC_R_SUCCESS) { +- dns_namereln_t namereln; +- int order; +- unsigned int nlabels; ++ dns_namereln_t namereln, lastreln; ++ int order, lastorder; ++ unsigned int nlabels, lastnlabels; + + name = NULL; + dns_message_currentname(message, DNS_SECTION_ANSWER, &name); + external = ISC_TF(!dns_name_issubdomain(name, &fctx->domain)); + namereln = dns_name_fullcompare(qname, name, &order, &nlabels); ++ + if (namereln == dns_namereln_equal) { + wanted_chaining = ISC_FALSE; + for (rdataset = ISC_LIST_HEAD(name->list); +@@ -6188,6 +6212,7 @@ answer_response(fetchctx_t *fctx) { + &fctx->domain)) { + return (DNS_R_SERVFAIL); + } ++ lastcname = name; + } else if (rdataset->type == dns_rdatatype_rrsig + && rdataset->covers == + dns_rdatatype_cname +@@ -6211,7 +6236,7 @@ answer_response(fetchctx_t *fctx) { + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; + rdataset->trust = dns_trust_answer; +- if (!chaining) { ++ if (chaining == 0) { + /* + * This data is "the" answer + * to our question only if +@@ -6288,10 +6313,21 @@ answer_response(fetchctx_t *fctx) { + * cause us to ignore the signatures of + * CNAMEs. + */ +- if (wanted_chaining) +- chaining = ISC_TRUE; ++ if (wanted_chaining && chaining < 2U) ++ chaining++; + } else { + dns_rdataset_t *dnameset = NULL; ++ isc_boolean_t synthcname = ISC_FALSE; ++ ++ if (lastcname != NULL) { ++ lastreln = dns_name_fullcompare(lastcname, ++ name, ++ &lastorder, ++ &lastnlabels); ++ if (lastreln == dns_namereln_subdomain && ++ lastnlabels == dns_name_countlabels(name)) ++ synthcname = ISC_TRUE; ++ } + + /* + * Look for a DNAME (or its SIG). Anything else is +@@ -6320,7 +6356,7 @@ answer_response(fetchctx_t *fctx) { + * If we're not chaining, then the DNAME and + * its signature should not be external. + */ +- if (!chaining && external) { ++ if (chaining == 0 && external) { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; + +@@ -6338,16 +6374,9 @@ answer_response(fetchctx_t *fctx) { + /* + * If DNAME + synthetic CNAME then the + * namereln is dns_namereln_subdomain. +- * +- * If synthetic CNAME + DNAME then the +- * namereln is dns_namereln_commonancestor +- * and the number of label must match the +- * DNAME. This order is not RFC compliant. + */ +- + if (namereln != dns_namereln_subdomain && +- (namereln != dns_namereln_commonancestor || +- nlabels != dns_name_countlabels(name))) ++ !synthcname) + { + char qbuf[DNS_NAME_FORMATSIZE]; + char obuf[DNS_NAME_FORMATSIZE]; +@@ -6367,8 +6396,19 @@ answer_response(fetchctx_t *fctx) { + want_chaining = ISC_TRUE; + POST(want_chaining); + aflag = DNS_RDATASETATTR_ANSWER; +- result = dname_target(rdataset, qname, +- nlabels, &fdname); ++ dns_fixedname_init(&fdname); ++ dname = dns_fixedname_name(&fdname); ++ if (synthcname) { ++ result = fromdname(rdataset, ++ lastcname, ++ lastnlabels, ++ qname); ++ } else { ++ result = dname_target(rdataset, ++ qname, ++ nlabels, ++ dname); ++ } + if (result == ISC_R_NOSPACE) { + /* + * We can't construct the +@@ -6382,8 +6422,8 @@ answer_response(fetchctx_t *fctx) { + else + dnameset = rdataset; + +- dname = dns_fixedname_name(&fdname); +- if (!is_answertarget_allowed(view, ++ if (!synthcname && ++ !is_answertarget_allowed(view, + qname, rdataset->type, + dname, &fctx->domain)) + { +@@ -6404,7 +6444,13 @@ answer_response(fetchctx_t *fctx) { + name->attributes |= DNS_NAMEATTR_CACHE; + rdataset->attributes |= DNS_RDATASETATTR_CACHE; + rdataset->trust = dns_trust_answer; +- if (!chaining) { ++ /* ++ * If we are not chaining or the first CNAME ++ * is a synthesised CNAME before the DNAME. ++ */ ++ if ((chaining == 0) || ++ (chaining == 1U && synthcname)) ++ { + /* + * This data is "the" answer to + * our question only if we're +@@ -6414,9 +6460,12 @@ answer_response(fetchctx_t *fctx) { + if (aflag == DNS_RDATASETATTR_ANSWER) { + have_answer = ISC_TRUE; + found_dname = ISC_TRUE; +- if (cname != NULL) ++ if (cname != NULL && ++ synthcname) ++ { + cname->attributes &= + ~DNS_NAMEATTR_ANSWER; ++ } + name->attributes |= + DNS_NAMEATTR_ANSWER; + } +@@ -6434,26 +6483,35 @@ answer_response(fetchctx_t *fctx) { + * DNAME chaining. + */ + if (dnameset != NULL) { +- /* +- * Copy the dname into the qname fixed name. +- * +- * Although we check for failure of the copy +- * operation, in practice it should never fail +- * since we already know that the result fits +- * in a fixedname. +- */ +- dns_fixedname_init(&fqname); +- qname = dns_fixedname_name(&fqname); +- result = dns_name_copy(dname, qname, NULL); +- if (result != ISC_R_SUCCESS) +- return (result); ++ if (!synthcname) { ++ /* ++ * Copy the dname into the qname fixed ++ * name. ++ * ++ * Although we check for failure of the ++ * copy operation, in practice it ++ * should never fail since we already ++ * know that the result fits in a ++ * fixedname. ++ */ ++ dns_fixedname_init(&fqname); ++ qname = dns_fixedname_name(&fqname); ++ result = dns_name_copy(dname, qname, ++ NULL); ++ if (result != ISC_R_SUCCESS) ++ return (result); ++ } + wanted_chaining = ISC_TRUE; + name->attributes |= DNS_NAMEATTR_CHAINING; + dnameset->attributes |= + DNS_RDATASETATTR_CHAINING; + } +- if (wanted_chaining) +- chaining = ISC_TRUE; ++ /* ++ * Ensure that we can't ever get chaining == 1 ++ * above if we have processed a DNAME. ++ */ ++ if (wanted_chaining && chaining < 2U) ++ chaining += 2; + } + result = dns_message_nextname(message, DNS_SECTION_ANSWER); + } +@@ -6478,7 +6536,7 @@ answer_response(fetchctx_t *fctx) { + /* + * Did chaining end before we got the final answer? + */ +- if (chaining) { ++ if (chaining != 0) { + /* + * Yes. This may be a negative reply, so hand off + * authority section processing to the noanswer code. +@@ -6527,7 +6585,7 @@ answer_response(fetchctx_t *fctx) { + DNS_NAMEATTR_CACHE; + rdataset->attributes |= + DNS_RDATASETATTR_CACHE; +- if (aa && !chaining) ++ if (aa && chaining == 0) + rdataset->trust = + dns_trust_authauthority; + else +-- +2.9.3 + diff --git a/SOURCES/dnszone.schema b/SOURCES/dnszone.schema new file mode 100644 index 0000000..cb72a3f --- /dev/null +++ b/SOURCES/dnszone.schema @@ -0,0 +1,148 @@ +# A schema for storing DNS zones in LDAP +# +attributetype ( 1.3.6.1.4.1.2428.20.0.0 NAME 'dNSTTL' + DESC 'An integer denoting time to live' + EQUALITY integerMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 ) + +attributetype ( 1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass' + DESC 'The class of a resource record' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.0.2 NAME 'zoneName' + DESC 'The name of a zone, i.e. the name of the highest node in the zone' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.0.3 NAME 'relativeDomainName' + DESC 'The starting labels of a domain name' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord' + DESC 'domain name pointer, RFC 1035' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord' + DESC 'host information, RFC 1035' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord' + DESC 'mailbox or mail list information, RFC 1035' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord' + DESC 'text string, RFC 1035' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord' + DESC 'for AFS Data Base location, RFC 1183' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord' + DESC 'Signature, RFC 2535' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord' + DESC 'Key, RFC 2535' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord' + DESC 'IPv6 address, RFC 1886' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord' + DESC 'Location, RFC 1876' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord' + DESC 'non-existant, RFC 2535' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord' + DESC 'service location, RFC 2782' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord' + DESC 'Naming Authority Pointer, RFC 2915' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord' + DESC 'Key Exchange Delegation, RFC 2230' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord' + DESC 'certificate, RFC 2538' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record' + DESC 'A6 Record Type, RFC 2874' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord' + DESC 'Non-Terminal DNS Name Redirection, RFC 2672' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord' + DESC 'Delegation Signer, RFC 3658' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord' + DESC 'RRSIG, RFC 3755' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +attributetype ( 1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord' + DESC 'NSEC, RFC 3755' + EQUALITY caseIgnoreIA5Match + SUBSTR caseIgnoreIA5SubstringsMatch + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 ) + +objectclass ( 1.3.6.1.4.1.2428.20.3 NAME 'dNSZone' + SUP top STRUCTURAL + MUST ( zoneName $ relativeDomainName ) + MAY ( DNSTTL $ DNSClass $ + ARecord $ MDRecord $ MXRecord $ NSRecord $ + SOARecord $ CNAMERecord $ PTRRecord $ HINFORecord $ + MINFORecord $ TXTRecord $ SIGRecord $ KEYRecord $ + AAAARecord $ LOCRecord $ NXTRecord $ SRVRecord $ + NAPTRRecord $ KXRecord $ CERTRecord $ A6Record $ + DNAMERecord ) ) diff --git a/SOURCES/generate-rndc-key.sh b/SOURCES/generate-rndc-key.sh new file mode 100755 index 0000000..194e65b --- /dev/null +++ b/SOURCES/generate-rndc-key.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +. /etc/rc.d/init.d/functions + +# This script generates /etc/rndc.key if doesn't exist AND if there is no rndc.conf + +if [ ! -s /etc/rndc.key -a ! -s /etc/rndc.conf ]; then + echo -n $"Generating /etc/rndc.key:" + if /usr/sbin/rndc-confgen -a -r /dev/urandom > /dev/null 2>&1; then + chmod 640 /etc/rndc.key + chown root.named /etc/rndc.key + [ -x /sbin/restorecon ] && /sbin/restorecon /etc/rndc.key + success $"/etc/rndc.key generation" + echo + else + failure $"/etc/rndc.key generation" + echo + fi +fi diff --git a/SOURCES/ldap2zone.1 b/SOURCES/ldap2zone.1 new file mode 100644 index 0000000..a48c69f --- /dev/null +++ b/SOURCES/ldap2zone.1 @@ -0,0 +1,41 @@ +.\" Copyright (C) 2004, 2005 Stig Venaas <venaas@uninett.no> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" Manpage written by Jan Gorig +.TH ldap2zone 1 "15 March 2010" "BIND9" +.SH NAME +ldap2zone - Creates zone file from LDAP dnszone information +.SH SYNOPSIS +.B ldap2zone zone-name LDAP-URL default-ttl [serial] +.SH DESCRIPTION +ldap2zone is a tool that reads info for a zone from LDAP and constructs a standard plain ascii zone file that is written to the standard output. The LDAP information has to be stored using the dnszone schema. The schema is used by BIND with LDAP back-end. + +\fBzone-name\fR +.RS 4 +Name of the zone, eg "mydomain.net." +.RE +.PP +\fBLDAP-URL\fR +.RS 4 +LDAP URL to dnszone information +.RE +.PP +\fBdefault-ttl\fR +.RS 4 +Default TTL value to be used in zone +.RE +.PP +\fBserial\fR +.RS 4 +(optional) Program checks this number to be different than SOA serial number. +.RE + +.SH "EXIT STATUS" +Exits with 0 on success or 1 on failure. +.SH "SEE ALSO" +named(8) ldap(3) +http://www.venaas.no/dns/ldap2zone/ +.SH "COPYRIGHT" +Copyright (C) 2004, 2005 Stig Venaas diff --git a/SOURCES/ldap2zone.c b/SOURCES/ldap2zone.c new file mode 100644 index 0000000..80e7919 --- /dev/null +++ b/SOURCES/ldap2zone.c @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2004, 2005 Stig Venaas <venaas@uninett.no> + * $Id: ldap2zone.c,v 1.1 2007/07/24 15:18:00 atkac Exp $ + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + */ + +#define LDAP_DEPRECATED 1 + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#include <ldap.h> + +struct string { + void *data; + size_t len; +}; + +struct assstack_entry { + struct string key; + struct string val; + struct assstack_entry *next; +}; + +struct assstack_entry *assstack_find(struct assstack_entry *stack, struct string *key); +void assstack_push(struct assstack_entry **stack, struct assstack_entry *item); +void assstack_insertbottom(struct assstack_entry **stack, struct assstack_entry *item); +void printsoa(struct string *soa); +void printrrs(char *defaultttl, struct assstack_entry *item); +void print_zone(char *defaultttl, struct assstack_entry *stack); +void usage(char *name); +void err(char *name, const char *msg); +int putrr(struct assstack_entry **stack, struct berval *name, char *type, char *ttl, struct berval *val); + +struct assstack_entry *assstack_find(struct assstack_entry *stack, struct string *key) { + for (; stack; stack = stack->next) + if (stack->key.len == key->len && !memcmp(stack->key.data, key->data, key->len)) + return stack; + return NULL; +} + +void assstack_push(struct assstack_entry **stack, struct assstack_entry *item) { + item->next = *stack; + *stack = item; +} + +void assstack_insertbottom(struct assstack_entry **stack, struct assstack_entry *item) { + struct assstack_entry *p; + + item->next = NULL; + if (!*stack) { + *stack = item; + return; + } + /* find end, should keep track of end somewhere */ + /* really a queue, not a stack */ + p = *stack; + while (p->next) + p = p->next; + p->next = item; +} + +void printsoa(struct string *soa) { + char *s; + size_t i; + + s = (char *)soa->data; + i = 0; + while (i < soa->len) { + putchar(s[i]); + if (s[i++] == ' ') + break; + } + while (i < soa->len) { + putchar(s[i]); + if (s[i++] == ' ') + break; + } + printf("(\n\t\t\t\t"); + while (i < soa->len) { + putchar(s[i]); + if (s[i++] == ' ') + break; + } + printf("; Serialnumber\n\t\t\t\t"); + while (i < soa->len) { + if (s[i] == ' ') + break; + putchar(s[i++]); + } + i++; + printf("\t; Refresh\n\t\t\t\t"); + while (i < soa->len) { + if (s[i] == ' ') + break; + putchar(s[i++]); + } + i++; + printf("\t; Retry\n\t\t\t\t"); + while (i < soa->len) { + if (s[i] == ' ') + break; + putchar(s[i++]); + } + i++; + printf("\t; Expire\n\t\t\t\t"); + while (i < soa->len) { + putchar(s[i++]); + } + printf(" )\t; Minimum TTL\n"); +} + +void printrrs(char *defaultttl, struct assstack_entry *item) { + struct assstack_entry *stack; + char *s; + int first; + size_t i; + char *ttl, *type; + int top; + + s = (char *)item->key.data; + + if (item->key.len == 1 && *s == '@') { + top = 1; + printf("@\t"); + } else { + top = 0; + for (i = 0; i < item->key.len; i++) + putchar(s[i]); + if (item->key.len < 8) + putchar('\t'); + putchar('\t'); + } + + first = 1; + for (stack = (struct assstack_entry *) item->val.data; stack; stack = stack->next) { + ttl = (char *)stack->key.data; + s = strchr(ttl, ' '); + *s++ = '\0'; + type = s; + + if (first) + first = 0; + else + printf("\t\t"); + + if (strcmp(defaultttl, ttl)) + printf("%s", ttl); + putchar('\t'); + + if (top) { + top = 0; + printf("IN\t%s\t", type); + /* Should always be SOA here */ + if (!strcmp(type, "SOA")) { + printsoa(&stack->val); + continue; + } + } else + printf("%s\t", type); + + s = (char *)stack->val.data; + for (i = 0; i < stack->val.len; i++) + putchar(s[i]); + putchar('\n'); + } +} + +void print_zone(char *defaultttl, struct assstack_entry *stack) { + printf("$TTL %s\n", defaultttl); + for (; stack; stack = stack->next) + printrrs(defaultttl, stack); +}; + +void usage(char *name) { + fprintf(stderr, "Usage:%s zone-name LDAP-URL default-ttl [serial]\n", name); + exit(1); +}; + +void err(char *name, const char *msg) { + fprintf(stderr, "%s: %s\n", name, msg); + exit(1); +}; + +int putrr(struct assstack_entry **stack, struct berval *name, char *type, char *ttl, struct berval *val) { + struct string key; + struct assstack_entry *rr, *rrdata; + + /* Do nothing if name or value have 0 length */ + if (!name->bv_len || !val->bv_len) + return 0; + + /* see if already have an entry for this name */ + key.len = name->bv_len; + key.data = name->bv_val; + + rr = assstack_find(*stack, &key); + if (!rr) { + /* Not found, create and push new entry */ + rr = (struct assstack_entry *) malloc(sizeof(struct assstack_entry)); + if (!rr) + return -1; + rr->key.len = name->bv_len; + rr->key.data = (void *) malloc(rr->key.len); + if (!rr->key.data) { + free(rr); + return -1; + } + memcpy(rr->key.data, name->bv_val, name->bv_len); + rr->val.len = sizeof(void *); + rr->val.data = NULL; + if (name->bv_len == 1 && *(char *)name->bv_val == '@') + assstack_push(stack, rr); + else + assstack_insertbottom(stack, rr); + } + + rrdata = (struct assstack_entry *) malloc(sizeof(struct assstack_entry)); + if (!rrdata) { + free(rr->key.data); + free(rr); + return -1; + } + rrdata->key.len = strlen(type) + strlen(ttl) + 1; + rrdata->key.data = (void *) malloc(rrdata->key.len); + if (!rrdata->key.data) { + free(rrdata); + free(rr->key.data); + free(rr); + return -1; + } + sprintf((char *)rrdata->key.data, "%s %s", ttl, type); + + rrdata->val.len = val->bv_len; + rrdata->val.data = (void *) malloc(val->bv_len); + if (!rrdata->val.data) { + free(rrdata->key.data); + free(rrdata); + free(rr->key.data); + free(rr); + return -1; + } + memcpy(rrdata->val.data, val->bv_val, val->bv_len); + + if (!strcmp(type, "SOA")) + assstack_push((struct assstack_entry **) &(rr->val.data), rrdata); + else + assstack_insertbottom((struct assstack_entry **) &(rr->val.data), rrdata); + return 0; +} + +int main(int argc, char **argv) { + char *s, *hostporturl, *base = NULL; + char *ttl, *defaultttl; + LDAP *ld; + char *fltr = NULL; + LDAPMessage *res, *e; + char *a, **ttlvals, **soavals, *serial; + struct berval **vals, **names; + char type[64]; + BerElement *ptr; + int i, j, rc, msgid; + struct assstack_entry *zone = NULL; + + if (argc < 4 || argc > 5) + usage(argv[0]); + + hostporturl = argv[2]; + + if (hostporturl != strstr( hostporturl, "ldap")) + err(argv[0], "Not an LDAP URL"); + + s = strchr(hostporturl, ':'); + + if (!s || strlen(s) < 3 || s[1] != '/' || s[2] != '/') + err(argv[0], "Not an LDAP URL"); + + s = strchr(s+3, '/'); + if (s) { + *s++ = '\0'; + base = s; + s = strchr(base, '?'); + if (s) + err(argv[0], "LDAP URL can only contain host, port and base"); + } + + defaultttl = argv[3]; + + rc = ldap_initialize(&ld, hostporturl); + if (rc != LDAP_SUCCESS) + err(argv[0], "ldap_initialize() failed"); + + if (argc == 5) { + /* serial number specified, check if different from one in SOA */ + fltr = (char *)malloc(strlen(argv[1]) + strlen("(&(relativeDomainName=@)(zoneName=))") + 1); + sprintf(fltr, "(&(relativeDomainName=@)(zoneName=%s))", argv[1]); + msgid = ldap_search(ld, base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0); + if (msgid == -1) + err(argv[0], "ldap_search() failed"); + + while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) { + /* not supporting continuation references at present */ + if (rc != LDAP_RES_SEARCH_ENTRY) + err(argv[0], "ldap_result() returned cont.ref? Exiting"); + + /* only one entry per result message */ + e = ldap_first_entry(ld, res); + if (e == NULL) { + ldap_msgfree(res); + err(argv[0], "ldap_first_entry() failed"); + } + + soavals = ldap_get_values(ld, e, "SOARecord"); + if (soavals) + break; + } + + ldap_msgfree(res); + if (!soavals) { + err(argv[0], "No SOA Record found"); + } + + /* We have a SOA, compare serial numbers */ + /* Only checkinf first value, should be only one */ + s = strchr(soavals[0], ' '); + s++; + s = strchr(s, ' '); + s++; + serial = s; + s = strchr(s, ' '); + *s = '\0'; + if (!strcmp(serial, argv[4])) { + ldap_value_free(soavals); + err(argv[0], "serial numbers match"); + } + ldap_value_free(soavals); + } + + if (!fltr) + fltr = (char *)malloc(strlen(argv[1]) + strlen("(zoneName=)") + 1); + if (!fltr) + err(argv[0], "Malloc failed"); + sprintf(fltr, "(zoneName=%s)", argv[1]); + + msgid = ldap_search(ld, base, LDAP_SCOPE_SUBTREE, fltr, NULL, 0); + if (msgid == -1) + err(argv[0], "ldap_search() failed"); + + while ((rc = ldap_result(ld, msgid, 0, NULL, &res)) != LDAP_RES_SEARCH_RESULT ) { + /* not supporting continuation references at present */ + if (rc != LDAP_RES_SEARCH_ENTRY) + err(argv[0], "ldap_result() returned cont.ref? Exiting"); + + /* only one entry per result message */ + e = ldap_first_entry(ld, res); + if (e == NULL) { + ldap_msgfree(res); + err(argv[0], "ldap_first_entry() failed"); + } + + names = ldap_get_values_len(ld, e, "relativeDomainName"); + if (!names) + continue; + + ttlvals = ldap_get_values(ld, e, "dNSTTL"); + ttl = ttlvals ? ttlvals[0] : defaultttl; + + for (a = ldap_first_attribute(ld, e, &ptr); a != NULL; a = ldap_next_attribute(ld, e, ptr)) { + char *s; + + for (s = a; *s; s++) + *s = toupper(*s); + s = strstr(a, "RECORD"); + if ((s == NULL) || (s == a) || (s - a >= (signed int)sizeof(type))) { + ldap_memfree(a); + continue; + } + + strncpy(type, a, s - a); + type[s - a] = '\0'; + vals = ldap_get_values_len(ld, e, a); + if (vals) { + for (i = 0; vals[i]; i++) + for (j = 0; names[j]; j++) + if (putrr(&zone, names[j], type, ttl, vals[i])) + err(argv[0], "malloc failed"); + ldap_value_free_len(vals); + } + ldap_memfree(a); + } + + if (ptr) + ber_free(ptr, 0); + if (ttlvals) + ldap_value_free(ttlvals); + ldap_value_free_len(names); + /* free this result */ + ldap_msgfree(res); + } + + /* free final result */ + ldap_msgfree(res); + + print_zone(defaultttl, zone); + return 0; +} diff --git a/SOURCES/named-chroot-setup.service b/SOURCES/named-chroot-setup.service new file mode 100644 index 0000000..9870a88 --- /dev/null +++ b/SOURCES/named-chroot-setup.service @@ -0,0 +1,12 @@ +[Unit] +Description=Set-up/destroy chroot environment for named (DNS) +BindsTo=named-chroot.service +Wants=named-setup-rndc.service +After=named-setup-rndc.service + + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/setup-named-chroot.sh /var/named/chroot on +ExecStop=/usr/libexec/setup-named-chroot.sh /var/named/chroot off diff --git a/SOURCES/named-chroot.service b/SOURCES/named-chroot.service new file mode 100644 index 0000000..4459336 --- /dev/null +++ b/SOURCES/named-chroot.service @@ -0,0 +1,30 @@ +# Don't forget to add "$AddUnixListenSocket /var/named/chroot/dev/log" +# line to your /etc/rsyslog.conf file. Otherwise your logging becomes +# broken when rsyslogd daemon is restarted (due update, for example). + +[Unit] +Description=Berkeley Internet Name Domain (DNS) +Wants=nss-lookup.target +Requires=named-chroot-setup.service +Before=nss-lookup.target +After=network.target +After=named-chroot-setup.service + +[Service] +Type=forking +Environment=NAMEDCONF=/etc/named.conf +EnvironmentFile=-/etc/sysconfig/named +Environment=KRB5_KTNAME=/etc/named.keytab +PIDFile=/var/named/chroot/run/named/named.pid + +ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -t /var/named/chroot -z "$NAMEDCONF"; else echo "Checking of zone files is disabled"; fi' +ExecStart=/usr/sbin/named -u named -c ${NAMEDCONF} -t /var/named/chroot $OPTIONS + +ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID' + +ExecStop=/bin/sh -c '/usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID' + +PrivateTmp=false + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/named-pkcs11.service b/SOURCES/named-pkcs11.service new file mode 100644 index 0000000..c1a19d1 --- /dev/null +++ b/SOURCES/named-pkcs11.service @@ -0,0 +1,26 @@ +[Unit] +Description=Berkeley Internet Name Domain (DNS) with native PKCS#11 +Wants=nss-lookup.target +Wants=named-setup-rndc.service +Before=nss-lookup.target +After=network.target +After=named-setup-rndc.service + +[Service] +Type=forking +Environment=NAMEDCONF=/etc/named.conf +EnvironmentFile=-/etc/sysconfig/named +Environment=KRB5_KTNAME=/etc/named.keytab +PIDFile=/run/named/named.pid + +ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z "$NAMEDCONF"; else echo "Checking of zone files is disabled"; fi' +ExecStart=/usr/sbin/named-pkcs11 -u named -c ${NAMEDCONF} $OPTIONS + +ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID' + +ExecStop=/bin/sh -c '/usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID' + +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/named-sdb-chroot-setup.service b/SOURCES/named-sdb-chroot-setup.service new file mode 100644 index 0000000..0967a60 --- /dev/null +++ b/SOURCES/named-sdb-chroot-setup.service @@ -0,0 +1,12 @@ +[Unit] +Description=Set-up/destroy chroot environment for named-sdb +BindsTo=named-sdb-chroot.service +Wants=named-setup-rndc.service +After=named-setup-rndc.service + + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/libexec/setup-named-chroot.sh /var/named/chroot_sdb on +ExecStop=/usr/libexec/setup-named-chroot.sh /var/named/chroot_sdb off diff --git a/SOURCES/named-sdb-chroot.service b/SOURCES/named-sdb-chroot.service new file mode 100644 index 0000000..1fe742d --- /dev/null +++ b/SOURCES/named-sdb-chroot.service @@ -0,0 +1,30 @@ +# Don't forget to add "$AddUnixListenSocket /var/named/chroot_sdb/dev/log" +# line to your /etc/rsyslog.conf file. Otherwise your logging becomes +# broken when rsyslogd daemon is restarted (due update, for example). + +[Unit] +Description=Berkeley Internet Name Domain (DNS) +Wants=nss-lookup.target +Requires=named-sdb-chroot-setup.service +Before=nss-lookup.target +After=network.target +After=named-sdb-chroot-setup.service + +[Service] +Type=forking +Environment=NAMEDCONF=/etc/named.conf +EnvironmentFile=-/etc/sysconfig/named +Environment=KRB5_KTNAME=/etc/named.keytab +PIDFile=/var/named/chroot_sdb/run/named/named.pid + +ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -t /var/named/chroot_sdb -z "$NAMEDCONF"; else echo "Checking of zone files is disabled"; fi' +ExecStart=/usr/sbin/named-sdb -u named -c ${NAMEDCONF} -t /var/named/chroot_sdb $OPTIONS + +ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID' + +ExecStop=/bin/sh -c '/usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID' + +PrivateTmp=false + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/named-sdb.8 b/SOURCES/named-sdb.8 new file mode 100644 index 0000000..1e456c3 --- /dev/null +++ b/SOURCES/named-sdb.8 @@ -0,0 +1 @@ +.so man8/named.8.gz \ No newline at end of file diff --git a/SOURCES/named-sdb.service b/SOURCES/named-sdb.service new file mode 100644 index 0000000..67867ea --- /dev/null +++ b/SOURCES/named-sdb.service @@ -0,0 +1,26 @@ +[Unit] +Description=Berkeley Internet Name Domain (DNS) +Wants=nss-lookup.target +Wants=named-setup-rndc.service +Before=nss-lookup.target +After=network.target +After=named-setup-rndc.service + +[Service] +Type=forking +Environment=NAMEDCONF=/etc/named.conf +EnvironmentFile=-/etc/sysconfig/named +Environment=KRB5_KTNAME=/etc/named.keytab +PIDFile=/run/named/named.pid + +ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z "$NAMEDCONF"; else echo "Checking of zone files is disabled"; fi' +ExecStart=/usr/sbin/named-sdb -u named -c ${NAMEDCONF} $OPTIONS + +ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID' + +ExecStop=/bin/sh -c '/usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID' + +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/named-setup-rndc.service b/SOURCES/named-setup-rndc.service new file mode 100644 index 0000000..ff85e3c --- /dev/null +++ b/SOURCES/named-setup-rndc.service @@ -0,0 +1,7 @@ +[Unit] +Description=Generate rndc key for BIND (DNS) + +[Service] +Type=oneshot + +ExecStart=/usr/libexec/generate-rndc-key.sh diff --git a/SOURCES/named.conf.sample b/SOURCES/named.conf.sample new file mode 100644 index 0000000..f091345 --- /dev/null +++ b/SOURCES/named.conf.sample @@ -0,0 +1,244 @@ +/* + Sample named.conf BIND DNS server 'named' configuration file + for the Red Hat BIND distribution. + + See the BIND Administrator's Reference Manual (ARM) for details about the + configuration located in /usr/share/doc/bind-{version}/Bv9ARM.html +*/ + +options +{ + // Put files that named is allowed to write in the data/ directory: + directory "/var/named"; // "Working" directory + dump-file "data/cache_dump.db"; + statistics-file "data/named_stats.txt"; + memstatistics-file "data/named_mem_stats.txt"; + + + /* + Specify listenning interfaces. You can use list of addresses (';' is + delimiter) or keywords "any"/"none" + */ + //listen-on port 53 { any; }; + listen-on port 53 { 127.0.0.1; }; + + //listen-on-v6 port 53 { any; }; + listen-on-v6 port 53 { ::1; }; + + /* + Access restrictions + + There are two important options: + allow-query { argument; }; + - allow queries for authoritative data + + allow-query-cache { argument; }; + - allow queries for non-authoritative data (mostly cached data) + + You can use address, network address or keywords "any"/"localhost"/"none" as argument + Examples: + allow-query { localhost; 10.0.0.1; 192.168.1.0/8; }; + allow-query-cache { ::1; fe80::5c63:a8ff:fe2f:4526; 10.0.0.1; }; + */ + + allow-query { localhost; }; + allow-query-cache { localhost; }; + + /* Enable/disable recursion - recursion yes/no; + + - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion. + - If you are building a RECURSIVE (caching) DNS server, you need to enable + recursion. + - If your recursive DNS server has a public IP address, you MUST enable access + control to limit queries to your legitimate users. Failing to do so will + cause your server to become part of large scale DNS amplification + attacks. Implementing BCP38 within your network would greatly + reduce such attack surface + */ + recursion yes; + + /* DNSSEC related options. See information about keys ("Trusted keys", bellow) */ + + /* Enable serving of DNSSEC related data - enable on both authoritative + and recursive servers DNSSEC aware servers */ + dnssec-enable yes; + + /* Enable DNSSEC validation on recursive servers */ + dnssec-validation yes; + + /* In RHEL-7 we use /run/named instead of default /var/run/named + so we have to configure paths properly. */ + pid-file "/run/named/named.pid"; + session-keyfile "/run/named/session.key"; + + managed-keys-directory "/var/named/dynamic"; +}; + +logging +{ +/* If you want to enable debugging, eg. using the 'rndc trace' command, + * named will try to write the 'named.run' file in the $directory (/var/named). + * By default, SELinux policy does not allow named to modify the /var/named directory, + * so put the default debug log file in data/ : + */ + channel default_debug { + file "data/named.run"; + severity dynamic; + }; +}; + +/* + Views let a name server answer a DNS query differently depending on who is asking. + + By default, if named.conf contains no "view" clauses, all zones are in the + "default" view, which matches all clients. + + Views are processed sequentially. The first match is used so the last view should + match "any" - it's fallback and the most restricted view. + + If named.conf contains any "view" clause, then all zones MUST be in a view. +*/ + +view "localhost_resolver" +{ +/* This view sets up named to be a localhost resolver ( caching only nameserver ). + * If all you want is a caching-only nameserver, then you need only define this view: + */ + match-clients { localhost; }; + recursion yes; + + # all views must contain the root hints zone: + zone "." IN { + type hint; + file "/var/named/named.ca"; + }; + + /* these are zones that contain definitions for all the localhost + * names and addresses, as recommended in RFC1912 - these names should + * not leak to the other nameservers: + */ + include "/etc/named.rfc1912.zones"; +}; +view "internal" +{ +/* This view will contain zones you want to serve only to "internal" clients + that connect via your directly attached LAN interfaces - "localnets" . + */ + match-clients { localnets; }; + recursion yes; + + zone "." IN { + type hint; + file "/var/named/named.ca"; + }; + + /* these are zones that contain definitions for all the localhost + * names and addresses, as recommended in RFC1912 - these names should + * not leak to the other nameservers: + */ + include "/etc/named.rfc1912.zones"; + + // These are your "authoritative" internal zones, and would probably + // also be included in the "localhost_resolver" view above : + + /* + NOTE for dynamic DNS zones and secondary zones: + + DO NOT USE SAME FILES IN MULTIPLE VIEWS! + + If you are using views and DDNS/secondary zones it is strongly + recommended to read FAQ on ISC site (www.isc.org), section + "Configuration and Setup Questions", questions + "How do I share a dynamic zone between multiple views?" and + "How can I make a server a slave for both an internal and an external + view at the same time?" + */ + + zone "my.internal.zone" { + type master; + file "my.internal.zone.db"; + }; + zone "my.slave.internal.zone" { + type slave; + file "slaves/my.slave.internal.zone.db"; + masters { /* put master nameserver IPs here */ 127.0.0.1; } ; + // put slave zones in the slaves/ directory so named can update them + }; + zone "my.ddns.internal.zone" { + type master; + allow-update { key ddns_key; }; + file "dynamic/my.ddns.internal.zone.db"; + // put dynamically updateable zones in the slaves/ directory so named can update them + }; +}; + +key ddns_key +{ + algorithm hmac-md5; + secret "use /usr/sbin/dnssec-keygen to generate TSIG keys"; +}; + +view "external" +{ +/* This view will contain zones you want to serve only to "external" clients + * that have addresses that are not match any above view: + */ + match-clients { any; }; + + zone "." IN { + type hint; + file "/var/named/named.ca"; + }; + + recursion no; + // you'd probably want to deny recursion to external clients, so you don't + // end up providing free DNS service to all takers + + // These are your "authoritative" external zones, and would probably + // contain entries for just your web and mail servers: + + zone "my.external.zone" { + type master; + file "my.external.zone.db"; + }; +}; + +/* Trusted keys + + This statement contains DNSSEC keys. If you want DNSSEC aware resolver you + have to configure at least one trusted key. + + Note that no key written below is valid. Especially root key because root zone + is not signed yet. +*/ +/* +trusted-keys { +// Root Key +"." 257 3 3 "BNY4wrWM1nCfJ+CXd0rVXyYmobt7sEEfK3clRbGaTwSJxrGkxJWoZu6I7PzJu/ + E9gx4UC1zGAHlXKdE4zYIpRhaBKnvcC2U9mZhkdUpd1Vso/HAdjNe8LmMlnzY3 + zy2Xy4klWOADTPzSv9eamj8V18PHGjBLaVtYvk/ln5ZApjYghf+6fElrmLkdaz + MQ2OCnACR817DF4BBa7UR/beDHyp5iWTXWSi6XmoJLbG9Scqc7l70KDqlvXR3M + /lUUVRbkeg1IPJSidmK3ZyCllh4XSKbje/45SKucHgnwU5jefMtq66gKodQj+M + iA21AfUVe7u99WzTLzY3qlxDhxYQQ20FQ97S+LKUTpQcq27R7AT3/V5hRQxScI + Nqwcz4jYqZD2fQdgxbcDTClU0CRBdiieyLMNzXG3"; + +// Key for forward zone +example.com. 257 3 5 "AwEAAaxPMcR2x0HbQV4WeZB6oEDX+r0QM65KbhTjrW1ZaARmPhEZZe + 3Y9ifgEuq7vZ/zGZUdEGNWy+JZzus0lUptwgjGwhUS1558Hb4JKUbb + OTcM8pwXlj0EiX3oDFVmjHO444gLkBO UKUf/mC7HvfwYH/Be22GnC + lrinKJp1Og4ywzO9WglMk7jbfW33gUKvirTHr25GL7STQUzBb5Usxt + 8lgnyTUHs1t3JwCY5hKZ6CqFxmAVZP20igTixin/1LcrgX/KMEGd/b + iuvF4qJCyduieHukuY3H4XMAcR+xia2 nIUPvm/oyWR8BW/hWdzOvn + SCThlHf3xiYleDbt/o1OTQ09A0="; + +// Key for reverse zone. +2.0.192.IN-ADDRPA.NET. 257 3 5 "AQOnS4xn/IgOUpBPJ3bogzwcxOdNax071L18QqZnQQQA + VVr+iLhGTnNGp3HoWQLUIzKrJVZ3zggy3WwNT6kZo6c0 + tszYqbtvchmgQC8CzKojM/W16i6MG/ea fGU3siaOdS0 + yOI6BgPsw+YZdzlYMaIJGf4M4dyoKIhzdZyQ2bYQrjyQ + 4LB0lC7aOnsMyYKHHYeRv PxjIQXmdqgOJGq+vsevG06 + zW+1xgYJh9rCIfnm1GX/KMgxLPG2vXTD/RnLX+D3T3UL + 7HJYHJhAZD5L59VvjSPsZJHeDCUyWYrvPZesZDIRvhDD + 52SKvbheeTJUm6EhkzytNN2SN96QRk8j/iI8ib"; +}; +*/ diff --git a/SOURCES/named.logrotate b/SOURCES/named.logrotate new file mode 100644 index 0000000..5df448f --- /dev/null +++ b/SOURCES/named.logrotate @@ -0,0 +1,12 @@ +/var/named/data/named.run { + missingok + su named named + create 0644 named named + postrotate + /usr/bin/systemctl reload named.service > /dev/null 2>&1 || true + /usr/bin/systemctl reload named-chroot.service > /dev/null 2>&1 || true + /usr/bin/systemctl reload named-sdb.service > /dev/null 2>&1 || true + /usr/bin/systemctl reload named-sdb-chroot.service > /dev/null 2>&1 || true + /usr/bin/systemctl reload named-pkcs11.service > /dev/null 2>&1 || true + endscript +} diff --git a/SOURCES/named.rwtab b/SOURCES/named.rwtab new file mode 100644 index 0000000..2cb3a41 --- /dev/null +++ b/SOURCES/named.rwtab @@ -0,0 +1,6 @@ +dirs /var/named + +files /var/named/named.ca +files /var/named/named.empty +files /var/named/named.localhost +files /var/named/named.loopback diff --git a/SOURCES/named.service b/SOURCES/named.service new file mode 100644 index 0000000..90a6a32 --- /dev/null +++ b/SOURCES/named.service @@ -0,0 +1,26 @@ +[Unit] +Description=Berkeley Internet Name Domain (DNS) +Wants=nss-lookup.target +Wants=named-setup-rndc.service +Before=nss-lookup.target +After=network.target +After=named-setup-rndc.service + +[Service] +Type=forking +Environment=NAMEDCONF=/etc/named.conf +EnvironmentFile=-/etc/sysconfig/named +Environment=KRB5_KTNAME=/etc/named.keytab +PIDFile=/run/named/named.pid + +ExecStartPre=/bin/bash -c 'if [ ! "$DISABLE_ZONE_CHECKING" == "yes" ]; then /usr/sbin/named-checkconf -z "$NAMEDCONF"; else echo "Checking of zone files is disabled"; fi' +ExecStart=/usr/sbin/named -u named -c ${NAMEDCONF} $OPTIONS + +ExecReload=/bin/sh -c '/usr/sbin/rndc reload > /dev/null 2>&1 || /bin/kill -HUP $MAINPID' + +ExecStop=/bin/sh -c '/usr/sbin/rndc stop > /dev/null 2>&1 || /bin/kill -TERM $MAINPID' + +PrivateTmp=true + +[Install] +WantedBy=multi-user.target diff --git a/SOURCES/named.sysconfig b/SOURCES/named.sysconfig new file mode 100644 index 0000000..3394d23 --- /dev/null +++ b/SOURCES/named.sysconfig @@ -0,0 +1,16 @@ +# BIND named process options +# ~~~~~~~~~~~~~~~~~~~~~~~~~~ +# +# OPTIONS="whatever" -- These additional options will be passed to named +# at startup. Don't add -t here, enable proper +# -chroot.service unit file. +# Use of parameter -c is not supported here. Extend +# systemd named*.service instead. For more +# information please read the following KB article: +# https://access.redhat.com/articles/2986001 +# +# DISABLE_ZONE_CHECKING -- By default, service file calls named-checkzone +# utility for every zone to ensure all zones are +# valid before named starts. If you set this option +# to 'yes' then service file doesn't perform those +# checks. diff --git a/SOURCES/nslookup-norec.patch b/SOURCES/nslookup-norec.patch new file mode 100644 index 0000000..77350ad --- /dev/null +++ b/SOURCES/nslookup-norec.patch @@ -0,0 +1,28 @@ +--- dighost.c.orig 2011-03-11 07:46:58.000000000 +0100 ++++ dighost.c 2011-10-28 14:31:29.806591603 +0200 +@@ -2619,8 +2619,13 @@ connect_timeout(isc_task_t *task, isc_ev + } + } else { + fputs(l->cmdline, stdout); +- printf(";; connection timed out; no servers could be " +- "reached\n"); ++ if (!next_origin(ISC_LIST_HEAD(l->q))) { ++ printf(";; connection timed out; no servers could be " ++ "reached\n"); ++ } else { ++ printf(";; connection timed out; trying next " ++ "origin\n"); ++ } + cancel_lookup(l); + check_next_lookup(l); + if (exitcode < 9) +@@ -3270,7 +3275,8 @@ recv_done(isc_task_t *task, isc_event_t + return; + } + if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) || +- (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse)) ++ (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && ++ msg->rcode != dns_rcode_noerror && l->recurse)) + { + dig_query_t *next = ISC_LIST_NEXT(query, link); + if (l->current_query == query) diff --git a/SOURCES/setup-named-chroot.sh b/SOURCES/setup-named-chroot.sh new file mode 100755 index 0000000..2326c49 --- /dev/null +++ b/SOURCES/setup-named-chroot.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Warning: the order is important +# If a directory containing $ROOTDIR is listed here, +# it MUST be listed last. (/var/named contains /var/named/chroot) +ROOTDIR_MOUNT='/etc/localtime /etc/named /etc/pki/dnssec-keys /etc/named.root.key /etc/named.conf +/etc/named.dnssec.keys /etc/named.rfc1912.zones /etc/rndc.conf /etc/rndc.key /etc/named.iscdlv.key /etc/protocols /etc/services +/usr/lib64/bind /usr/lib/bind /run/named +/var/named' + +usage() +{ + echo + echo 'This script setups chroot environment for BIND' + echo 'Usage: setup-named-chroot.sh ROOTDIR [on|off]' +} + +if ! [ "$#" -eq 2 ]; then + echo 'Wrong number of arguments' + usage + exit 1 +fi + +ROOTDIR="$1" + +# Exit if ROOTDIR doesn't exist +if ! [ -d "$ROOTDIR" ]; then + echo "Root directory $ROOTDIR doesn't exist" + usage + exit 1 +fi + +mount_chroot_conf() +{ + if [ -n "$ROOTDIR" ]; then + for all in $ROOTDIR_MOUNT; do + # Skip nonexistant files + [ -e "$all" ] || continue + + # If mount source is a file + if ! [ -d "$all" ]; then + # mount it only if it is not present in chroot or it is empty + if ! [ -e "$ROOTDIR$all" ] || [ `stat -c'%s' "$ROOTDIR$all"` -eq 0 ]; then + touch "$ROOTDIR$all" + mount --bind "$all" "$ROOTDIR$all" + fi + else + # Mount source is a directory. Mount it only if directory in chroot is + # empty. + if [ -e "$all" ] && [ `ls -1A $ROOTDIR$all | wc -l` -eq 0 ]; then + mount --bind --make-private "$all" "$ROOTDIR$all" + fi + fi + done + fi +} + +umount_chroot_conf() +{ + if [ -n "$ROOTDIR" ]; then + for all in $ROOTDIR_MOUNT; do + # Check if file is mount target. Do not use /proc/mounts because detecting + # of modified mounted files can fail. + if mount | grep -q '.* on '"$ROOTDIR$all"' .*'; then + umount "$ROOTDIR$all" + # Remove temporary created files + [ -f "$all" ] && rm -f "$ROOTDIR$all" + fi + done + fi +} + +case "$2" in + on) + mount_chroot_conf + ;; + off) + umount_chroot_conf + ;; + *) + echo 'Second argument has to be "on" or "off"' + usage + exit 1 +esac + +exit 0 diff --git a/SOURCES/trusted-key.key b/SOURCES/trusted-key.key new file mode 100644 index 0000000..df2fd0d --- /dev/null +++ b/SOURCES/trusted-key.key @@ -0,0 +1,2 @@ +. 3600 IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0= +. 3600 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU= diff --git a/SOURCES/zone2sqlite.1 b/SOURCES/zone2sqlite.1 new file mode 100644 index 0000000..6897827 --- /dev/null +++ b/SOURCES/zone2sqlite.1 @@ -0,0 +1,53 @@ +.\" Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 Internet Software Consortium. +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +.\" PERFORMANCE OF THIS SOFTWARE. +.\" +.\" Manpage written by Jan Gorig +.TH zone2sqlite 1 "15 March 2010" "BIND9" +.SH NAME +zone2sqlite - Load BIND 9 zone file into SQLite database +.SH SYNOPSIS +.B zone2sqlite zone zonefile dbfile dbtable +.SH DESCRIPTION +zone2sqlite parses DNS zone file and creates database for use with SQLite BIND SDB driver. + +\fBzone\fR +.RS 4 +Zone origin, eg "mydomain.net." +.RE +.PP +\fBzonefile\fR +.RS 4 +Master zone database file, eg. mydomain.net.zone +.RE +.PP +\fBdbfile\fR +.RS 4 +Name of SQLite database file +.RE +.PP +\fBdbtable\fR +.RS 4 +Name of table in database +.RE + +.SH "EXIT STATUS" +Exits with 0 on success or 1 on failure. +.SH "SEE ALSO" +named(8) +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007\-2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000, 2001 Internet Software Consortium. +.br diff --git a/SOURCES/zonetodb.1 b/SOURCES/zonetodb.1 new file mode 100644 index 0000000..897e74f --- /dev/null +++ b/SOURCES/zonetodb.1 @@ -0,0 +1,53 @@ +.\" Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") +.\" Copyright (C) 2000, 2001 Internet Software Consortium. +.\" +.\" Permission to use, copy, modify, and/or distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +.\" REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +.\" AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +.\" INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +.\" LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +.\" OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +.\" PERFORMANCE OF THIS SOFTWARE. +.\" +.\" Manpage written by Jan Gorig +.TH zonetodb 1 "15 March 2010" "BIND9" +.SH NAME +zonetodb - Generate a PostgreSQL table from a zone. +.SH SYNOPSIS +.B zonetodb origin file dbname dbtable +.SH DESCRIPTION +zonetodb parses DNS zone file and creates table in selected database for use with PostgreSQL BIND SDB driver. + +\fBzone\fR +.RS 4 +Zone origin, eg "pgdb.net." +.RE +.PP +\fBfile\fR +.RS 4 +Master zone database file, eg. pgdb.net.db +.RE +.PP +\fBdbname\fR +.RS 4 +Name of PostgreSQL database (database must exist) +.RE +.PP +\fBdbtable\fR +.RS 4 +Name of table in database +.RE + +.SH "EXIT STATUS" +Exits with 0 on success or 1 on failure. +.SH "SEE ALSO" +named(8) +.SH "COPYRIGHT" +Copyright \(co 2004, 2005, 2007\-2009 Internet Systems Consortium, Inc. ("ISC") +.br +Copyright \(co 2000, 2001 Internet Software Consortium. +.br diff --git a/SPECS/bind.spec b/SPECS/bind.spec new file mode 100644 index 0000000..58bb869 --- /dev/null +++ b/SPECS/bind.spec @@ -0,0 +1,3415 @@ +# +# Red Hat BIND package .spec file +# + +#%%global PATCHVER P2 +#%%global PREVER rc2 +#%%global VERSION %{version}%{PREVER} +%global VERSION %{version} +#%%global VERSION %{version}-%{PATCHVER} + +%{?!SDB: %global SDB 1} +%{?!test: %global test 0} +%{?!bind_uid: %global bind_uid 25} +%{?!bind_gid: %global bind_gid 25} +%{?!GSSTSIG: %global GSSTSIG 1} +%{?!PKCS11: %global PKCS11 1} +%{?!DEVEL: %global DEVEL 1} +%global bind_dir /var/named +%global chroot_prefix %{bind_dir}/chroot +%if %{SDB} +%global chroot_sdb_prefix %{bind_dir}/chroot_sdb +%endif +# +Summary: The Berkeley Internet Name Domain (BIND) DNS (Domain Name System) server +Name: bind +License: ISC +Version: 9.9.4 +Release: 51%{?PATCHVER}%{?PREVER}%{?dist}.1 +Epoch: 32 +Url: http://www.isc.org/products/BIND/ +Buildroot:%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) +Group: System Environment/Daemons +# +Source: https://ftp.isc.org/isc/bind9/%{VERSION}/bind-%{VERSION}.tar.gz +Source1: named.sysconfig +Source3: named.logrotate +Source7: bind-9.3.1rc1-sdb_tools-Makefile.in +Source8: dnszone.schema +Source12: README.sdb_pgsql +Source25: named.conf.sample +Source28: config-15.tar.bz2 +# Up-to-date bind.keys from upstream +# Fetch a new one from page https://www.isc.org/bind-keys +Source29: bind.keys +Source30: ldap2zone.c +Source31: ldap2zone.1 +Source32: named-sdb.8 +Source33: zonetodb.1 +Source34: zone2sqlite.1 +Source35: bind.tmpfiles.d +Source36: trusted-key.key +Source37: named.service +Source38: named-chroot.service +Source39: named-sdb.service +Source40: named-sdb-chroot.service +Source41: setup-named-chroot.sh +Source42: generate-rndc-key.sh +Source43: named.rwtab +Source44: named-chroot-setup.service +Source45: named-sdb-chroot-setup.service +Source46: named-setup-rndc.service +Source47: named-pkcs11.service +# added due to GeoIP functionality tests +# patch tool does not support binary patches +Source48: geoip-testing-data.tar.xz + +# Common patches +Patch5: bind-nonexec.patch +Patch10: bind-9.5-PIE.patch +Patch16: bind-9.3.2-redhat_doc.patch +Patch72: bind-9.5-dlz-64bit.patch +Patch87: bind-9.5-parallel-build.patch +Patch101:bind-96-old-api.patch +Patch102:bind-95-rh452060.patch +Patch106:bind93-rh490837.patch +Patch109:bind97-rh478718.patch +Patch110:bind97-rh570851.patch +Patch111:bind97-exportlib.patch +Patch112:bind97-rh645544.patch +Patch119:bind97-rh693982.patch +Patch123:bind98-rh735103.patch +Patch124:nslookup-norec.patch +# FIXME: This disables dlzexternal, which I will enable later again +# Make tests on all architectures and disable it +Patch127:bind99-forward.patch +Patch130:bind-9.9.1-P2-dlz-libdb.patch +Patch131:bind-9.9.1-P2-multlib-conflict.patch +Patch133:bind99-rh640538.patch +Patch134:bind97-rh669163.patch +Patch137:bind99-rrl.patch +# Install dns/update.h header for bind-dyndb-ldap plugin +Patch138:bind-9.9.3-include-update-h.patch +Patch139:bind99-ISC-Bugs-34738.patch +Patch140:bind99-ISC-Bugs-34870-v3.patch +Patch141:bind99-ISC-Bugs-35073.patch +Patch142:bind99-ISC-Bugs-35080.patch +Patch143:bind99-CVE-2014-0591.patch +Patch144:bind99-rh1067424.patch +Patch145:bind99-rh1072379.patch +Patch146:bind99-rh1098959.patch +Patch147:bind99-CVE-2014-8500.patch +Patch148:bind99-CVE-2015-1349.patch +Patch149:bind99-rh1215687-limits.patch +Patch154:bind99-rh1215164.patch +Patch155:bind99-rh1214827.patch +Patch156:bind99-CVE-2015-4620.patch +Patch157:bind99-CVE-2015-5477.patch +Patch158:bind-99-socket-maxevents.patch +Patch159:bind99-CVE-2015-5722.patch +Patch160:bind99-CVE-2015-8000.patch +Patch161:bind99-CVE-2015-8704.patch +Patch162:bind99-CVE-2016-1285-CVE-2016-1286.patch +Patch163:bind99-rh1291185.patch +Patch164:bind99-rh1259514.patch +Patch165:bind99-rh1306610.patch +Patch166:bind99-rh1220594-geoip.patch +Patch167:bind99-automatic-interface-scanning-rh1294506.patch +# commit 51bcc28543ce205f7af238ef2f3889ef020a0961 ISC 4467 +patch168:bind99-CVE-2016-2776.patch +# commit bbb7c613b3e41495db627909660334695b48e60b ISC 4489 +patch169:bind99-CVE-2016-8864.patch +# commit d372472f604d45f85b3bbae5d6f523fb561a8823 ISC 4508 +patch170:bind99-CVE-2016-9131.patch +# commit a14b7f0187315767a1fa855f116fe937a7b402e3 ISC 4510 +patch171:bind99-CVE-2016-9147.patch +# commit 69cb8ebf157183d9c36a9813f945348dd81b521f ISC 4517 +Patch172:bind99-CVE-2016-9444.patch +# commit 2c74ad28efe5710ad04562c6f9902bc48d3be0ed ISC 4530 +Patch173:bind99-rt43779.patch +# commit 062b04898be720ed0855efc192847fcbc667b3e1 ISC 4406 +Patch174:bind99-CVE-2016-2775.patch +# ISC 4557 +Patch175:bind99-CVE-2017-3135.patch +# ISC 4558 +Patch176:bind99-rt44318.patch +# commit c550e75ade4ceb4ece96f660292799519a5c3183 ISC 4567 +Patch177:bind99-rh1392362.patch +# commit 1f3ac11cb4ecfab52f517ebf78493b0f05318be2 +Patch178:bind99-coverity-fixes2.patch +# ISC 4575 +Patch179:bind99-CVE-2017-3136.patch +# ISC 4578 +Patch180:bind99-CVE-2017-3137.patch +# commit 5e746ab61ed8158f784b86111fef95581a08b7dd ISC 3905 +Patch181:bind99-rh1416304.patch +# ISC 4643 +Patch182: bind99-CVE-2017-3142+3143.patch + +# Native PKCS#11 functionality from 9.10 +Patch150:bind-9.9-allow_external_dnskey.patch +Patch151:bind-9.9-native-pkcs11.patch +Patch152:bind-9.9-dist-native-pkcs11.patch +Patch153:bind99-coverity-fixes.patch + +# SDB patches +Patch11: bind-9.3.2b2-sdbsrc.patch +Patch12: bind-9.5-sdb.patch +Patch62: bind-9.5-sdb-sqlite-bld.patch + +# needs inpection +Patch17: bind-9.3.2b1-fix_sdb_ldap.patch +Patch104: bind99-dyndb.patch + +# IDN paches +Patch73: bind-9.5-libidn.patch +Patch83: bind-9.5-libidn2.patch +Patch85: bind-9.5-libidn3.patch +Patch94: bind95-rh461409.patch +Patch135:bind99-libidn4.patch + +# +Requires(preun): systemd +Requires(postun): systemd +Requires: coreutils +Requires: systemd-units +Requires(post): grep, systemd +Requires(pre): shadow-utils +Requires: bind-libs = %{epoch}:%{version}-%{release} +Obsoletes: bind-config < 30:9.3.2-34.fc6 +Provides: bind-config = 30:9.3.2-34.fc6 +Obsoletes: caching-nameserver < 31:9.4.1-7.fc8 +Provides: caching-nameserver = 31:9.4.1-7.fc8 +Obsoletes: dnssec-conf < 1.27-2 +Provides: dnssec-conf = 1.27-1 +BuildRequires: openssl-devel, libtool, autoconf, pkgconfig, libcap-devel +BuildRequires: libidn-devel, libxml2-devel, GeoIP-devel +BuildRequires: systemd-units +%if %{SDB} +BuildRequires: openldap-devel, postgresql-devel, sqlite-devel, mysql-devel +BuildRequires: libdb-devel +%endif +%if %{test} +BuildRequires: net-tools +%endif +%if %{GSSTSIG} +BuildRequires: krb5-devel +%endif +# Needed to regenerate dig.1 manpage +BuildRequires: docbook-style-xsl, libxslt + +%description +BIND (Berkeley Internet Name Domain) is an implementation of the DNS +(Domain Name System) protocols. BIND includes a DNS server (named), +which resolves host names to IP addresses; a resolver library +(routines for applications to use when interfacing with DNS); and +tools for verifying that the DNS server is operating properly. + +%if %{PKCS11} +%package pkcs11 +Summary: Bind with native PKCS#11 functionality for crypto +Group: System Environment/Daemons +Requires: bind = %{epoch}:%{version}-%{release} +Requires: bind-libs = %{epoch}:%{version}-%{release} +Requires: bind-pkcs11-libs = %{epoch}:%{version}-%{release} + +%description pkcs11 +This is a version of BIND server built with native PKCS#11 functionality. +It is important to have SoftHSM v2+ installed and some token initialized. +For other supported HSM modules please check the BIND documentation. +This version of BIND binary is supported only in setup with the IPA server. + +%package pkcs11-utils +Summary: Bind tools with native PKCS#11 for using DNSSEC +Group: System Environment/Daemons +Requires: bind-pkcs11-libs = %{epoch}:%{version}-%{release} + +%description pkcs11-utils +This is a set of PKCS#11 utilities that when used together create rsa +keys in a PKCS11 keystore. Also utilities for working with DNSSEC +compiled with native PKCS#11 functionality are included. + +%package pkcs11-libs +Summary: Bind libraries compiled with native PKCS#11 +Group: System Environment/Daemons +Requires: bind-license = %{epoch}:%{version}-%{release} +Requires: bind-libs = %{epoch}:%{version}-%{release} + +%description pkcs11-libs +This is a set of BIND libraries (dns, isc) compiled with native PKCS#11 +functionality. + +%package pkcs11-devel +Summary: Development files for Bind libraries compiled with native PKCS#11 +Group: System Environment/Daemons +Requires: bind-pkcs11-libs = %{epoch}:%{version}-%{release} + +%description pkcs11-devel +This a set of development files for BIND libraries (dns, isc) compiled +with native PKCS#11 functionality. +%endif + +%if %{SDB} +%package sdb +Summary: BIND server with database backends and DLZ support +Group: System Environment/Daemons +Requires: bind +Requires: bind-libs = %{epoch}:%{version}-%{release} +Requires: systemd-units + +%description sdb +BIND (Berkeley Internet Name Domain) is an implementation of the DNS +(Domain Name System) protocols. BIND includes a DNS server (named-sdb) +which has compiled-in SDB (Simplified Database Backend) which includes +support for using alternative Zone Databases stored in an LDAP server +(ldapdb), a postgreSQL database (pgsqldb), an sqlite database (sqlitedb), +or in the filesystem (dirdb), in addition to the standard in-memory RBT +(Red Black Tree) zone database. It also includes support for DLZ +(Dynamic Loadable Zones) +%endif + +%package libs-lite +Summary: Libraries for working with the DNS protocol +Group: Applications/System +Obsoletes:bind-libbind-devel < 31:9.3.3-4.fc7 +Provides: bind-libbind-devel = 31:9.3.3-4.fc7 +Requires: bind-license = %{epoch}:%{version}-%{release} + +%description libs-lite +Contains lite version of BIND suite libraries which are used by various +programs to work with DNS protocol. + +%package libs +Summary: Libraries used by the BIND DNS packages +Group: Applications/System +Requires: bind-license = %{epoch}:%{version}-%{release} + +%description libs +Contains heavyweight version of BIND suite libraries used by both named DNS +server and utilities in bind-utils package. + +%package license +Summary: License of the BIND DNS suite +Group: Applications/System +BuildArch:noarch + +%description license +Contains license of the BIND DNS suite. + +%package utils +Summary: Utilities for querying DNS name servers +Group: Applications/System +Requires: bind-libs = %{epoch}:%{version}-%{release} + +%description utils +Bind-utils contains a collection of utilities for querying DNS (Domain +Name System) name servers to find out information about Internet +hosts. These tools will provide you with the IP addresses for given +host names, as well as other information about registered domains and +network addresses. + +You should install bind-utils if you need to get information from DNS name +servers. + +%if %{DEVEL} +%package devel +Summary: Header files and libraries needed for BIND DNS development +Group: Development/Libraries +Obsoletes:bind-libbind-devel < 31:9.3.3-4.fc7 +Provides: bind-libbind-devel = 31:9.3.3-4.fc7 +Requires: bind-libs = %{epoch}:%{version}-%{release} + +%description devel +The bind-devel package contains full version of the header files and libraries +required for development with ISC BIND 9 +%endif + +%package lite-devel +Summary: Lite version of header files and libraries needed for BIND DNS development +Group: Development/Libraries +Requires: bind-libs-lite = %{epoch}:%{version}-%{release} + +%description lite-devel +The bind-lite-devel package contains lite version of the header +files and libraries required for development with ISC BIND 9 + +%package chroot +Summary: A chroot runtime environment for the ISC BIND DNS server, named(8) +Group: System Environment/Daemons +Prefix: %{chroot_prefix} +Requires(post): grep +Requires(preun):grep +Requires: bind = %{epoch}:%{version}-%{release} +Requires: systemd-units + +%description chroot +This package contains a tree of files which can be used as a +chroot(2) jail for the named(8) program from the BIND package. +Based on the code from Jan "Yenya" Kasprzak <kas@fi.muni.cz> + +%if %{SDB} +%package sdb-chroot +Summary: A chroot runtime environment for the ISC BIND DNS server, named-sdb(8) +Group: System Environment/Daemons +Prefix: %{chroot_prefix} +Requires: bind-sdb +Requires: systemd-units + +%description sdb-chroot +This package contains a tree of files which can be used as a +chroot(2) jail for the named-sdb(8) program from the BIND package. +Based on the code from Jan "Yenya" Kasprzak <kas@fi.muni.cz> +%endif + + +%prep +%setup -q -n %{name}-%{VERSION} + +# Common patches +%patch5 -p1 -b .nonexec +%patch10 -p1 -b .PIE +%patch16 -p1 -b .redhat_doc +%ifnarch alpha ia64 +%patch72 -p1 -b .64bit +%endif +%patch73 -p1 -b .libidn +%patch83 -p1 -b .libidn2 +%patch85 -p1 -b .libidn3 +%patch87 -p1 -b .parallel +%patch94 -p1 -b .rh461409 + +%patch102 -p1 -b .rh452060 +%patch106 -p0 -b .rh490837 +%patch109 -p1 -b .rh478718 +%patch110 -p1 -b .rh570851 +%patch111 -p1 -b .exportlib +%patch112 -p1 -b .rh645544 +%patch119 -p1 -b .rh693982 +%patch123 -p1 -b .rh735103 +pushd bin/dig +%patch124 -p0 -b .nslookup-norec +popd +%patch127 -p1 -b .forward +%patch130 -p1 -b .libdb +%patch131 -p1 -b .multlib-conflict +%patch137 -p1 -b .rrl +%patch138 -p1 -b .update +%patch139 -p1 -b .journal +%patch140 -p1 -b .send_buffers +%patch141 -p1 -b .leak_35073 +%patch142 -p1 -b .rbt_crash +%patch143 -p1 -b .CVE-2014-059 +%patch144 -p1 -b .rh1067424 +%patch145 -p1 -b .rh1072379 +%patch146 -p1 -b .rh1098959 +%patch147 -p1 -b .CVE-2014-8500 +%patch148 -p1 -b .CVE-2015-1349 +%patch149 -p1 -b .rh1215687-limits + +%patch150 -p1 -b .external_key +%patch151 -p1 -b .native_pkcs11 +# http://cov01.lab.eng.brq.redhat.com/covscanhub/waiving/9377/ +%patch153 -p1 -b .coverity_9377 +%patch154 -p1 -b .rh1215164 +%patch155 -p1 -b .nsupdate_realm +%patch156 -p1 -b .CVE-2015-4620 +%patch157 -p1 -b .CVE-2015-5477 +%patch158 -p1 -b .sock-maxevents +%patch159 -p1 -b .CVE-2015-5722 +%patch160 -p1 -b .CVE-2015-8000 +%patch161 -p1 -b .CVE-2015-8704 +%patch162 -p1 -b .CVE-2016-1285-CVE-2016-1286 +%patch163 -p1 -b .rh1291185 +%patch164 -p1 -b .rh1259514 +%patch165 -p1 -b .rh1306610-caa +%patch104 -p1 -b .dyndb + +# GeoIP support +%patch166 -p1 -b .rh1220594-geoip +# extract the binary testing data +tar -xf %{SOURCE48} -C bin/tests/system/geoip/data + +%patch167 -p1 -b .rh1294506 +%patch168 -p1 -b .CVE-2016-2776 +%patch169 -p1 -b .CVE-2016-8864 +%patch170 -p1 -b .CVE-2016-9131 +%patch171 -p1 -b .CVE-2016-9147 +%patch172 -p1 -b .CVE-2016-9444 +%patch173 -p1 -b .rt43779 +%patch174 -p1 -b .CVE-2016-2775 +%patch175 -p1 -b .CVE-2017-3135 +%patch176 -p1 -b .rt44318 +%patch177 -p1 -b .rh1392362 +%patch178 -p1 -b .coverity2 +%patch179 -p1 -b .CVE-2017-3136 +%patch180 -p1 -b .CVE-2017-3137 +%patch181 -p1 -b .rh1416304 +%patch182 -p1 -b .CVE-2017-3142+3143 + +# Override upstream builtin keys +cp -fp %{SOURCE29} bind.keys + +%if %{PKCS11} +cp -r bin/named{,-pkcs11} +cp -r bin/dnssec{,-pkcs11} +cp -r lib/isc{,-pkcs11} +cp -r lib/dns{,-pkcs11} +cp -r lib/export/isc{,-pkcs11} +cp -r lib/export/dns{,-pkcs11} +%patch152 -p1 -b .dist_pkcs11 +%endif + +%if %{SDB} +%patch101 -p1 -b .old-api +mkdir bin/named-sdb +cp -r bin/named/* bin/named-sdb +%patch11 -p1 -b .sdbsrc +# SDB ldap +cp -fp contrib/sdb/ldap/ldapdb.[ch] bin/named-sdb +# SDB postgreSQL +cp -fp contrib/sdb/pgsql/pgsqldb.[ch] bin/named-sdb +# SDB sqlite +cp -fp contrib/sdb/sqlite/sqlitedb.[ch] bin/named-sdb +# SDB Berkeley DB - needs to be ported to DB4! +#cp -fp contrib/sdb/bdb/bdb.[ch] bin/named_sdb +# SDB dir +cp -fp contrib/sdb/dir/dirdb.[ch] bin/named-sdb +# SDB tools +mkdir -p bin/sdb_tools +cp -fp %{SOURCE30} bin/sdb_tools/ldap2zone.c +cp -fp %{SOURCE7} bin/sdb_tools/Makefile.in +#cp -fp contrib/sdb/bdb/zone2bdb.c bin/sdb_tools +cp -fp contrib/sdb/ldap/{zone2ldap.1,zone2ldap.c} bin/sdb_tools +cp -fp contrib/sdb/pgsql/zonetodb.c bin/sdb_tools +cp -fp contrib/sdb/sqlite/zone2sqlite.c bin/sdb_tools +%patch12 -p1 -b .sdb +%endif +%if %{SDB} +%patch17 -p1 -b .fix_sdb_ldap +%endif +%if %{SDB} +%patch62 -p1 -b .sdb-sqlite-bld +%endif +%patch133 -p1 -b .rh640538 +%patch134 -p1 -b .rh669163 +%patch135 -p1 -b .libidn4 + +# Sparc and s390 arches need to use -fPIE +%ifarch sparcv9 sparc64 s390 s390x +for i in bin/named{,-sdb}/{,unix}/Makefile.in; do + sed -i 's|fpie|fPIE|g' $i +done +%endif + +:; + +%build +export CFLAGS="$CFLAGS $RPM_OPT_FLAGS" +export CPPFLAGS="$CPPFLAGS -DDIG_SIGCHASE" +export STD_CDEFINES="$CPPFLAGS" + +sed -i -e \ +'s/RELEASEVER=\(.*\)/RELEASEVER=\1-RedHat-%{version}-%{release}/' \ +version + +libtoolize -c -f; aclocal -I libtool.m4 --force; autoconf -f + +%configure \ + --with-libtool \ + --localstatedir=/var \ + --enable-threads \ + --with-geoip \ + --enable-ipv6 \ + --enable-filter-aaaa \ + --enable-rrl \ + --with-pic \ + --disable-static \ + --disable-openssl-version-check \ + --enable-exportlib \ + --with-export-libdir=%{_libdir} \ + --with-export-includedir=%{_includedir} \ + --includedir=%{_includedir}/bind9 \ +%if %{PKCS11} + --enable-native-pkcs11 \ + --with-pkcs11=%{_libdir}/pkcs11/libsofthsm2.so \ +%endif +%if %{SDB} + --with-dlopen=yes \ + --with-dlz-ldap=yes \ + --with-dlz-postgres=yes \ + --with-dlz-mysql=yes \ + --with-dlz-filesystem=yes \ + --with-dlz-bdb=yes \ +%endif +%if %{GSSTSIG} + --with-gssapi=yes \ + --disable-isc-spnego \ +%endif + --enable-fixed-rrset \ + --with-docbook-xsl=%{_datadir}/sgml/docbook/xsl-stylesheets \ +; +make %{?_smp_mflags} + +# Regenerate dig.1 manpage +pushd bin/dig +make man +popd +pushd bin/python +make man +popd + +%if %{test} +%check +if [ "`whoami`" = 'root' ]; then + set -e + chmod -R a+rwX . + pushd bin/tests + pushd system + ./ifconfig.sh up + popd + make test + e=$? + pushd system + ./ifconfig.sh down + popd + popd + if [ "$e" -ne 0 ]; then + echo "ERROR: this build of BIND failed 'make test'. Aborting." + exit $e; + fi; +else + echo 'only root can run the tests (they require an ifconfig).' +%endif + +%install +rm -rf ${RPM_BUILD_ROOT} + +# Build directory hierarchy +mkdir -p ${RPM_BUILD_ROOT}/etc/logrotate.d +mkdir -p ${RPM_BUILD_ROOT}%{_libdir}/bind +mkdir -p ${RPM_BUILD_ROOT}/var/named/{slaves,data,dynamic} +mkdir -p ${RPM_BUILD_ROOT}%{_mandir}/{man1,man5,man8} +mkdir -p ${RPM_BUILD_ROOT}/run/named +mkdir -p ${RPM_BUILD_ROOT}/var/log + +#chroot +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_prefix}/{dev,etc,var,run/named} +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_prefix}/var/{log,named,tmp} + +# create symlink as it is on real filesystem +pushd ${RPM_BUILD_ROOT}/%{chroot_prefix}/var +ln -s ../run run +popd + +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_prefix}/etc/{pki/dnssec-keys,named} +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_prefix}/%{_libdir}/bind +# these are required to prevent them being erased during upgrade of previous +touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/dev/null +touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/dev/random +touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/dev/zero +touch ${RPM_BUILD_ROOT}/%{chroot_prefix}/etc/named.conf +#end chroot + +#sdb-chroot +%if %{SDB} +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/{dev,etc,var,run/named} +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/var/{log,named,tmp} + +# create symlink as it is on real filesystem +pushd ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/var +ln -s ../run run +popd + +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/etc/{pki/dnssec-keys,named} +mkdir -p ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/%{_libdir}/bind +# these are required to prevent them being erased during upgrade of previous +touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/dev/null +touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/dev/random +touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/dev/zero +touch ${RPM_BUILD_ROOT}/%{chroot_sdb_prefix}/etc/named.conf +%endif +#end sdb-chroot + +make DESTDIR=${RPM_BUILD_ROOT} install + +# Remove unwanted files +rm -f ${RPM_BUILD_ROOT}/etc/bind.keys + +# Systemd unit files +mkdir -p ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE37} ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE38} ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE44} ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE46} ${RPM_BUILD_ROOT}%{_unitdir} + +%if %{SDB} +install -m 644 %{SOURCE39} ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE40} ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE45} ${RPM_BUILD_ROOT}%{_unitdir} +%endif +%if %{PKCS11} +install -m 644 %{SOURCE47} ${RPM_BUILD_ROOT}%{_unitdir} +%endif + +mkdir -p ${RPM_BUILD_ROOT}%{_libexecdir} +install -m 755 %{SOURCE41} ${RPM_BUILD_ROOT}%{_libexecdir}/setup-named-chroot.sh +install -m 755 %{SOURCE42} ${RPM_BUILD_ROOT}%{_libexecdir}/generate-rndc-key.sh + +install -m 644 %SOURCE3 ${RPM_BUILD_ROOT}/etc/logrotate.d/named +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig +install -m 644 %{SOURCE1} ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/named +%if %{SDB} +mkdir -p ${RPM_BUILD_ROOT}/etc/openldap/schema +install -m 644 %{SOURCE8} ${RPM_BUILD_ROOT}/etc/openldap/schema/dnszone.schema +install -m 644 %{SOURCE12} contrib/sdb/pgsql/ +%endif + +# Install isc/errno2result.h header +install -m 644 lib/isc/unix/errno2result.h ${RPM_BUILD_ROOT}%{_includedir}/isc + +# Files required to run test-suite outside of build tree: +cp -fp config.h ${RPM_BUILD_ROOT}/%{_includedir}/bind9 +cp -fp lib/dns/include/dns/forward.h ${RPM_BUILD_ROOT}/%{_includedir}/dns +cp -fp lib/isc/unix/include/isc/keyboard.h ${RPM_BUILD_ROOT}/%{_includedir}/isc + +# Remove libtool .la files: +find ${RPM_BUILD_ROOT}/%{_libdir} -name '*.la' -exec '/bin/rm' '-f' '{}' ';'; + +# Remove -devel files out of buildroot if not needed +%if !%{DEVEL} +rm -f ${RPM_BUILD_ROOT}/%{_libdir}/bind9/*so +rm -rf ${RPM_BUILD_ROOT}/%{_includedir}/bind9 +rm -f ${RPM_BUILD_ROOT}/%{_mandir}/man1/isc-config.sh.1* +rm -f ${RPM_BUILD_ROOT}/%{_mandir}/man3/lwres* +rm -f ${RPM_BUILD_ROOT}/%{_bindir}/isc-config.sh +%endif + +# SDB manpages +%if %{SDB} +install -m 644 %{SOURCE31} ${RPM_BUILD_ROOT}%{_mandir}/man1/ldap2zone.1 +install -m 644 %{SOURCE32} ${RPM_BUILD_ROOT}%{_mandir}/man8/named-sdb.8 +install -m 644 %{SOURCE33} ${RPM_BUILD_ROOT}%{_mandir}/man1/zonetodb.1 +install -m 644 %{SOURCE34} ${RPM_BUILD_ROOT}%{_mandir}/man1/zone2sqlite.1 +%endif + +# PKCS11 versions manpages +%if %{PKCS11} +pushd ${RPM_BUILD_ROOT}%{_mandir}/man8 +ln -s named.8.gz named-pkcs11.8.gz +ln -s dnssec-checkds.8.gz dnssec-checkds-pkcs11.8.gz +ln -s dnssec-coverage.8.gz dnssec-coverage-pkcs11.8.gz +ln -s dnssec-dsfromkey.8.gz dnssec-dsfromkey-pkcs11.8.gz +ln -s dnssec-keyfromlabel.8.gz dnssec-keyfromlabel-pkcs11.8.gz +ln -s dnssec-keygen.8.gz dnssec-keygen-pkcs11.8.gz +ln -s dnssec-revoke.8.gz dnssec-revoke-pkcs11.8.gz +ln -s dnssec-settime.8.gz dnssec-settime-pkcs11.8.gz +ln -s dnssec-signzone.8.gz dnssec-signzone-pkcs11.8.gz +ln -s dnssec-verify.8.gz dnssec-verify-pkcs11.8.gz +popd +%endif + +# Ghost config files: +touch ${RPM_BUILD_ROOT}%{_localstatedir}/log/named.log + +# configuration files: +tar -C ${RPM_BUILD_ROOT} -xjf %{SOURCE28} +touch ${RPM_BUILD_ROOT}/etc/rndc.key +touch ${RPM_BUILD_ROOT}/etc/rndc.conf +mkdir ${RPM_BUILD_ROOT}/etc/named +install -m 644 bind.keys ${RPM_BUILD_ROOT}/etc/named.iscdlv.key +install -m 644 %{SOURCE36} ${RPM_BUILD_ROOT}/etc/trusted-key.key + +# sample bind configuration files for %%doc: +mkdir -p sample/etc sample/var/named/{data,slaves} +install -m 644 %{SOURCE25} sample/etc/named.conf +# Copy default configuration to %%doc to make it usable from system-config-bind +install -m 644 ${RPM_BUILD_ROOT}/etc/named.conf named.conf.default +install -m 644 ${RPM_BUILD_ROOT}/etc/named.rfc1912.zones sample/etc/named.rfc1912.zones +install -m 644 ${RPM_BUILD_ROOT}/var/named/{named.ca,named.localhost,named.loopback,named.empty} sample/var/named +for f in my.internal.zone.db slaves/my.slave.internal.zone.db slaves/my.ddns.internal.zone.db my.external.zone.db; do + echo '@ in soa localhost. root 1 3H 15M 1W 1D + ns localhost.' > sample/var/named/$f; +done +:; + +mkdir -p ${RPM_BUILD_ROOT}%{_tmpfilesdir} +install -m 644 %{SOURCE35} ${RPM_BUILD_ROOT}%{_tmpfilesdir}/named.conf + +mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/rwtab.d +install -m 644 %{SOURCE43} ${RPM_BUILD_ROOT}%{_sysconfdir}/rwtab.d/named + +%pre +if [ "$1" -eq 1 ]; then + /usr/sbin/groupadd -g %{bind_gid} -f -r named >/dev/null 2>&1 || :; + /usr/sbin/useradd -u %{bind_uid} -r -N -M -g named -s /sbin/nologin -d /var/named -c Named named >/dev/null 2>&1 || :; +fi; +:; + +%post +/sbin/ldconfig +%systemd_post named.service +if [ "$1" -eq 1 ]; then + # Initial installation + [ -x /sbin/restorecon ] && /sbin/restorecon /etc/rndc.* /etc/named.* >/dev/null 2>&1 ; + # rndc.key has to have correct perms and ownership, CVE-2007-6283 + [ -e /etc/rndc.key ] && chown root:named /etc/rndc.key + [ -e /etc/rndc.key ] && chmod 0640 /etc/rndc.key +fi +:; + +%preun +# Package removal, not upgrade +%systemd_preun named.service + +%postun +/sbin/ldconfig +# Package upgrade, not uninstall +%systemd_postun_with_restart named.service + +%if %{SDB} +%post sdb +# Initial installation +%systemd_post named-sdb.service + +%preun sdb +# Package removal, not upgrade +%systemd_preun named-sdb.service + +%postun sdb +# Package upgrade, not uninstall +%systemd_postun_with_restart named-sdb.service +%endif + +%if %{PKCS11} +%post pkcs11 +# Initial installation +%systemd_post named-pkcs11.service + +%preun pkcs11 +# Package removal, not upgrade +%systemd_preun named-pkcs11.service + +%postun pkcs11 +# Package upgrade, not uninstall +%systemd_postun_with_restart named-pkcs11.service +%endif + +%triggerpostun -n bind -- bind <= 32:9.5.0-20.b1 +if [ "$1" -gt 0 ]; then + [ -e /etc/rndc.key ] && chown root:named /etc/rndc.key + [ -e /etc/rndc.key ] && chmod 0640 /etc/rndc.key +fi +:; + +%triggerun -- bind < 32:9.9.0-0.6.rc1 +/sbin/chkconfig --del named >/dev/null 2>&1 || : +/bin/systemctl try-restart named.service >/dev/null 2>&1 || : + +%post libs -p /sbin/ldconfig + +%postun libs -p /sbin/ldconfig + +%post libs-lite -p /sbin/ldconfig + +%postun libs-lite -p /sbin/ldconfig + +%pre chroot +# updating +if [ "$1" -gt 1 ]; then + # if %%{chroot_prefix}/var/run is a directory, remove it + # fix for Bug #1091341 + if [ -d %{chroot_prefix}/var/run ]; then + rm -rf %{chroot_prefix}/var/run + fi +fi + +%post chroot +%systemd_post named-chroot.service +if [ "$1" -gt 0 ]; then + [ -e %{chroot_prefix}/dev/random ] || \ + /bin/mknod %{chroot_prefix}/dev/random c 1 8 + [ -e %{chroot_prefix}/dev/zero ] || \ + /bin/mknod %{chroot_prefix}/dev/zero c 1 5 + [ -e %{chroot_prefix}/dev/null ] || \ + /bin/mknod %{chroot_prefix}/dev/null c 1 3 +fi; +:; + +%posttrans chroot +if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then + [ -x /sbin/restorecon ] && /sbin/restorecon %{chroot_prefix}/dev/* > /dev/null 2>&1; +fi; +:; + +%preun chroot +%systemd_preun named-chroot.service +if [ "$1" -eq 0 ]; then + # Package removal, not upgrade + rm -f %{chroot_prefix}/dev/{random,zero,null} +fi +:; + +%postun chroot +# Package upgrade, not uninstall +%systemd_postun_with_restart named-chroot.service + + +%if %{SDB} + +%post sdb-chroot +%systemd_post named-sdb-chroot.service +if [ "$1" -gt 0 ]; then + [ -e %{chroot_sdb_prefix}/dev/random ] || \ + /bin/mknod %{chroot_sdb_prefix}/dev/random c 1 8 + [ -e %{chroot_sdb_prefix}/dev/zero ] || \ + /bin/mknod %{chroot_sdb_prefix}/dev/zero c 1 5 + [ -e %{chroot_sdb_prefix}/dev/null ] || \ + /bin/mknod %{chroot_sdb_prefix}/dev/null c 1 3 +fi; +:; + +%posttrans sdb-chroot +if [ -x /usr/sbin/selinuxenabled ] && /usr/sbin/selinuxenabled; then + [ -x /sbin/restorecon ] && /sbin/restorecon %{chroot_sdb_prefix}/dev/* > /dev/null 2>&1; +fi; +:; + +%preun sdb-chroot +%systemd_preun named-sdb-chroot.service +if [ "$1" -eq 0 ]; then + # Package removal, not upgrade + rm -f %{chroot_sdb_prefix}/dev/{random,zero,null} +fi +:; + +%postun sdb-chroot +# Package upgrade, not uninstall +%systemd_postun_with_restart named-sdb-chroot.service + +%endif + +%clean +rm -rf ${RPM_BUILD_ROOT} +:; + +%files +%defattr(-,root,root,-) +%{_libdir}/bind +%config(noreplace) %verify(not md5 size mtime) %{_sysconfdir}/sysconfig/named +%config(noreplace) %attr(0644,root,named) %{_sysconfdir}/named.iscdlv.key +%config(noreplace) %attr(0644,root,named) %{_sysconfdir}/named.root.key +%{_tmpfilesdir}/named.conf +%{_sysconfdir}/rwtab.d/named +%{_unitdir}/named.service +%{_unitdir}/named-setup-rndc.service +%{_sbindir}/arpaname +%{_sbindir}/ddns-confgen +%{_sbindir}/genrandom +%{_sbindir}/named-journalprint +%{_sbindir}/nsec3hash +%{_sbindir}/dnssec* +%exclude %{_sbindir}/dnssec*pkcs11 +%{_sbindir}/named-check* +%{_sbindir}/lwresd +%{_sbindir}/named +%{_sbindir}/rndc* +%{_sbindir}/named-compilezone +%{_sbindir}/isc-hmac-fixup +%{_libexecdir}/generate-rndc-key.sh +%{_mandir}/man1/arpaname.1* +%{_mandir}/man5/named.conf.5* +%{_mandir}/man5/rndc.conf.5* +%{_mandir}/man8/rndc.8* +%{_mandir}/man8/named.8* +%{_mandir}/man8/lwresd.8* +%{_mandir}/man8/dnssec*.8* +%exclude %{_mandir}/man8/dnssec*-pkcs11.8* +%{_mandir}/man8/named-checkconf.8* +%{_mandir}/man8/named-checkzone.8* +%{_mandir}/man8/named-compilezone.8* +%{_mandir}/man8/rndc-confgen.8* +%{_mandir}/man8/ddns-confgen.8* +%{_mandir}/man8/genrandom.8* +%{_mandir}/man8/named-journalprint.8* +%{_mandir}/man8/nsec3hash.8* +%{_mandir}/man8/isc-hmac-fixup.8* +%doc CHANGES README named.conf.default +%doc doc/arm/*html doc/arm/*pdf +%doc sample/ + +# Hide configuration +%defattr(0640,root,named,0750) +%dir %{_sysconfdir}/named +%dir %{_localstatedir}/named +%config(noreplace) %verify(not link) %{_sysconfdir}/named.conf +%config(noreplace) %verify(not link) %{_sysconfdir}/named.rfc1912.zones +%config %verify(not link) %{_localstatedir}/named/named.ca +%config %verify(not link) %{_localstatedir}/named/named.localhost +%config %verify(not link) %{_localstatedir}/named/named.loopback +%config %verify(not link) %{_localstatedir}/named/named.empty +%defattr(0660,named,named,0770) +%dir %{_localstatedir}/named/slaves +%dir %{_localstatedir}/named/data +%dir %{_localstatedir}/named/dynamic +%ghost %{_localstatedir}/log/named.log +%defattr(0640,root,named,0750) +%ghost %config(noreplace) %{_sysconfdir}/rndc.key +# ^- rndc.key now created on first install only if it does not exist +# %%verify(not size,not md5) %%config(noreplace) %%attr(0640,root,named) /etc/rndc.conf +# ^- Let the named internal default rndc.conf be used - +# rndc.conf not required unless it differs from default. +%ghost %config(noreplace) %{_sysconfdir}/rndc.conf +# ^- The default rndc.conf which uses rndc.key is in named's default internal config - +# so rndc.conf is not necessary. +%config(noreplace) %{_sysconfdir}/logrotate.d/named +%defattr(-,named,named,-) +%dir /run/named + +%if %{SDB} +%files sdb +%defattr(-,root,root,-) +%{_unitdir}/named-sdb.service +%{_mandir}/man1/zone2ldap.1* +%{_mandir}/man1/ldap2zone.1* +%{_mandir}/man1/zonetodb.1* +%{_mandir}/man1/zone2sqlite.1* +%{_mandir}/man8/named-sdb.8* +%doc contrib/sdb/ldap/README.ldap contrib/sdb/ldap/INSTALL.ldap contrib/sdb/pgsql/README.sdb_pgsql +%dir %{_sysconfdir}/openldap/schema +%config(noreplace) %{_sysconfdir}/openldap/schema/dnszone.schema +%{_sbindir}/named-sdb +%{_sbindir}/zone2ldap +%{_sbindir}/ldap2zone +%{_sbindir}/zonetodb +%{_sbindir}/zone2sqlite +%endif + +%files libs +%defattr(-,root,root,-) +%{_libdir}/*so.* +%exclude %{_libdir}/*export.so.* +%exclude %{_libdir}/*pkcs11.so.* +%exclude %{_libdir}/*pkcs11-export.so.* + +%files libs-lite +%defattr(-,root,root,-) +%{_libdir}/*export.so.* +%exclude %{_libdir}/*pkcs11-export.so.* + +%files license +%defattr(-,root,root,-) +%doc COPYRIGHT + +%files utils +%defattr(-,root,root,-) +%{_bindir}/dig +%{_bindir}/host +%{_bindir}/nslookup +%{_bindir}/nsupdate +%{_mandir}/man1/host.1* +%{_mandir}/man1/nsupdate.1* +%{_mandir}/man1/dig.1* +%{_mandir}/man1/nslookup.1* +%{_sysconfdir}/trusted-key.key + +%if %{DEVEL} +%files devel +%defattr(-,root,root,-) +%{_libdir}/*so +%exclude %{_libdir}/*export.so +%exclude %{_libdir}/*pkcs11.so +%exclude %{_libdir}/*pkcs11-export.so +%{_includedir}/bind9 +%exclude %{_includedir}/bind9/pkcs11 +%exclude %{_includedir}/bind9/pk11 +%{_mandir}/man1/isc-config.sh.1* +%{_mandir}/man3/lwres* +%{_bindir}/isc-config.sh +%endif + +%files lite-devel +%defattr(-,root,root,-) +%{_libdir}/*export.so +%exclude %{_libdir}/*pkcs11-export.so +%{_includedir}/dns +%{_includedir}/dst +%{_includedir}/irs +%{_includedir}/isc +%{_includedir}/isccfg + +%files chroot +%defattr(-,root,root,-) +%{_unitdir}/named-chroot.service +%{_unitdir}/named-chroot-setup.service +%{_libexecdir}/setup-named-chroot.sh +%ghost %{chroot_prefix}/dev/null +%ghost %{chroot_prefix}/dev/random +%ghost %{chroot_prefix}/dev/zero +%defattr(0640,root,named,0750) +%dir %{chroot_prefix} +%dir %{chroot_prefix}/dev +%dir %{chroot_prefix}/etc +%dir %{chroot_prefix}/etc/named +%dir %{chroot_prefix}/etc/pki +%dir %{chroot_prefix}/etc/pki/dnssec-keys +%dir %{chroot_prefix}/var +%dir %{chroot_prefix}/run +%dir %{chroot_prefix}/var/named +%ghost %config(noreplace) %{chroot_prefix}/etc/named.conf +%defattr(-,root,root,-) +%dir %{chroot_prefix}/usr +%dir %{chroot_prefix}/%{_libdir} +%dir %{chroot_prefix}/%{_libdir}/bind +%defattr(0660,named,named,0770) +%dir %{chroot_prefix}/var/tmp +%dir %{chroot_prefix}/var/log +%defattr(-,named,named,-) +%dir %{chroot_prefix}/run/named +%{chroot_prefix}/var/run + +%if %{SDB} +%files sdb-chroot +%defattr(-,root,root,-) +%{_unitdir}/named-sdb-chroot.service +%{_unitdir}/named-sdb-chroot-setup.service +%{_libexecdir}/setup-named-chroot.sh +%ghost %{chroot_sdb_prefix}/dev/null +%ghost %{chroot_sdb_prefix}/dev/random +%ghost %{chroot_sdb_prefix}/dev/zero +%defattr(0640,root,named,0750) +%dir %{chroot_sdb_prefix} +%dir %{chroot_sdb_prefix}/dev +%dir %{chroot_sdb_prefix}/etc +%dir %{chroot_sdb_prefix}/etc/named +%dir %{chroot_sdb_prefix}/etc/pki +%dir %{chroot_sdb_prefix}/etc/pki/dnssec-keys +%dir %{chroot_sdb_prefix}/var +%dir %{chroot_sdb_prefix}/run +%dir %{chroot_sdb_prefix}/var/named +%ghost %config(noreplace) %{chroot_sdb_prefix}/etc/named.conf +%defattr(-,root,root,-) +%dir %{chroot_sdb_prefix}/usr +%dir %{chroot_sdb_prefix}/%{_libdir} +%dir %{chroot_sdb_prefix}/%{_libdir}/bind +%defattr(0660,named,named,0770) +%dir %{chroot_sdb_prefix}/var/tmp +%dir %{chroot_sdb_prefix}/var/log +%defattr(-,named,named,-) +%dir %{chroot_sdb_prefix}/run/named +%{chroot_sdb_prefix}/var/run +%endif + +%if %{PKCS11} +%files pkcs11 +%defattr(-,root,root,-) +%{_sbindir}/named-pkcs11 +%{_unitdir}/named-pkcs11.service +%{_mandir}/man8/named-pkcs11.8* + +%files pkcs11-utils +%defattr(-,root,root,-) +%{_sbindir}/dnssec*pkcs11 +%{_sbindir}/pkcs11-destroy +%{_sbindir}/pkcs11-keygen +%{_sbindir}/pkcs11-list +%{_sbindir}/pkcs11-tokens +%{_mandir}/man8/pkcs11*.8* +%{_mandir}/man8/dnssec*-pkcs11.8* + +%files pkcs11-libs +%defattr(-,root,root,-) +%{_libdir}/*pkcs11.so.* +%{_libdir}/*pkcs11-export.so.* + +%files pkcs11-devel +%defattr(-,root,root,-) +%{_includedir}/bind9/pk11 +%{_includedir}/bind9/pkcs11 +%{_libdir}/*pkcs11.so +%{_libdir}/*pkcs11-export.so + +%endif + +%changelog +* Fri Oct 20 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-51.1 +- Fix named-chroot restart leak (#1504700) + +* Thu Jun 29 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-51 +- Fix CVE-2017-3142 and CVE-2017-3143 + +* Mon May 22 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-50 +- Update root servers and trust anchor (#1452635) + +* Thu Apr 20 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-49 +- Address deadlock between view.c and adb.c (#1416304) + +* Tue Apr 11 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-48 +- Fix CVE-2017-3136 (ISC change 4575) +- Fix CVE-2017-3137 (ISC change 4578) + +* Wed Mar 29 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-47 +- Simplify change of used config file, point to KB article (#1271315) + +* Tue Mar 28 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-46 +- Make comment how to use different config file (#1271315) + +* Thu Mar 16 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-45 +- Install again dns/dlz.h skipped in rebase +- Fixed coverity warnings on reenabled test dlzexternal + +* Tue Mar 14 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-44 +- Backported new upstream dyndb interface, removed dynamic_db (#1393886) + +* Mon Feb 27 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-43 +- Do not warn on WKS patch (#1392362) + +* Tue Feb 21 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-42 +- Support WKS records in chroot + +* Wed Feb 08 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-41 +- Fix CVE-2017-3135 (ISC change 4557) +- Fix and test caching CNAME before DNAME (ISC change 4558) + +* Fri Jan 20 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-40 +- Fix possible infinite loop in start_lookup (CVE-2016-2775) +- Do not change lib permissions in chroot (#1392531) + +* Mon Jan 09 2017 Petr Menšík <pemensik@redhat.com> - 32:9.9.4-39 +- Fix CVE-2016-9131 (ISC change 4508) +- Fix CVE-2016-9147 (ISC change 4510) +- Fix regression introduced by CVE-2016-8864 (ISC change 4530) +- Fix CVE-2016-9444 (ISC change 4517) + +* Mon Oct 31 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-38 +- Fix CVE-2016-8864 + +* Fri Sep 23 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-37 +- Fix CVE-2016-2776 + +* Wed May 11 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-36 +- Added automatic interface scan functionality (#1294506) +- Removed NetworkManager dispatcher script since it is not needed any more (#1294506) + +* Wed Apr 13 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-35 +- Added GeoIP support (#1220594) + +* Fri Apr 01 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-34 +- Added support for CAA records (#1306610) +- Use HTTPS URL instead of FTP for upstream sources (#1319280) + +* Tue Mar 22 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-33 +- Fix excessive queries caused by DS chasing with stub zones when DNSSEC is not used (#1291185) +- Fix error in internal test suite (#1259514) +- Fix named-checkconf call in *-chroot.service files (#1278082) +- Fix incorrect path in BIND sample configuration and added comment to default configuration (#1247502) + +* Tue Mar 08 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-32 +- Fix CVE-2016-1285 and CVE-2016-1286 + +* Mon Jan 18 2016 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-31 +- Fix CVE-2015-8704 + +* Mon Dec 14 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-30 +- Fix CVE-2015-8000 + +* Wed Sep 02 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-29 +- Fix CVE-2015-5722 + +* Wed Aug 05 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-28 +- Increase ISC_SOCKET_MAXEVENTS to 2048 (#1235609) + +* Tue Jul 28 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-27 +- Fix CVE-2015-5477 + +* Wed Jul 08 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-26 +- Fix CVE-2015-4620 + +* Tue Jul 07 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-25 +- Fixed nsupdate realm auto-detection (#1214827) + +* Mon Jun 29 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-24 +- Reintroduce the DISABLE_ZONE_CHECKING into /etc/sysconfig/named (#1236475) + +* Mon Jun 01 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-23 +- Don't copy /etc/localtime on -chroot package installation (#1186773) +- Fix SPF resource records check to comply with RFC7208 (#1215164) +- Don't use ISC's DLV by default (#1223336) + +* Fri May 22 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-22 +- Add version specific requires on bind for bind-pkcs11 (Related: #1097753) +- Resolve issues found by static analysis (Related: #1097753) + +* Thu May 21 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-21 +- Added native PKCS#11 functionality (#1097753) + +* Wed May 20 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-20 +- DNS resolution failure in high load environment with SERVFAIL and "out of memory/success" in the log (#1221180) + +* Thu May 14 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-19 +- Install config for tmpfiles under %%{_tmpfilesdir} (#1180976) +- Fixed systemctl path in logrotate configuration (#1164264) +- remove information about system-config-bind from named.8 man page (#1152066) + +* Mon Mar 02 2015 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-18.1 +- Fix CVE-2015-1349 + +* Wed Dec 10 2014 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-18 +- Fix CVE-2014-8500 (#1171976) + +* Thu Sep 18 2014 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-17 +- Fix error in dyndb API that can cause named to freeze on shutdown (#1142150) +- Fix error in triggerun scriptlet (#1143033) +- Remove /var/named/chroot/var/run on bind-chroot update if it is a directory (#1091341) + +* Thu Aug 21 2014 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-16 +- Add versioned requires on bind-libs to bind-utils and bind-sdb + +* Wed Aug 20 2014 Tomas Hozza <thozza@redhat.com> - 32:9.9.4-15 +- Use /dev/urandom when generating rndc.key file (#1107568) +- Allow authentication using TSIG in allow-notify configuration statement (#1067424) +- Fix race condition when destroying a resolver fetch object (#1072379) +- Increase defaults for lwresd workers and make workers and client objects number configurable (#1098959) +- Configure BIND with --with-dlopen=yes to support dynamically loadable DLZ drivers (#1096688) + +* Fri Jan 24 2014 Daniel Mach <dmach@redhat.com> - 32:9.9.4-14 +- Mass rebuild 2014-01-24 + +* Wed Jan 15 2014 Honza Horak <hhorak@redhat.com> - 32:9.9.4-13 +- Rebuild for mariadb-libs + Related: #1045013 + +* Tue Jan 14 2014 Tomas Hozza <thozza@redhat.com> 32:9.9.4-12 +- Fix CVE-2014-0591 + +* Mon Jan 06 2014 Tomas Hozza <thozza@redhat.com> 32:9.9.4-11 +- Build against libdb instead of libdb4 (#1044990) + +* Fri Dec 27 2013 Daniel Mach <dmach@redhat.com> - 32:9.9.4-10 +- Mass rebuild 2013-12-27 + +* Wed Dec 18 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-9 +- Fix crash in rbtdb after two sucessive getoriginnode() calls (#1044026) + +* Tue Dec 17 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-8 +- Split chroot package for named and named-sdb +- Extract setting-up/destroying of chroot to a separate systemd service (#1004300) + +* Thu Dec 05 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-7 +- Create symlink /var/named/chroot/var/run -> /var/named/chroot/run (#1024384) +- Added session-keyfile statement into default named.conf since we use /run/named (#1024384) + +* Thu Nov 28 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-6 +- Fixed memory leak in nsupdate if 'realm' was used multiple times (#1034824) + +* Tue Nov 12 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-5 +- Install configuration for rwtab and fix chroot setup script (#1028189) +- use --enable-filter-aaaa when building bind to enable filter-aaaa-on-v4 option (#1025245) + +* Thu Oct 31 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-4 +- Correct the patch for #1020683 + +* Tue Oct 29 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-3 +- Fix race condition on send buffers in dighost.c (#1020683) + +* Tue Oct 08 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-2 +- install isc/errno2result.h header (#1015165) + +* Mon Sep 23 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.4-1 +- update to 9.9.4 (#1010200) +- drop merged patches +- modify patches to fit on new version + +* Tue Sep 10 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-8.P2 +- Fix [ISC-Bugs #34738] dns_journal_open() returns a pointer to stack + +* Fri Aug 16 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-7.P2 +- Don't generate rndc.key if there exists rndc.conf + +* Fri Aug 16 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-6.P2 +- don't install named-sdb.service if SDB macro is defined to zero + +* Sun Jul 28 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-5.P2 +- update to 9.9.3-P2 (fix for CVE-2013-4854) +- update RRL patch to 9.9.3-P2-rl.13207.22 +- Fix script for setting up chroot so it unmounts everything successfully + +* Wed Jul 10 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-4.P1 +- Fix dates in Changelog + +* Wed Jun 05 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-3.P1 +- update to 9.9.3-P1 (fix for CVE-2013-3919) +- update RRL patch to 9.9.3-P1-rl.156.01 + +* Mon Jun 03 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-2 +- bump release to prevent update path issues + +* Mon Jun 03 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-1 +- update to 9.9.3 +- install dns/update.h header +- update RRL patch to the latest version 9.9.3-rl.150.20 + +* Fri May 17 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-0.7.rc2 +- Fix segfault in host/nslookup (#878139) + +* Mon May 13 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-0.6.rc2 +- update to 9.9.3rc2 +- part of bind97-exportlib.patch not needed any more +- bind-9.9.1-P2-multlib-conflict.patch modified to reflect latest source +- rl-9.9.3rc1.patch -> rl-9.9.3rc2.patch +- bind99-opts.patch merged + +* Fri May 03 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-0.5.rc1 +- Include recursion Warning in named.conf and named.conf.sample (#740894) +- Include managed-keys-directory statement in named.conf.sample (#948026) + +* Thu May 02 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.3-0.4.rc1 +- Fix zone2sqlite to quote table names when creating/dropping/inserting (#919417) + +* Fri Apr 19 2013 Adam Tkac <atkac redhat com> 32:9.9.3-0.3.rc1 +- fix crash in nsupdate when processing "-r" parameter (#949544) + +* Tue Apr 16 2013 Adam Tkac <atkac redhat com> 32:9.9.3-0.2.rc1 +- ship dns/rrl.h in -devel subpkg + +* Tue Apr 16 2013 Adam Tkac <atkac redhat com> 32:9.9.3-0.1.rc1 +- update to 9.9.3rc1 +- bind-96-libtool2.patch has been merged +- fix bind tmpfiles.d for named.pid /run migration (#920713) + +* Wed Mar 27 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.2-12.P2 +- New upstream patch version fixing CVE-2013-2266 (#928032) + +* Tue Mar 19 2013 Adam Tkac <atkac redhat com> 32:9.9.2-11.P1 +- move pidfile to /run/named/named.pid + +* Wed Mar 06 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.2-10.P1 +- Fix Makefile.in to include header added by rate limiting patch (#918330) + +* Tue Mar 05 2013 Adam Tkac <atkac redhat com> 32:9.9.2-9.P1 +- drop some developer-only documentation and move ARM to %%docdir + +* Mon Feb 18 2013 Adam Tkac <atkac redhat com> 32:9.9.2-8.P1 +- include rate limiting patch + +* Tue Jan 29 2013 Tomas Hozza <thozza@redhat.com> 32:9.9.2-7.P1 +- Corrected IP addresses in named.ca (#901741) +- mount/umount /var/named in setup-named-chroot.sh as the last one (#904666) + +* Thu Dec 20 2012 Adam Tkac <atkac redhat com> 32:9.9.2-6.P1 +- generate /etc/rndc.key during named service startup if doesn't exist +- increase startup timeout in systemd units to 90sec (default) +- fix IDN related statement in dig.1 manpage + +* Wed Dec 05 2012 Tomas Hozza <thozza@redhat.com> 32:9.9.2-5.P1 +- update to bind-9.9.2-P1 + +* Mon Nov 12 2012 Adam Tkac <atkac redhat com> 32:9.9.2-4 +- document dig exit codes in manpage +- ignore empty "search" options in resolv.conf + +* Mon Nov 12 2012 Adam Tkac <atkac redhat com> 32:9.9.2-3 +- drop PKCS11 support on rhel + +* Thu Oct 11 2012 Adam Tkac <atkac redhat com> 32:9.9.2-2 +- install isc/stat.h + +* Thu Oct 11 2012 Adam Tkac <atkac redhat com> 32:9.9.2-1 +- update to 9.9.2 +- bind97-rh714049.patch has been dropped +- patches merged + - bind98-rh816164.patch + +* Thu Sep 13 2012 Adam Tkac <atkac redhat com> 32:9.9.1-10.P3 +- update to bind-9.9.1-P3 + +* Wed Aug 22 2012 Tomas Hozza <thozza@redhat.com> 32:9.9.1-9.P2 +- fixed SPEC file so it comply with new systemd-rpm macros guidelines (#850045) +- changed %%define macros to %%global and fixed several rpmlint warnings + +* Wed Aug 08 2012 Tomas Hozza <thozza@redhat.com> 32:9.9.1-8.P2 +- Changed PrivateTmp to "false" in *-chroot.service unit files (#825869) + +* Wed Aug 01 2012 Tomas Hozza <thozza@redhat.com> 32:9.9.1-7.P2 +- Fixed bind-devel multilib conflict (#478718) + +* Mon Jul 30 2012 Tomas Hozza <thozza@redhat.com> 32:9.9.1-6.P2 +- Fixed bad path to systemctl in /etc/NetworkManager/dispatcher.d/13-named (#844047) +- Fixed path to libdb.so in config.dlz.in + +* Thu Jul 26 2012 Adam Tkac <atkac redhat com> 32:9.9.1-5.P2 +- update to 9.9.1-P2 + +* Wed Jul 18 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 32:9.9.1-4.P1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Wed Jul 11 2012 Ville Skyttä <ville.skytta@iki.fi> - 32:9.9.1-3.P1 +- Avoid shell invocation and dep for -libs-lite %%postun. + +* Mon Jun 04 2012 Adam Tkac <atkac redhat com> 32:9.9.1-2.P1 +- update to 9.9.1-P1 (CVE-2012-1667) + +* Thu May 24 2012 Adam Tkac <atkac redhat com> 32:9.9.1-1 +- update to 9.9.1 +- bind99-coverity.patch merged +- bind-9.5-overflow.patch merged + +* Mon May 07 2012 Adam Tkac <atkac redhat com> 32:9.9.0-6 +- nslookup: return non-zero exit code when fail to get answer (#816164) + +* Thu Apr 26 2012 Adam Tkac <atkac redhat com> 32:9.9.0-5 +- initscript: don't umount /var/named when didn't mount it + +* Tue Apr 24 2012 Adam Tkac <atkac redhat com> 32:9.9.0-4 +- apply all non-SDB patches before SDB ones (#804475) +- enable Berkeley DB DLZ backend (#804478) + +* Thu Apr 12 2012 Adam Tkac <atkac redhat com> 32:9.9.0-3 +- bind97-rh699951.patch is no longer needed (different fix is in 9.9.0) + +* Mon Mar 26 2012 Adam Tkac <atkac redhat com> 32:9.9.0-2 +- remove unneeded bind99-v6only.patch + +* Mon Mar 05 2012 Adam Tkac <atkac redhat com> 32:9.9.0-1 +- update to 9.9.0 +- load dynamic DBs later (and update dyndb patch) +- fix memory leak in named during processing of rndc command +- don't call `rndc-confgen -a` in "post" section +- fix some packaging bugs in bind-chroot + +* Wed Feb 15 2012 Adam Tkac <atkac redhat com> 32:9.9.0-0.8.rc2 +- build with "--enable-fixed-rrset" + +* Wed Feb 01 2012 Adam Tkac <atkac redhat com> 32:9.9.0-0.7.rc2 +- update to 9.9.0rc2 +- doc/rfc and doc/draft are no longer shipped in tarball + +* Mon Jan 30 2012 Adam Tkac <atkac redhat com> 32:9.9.0-0.6.rc1 +- retire initscript in favour of systemd unit files (#719419) + +* Thu Jan 12 2012 Adam Tkac <atkac redhat com> 32:9.9.0-0.5.rc1 +- update to 9.9.0rc1 + +* Wed Dec 07 2011 Adam Tkac <atkac redhat com> 32:9.9.0-0.4.b2 +- ship dns/forward.h in -devel subpkg + +* Tue Nov 22 2011 Adam Tkac <atkac redhat com> 32:9.9.0-0.3.b2 +- update to 9.9.0b2 (CVE-2011-4313) +- patches merged + - bind97-rh700097.patch + - bind99-cinfo.patch + +* Mon Nov 14 2011 Adam Tkac <atkac redhat com> 32:9.9.0-0.2.b1 +- ship dns/clientinfo.h in bind-devel + +* Fri Nov 11 2011 Adam Tkac <atkac redhat com> 32:9.9.0-0.1.b1 +- update to 9.9.0b1 +- bind98-dlz_buildfix.patch merged + +* Fri Oct 28 2011 Adam Tkac <atkac redhat com> 32:9.8.1-4 +- nslookup failed to resolve name in certain cases + +* Mon Sep 26 2011 Adam Tkac <atkac redhat com> 32:9.8.1-3 +- remove deps filter, it is no longer needed (#739663) + +* Fri Sep 09 2011 Adam Tkac <atkac redhat com> 32:9.8.1-2 +- fix logrotate config file (#725256) + +* Wed Sep 07 2011 Adam Tkac <atkac redhat com> 32:9.8.1-1 +- update to 9.8.1 +- ship /etc/trusted-key.key (needed by dig) +- use select instead of epoll in export libs (#735103) + +* Wed Aug 31 2011 Adam Tkac <atkac redhat com> 32:9.8.1-0.3.rc1 +- fix DLZ related compilation issues +- make /etc/named.{root,iscdlv}.key world-readable +- add bind-libs versioned requires to bind pkg + +* Wed Aug 31 2011 Adam Tkac <atkac redhat com> 32:9.8.1-0.2.rc1 +- fix rare race condition in request.c +- print "the working directory is not writable" as debug message +- re-add configtest target to initscript +- initscript: sybsys name is always named, not named-sdb +- nsupdate returned zero when target zone didn't exist (#700097) +- nsupdate could have failed if server has multiple IPs and the first + was unreachable (#714049) + +* Wed Aug 31 2011 Adam Tkac <atkac redhat com> 32:9.8.1-0.1.rc1 +- update to 9.8.1rc1 +- patches merged + - bind97-rh674334.patch + - bind97-cleanup.patch + - bind98-includes.patch + +* Wed Aug 03 2011 Adam Tkac <atkac redhat com> 32:9.8.0-9.P4 +- improve patch for #725741 + +* Tue Jul 26 2011 Adam Tkac <atkac redhat com> 32:9.8.0-8.P4 +- named could have crashed during reload when dyndb module is used (#725741) + +* Tue Jul 05 2011 Adam Tkac <atkac redhat com> 32:9.8.0-7.P4 +- update to 9.8.0-P4 + - bind98-libdns-export.patch merged + +* Thu Jun 02 2011 Adam Tkac <atkac redhat com> 32:9.8.0-6.P2 +- update the dyndb patch + +* Fri May 27 2011 Adam Tkac <atkac redhat com> 32:9.8.0-5.P2 +- fix compilation of libdns-export.so + +* Fri May 27 2011 Adam Tkac <atkac redhat com> 32:9.8.0-4.P2 +- update to 9.8.0-P2 (CVE-2011-1910) + +* Fri May 06 2011 Adam Tkac <atkac redhat com> 32:9.8.0-3.P1 +- update to 9.8.0-P1 (CVE-2011-1907) + +* Wed Mar 23 2011 Dan Horák <dan@danny.cz> - 32:9.8.0-2 +- rebuilt for mysql 5.5.10 (soname bump in libmysqlclient) + +* Thu Mar 03 2011 Adam Tkac <atkac redhat com> 32:9.8.0-1 +- update to 9.8.0 +- bind97-rh665971.patch merged + +* Thu Mar 03 2011 Adam Tkac <atkac redhat com> 32:9.8.0-0.4.rc1 +- revert previous change (integration with libnmserver) + +* Tue Feb 22 2011 Adam Tkac <atkac redhat com> 32:9.8.0-0.3.rc1 +- integrate named with libnmserver library + +* Tue Feb 22 2011 Adam Tkac <atkac redhat com> 32:9.8.0-0.2.rc1 +- include dns/rpz.h in -devel subpkg + +* Mon Feb 21 2011 Adam Tkac <atkac redhat com> 32:9.8.0-0.1.rc1 +- update to 9.8.0rc1 + +* Fri Feb 18 2011 Adam Tkac <atkac redhat com> 32:9.7.3-1 +- update to 9.7.3 +- fix dig +trace on dualstack systems (#674334) +- fix linkage order when building on system with older BIND (#665971) +- reduce number of gcc warnings + +* Mon Feb 07 2011 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 32:9.7.3-0.6.rc1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Tue Jan 25 2011 Adam Tkac <atkac redhat com> 32:9.7.3-0.5.rc1 +- update to 9.7.3rc1 + - bind97-krb5-self.patch merged + +* Wed Jan 12 2011 Adam Tkac <atkac redhat com> 32:9.7.3-0.4.b1 +- fix typo in initscript + +* Thu Jan 06 2011 Adam Tkac <atkac redhat com> 32:9.7.3-0.3.b1 +- fix "service named status" when used with named-sdb +- don't check MD5, size and mtime of sysconfig/named + +* Wed Jan 05 2011 Adam Tkac <atkac redhat com> 32:9.7.3-0.2.b1 +- add new option DISABLE_ZONE_CHECKING to sysconfig/named + +* Wed Jan 05 2011 Adam Tkac <atkac redhat com> 32:9.7.3-0.1.b1 +- update to 9.7.3b1 + +* Wed Jan 05 2011 Adam Tkac <atkac redhat com> 32:9.7.2-10.P3 +- initscript should terminate only the correct "named" process (#622785) + +* Mon Dec 20 2010 Adam Tkac <atkac redhat com> 32:9.7.2-9.P3 +- fix "krb5-self" update-policy rule processing + +* Thu Dec 02 2010 Adam Tkac <atkac redhat com> 32:9.7.2-8.P3 +- update to 9.7.2-P3 + +* Mon Nov 29 2010 Jan Görig <jgorig redhat com> 32:9.7.2-7.P2 +- added tmpfiles.d support (#656550) +- removed old PID checking in initscript + +* Mon Nov 08 2010 Adam Tkac <atkac redhat com> 32:9.7.2-6.P2 +- don't emit various informational messages by default (#645544) + +* Wed Oct 20 2010 Adam Tkac <atkac redhat com> 32:9.7.2-5.P2 +- move BIND9 internal libs back to %%{_libdir} +- add "-export" suffix to public libraries (-lite subpkg) + +* Thu Oct 07 2010 Adam Tkac <atkac redhat com> 32:9.7.2-4.P2 +- ship -devel subpkg for internal libs, dnsperf needs it + +* Thu Oct 07 2010 Adam Tkac <atkac redhat com> 32:9.7.2-3.P2 +- new bind-libs-lite and bind-lite-devel subpkgs which contain + public version of BIND 9 libraries +- don't ship devel files for internal version of BIND 9 libraries + +* Wed Sep 29 2010 Adam Tkac <atkac redhat com> 32:9.7.2-2.P2 +- update to 9.7.2-P2 + +* Thu Sep 16 2010 Adam Tkac <atkac redhat com> 32:9.7.2-1 +- update to 9.7.2 + +* Fri Aug 27 2010 Adam Tkac <atkac redhat com> 32:9.7.2-0.3.rc1 +- update to 9.7.2rc1 + +* Tue Aug 10 2010 Adam Tkac <atkac redhat com> 32:9.7.2-0.2.b1 +- host: handle "debug", "attempts" and "timeout" options in resolv.conf well + +* Tue Aug 03 2010 Adam Tkac <atkac redhat com> 32:9.7.2-0.1.b1 +- update to 9.7.2b1 +- patches merged + - bind97-rh507429.patch + +* Mon Jul 19 2010 Adam Tkac <atkac redhat com> 32:9.7.1-5.P2 +- supply root zone DNSKEY in default configuration + +* Mon Jul 19 2010 Adam Tkac <atkac redhat com> 32:9.7.1-4.P2 +- update to 9.7.1-P2 (CVE-2010-0213) + +* Mon Jul 12 2010 Adam Tkac <atkac redhat com> 32:9.7.1-3.P1 +- remove outdated Copyright.caching-nameserver file +- remove rfc1912.txt, it is already located in %%doc/rfc directory +- move COPYRIGHT to the bind-libs subpkg +- add COPYRIGHT to the -pkcs11 subpkg + +* Fri Jul 09 2010 Adam Tkac <atkac redhat com> 32:9.7.1-2.P1 +- update to 9.7.1-P1 + +* Mon Jun 28 2010 Adam Tkac <atkac redhat com> 32:9.7.1-1 +- update to 9.7.1 +- improve the "dnssec-conf" trigger + +* Wed Jun 09 2010 Adam Tkac <atkac redhat com> 32:9.7.1-0.2.rc1 +- update to 9.7.1rc1 +- patches merged + - bind97-keysdir.patch + +* Mon May 31 2010 Adam Tkac <atkac redhat com> 32:9.7.1-0.1.b1 +- update to 9.7.1b1 +- make /var/named/dynamic as a default directory for managed DNSSEC keys +- add patch to get "managed-keys-directory" option working +- patches merged + - bind97-managed-keyfile.patch + - bind97-rh554316.patch + +* Fri May 21 2010 Adam Tkac <atkac redhat com> 32:9.7.0-11.P2 +- update dnssec-conf Obsoletes/Provides + +* Thu May 20 2010 Adam Tkac <atkac redhat com> 32:9.7.0-10.P2 +- update to 9.7.0-P2 + +* Fri Mar 26 2010 Adam Tkac <atkac redhat com> 32:9.7.0-9.P1 +- added lost patch for #554316 (occasional crash in keytable.c) + +* Fri Mar 26 2010 Adam Tkac <atkac redhat com> 32:9.7.0-8.P1 +- active query might be destroyed in resume_dslookup() which triggered REQUIRE + failure (#507429) + +* Mon Mar 22 2010 Adam Tkac <atkac redhat com> 32:9.7.0-7.P1 +- install SDB related manpages only when build with SDB + +* Fri Mar 19 2010 Adam Tkac <atkac redhat com> 32:9.7.0-6.P1 +- update to 9.7.0-P1 + +* Tue Mar 16 2010 Jan Görig <jgorig redhat com> 32:9.7.0-5 +- bind-sdb now requires bind + +* Mon Mar 15 2010 Jan Görig <jgorig redhat com> 32:9.7.0-4 +- add man-pages ldap2zone.1 zonetodb.1 zone2sqlite.1 named-sdb.8 (#525655) + +* Mon Mar 01 2010 Adam Tkac <atkac redhat com> 32:9.7.0-3 +- fix multilib issue (#478718) [jgorig] + +* Mon Mar 01 2010 Adam Tkac <atkac redhat com> 32:9.7.0-2 +- improve automatic DNSSEC reconfiguration trigger +- initscript now returns 2 in case that action doesn't exist (#523435) +- enable/disable chroot when bind-chroot is installed/uninstalled + +* Wed Feb 17 2010 Adam Tkac <atkac redhat com> 32:9.7.0-1 +- update to 9.7.0 final + +* Mon Feb 15 2010 Adam Tkac <atkac redhat com> 32:9.7.0-0.14.rc2 +- obsolete dnssec-conf +- automatically update configuration from old dnssec-conf based +- improve default configuration; enable DLV by default +- remove obsolete triggerpostun from bind-libs subpackage + +* Thu Jan 28 2010 Adam Tkac <atkac redhat com> 32:9.7.0-0.13.rc2 +- update to 9.7.0rc2 + +* Wed Jan 27 2010 Adam Tkac <atkac redhat com> 32:9.7.0-0.12.rc1 +- initscript LSB related fixes (#523435) + +* Wed Jan 27 2010 Adam Tkac <atkac redhat com> 32:9.7.0-0.11.rc1 +- revert the "DEBUG" feature (#510283), it causes too many problems (#545128) + +* Tue Dec 15 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.10.rc1 +- update to 9.7.0rc1 +- bind97-headers.patch merged +- update default configuration + +* Tue Dec 01 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.9.b3 +- update to 9.7.0b3 + +* Thu Nov 26 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.8.b2 +- install isc/namespace.h header + +* Fri Nov 06 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.7.b2 +- update to 9.7.0b2 + +* Tue Nov 03 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.6.b1 +- update to 9.7.0b1 +- add bind-pkcs11 subpackage to support PKCS11 compatible keystores for DNSSEC + keys + +* Thu Oct 08 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.5.a3 +- don't package named-bootconf utility, it is very outdated and unneeded + +* Mon Sep 21 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.4.a3 +- determine file size via `stat` instead of `ls` (#523682) + +* Wed Sep 16 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.3.a3 +- update to 9.7.0a3 + +* Tue Sep 15 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.2.a2 +- improve chroot related documentation (#507795) +- add NetworkManager dispatcher script to reload named when network interface is + activated/deactivated (#490275) +- don't set/unset named_write_master_zones SELinux boolean every time in + initscript, modify it only when it's actually needed + +* Tue Sep 15 2009 Adam Tkac <atkac redhat com> 32:9.7.0-0.1.a2 +- update to 9.7.0a2 +- merged patches + - bind-96-db_unregister.patch + - bind96-rh507469.patch + +* Tue Sep 01 2009 Adam Tkac <atkac redhat com> 32:9.6.1-9.P1 +- next attempt to fix the postun trigger (#520385) +- remove obsolete bind-9.3.1rc1-fix_libbind_includedir.patch + +* Fri Aug 21 2009 Tomas Mraz <tmraz@redhat.com> - 32:9.6.1-8.P1 +- rebuilt with new openssl + +* Tue Aug 04 2009 Martin Nagy <mnagy redhat com> 32:9.6.1-7.P1 +- update the patch for dynamic loading of database backends + +* Wed Jul 29 2009 Adam Tkac <atkac redhat com> 32:9.6.1-6.P1 +- 9.6.1-P1 release (CVE-2009-0696) +- fix postun trigger (#513016, hopefully) + +* Fri Jul 24 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 32:9.6.1-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Mon Jul 20 2009 Adam Tkac <atkac redhat com> 32:9.6.1-4 +- remove useless bind-9.3.3rc2-rndckey.patch + +* Mon Jul 13 2009 Adam Tkac <atkac redhat com> 32:9.6.1-3 +- fix broken symlinks in bind-libs (#509635) +- fix typos in /etc/sysconfig/named (#509650) +- add DEBUG option to /etc/sysconfig/named (#510283) + +* Wed Jun 24 2009 Adam Tkac <atkac redhat com> 32:9.6.1-2 +- improved "chroot automount" patches (#504596) +- host should fail if specified server doesn't respond (#507469) + +* Wed Jun 17 2009 Adam Tkac <atkac redhat com> 32:9.6.1-1 +- 9.6.1 release +- simplify chroot maintenance. Important files and directories are mounted into + chroot (see /etc/sysconfig/named for more info, #504596) +- fix doc/named.conf.default perms + +* Wed May 27 2009 Adam Tkac <atkac redhat com> 32:9.6.1-0.4.rc1 +- 9.6.1rc1 release + +* Wed Apr 29 2009 Martin Nagy <mnagy redhat com> 32:9.6.1-0.3.b1 +- update the patch for dynamic loading of database backends +- create %%{_libdir}/bind directory +- copy default named.conf to doc directory, shared with s-c-bind (atkac) + +* Fri Apr 24 2009 Martin Nagy <mnagy redhat com> 32:9.6.1-0.2.b1 +- update the patch for dynamic loading of database backends +- fix dns_db_unregister() +- useradd now takes "-N" instead of "-n" (atkac, #495726) +- print nicer error msg when zone file is actually a directory (atkac, #490837) + +* Mon Mar 30 2009 Adam Tkac <atkac redhat com> 32:9.6.1-0.1.b1 +- 9.6.1b1 release +- patches merged + - bind-96-isc_header.patch + - bind-95-rh469440.patch + - bind-96-realloc.patch + - bind9-fedora-0001.diff +- use -version-number instead of -version-info libtool param + +* Mon Mar 23 2009 Adam Tkac <atkac redhat com> 32:9.6.0-11.1.P1 +- logrotate configuration file now points to /var/named/data/named.run by + default (#489986) + +* Tue Mar 17 2009 Adam Tkac <atkac redhat com> 32:9.6.0-11.P1 +- fall back to insecure mode when no supported DNSSEC algorithm is found + instead of SERVFAIL +- don't fall back to non-EDNS0 queries when DO bit is set + +* Tue Mar 10 2009 Adam Tkac <atkac redhat com> 32:9.6.0-10.P1 +- enable DNSSEC only if it is enabled in sysconfig/dnssec + +* Mon Mar 09 2009 Adam Tkac <atkac redhat com> 32:9.6.0-9.P1 +- add DNSSEC support to initscript, enabled it per default +- add requires dnssec-conf + +* Mon Mar 09 2009 Adam Tkac <atkac redhat com> 32:9.6.0-8.P1 +- fire away libbind, it is now separate package + +* Wed Mar 04 2009 Adam Tkac <atkac redhat com> 32:9.6.0-7.P1 +- fixed some read buffer overflows (upstream) + +* Mon Feb 23 2009 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> 32:9.6.0-6.P1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_11_Mass_Rebuild + +* Thu Feb 12 2009 Martin Nagy <mnagy redhat com> 32:9.6.0-5.P1 +- update the patch for dynamic loading of database backends +- include iterated_hash.h + +* Sat Jan 24 2009 Caolán McNamara <caolanm@redhat.com> 32:9.6.0-4.P1 +- rebuild for dependencies + +* Wed Jan 21 2009 Adam Tkac <atkac redhat com> 32:9.6.0-3.P1 +- rebuild against new openssl + +* Thu Jan 08 2009 Adam Tkac <atkac redhat com> 32:9.6.0-2.P1 +- 9.6.0-P1 release (CVE-2009-0025) + +* Mon Jan 05 2009 Adam Tkac <atkac redhat com> 32:9.6.0-1 +- Happy new year +- 9.6.0 release + +* Thu Dec 18 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.7.rc2 +- 9.6.0rc2 release +- bind-96-rh475120.patch merged + +* Tue Dec 16 2008 Martin Nagy <mnagy redhat com> 32:9.6.0-0.6.rc1 +- add patch for dynamic loading of database backends + +* Tue Dec 09 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.5.1.rc1 +- allow to reuse address for non-random query-source ports (#475120) + +* Wed Dec 03 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.5.rc1 +- 9.6.0rc1 release +- patches merged + - bind-9.2.0rc3-varrun.patch + - bind-95-sdlz-include.patch + - bind-96-libxml2.patch +- fixed rare use-after-free problem in host utility (#452060) +- enabled chase of DNSSEC signature chains in dig + +* Mon Dec 01 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.4.1.b1 +- improved sample config file (#473586) + +* Wed Nov 26 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.4.b1 +- reverted previous change, koji doesn't like it + +* Wed Nov 26 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.3.b1 +- build bind-chroot as noarch + +* Mon Nov 24 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.2.1.b1 +- updates due libtool 2.2.6 +- don't pass -DLDAP_DEPRECATED to cpp, handle it directly in sources + +* Tue Nov 11 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.2.b1 +- make statistics http server working, patch backported from 9.6 HEAD + +* Mon Nov 10 2008 Adam Tkac <atkac redhat com> 32:9.6.0-0.1.b1 +- 9.6.0b1 release +- don't build ODBC and Berkeley DB DLZ drivers +- end of bind-chroot-admin script, copy config files to chroot manually +- /proc doesn't have to be mounted to chroot +- temporary use libbind from 9.5 series, noone has been released for 9.6 yet + +* Mon Nov 03 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.8.4.b2 +- dig/host: use only IPv4 addresses when -4 option is specified (#469440) + +* Thu Oct 30 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.8.2.b2 +- removed unneeded bind-9.4.1-ldap-api.patch + +* Thu Oct 30 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.8.1.b2 +- ship dns/{s,}dlz.h and isc/radix.h in bind-devel + +* Tue Oct 07 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.8.b2 +- removed bind-9.4.0-dnssec-directory.patch, it is wrong + +* Wed Sep 24 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.7.b2 +- 9.5.1b2 release +- patches merged + - bind95-rh454783.patch + - bind-9.5-edns.patch + - bind95-rh450995.patch + - bind95-rh457175.patch + +* Wed Sep 17 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.6.b1 +- IDN output strings didn't honour locale settings (#461409) + +* Tue Aug 05 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.5.b1 +- disable transfer stats on DLZ zones (#454783) + +* Mon Aug 04 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.4.b1 +- add forgotten patch for #457175 +- build with -O2 + +* Thu Jul 31 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.3.b1 +- static libraries are no longer supported +- IP acls weren't merged correctly (#457175) +- use fPIE on sparcv9/sparc64 (Dennis Gilmore) +- add sparc64 to list of 64bit arches in spec (Dennis Gilmore) + +* Mon Jul 21 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.2.b1 +- updated patches due new rpm (--fuzz=0 patch parameter) + +* Mon Jul 14 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.1.1.b1 +- use %%patch0 for Patch0 (#455061) +- correct source address (#455118) + +* Tue Jul 08 2008 Adam Tkac <atkac redhat com> 32:9.5.1-0.1.b1 +- 9.5.1b1 release (CVE-2008-1447) +- dropped bind-9.5-recv-race.patch because upstream doesn't want it + +* Mon Jun 30 2008 Adam Tkac <atkac redhat com> 32:9.5.0-37.1 +- update default named.conf statements (#452708) + +* Thu Jun 26 2008 Adam Tkac <atkac redhat com> 32:9.5.0-37 +- some compat changes to fix building on RHEL4 + +* Mon Jun 23 2008 Adam Tkac <atkac redhat com> 32:9.5.0-36.3 +- fixed typo in %%posttrans script + +* Wed Jun 18 2008 Adam Tkac <atkac redhat com> 32:9.5.0-36.2 +- parse inner acls correctly (#450995) + +* Mon Jun 02 2008 Adam Tkac <atkac redhat com> 32:9.5.0-36.1 +- removed dns-keygen utility in favour of rndc-confgen -a (#449287) +- some minor sample fixes (#449274) + +* Thu May 29 2008 Adam Tkac <atkac redhat com> 32:9.5.0-36 +- updated to 9.5.0 final +- use getifaddrs to find available interfaces + +* Mon May 26 2008 Adam Tkac <atkac redhat com> 32:9.5.0-35.rc1 +- make /var/run/named writable by named (#448277) +- fixed one non-utf8 file + +* Thu May 22 2008 Adam Tkac <atkac redhat com> 32:9.5.0-34.rc1 +- fixes needed to pass package review (#225614) + +* Wed May 21 2008 Adam Tkac <atkac redhat com> 32:9.5.0-33.1.rc1 +- bind-chroot now depends on bind (#446477) + +* Wed May 14 2008 Adam Tkac <atkac redhat com> 32:9.5.0-33.rc1 +- updated to 9.5.0rc1 +- merged patches + - bind-9.5-libcap.patch +- make binaries readable by others (#427826) + +* Tue May 13 2008 Adam Tkac <atkac redhat com> 32:9.5.0-32.b3 +- reverted "any" patch, upstream says not needed +- log EDNS failure only when we really switch to plain EDNS (#275091) +- detect configuration file better + +* Tue May 06 2008 Adam Tkac <atkac redhat com> 32:9.5.0-31.1.b3 +- addresses 0.0.0.0 and ::0 really match any (#275091, comment #28) + +* Mon May 05 2008 Adam Tkac <atkac redhat com> 32:9.5.0-31.b3 +- readded bind-9.5-libcap.patch +- added bind-9.5-recv-race.patch from F8 branch (#400461) + +* Wed Apr 23 2008 Adam Tkac <atkac redhat com> 32:9.5.0-30.1.b3 +- build Berkeley DB DLZ backend + +* Mon Apr 21 2008 Adam Tkac <atkac redhat com> 32:9.5.0-30.b3 +- 9.5.0b3 release +- dropped patches (upstream) + - bind-9.5-transfer-segv.patch + - bind-9.5-mudflap.patch + - bind-9.5.0-generate-xml.patch + - bind-9.5-libcap.patch + +* Wed Apr 02 2008 Adam Tkac <atkac redhat com> 32:9.5.0-29.3.b2 +- fixed named.conf.sample file (#437569) + +* Fri Mar 14 2008 Adam Tkac <atkac redhat com> 32:9.5.0-29.2.b2 +- fixed URLs + +* Mon Feb 25 2008 Adam Tkac <atkac redhat com> 32:9.5.0-29.1.b2 +- BuildRequires cleanup + +* Sun Feb 24 2008 Adam Tkac <atkac redhat com> 32:9.5.0-29.b2 +- rebuild without mudflap (#434159) + +* Wed Feb 20 2008 Adam Tkac <atkac redhat com> 32:9.5.0-28.b2 +- port named to use libcap library, enable threads (#433102) +- removed some unneeded Requires + +* Tue Feb 19 2008 Adam Tkac <atkac redhat com> 32:9.5.0-27.b2 +- removed conditional build with libefence (use -fmudflapth instead) +- fixed building of DLZ stuff (#432497) +- do not build Berkeley DB DLZ backend +- temporary build with --disable-linux-caps and without threads (#433102) +- update named.ca file to affect IPv6 changes in root zone + +* Mon Feb 11 2008 Adam Tkac <atkac redhat com> 32:9.5.0-26.b2 +- build with -D_GNU_SOURCE (#431734) +- improved fix for #253537, posttrans script is now used +- improved fix for #400461 +- 9.5.0b2 + - bind-9.3.2b1-PIE.patch replaced by bind-9.5-PIE.patch + - only named, named-sdb and lwresd are PIE + - bind-9.5-sdb.patch has been updated + - bind-9.5-libidn.patch has been updated + - bind-9.4.0-sdb-sqlite-bld.patch replaced by bind-9.5-sdb-sqlite-bld.patch + - removed bind-9.5-gssapi-header.patch (upstream) + - removed bind-9.5-CVE-2008-0122.patch (upstream) +- removed bind-9.2.2-nsl.patch +- improved sdb_tools Makefile.in + +* Mon Feb 04 2008 Adam Tkac <atkac redhat com> 32:9.5.0-25.b1 +- fixed segfault during sending notifies (#400461) +- rebuild with gcc 4.3 series + +* Tue Jan 22 2008 Adam Tkac <atkac redhat com> 32:9.5.0-24.b1 +- removed bind-9.3.2-prctl_set_dumpable.patch (upstream) +- allow parallel building of libdns library +- CVE-2008-0122 + +* Thu Dec 27 2007 Adam Tkac <atkac redhat com> 32:9.5.0-23.b1 +- fixed initscript wait loop (#426382) +- removed dependency on policycoreutils and libselinux (#426515) + +* Thu Dec 20 2007 Adam Tkac <atkac redhat com> 32:9.5.0-22.b1 +- fixed regression caused by libidn2 patch (#426348) + +* Wed Dec 19 2007 Adam Tkac <atkac redhat com> 32:9.5.0-21.b1 +- fixed typo in post section (CVE-2007-6283) + +* Wed Dec 19 2007 Adam Tkac <atkac redhat com> 32:9.5.0-20.b1 +- removed obsoleted triggers +- CVE-2007-6283 + +* Wed Dec 12 2007 Adam Tkac <atkac redhat com> 32:9.5.0-19.2.b1 +- added dst/gssapi.h to -devel subpackage (#419091) +- improved fix for (#417431) + +* Mon Dec 10 2007 Adam Tkac <atkac redhat com> 32:9.5.0-19.1.b1 +- fixed shutdown with initscript when rndc doesn't work (#417431) +- fixed IDN patch (#412241) + +* Thu Dec 06 2007 Adam Tkac <atkac redhat com> 32:9.5.0-19.b1 +- 9.5.0b1 (#405281, #392491) + +* Thu Dec 06 2007 Release Engineering <rel-eng at fedoraproject dot org> 32:9.5.0-18.6.a7 +- Rebuild for deps + +* Wed Dec 05 2007 Adam Tkac <atkac redhat com> 32:9.5.0-18.5.a7 +- build with -O0 + +* Mon Dec 03 2007 Adam Tkac <atkac redhat com> 32:9.5.0-18.4.a7 +- bind-9.5-random_ports.patch was removed because upstream doesn't + like it. query-source{,v6} options are sufficient (#391931) +- bind-chroot-admin called restorecon on /proc filesystem (#405281) + +* Mon Nov 26 2007 Adam Tkac <atkac redhat com> 32:9.5.0-18.3.a7 +- removed edns patch to keep compatibility with vanilla bind + (#275091, comment #20) + +* Wed Nov 21 2007 Adam Tkac <atkac redhat com> 32:9.5.0-18.2.a7 +- use system port selector instead ISC's (#391931) + +* Mon Nov 19 2007 Adam Tkac <atkac redhat com> 32:9.5.0-18.a7 +- removed statement from initscript which passes -D to named + +* Thu Nov 15 2007 Adam Tkac <atkac redhat com> 32:9.5.0-17.a7 +- 9.5.0a7 +- dropped patches (upstream) + - bind-9.5-update.patch + - bind-9.5-pool_badfree.patch + - bind-9.5-_res_errno.patch + +* Thu Nov 15 2007 Adam Tkac <atkac redhat com> 32:9.5.0-16.5.a6 +- added bind-sdb again, contains SDB modules and DLZ modules +- bind-9.3.1rc1-sdb.patch replaced by bind-9.5-sdb.patch + +* Mon Nov 12 2007 Adam Tkac <atkac redhat com> 32:9.5.0-16.4.a6 +- removed Requires: openldap, postgresql, mysql, db4, unixODBC +- new L.ROOT-SERVERS.NET address + +* Mon Oct 29 2007 Adam Tkac <atkac redhat com> 32:9.5.0-16.3.a6 +- completely disable DBUS + +* Fri Oct 26 2007 Adam Tkac <atkac redhat com> 32:9.5.0-16.2.a6 +- minor cleanup in bind-chroot-admin + +* Thu Oct 25 2007 Adam Tkac <atkac redhat com> 32:9.5.0-16.1.a6 +- fixed typo in initscript + +* Tue Oct 23 2007 Adam Tkac <atkac redhat com> 32:9.5.0-16.a6 +- disabled DBUS (dhcdbd doesn't exist & #339191) + +* Thu Oct 18 2007 Adam Tkac <atkac redhat com> 32:9.5.0-15.1.a6 +- fixed missing va_end () functions (#336601) +- fixed memory leak when dbus initialization fails + +* Tue Oct 16 2007 Adam Tkac <atkac redhat com> 32:9.5.0-15.a6 +- corrected named.5 SDB statement (#326051) + +* Mon Sep 24 2007 Adam Tkac <atkac redhat com> 32:9.5.0-14.a6 +- added edns patch again (#275091) + +* Mon Sep 24 2007 Adam Tkac <atkac redhat com> 32:9.5.0-13.a6 +- removed bind-9.3.3-edns.patch patch (see #275091 for reasons) + +* Thu Sep 20 2007 Adam Tkac <atkac redhat com> 32:9.5.0-12.4.a6 +- build with O2 +- removed "autotools" patch +- bugfixing in bind-chroot-admin (#279901) + +* Thu Sep 06 2007 Adam Tkac <atkac redhat com> 32:9.5.0-12.a6 +- bind-9.5-2119_revert.patch and bind-9.5-fix_h_errno.patch are + obsoleted by upstream bind-9.5-_res_errno.patch + +* Wed Sep 05 2007 Adam Tkac <atkac redhat com> 32:9.5.0-11.9.a6 +- fixed wrong resolver's dispatch pool cleanup (#275011, patch from + tmraz redhat com) + +* Wed Sep 05 2007 Adam Tkac <atkac redhat com> 32:9.5.0-11.3.a6 +- initscript failure message is now printed correctly (#277981, + Quentin Armitage (quentin armitage org uk) ) + +* Mon Sep 03 2007 Adam Tkac <atkac redhat com> 32:9.5.0-11.2.a6 +- temporary revert ISC 2119 change and add "libbind-errno" patch + (#254501) again + +* Thu Aug 23 2007 Adam Tkac <atkac redhat com> 32:9.5.0-11.1.a6 +- removed end dots from Summary sections (skasal@redhat.com) +- fixed wrong file creation by autotools patch (skasal@redhat.com) + +* Thu Aug 23 2007 Adam Tkac <atkac redhat com> 32:9.5.0-11.a6 +- start using --disable-isc-spnego configure option + - remove bind-9.5-spnego-memory_management.patch (source isn't + compiled) + +* Wed Aug 22 2007 Adam Tkac <atkac redhat com> 32:9.5.0-10.2.a6 +- added new initscript option KEYTAB_FILE which specified where + is located kerberos .keytab file for named service +- obsolete temporary bind-9.5-spnego-memory_management.patch by + bind-9.5-gssapictx-free.patch which conforms BIND coding standards + (#251853) + +* Tue Aug 21 2007 Adam Tkac <atkac redhat com> 32:9.5.0-10.a6 +- dropped direct dependency to /etc/openldap/schema directory +- changed hardcoded paths to macros +- fired away code which configure LDAP server + +* Tue Aug 14 2007 Adam Tkac <atkac redhat com> 32:9.5.0-9.1.a6 +- named could crash with SRV record UPDATE (#251336) + +* Mon Aug 13 2007 Adam Tkac <atkac redhat com> 32:9.5.0-9.a6 +- disable 64bit dlz driver patch on alpha and ia64 (#251298) +- remove wrong malloc functions from lib/dns/spnego.c (#251853) + +* Mon Aug 06 2007 Adam Tkac <atkac redhat com> 32:9.5.0-8.2.a6 +- changed licence from BSD-like to ISC + +* Tue Jul 31 2007 Adam Tkac <atkac redhat com> 32:9.5.0-8.1.a6 +- disabled named on all runlevels by default + +* Mon Jul 30 2007 Adam Tkac <atkac redhat com> 32:9.5.0-8.a6 +- minor next improvements on autotools patch +- dig and host utilities now using libidn instead idnkit for + IDN support + +* Wed Jul 25 2007 Warren Togami <wtogami@redhat.com> 32:9.5.0-7.a6 +- binutils/gcc bug rebuild (#249435) + +* Tue Jul 24 2007 Adam Tkac <atkac redhat com> 32:9.5.0-6.a6 +- updated to 9.5.0a6 which contains fixes for CVE-2007-2925 and + CVE-2007-2926 +- fixed building on 64bits + +* Mon Jul 23 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-5 +- integrated "autotools" patch for testing purposes (upstream will + accept it in future, for easier building) + +* Mon Jul 23 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-4.1 +- fixed DLZ drivers building on 64bit systems + +* Fri Jul 20 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-4 +- fixed relation between logrotated and chroot-ed named + +* Wed Jul 18 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-3.9 +- removed bind-sdb package (default named has compiled SDB backend now) +- integrated DLZ (Dynamically loadable zones) drivers +- integrated GSS-TSIG support (RFC 3645) +- build with -O0 (many new features, potential core dumps will be more useful) + +* Tue Jul 17 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-3.2 +- initscript should be ready for parallel booting (#246878) + +* Tue Jul 17 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-3 +- handle integer overflow in isc_time_secondsastimet function gracefully (#247856) + +* Mon Jul 16 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-2.2 +- moved chroot configfiles into chroot subpackage (#248306) + +* Mon Jul 02 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-2 +- minor changes in default configuration +- fix h_errno assigment during resolver initialization (unbounded recursion, #245857) +- removed wrong patch to #150288 + +* Tue Jun 19 2007 Adam Tkac <atkac redhat com> 31:9.5.0a5-1 +- updated to latest upstream + +* Wed Jun 13 2007 Adam Tkac <atkac redhat com> 31:9.4.1-7 +- marked caching-nameserver as obsolete (#244604) +- fixed typo in initscript (causes that named doesn't detect NetworkManager + correctly) +- next cleanup in configuration - moved configfiles into config.tar +- removed delay between start & stop in restart function in named.init + +* Tue Jun 12 2007 Adam Tkac <atkac redhat com> 31:9.4.1-6 +- major changes in initscript. Could be LSB compatible now +- removed caching-nameserver subpackage. Move configs from this + package to main bind package as default configuration and major + configuration cleanup + +* Mon Jun 04 2007 Adam Tkac <atkac redhat com> 31:9.4.1-5 +- very minor compatibility change in bind-chroot-admin (line 215) +- enabled IDN support by default and don't distribute IDN libraries +- specfile cleanup +- add dynamic directory to /var/named. This directory will be primarily used for + dynamic DNS zones. ENABLE_ZONE_WRITE and SELinux's named_write_master_zones no longer exist + +* Thu May 24 2007 Adam Tkac <atkac redhat com> 31:9.4.1-4 +- removed ldap-api patch and start using deprecated API +- fixed minor problem in bind-chroot-admin script (#241103) + +* Tue May 22 2007 Adam Tkac <atkac redhat com> 31:9.4.1-3 +- fixed bind-chroot-admin dynamic DNS handling (#239149) +- updated zone-freeze patch to latest upstream +- ldap sdb has been rewriten to latest api (#239802) + +* Mon May 07 2007 Adam Tkac <atkac redhat com> 31:9.4.1-2.fc7 +- test build on new build system + +* Wed May 02 2007 Adam Tkac <atkac redhat com> 31:9.4.1-1.fc7 +- updated to 9.4.1 which contains fix to CVE-2007-2241 + +* Fri Apr 27 2007 Adam Tkac <atkac redhat com> 31:9.4.0-8.fc7 +- improved "zone freeze patch" - if multiple zone with same name exists + no zone is freezed +- minor cleanup in caching-nameserver's config file +- fixed race-condition in dbus code (#235809) +- added forgotten restorecon statement in bind-chroot-admin + +* Tue Apr 17 2007 Adam Tkac <atkac redhat com> 31:9.4.0-7.fc7 +- removed DEBUGINFO option because with this option (default) was bind + builded with -O0 and without this flag no debuginfo package was produced. + (I want faster bind => -O2 + debuginfo) +- fixed zone finding (#236426) + +* Mon Apr 16 2007 Adam Tkac <atkac redhat com> 31:9.4.0-6.fc7 +- added idn support (still under development with upstream, disabled by default) + +* Wed Apr 11 2007 Adam Tkac <atkac redhat com> 31:9.4.0-5.fc7 +- dnssec-signzone utility now doesn't ignore -d parameter + +* Tue Apr 10 2007 Adam Tkac <atkac redhat com> 31:9.4.0-4.fc7 +- removed query-source[-v6] options from caching-nameserver config + (#209954, increase security) +- throw away idn. It won't be ready in fc7 + +* Tue Mar 13 2007 Adam Tkac <atkac redhat com> 31:9.4.0-3.fc7 +- prepared bind to merge review +- added experimental idn support to bind-utils utils (not enabled by default yet) +- change chroot policy in caching-nameserver post section +- fixed bug in bind-chroot-admin - rootdir function is called properly now + +* Mon Mar 12 2007 Adam Tkac <atkac redhat com> 31:9.4.0-2.fc7 +- added experimental SQLite support (written by John Boyd <jaboydjr@netwalk.com>) +- moved bind-chroot-admin script to chroot package +- bind-9.3.2-redhat_doc.patch is always applied (#231738) + +* Tue Mar 06 2007 Adam Tkac <atkac@redhat.com> 31:9.4.0-1.fc7 +- updated to 9.4.0 +- bind-chroot-admin now sets EAs correctly (#213926) +- throw away next_server_on_referral and no_servfail_stops patches (fixed in 9.4.0) + +* Thu Feb 15 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-7.fc7 +- minor cleanup in bind-chroot-admin script + +* Fri Feb 09 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-6.fc7 +- fixed broken bind-chroot-admin script (#227995) + +* Wed Feb 07 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-5.fc7 +- bind-chroot-admin now uses correct chroot path (#227600) + +* Mon Feb 05 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-4.fc7 +- fixed conflict between bind-sdb and ldap +- removed duplicated bind directory in bind-libs + +* Thu Feb 01 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-3.fc7 +- fixed building without libbind +- fixed post section (selinux commands is now in if-endif statement) +- prever macro has been removed from version + +* Mon Jan 29 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-2.fc7 +- redirected output from bind-chroot prep and %%preun stages to /dev/null + +* Thu Jan 25 2007 Adam Tkac <atkac@redhat.com> 31:9.3.4-1.fc7 +- updated to version 9.3.4 which contains security bugfixes + +* Tue Jan 23 2007 Adam Tkac <atkac@redhat.com> 31:9.3.3-5.fc7 +- package bind-libbind-devel has been marked as obsolete + +* Mon Jan 22 2007 Adam Tkac <atkac@redhat.com> 31:9.3.3-4.fc7 +- package bind-libbind-devel has beed removed (libs has been moved to bind-devel & bind-libs) +- Resolves: #214208 + +* Tue Jan 16 2007 Martin Stransky <stransky@redhat.com> - 31:9.3.3-3 +- fixed a multi-lib issue +- Resolves: rhbz#222717 + +* Thu Jan 4 2007 Martin Stransky <stransky@redhat.com> - 31:9.3.3-2 +- added namedGetForwarders written in shell (#176100), + created by Baris Cicek <baris@nerd.com.tr>. + +* Sun Dec 10 2006 Martin Stransky <stransky@redhat.com> - 31:9.3.3-1 +- update to 9.3.3 final +- fix for #219069: file included twice in src.rpm + +* Wed Dec 6 2006 Martin Stransky <stransky@redhat.com> - 31:9.3.3-0.1.rc3 +- added back an interval to restart +- renamed package, it should meet the N-V-R criteria +- fix for #216185: bind-chroot-admin able to change root mode 750 +- added fix from #215997: incorrect permissions on dnszone.schema +- added a notice to init script when /etc/named.conf doesn't exist (#216075) + +* Mon Oct 30 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.3-6 +- fix for #200465: named-checkzone and co. cannot be run as non-root user +- fix for #212348: chroot'd named causes df permission denied error +- fix for #211249, #211083 - problems with stopping named +- fix for #212549: init script does not unmount /proc filesystem +- fix for #211282: EDNS is globally enabled, crashing CheckPoint FW-1, + added edns-enable options to named configuration file which can suppress + EDNS in queries to DNS servers (see /usr/share/doc/bind-9.3.3/misc/options) +- fix for #212961: bind-chroot doesn't clean up its mess on %%preun +- update to 9.3.3rc3, removed already merged patches + +* Fri Oct 13 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.3-5 +- fix for #209359: bind-libs from compatlayer CD will not + install on ia64 + +* Tue Oct 10 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.3-4 +- added fix for #210096: warning: group named does not exist - using root + +* Thu Oct 5 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.3-3 +- added fix from #209400 - Bind Init Script does not create + the PID file always, created by Jeff Means +- added timeout to stop section of init script. + The default is 100 sec. and can be adjusted by NAMED_SHUTDOWN_TIMEOUT + shell variable. + +* Mon Oct 2 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.3-2 +- removed chcon from %%post script, replaced by restorecon + (Bug 202547, comment no. 37) + +* Fri Sep 15 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.3-1 +- updated to the latest upstream (9.3.3rc2) + +* Wed Sep 6 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-41 +- added upstream patch for correct SIG handling - CVE-2006-4095 + +* Tue Sep 5 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-40 +- suppressed messages from bind-chroot-admin +- cleared notes about bind-config + +* Tue Aug 22 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-39 +- added fix for #203522 - "bind-chroot-admin -e" command fails + +* Mon Aug 21 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-38 +- fix for #203194 - tmpfile usage + +* Thu Aug 17 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-37 +- fix for #202542 - /usr/sbin/bind-chroot-admin: No such file or directory +- fix for #202547 - file_contexts: invalid context + +* Fri Aug 11 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-36 +- added Provides: bind-config + +* Fri Aug 11 2006 Martin Stransky <stransky@redhat.com> - 30:9.3.2-35 +- fix bug 197493: renaming subpackage bind-config to caching-nameserver + +* Mon Jul 24 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-34 +- fix bug 199876: make '%%exclude libbbind.*' conditional on %%{LIBBIND} + +* Mon Jul 24 2006 Florian La Roche <laroche@redhat.com> - 30:9.3.2-33 +- fix #195881, perms are not packaged correctly + +* Fri Jul 21 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-32 +- fix addenda to bug 189789: + determination of selinux enabled was still not 100% correct in bind-chroot-admin +- fix addenda to bug 196398: + make named.init test for NetworkManager being enabled AFTER testing for -D absence; + named.init now supports a 'DISABLE_NAMED_DBUS' /etc/sysconfig/named setting to disable + auto-enable of named dbus support if NetworkManager enabled. + +* Wed Jul 19 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-30 +- fix bug 196398 - Enable -D option automatically in initscript + if NetworkManager enabled in any runlevel. +- fix namedGetForwarders for new dbus +- fix bug 195881 - libbind.so should be owned by bind-libbind-devel + +* Wed Jul 19 2006 Matthias Clasen <mclasen@redhat.com> - 30:9.3.2-28.FC6 +- Rebuild against new dbus + +* Wed Jul 12 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-27.FC6 +- rebuild with fixed glibc-kernheaders + +* Wed Jul 12 2006 Jesse Keating <jkeating@redhat.com> - 30:9.3.2-26.FC6.1 +- rebuild + +* Wed Jun 14 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-26.FC6 +- fix bugs 191093, 189789 +- backport selected fixes from upstream bind9 'v9_3_3b1' CVS version: + ( see http://www.isc.org/sw/bind9.3.php "Fixes" ): + o change 2024 / bug 16027: + named emitted spurious "zone serial unchanged" messages on reload + o change 2013 / bug 15941: + handle unexpected TSIGs on unsigned AXFR/IXFR responses more gracefully + o change 2009 / bug 15808: coverity fixes + o change 1997 / bug 15818: + named was failing to replace negative cache entries when a positive one + for the type was learnt + o change 1994 / bug 15694: OpenSSL 0.9.8 support + o change 1991 / bug 15813: + The configuration data, once read, should be treated as readonly. + o misc. validator fixes + o misc. resolver fixes + o misc. dns fixes + o misc. isc fixes + o misc. libbind fixes + o misc. isccfg fix + o misc. lwres fix + o misc. named fixes + o misc. dig fixes + o misc. nsupdate fix + o misc. tests fixes + +* Wed Jun 7 2006 Jeremy Katz <katzj@redhat.com> - 30:9.3.2-24.FC6 +- and actually put the devel symlinks in the right subpackage + +* Thu May 25 2006 Jeremy Katz <katzj@redhat.com> - 30:9.3.2-23.FC6 +- rebuild for -devel deps + +* Tue Apr 18 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-22 +- apply upstream patch for ncache_adderesult segfault bug 173961 addenda +- fix bug 188382: rpm --verify permissions inconsistencies +- fix bug 189186: use /sbin/service instead of initscript +- rebuild for new gcc, glibc-kernheaders + +* Tue Apr 04 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-20 +- fix resolver.c ncache_adderesult segfault reported in addenda to bug 173961 + (upstream bugs #15642, #15528 ?) +- allow named ability to generate core dumps after setuid (upstream bug #15753) + +* Mon Apr 03 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-18 +- fix bug 187529: make bind-chroot-admin deal with subdirectories properly + +* Thu Mar 30 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-16 +- fix bug 187286: + prevent host(1) printing duplicate 'is an alias for' messages + for the default AAAA and MX lookups as well as for the A lookup + (it now uses the CNAME returned for the A lookup for the AAAA and MX lookups). + This is upstream bug #15702 fixed in the unreleased bind-9.3.3 +- fix bug 187333: fix SOURCE24 and SOURCE25 transposition + +* Wed Mar 29 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-14 +- fix bug 186577: remove -L/usr/lib from libbind.pc and more .spec file cleanup +- add '%%doc' sample configuration files in /usr/share/doc/bind*/sample +- rebuild with new gcc and glibc + +* Wed Mar 22 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-12 +- fix typo in initscript +- fix Requires(post): policycoreutils in sub-packages + +* Mon Mar 20 2006 Jason Vas Dias <jvdias@redhat.com> - 30.9.3.2-10 +- fix bug 185969: more .spec file cleanup + +* Wed Mar 08 2006 Jason Vas Dias <jvdias@redhat.com> - 30.9.3.2-8 +- Do not allow package to be installed if named:25 userid creation fails +- Give libbind a pkg-config file +- remove restorecon from bind-chroot-admin (not required). +- fix named.caching-nameserver.conf (listen-on-v6 port 53 { ::1 };) + +* Tue Mar 07 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-7 +- fix issues with bind-chroot-admin + +* Mon Mar 06 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-6 +- replace caching-nameserver with bind-config sub-package +- fix bug 177595: handle case where $ROOTDIR is a link in initscript +- fix bug 177001: bind-config creates symlinks OK now +- fix bug 176388: named.conf is now never replaced by any RPM +- fix bug 176248: remove unecessary creation of rpmsave links +- fix bug 174925: no replacement of named.conf +- fix bug 173963: existing named.conf never modified +- major .spec file cleanup + +* Fri Feb 10 2006 Jesse Keating <jkeating@redhat.com> - 30:9.3.2-4.1 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-4 +- regenerate redhat_doc patch for non-DBUS builds +- allow dbus builds to work with dbus version < 0.6 (bz #179816) + +* Tue Feb 07 2006 Florian La Roche <laroche@redhat.com> 30:9.3.2-3 +- try supporting without dbus support + +* Mon Feb 06 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-2.1 +- Rebuild for new gcc, glibc, glibc-kernheaders + +* Mon Jan 16 2006 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-2 +- fix bug 177854: temporary fix for broken kernel-2.6.15-1854+ + /proc/net/if_inet6 format + +* Wed Dec 21 2005 Jason Vas Dias <jvdias@redhat.com> - 30:9.3.2-1 +- Upgrade to 9.3.2, released today + +* Tue Dec 20 2005 Jason Vas Dias <jvdias@redhat.com> - 28:9.3.2rc1-2 +- fix bug 176100: do not Require: perl just for namedGetForwarders ! + +* Fri Dec 09 2005 Jesse Keating <jkeating@redhat.com> +- rebuilt + +* Fri Dec 02 2005 Jason Vas Dias <jvdias@redhat.com> - 28:9.3.2rc-1 +- Upgrade to upstream version 9.3.2rc1 +- fix namedSetForwarders -> namedGetForwarders SOURCE14 typo + +* Thu Dec 01 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-26 +- rebuild for new dbus 0.6 dependency; remove use of + DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT + +* Wed Nov 23 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-24 +- allow D-BUS support to work in bind-chroot environment: + workaround latest selinux policy by mounting /var/run/dbus/ + under chroot instead of /var/run/dbus/system-bus-socket + +* Sun Nov 13 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-22 +- fix bug 172632 - remove .la files +- ship namedGetForwarders and namedSetForwarders scripts +- fix detection of -D option in chroot + +* Tue Nov 8 2005 Tomas Mraz <tmraz@redhat.com> - 24:9.3.1-21 +- rebuilt with new openssl + +* Wed Oct 19 2005 Jason Vas Dias <jvdias@redhat.com> - 24.9.3.1-20 +- Allow the -D enable D-BUS option to be used within bind-chroot . +- fix bug 171226: supply some documentation for pgsql SDB . + +* Thu Oct 06 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-18 +- fix bug 169969: do NOT call dbus_svc_dispatch() in dbus_mgr_init_dbus() - + task->state != task_ready and will cause Abort in task.c if process + is waiting for NameOwnerChanged to do a SetForwarders + +* Wed Oct 05 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-16 +- Fix reconnecting to dbus-daemon after it stops & restarts . + +* Tue Sep 27 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-14 +- When forwarder nameservers are changed with D-BUS, flush the cache. + +* Mon Sep 26 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-12 +- fix bug 168302: use %%{__cc} for compiling dns-keygen +- fix bug 167682: bind-chroot directory permissions +- fix issues with -D dbus option when dbus service not running or disabled + +* Tue Aug 30 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-12 +- fix bug 167062: named should be started after syslogd by default + +* Mon Aug 22 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-11 +- fix bug 166227: host: don't do default AAAA and MX lookups with '-t a' option + +* Tue Aug 16 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-10 +- Build with D-BUS patch by default; D-BUS support enabled with named -D option +- Enable D-BUS for named_sdb also +- fix sdb pgsql's zonetodb.c: must use isc_hash_create() before dns_db_create() +- update fix for bug 160914 : test for RD=1 and ARCOUNT=0 also before trying next server +- fix named.init script to handle named_sdb properly +- fix named.init script checkconfig() to handle named '-c' option + and make configtest, test, check configcheck synonyms + +* Tue Jul 19 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-8 +- fix named.init script bugs 163598, 163409, 151852(addendum) + +* Tue Jul 12 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-7 +- fix bug 160914: resolver utilities should try next server on empty referral + (now that glibc bug 162625 is fixed) + host and nslookup now by default try next server on SERVFAIL + (host now has '-s' option to disable, and nslookup given + '[no]fail' option similar to dig's [no]fail option). +- rebuild and re-test with new glibc & gcc (all tests passed). + +* Tue May 31 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-6 +- fix bug 157950: dig / host / nslookup should reject invalid resolv.conf + files and not use uninitialized garbage nameserver values + (ISC bug 14841 raised). + +* Mon May 23 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-4_FC4 +- Fix SDB LDAP + +* Mon May 16 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-4 +- Fix bug 157601: give named.init a configtest function +- Fix bug 156797: named.init should check SELinux booleans.local before booleans +- Fix bug 154335: if no controls in named.conf, stop named with -TERM sig, not rndc +- Fix bug 155848: add NOTES section to named.8 man-page with info on all Red Hat + BIND quirks and SELinux DDNS / slave zone file configuration +- D-BUS patches NOT applied until dhcdbd is in FC + +* Sun May 15 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-4_dbus +- Enhancement to allow dynamic forwarder table management and +- DHCP forwarder auto-configuration with D-BUS + +* Thu Apr 14 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-2_FC4 +- Rebuild for bind-sdb libpq.so.3 dependency +- fix bug 150981: don't install libbind man-pages if no libbind +- fix bug 151852: mount proc on $ROOTDIR/proc to allow sysconf(...) + to work and correct number of CPUs to be determined + +* Fri Mar 11 2005 Jason Vas Dias <jvdias@redhat.com> - 24:9.3.1-1_FC4 +- Upgrade to ISC BIND 9.3.1 (final release) released today. + +* Wed Mar 9 2005 Jason Vas Dias <jvdias@redhat.com> - 22.9.3.1rc1-5 +- fix bug 150288: h_errno not being accessed / set correctly in libbind +- add libbind man-pages from bind-8.4.6 + +* Mon Mar 7 2005 Jason Vas Dias <jvdias@redhat.com> - 22:9.3.1rc1-4 +- Rebuild with gcc4 / glibc-2.3.4-14. + +* Tue Mar 1 2005 Nalin Dahyabhai <nalin@redhat.com> - 22:9.3.1rc1-3 +- configure with --with-pic to get PIC libraries + +* Sun Feb 20 2005 Jason Vas Dias <jvdias@redhat.com> - 22:9.3.1rc1-2 +- fix bug 149183: don't use getifaddrs() . + +* Wed Feb 16 2005 Jason Vas Dias <jvdias@redhat.com> - 22:9.3.1rc1-1 +- Upgrade to 9.3.1rc1 +- Add Simplified Database Backend (SDB) sub-package ( bind-sdb ) +- add named_sdb - ldap + pgsql + dir database backend support with +- 'ENABLE_SDB' named.sysconfig option +- Add BIND resolver library & includes sub-package ( libbind-devel) +- fix bug 147824 / 147073 / 145664: ENABLE_ZONE_WRITE in named.init +- fix bug 146084 : shutup restorecon + +* Tue Jan 11 2005 Jason Vas Dias <jvdias@redhat.com> - 22:9.3.0-2 +- Fix bug 143438: named.init will now make correct ownership of $ROOTDIR/var/named +- based on 'named_write_master_zones' SELinux boolean. +- Fix bug 143744: dig & nsupdate IPv6 timeout (dup of 140528) + +* Mon Nov 29 2004 Jason Vas Dias <jvdias@redhat.com> - 9.3.0-1 +- Upgrade BIND to 9.3.0 in Rawhide / FC4 (bugs 134529, 133654...) + +* Mon Nov 29 2004 Jason Vas Dias <jvdias@redhat.com> - 20:9.2.4-4 +- Fix bugs 140528 and 141113: +- 2 second timeouts when IPv6 not configured and root nameserver's +- AAAA addresses are queried + +* Mon Oct 18 2004 Jason Vas Dias <jvdias@redhat.com> - 20:9.2.4-2 +- Fix bug 136243: bind-chroot %%post must run restorecon -R %%{prefix} +- Fix bug 135175: named.init must return non-zero if named is not run +- Fix bug 134060: bind-chroot %%post must use mktemp, not /tmp/named +- Fix bug 133423: bind-chroot %%files entries should have been %%dirs + +* Thu Sep 23 2004 Jason Vas Dias <jvdias@redhat.com> - 20:9.2.4-1 +- BIND 9.2.4 (final release) released - source code actually +- identical to 9.2.4rc8, with only version number change. + +* Mon Sep 20 2004 Jason Vas Dias <jvdias@redhat.com> - 10:9.2.4rc8-14 +- Upgrade to upstream bind-9.2.4rc8 . +- Progress: Finally! Hooray! ISC bind now distributes: +- o named.conf(5) and nslookup(8) manpages +- 'bind-manpages.bz2' source can now disappear +- (could this have something to do with ISC bug I raised about this?) +- o 'deprecation_msg' global has vanished +- bind-9.2.3rc3-deprecation_msg_shut_up.diff.bz2 can disappear + +* Mon Sep 20 2004 Jason Vas Dias <jvdias@redhat.com> - 10:9.2.4rc8-14 +- Fix bug 106572/132385: copy /etc/localtime to chroot on start + +* Fri Sep 10 2004 Jason Vas Dias <jvdias@redhat.com> - 10:9.2.4rc7-12_EL3 +- Fix bug 132303: if ROOTDIR line was replaced after upgrade from +- bind-chroot-9.2.2-21, restart named + +* Wed Sep 8 2004 Jason Vas Dias <jvdias@redhat.com> - 10:9.2.4rc7-11_EL3 +- Fix bug 131803: replace ROOTDIR line removed by broken +- bind-chroot 9.2.2-21's '%%postun'; added %%triggerpostun for bind-chroot + +* Tue Sep 7 2004 Jason Vas Dias <jvdias@redhat.com> - 10:9.2.4rc7-10_EL3 +- Fix bugs 130121 & 130981 for RHEL-3 + +* Mon Aug 30 2004 Jason Vas Dias <jvdias@redhat.com> - 10:9.2.4rc7-10 +- Fix bug 130121: add '%%ghost' entries for files included in previous +- bind-chroot & not in current - ie. named.conf, rndc.key, dev/* - +- that RPM removed after upgrade . + +* Thu Aug 26 2004 Jason Vas Dias <jvdias@redhat.com> +- Fix bug 130981: add '-t' option to named-checkconf invocation in +- named.init if chroot installed. + +* Wed Aug 25 2004 Jason Vas Dias <jvdias@redhat.com> +- Remove resolver(5) manpage now in man-pages (bug 130792); +- Don't create /dev/ entries in bind-chroot if already there (bug 127556); +- fix bind-devel Requires (bug 130919) +- Set default location for dumpdb & stats files to /var/named/data + +* Tue Aug 24 2004 Jason Vas Dias <jvdias@redhat.com> +- Fix devel Requires for bug 130738 & fix version + +* Tue Aug 24 2004 Jason Vas Dias <jvdias@redhat.com> +- Fix errors on clean install if named group does not exist +- (bug 130777) + +* Thu Aug 19 2004 Jason Vas Dias <jvdias@redhat.com> +- Upgrade to bind-9.2.4rc7; applied initscript fix +- for bug 102035. + +* Mon Aug 9 2004 Jason Vas Dias <jvdias@redhat.com> +- Fixed bug 129289: bind-chroot install / deinstall +- on install, existing config files 'safe_replace'd +- with links to chroot copies; on uninstall, moved back. + +* Fri Aug 6 2004 Jason Vas Dias <jvdias@redhat.com> +- Fixed bug 129258: "${prefix}/var/tmp" typo in spec + +* Wed Jul 28 2004 Jason Vas Dias <jvdias@redhat.com> +- Fixed bug 127124 : 'Requires: kernel >= 2.4' +- causes problems with Linux VServers + +* Tue Jul 27 2004 Jason Vas Dias <jvdias@redhat.com> +- Fixed bug 127555 : chroot tar missing var/named/slaves + +* Fri Jul 16 2004 Jason Vas Dias <jvdias@redhat.com> +- Upgraded to ISC version 9.2.4rc6 + +* Fri Jul 16 2004 Jason Vas Dias <jvdias@redhat.com> +- Fixed named.init generation of error messages on +- 'service named stop' and 'service named reload' +- as per bug 127775 + +* Wed Jun 23 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-19 +- Bump for rhel 3.0 U3 + +* Wed Jun 23 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-18 +- remove disable-linux-caps + +* Wed Jun 16 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-17 +- Update RHEL3 to latest bind + +* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com> +- rebuilt + +* Tue Jun 8 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-15 +- Remove device files from chroot, Named uses the system one + +* Fri Mar 26 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-14 +- Move RFC to devel package + +* Fri Mar 26 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-13 +- Fix location of restorecon + +* Thu Mar 25 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-12 +- Tighten security on config files. Should be owned by root + +* Thu Mar 25 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-11 +- Update key patch to include conf-keygen + +* Tue Mar 23 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-10 +- fix chroot to only happen once. +- fix init script to do kill insteall of killall + +* Mon Mar 15 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-9 +- Add fix for SELinux security context + +* Tue Mar 02 2004 Elliot Lee <sopwith@redhat.com> +- rebuilt + +* Sat Feb 28 2004 Florian La Roche <Florian.LaRoche@redhat.de> +- run ldconfig for libs subrpm + +* Mon Feb 23 2004 Tim Waugh <twaugh@redhat.com> +- Use ':' instead of '.' as separator for chown. + +* Tue Feb 17 2004 Daniel Walsh <dwalsh@redhat.com> 9.2.3-7 +- Add COPYRIGHT + +* Fri Feb 13 2004 Elliot Lee <sopwith@redhat.com> +- rebuilt + +* Tue Dec 30 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.3-5 +- Add defattr to libs + +* Mon Dec 29 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.3-4 +- Break out library package + +* Mon Dec 22 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.3-3 +- Fix condrestart + +* Wed Nov 12 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.3-2 +- Move libisc and libdns to bind from bind-util + +* Tue Nov 11 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.3-1 +- Move to 9.2.3 + +* Mon Oct 27 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-10 +- Add PIE support + +* Fri Oct 17 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-9 +- Add /var/named/slaves directory + +* Sun Oct 12 2003 Florian La Roche <Florian.LaRoche@redhat.de> +- do not link against libnsl, not needed for Linux + +* Wed Oct 8 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-6 +- Fix local time in log file + +* Tue Oct 7 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-5 +- Try again + +* Mon Oct 6 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-4 +- Fix handling of chroot -/dev/random + +* Thu Oct 2 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-3 +- Stop hammering stuff on update of chroot environment + +* Mon Sep 29 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-2 +- Fix chroot directory to grab all subdirectories + +* Wed Sep 24 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2.P3-1 +- New patch to support for "delegation-only" + +* Wed Sep 17 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-23 +- patch support for "delegation-only" + +* Wed Jul 30 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-22 +- Update to build on RHL + +* Wed Jul 30 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-21 +- Install libraries as exec so debug info will be pulled + +* Sat Jul 19 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-20 +- Remove BSDCOMPAT (BZ 99454) + +* Tue Jul 15 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-19 +- Update to build on RHL + +* Tue Jul 15 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-18 +- Change protections on /var/named and /var/chroot/named + +* Tue Jun 17 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-17 +- Update to build on RHL + +* Tue Jun 17 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-16 +- Update to build on RHEL + +* Wed Jun 04 2003 Elliot Lee <sopwith@redhat.com> +- rebuilt + +* Tue Apr 22 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-14 +- Update to build on RHEL + +* Tue Apr 22 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-13 +- Fix config description of named.conf in chroot +- Change named.init script to check for existence of /etc/sysconfig/network + +* Fri Apr 18 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-12 +- Update to build on RHEL + +* Fri Apr 18 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-11 +- Update to build on RHEL + +* Fri Apr 18 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-10 +- Fix echo OK on starting/stopping service + +* Fri Mar 28 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-9 +- Update to build on RHEL + +* Fri Mar 28 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-8 +- Fix echo on startup + +* Tue Mar 25 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-7 +- Fix problems with chroot environment +- Eliminate posix threads + +* Mon Mar 24 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-6 +- Fix build problems + +* Fri Mar 14 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-5 +- Fix build on beehive + +* Thu Mar 13 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-4 +- build bind-chroot kit + +* Tue Mar 11 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-3 +- Change configure to use proper threads model + +* Fri Mar 7 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-2 +- update to 9.2.2 + +* Tue Mar 4 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.2-1 +- update to 9.2.2 + +* Fri Jan 24 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.1-16 +- Put a sleep in restart to make sure stop completes + +* Wed Jan 22 2003 Tim Powers <timp@redhat.com> +- rebuilt + +* Tue Jan 7 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.1-14 +- Separate /etc/rndc.key to separate file + +* Tue Jan 7 2003 Nalin Dahyabhai <nalin@redhat.com> 9.2.1-13 +- Use openssl's pkgconfig data, if available, at build-time. + +* Mon Jan 6 2003 Daniel Walsh <dwalsh@redhat.com> 9.2.1-12 +- Fix log rotate to use service named reload +- Change service named reload to give success/failure message [73770] +- Fix File checking [75710] +- Begin change to automatically run in CHROOT environment + +* Tue Dec 24 2002 Daniel Walsh <dwalsh@redhat.com> 9.2.1-10 +- Fix startup script to work like all others. + +* Mon Dec 16 2002 Daniel Walsh <dwalsh@redhat.com> 9.2.1-9 +- Fix configure to build on x86_64 platforms + +* Wed Aug 07 2002 Karsten Hopp <karsten@redhat.de> +- fix #70583, doesn't build on IA64 + +* Tue Jul 30 2002 Karsten Hopp <karsten@redhat.de> 9.2.1-8 +- bind-utils shouldn't require bind + +* Mon Jul 22 2002 Karsten Hopp <karsten@redhat.de> 9.2.1-7 +- fix name of pidfine in logrotate script (#68842) +- fix owner of logfile in logrotate script (#41391) +- fix nslookup and named.conf man pages (output on stderr) + (#63553, #63560, #63561, #54889, #57457) +- add rfc1912 (#50005) +- gzip all rfc's +- fix typo in keygen.c (#54870) +- added missing manpages (#64065) +- shutdown named properly with rndc stop (#62492) +- /sbin/nologin instead of /bin/false (#68607) +- move nsupdate to bind-utils (where the manpage already was) (#66209, #66381) +- don't kill initscript when rndc fails (reload) (#58750) + + +* Mon Jun 24 2002 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.1-5 +- Fix #65975 + +* Fri Jun 21 2002 Tim Powers <timp@redhat.com> +- automated rebuild + +* Thu May 23 2002 Tim Powers <timp@redhat.com> +- automated rebuild + +* Thu May 9 2002 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.1-2 +- Move libisccc, lib isccfg and liblwres from bind-utils to bind, + they're not required if you aren't running a nameserver. + +* Fri May 03 2002 Florian La Roche <Florian.LaRoche@redhat.de> +- update to 9.2.1 release + +* Thu Mar 14 2002 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-8 +- Merge 30+ bug fixes from 9.2.1rc1 code + +* Mon Mar 11 2002 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-7 +- Don't exit if /etc/named.conf doesn't exist if we're running + chroot (#60868) +- Revert Elliot's changes, we do require specific glibc/glibc-kernheaders + versions or bug #58335 will be back. "It compiles, therefore it works" + isn't always true. + +* Thu Feb 28 2002 Elliot Lee <sopwith@redhat.com> 9.2.0-6 +- Fix BuildRequires (we don't need specific glibc/glibc-kernheaders +versions). +- Use _smp_mflags + +* Wed Feb 20 2002 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-4 +- rebuild, require recent autoconf, automake (#58335) + +* Fri Jan 25 2002 Tim Powers <timp@redhat.com> +- rebuild against new libssl + +* Wed Jan 09 2002 Tim Powers <timp@redhat.com> +- automated rebuild + +* Tue Nov 27 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-1 +- 9.2.0 + +* Thu Nov 22 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc10.2 +- 9.2.0rc10 + +* Mon Nov 5 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc8.2 +- Fix up rndc.conf (#55574) + +* Thu Oct 25 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc8.1 +- rc8 +- Enforce --enable-threads + +* Mon Oct 22 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc7.1 +- 9.2.0rc7 +- Use rndc status for "service named status", it's supposed to actually + work in 9.2.x. + +* Wed Oct 3 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc5.1 +- 9.2.0rc5 +- Fix rpm --rebuild with ancient libtool versions (#53938, #54257) + +* Tue Sep 25 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc4.1 +- 9.2.0rc4 + +* Fri Sep 14 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.2.0-0.rc3.1 +- 9.2.0rc3 +- remove ttl patch, I don't think we need this for 8.0. +- remove dig.1.bz2 from the bind8-manpages tar file, 9.2 has a new dig man page +- add lwres* man pages to -devel + +* Mon Sep 3 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-4 +- Make sure /etc/rndc.conf isn't world-readable even after the + %%post script inserted a random key (#53009) + +* Thu Jul 19 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-3 +- Add build dependencies (#49368) +- Make sure running service named start several times doesn't create + useless processes (#47596) +- Work around the named parent process returning 0 even if the config + file is broken (it's parsed later by the child processes) (#45484) + +* Mon Jul 16 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-2 +- Don't use rndc status, it's not yet implemented (#48839) + +* Sun Jul 08 2001 Florian La Roche <Florian.LaRoche@redhat.de> +- update to 9.1.3 release + +* Tue Jul 3 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-0.rc3.1 +- Fix up rndc configuration and improve security (#46586) + +* Tue Jun 26 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-0.rc2.2 +- Sync with caching-nameserver-7.1-6 + +* Mon Jun 25 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-0.rc2.1 +- Update to rc2 + +* Fri Jun 1 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-0.rc1.3 +- Remove resolv.conf(5) man page, it's now in man-pages + +* Thu May 31 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-0.rc1.2 +- Add named.conf man page from bind 8.x (outdated, but better than nothing, + #42732) +- Rename the rndc key (#42895) +- Add dnssec* man pages + +* Mon May 28 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.3-0.rc1.1 +- 9.1.3rc1 +- s/Copyright/License/ + +* Mon May 7 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.2-1 +- 9.1.2 final. No changes between 9.1.2-0.rc1.1 and this one, except for + the version number, though. + +* Thu May 3 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.2-0.rc1.1 +- 9.1.2rc1 + +* Thu Mar 29 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.1-1 +- 9.1.1 + +* Thu Mar 15 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.0-10 +- Merge fixes from 9.1.1rc5 + +* Sun Mar 11 2001 Bernhard Rosenkraenzer <bero@redhat.com> 9.1.0-9 +- Work around bind 8 -> bind 9 migration problem when using buggy zone files: + accept zones without a TTL, but spew out a big fat warning. (#31393) + +* Thu Mar 8 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Add fixes from rc4 + +* Fri Mar 2 2001 Nalin Dahyabhai <nalin@redhat.com> +- rebuild in new environment + +* Thu Mar 1 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- killall -HUP named if rndc reload fails (#30113) + +* Tue Feb 27 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Merge some fixes from 9.1.1rc3 + +* Tue Feb 20 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Don't use the standard rndc key from the documentation, instead, create a random one + at installation time (#26358) +- Make /etc/rndc.conf readable by user named only, it contains secret keys + +* Tue Feb 20 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.1.1 probably won't be out in time, revert to 9.1.0 and apply fixes + from 9.1.1rc2 +- bind requires bind-utils (#28317) + +* Tue Feb 13 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Update to rc2, fixes 2 more bugs +- Fix build with glibc >= 2.2.1-7 + +* Thu Feb 8 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Update to 9.1.1rc1; fixes 17 bugs (14 of them affecting us; + 1 was fixed in a Red Hat patch already, 2 others are portability + improvements) + +* Wed Feb 7 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Remove initscripts 5.54 requirement (#26489) + +* Mon Jan 29 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Add named-checkconf, named-checkzone (#25170) + +* Mon Jan 29 2001 Trond Eivind Glomsrod <teg@redhat.com> +- use echo, not gprintf + +* Wed Jan 24 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix problems with $GENERATE + Patch from Daniel Roesen <droesen@entire-systems.com> + Bug #24890 + +* Thu Jan 18 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.1.0 final + +* Sat Jan 13 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.1.0rc1 +- i18nify init script +- bzip2 source to save space + +* Thu Jan 11 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix %%postun script + +* Tue Jan 9 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.1.0b3 + +* Mon Jan 8 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Add named.conf man page from bind8 (#23503) + +* Sun Jan 7 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Make /etc/rndc.conf and /etc/sysconfig/named noreplace +- Make devel require bind = %%{version} rather than just bind + +* Sun Jan 7 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix init script for real + +* Sat Jan 6 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix init script when ROOTDIR is not set + +* Thu Jan 4 2001 Bernhard Rosenkraenzer <bero@redhat.com> +- Add hooks for setting up named to run chroot (RFE #23246) +- Fix up requirements + +* Fri Dec 29 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.1.0b2 + +* Wed Dec 20 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- Move run files to /var/run/named/ - /var/run isn't writable + by the user we're running as. (Bug #20665) + +* Tue Dec 19 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix reverse lookups (#22272) +- Run ldconfig in %%post utils + +* Tue Dec 12 2000 Karsten Hopp <karsten@redhat.de> +- fixed logrotate script (wrong path to kill) +- include header files in -devel package +- bugzilla #22049, #19147, 21606 + +* Fri Dec 8 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.1.0b1 (9.1.0 is in our timeframe and less buggy) + +* Mon Nov 13 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.0.1 + +* Mon Oct 30 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix initscript (Bug #19956) +- Add sample rndc.conf (Bug #19956) +- Fix build with tar 1.13.18 + +* Tue Oct 10 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- Add some missing man pages (taken from bind8) (Bug #18794) + +* Sun Sep 17 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.0.0 final + +* Wed Aug 30 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- rc5 +- fix up nslookup + +* Thu Aug 24 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- rc4 + +* Thu Jul 13 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- 9.0.0rc1 + +* Wed Jul 12 2000 Prospector <bugzilla@redhat.com> +- automatic rebuild + +* Sun Jul 9 2000 Florian La Roche <Florian.LaRoche@redhat.de> +- add "exit 0" for uninstall case + +* Fri Jul 7 2000 Florian La Roche <Florian.LaRoche@redhat.de> +- add prereq init.d and cleanup install section + +* Fri Jun 30 2000 Trond Eivind Glomsrod <teg@redhat.com> +- fix the init script + +* Wed Jun 28 2000 Nalin Dahyabhai <nalin@redhat.com> +- make libbind.a and nslookup.help readable again by setting INSTALL_LIB to "" + +* Mon Jun 26 2000 Bernhard Rosenkranzer <bero@redhat.com> +- Fix up the initscript (Bug #13033) +- Fix build with current glibc (Bug #12755) +- /etc/rc.d/init.d -> /etc/init.d +- use %%{_mandir} rather than /usr/share/man + +* Mon Jun 19 2000 Bill Nottingham <notting@redhat.com> +- fix conflict with man-pages +- remove compatibilty chkconfig links +- initscript munging + +* Wed Jun 14 2000 Nalin Dahyabhai <nalin@redhat.com> +- modify logrotate setup to use PID file +- temporarily disable optimization by unsetting $RPM_OPT_FLAGS at build-time +- actually bump the release this time + +* Sun Jun 4 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- FHS compliance + +* Mon Apr 17 2000 Nalin Dahyabhai <nalin@redhat.com> +- clean up restart patch + +* Mon Apr 10 2000 Nalin Dahyabhai <nalin@redhat.com> +- provide /var/named (fix for bugs #9847, #10205) +- preserve args when restarted via ndc(8) (bug #10227) +- make resolv.conf(5) a link to resolver(5) (bug #10245) +- fix SYSTYPE bug in all makefiles +- move creation of named user from %%post into %%pre + +* Mon Feb 28 2000 Bernhard Rosenkranzer <bero@redhat.com> +- Fix TTL (patch from ISC, Bug #9820) + +* Wed Feb 16 2000 Bernhard Rosenkranzer <bero@redhat.com> +- fix typo in spec (it's %%post, without a leading blank) introduced in -6 +- change SYSTYPE to linux + +* Fri Feb 11 2000 Bill Nottingham <notting@redhat.com> +- pick a standard < 100 uid/gid for named + +* Fri Feb 04 2000 Elliot Lee <sopwith@redhat.com> +- Pass named a '-u named' parameter by default, and add/remove user. + +* Thu Feb 3 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- fix host mx bug (Bug #9021) + +* Mon Jan 31 2000 Cristian Gafton <gafton@redhat.com> +- rebuild to fix dependencies +- man pages are compressed + +* Wed Jan 19 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- It's /usr/bin/killall, not /usr/sbin/killall (Bug #8063) + +* Mon Jan 17 2000 Bernhard Rosenkraenzer <bero@redhat.com> +- Fix up location of named-bootconf.pl and make it executable + (Bug #8028) +- bind-devel requires bind + +* Mon Nov 15 1999 Bernhard Rosenkraenzer <bero@redhat.com> +- update to 8.2.2-P5 + +* Wed Nov 10 1999 Bill Nottingham <notting@redhat.com> +- update to 8.2.2-P3 + +* Tue Oct 12 1999 Cristian Gafton <gafton@redhat.com> +- add patch to stop a cache only server from complaining about lame servers + on every request. + +* Fri Sep 24 1999 Preston Brown <pbrown@redhat.com> +- use real stop and start in named.init for restart, not ndc restart, it has + problems when named has changed during a package update... (# 4890) + +* Fri Sep 10 1999 Bill Nottingham <notting@redhat.com> +- chkconfig --del in %%preun, not %%postun + +* Mon Aug 16 1999 Bill Nottingham <notting@redhat.com> +- initscript munging + +* Mon Jul 26 1999 Bill Nottingham <notting@redhat.com> +- fix installed chkconfig links to match init file + +* Sat Jul 3 1999 Jeff Johnson <jbj@redhat.com> +- conflict with new (in man-1.24) man pages (#3876,#3877). + +* Tue Jun 29 1999 Bill Nottingham <notting@redhat.com> +- fix named.logrotate (wrong %%SOURCE) + +* Fri Jun 25 1999 Jeff Johnson <jbj@redhat.com> +- update to 8.2.1. +- add named.logrotate (#3571). +- hack around egcs-1.1.2 -m486 bug (#3413, #3485). +- vet file list. + +* Fri Jun 18 1999 Bill Nottingham <notting@redhat.com> +- don't run by default + +* Sun May 30 1999 Jeff Johnson <jbj@redhat.com> +- nslookup fixes (#2463). +- missing files (#3152). + +* Sat May 1 1999 Stepan Kasal <kasal@math.cas.cz> +- nslookup patched: + to count numRecords properly + to fix subsequent calls to ls -d + to parse "view" and "finger" commands properly + the view hack updated for bind-8 (using sed) + +* Wed Mar 31 1999 Bill Nottingham <notting@redhat.com> +- add ISC patch +- add quick hack to make host not crash +- add more docs + +* Fri Mar 26 1999 Cristian Gafton <gafton@redhat.com> +- add probing information in the init file to keep linuxconf happy +- dont strip libbind + +* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com> +- auto rebuild in the new build environment (release 3) + +* Wed Mar 17 1999 Preston Brown <pbrown@redhat.com> +- removed 'done' output at named shutdown. + +* Tue Mar 16 1999 Cristian Gafton <gafton@redhat.com> +- version 8.2 + +* Wed Dec 30 1998 Cristian Gafton <gafton@redhat.com> +- patch to use the __FDS_BITS macro +- build for glibc 2.1 + +* Wed Sep 23 1998 Jeff Johnson <jbj@redhat.com> +- change named.restart to /usr/sbin/ndc restart + +* Sat Sep 19 1998 Jeff Johnson <jbj@redhat.com> +- install man pages correctly. +- change K10named to K45named. + +* Wed Aug 12 1998 Jeff Johnson <jbj@redhat.com> +- don't start if /etc/named.conf doesn't exist. + +* Sat Aug 8 1998 Jeff Johnson <jbj@redhat.com> +- autmagically create /etc/named.conf from /etc/named.boot in %%post +- remove echo in %%post + +* Wed Jun 10 1998 Jeff Johnson <jbj@redhat.com> +- merge in 5.1 mods + +* Sun Apr 12 1998 Manuel J. Galan <manolow@step.es> +- Several essential modifications to build and install correctly. +- Modified 'ndc' to avoid deprecated use of '-' + +* Mon Dec 22 1997 Scott Lampert <fortunato@heavymetal.org> +- Used buildroot +- patched bin/named/ns_udp.c to use <libelf/nlist.h> for include + on Redhat 5.0 instead of <nlist.h>