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 + #include + #include ++#include + #include + + #include +@@ -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 + #include + +-#include ++#include "bdb.h" + #include + #include + +--- 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 + #include + +-#include ++#include + + #include + #include +--- 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 + #include + +-#include ++#include + + /* + * 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 + #endif + ++#ifdef WITH_LIBIDN ++#include ++#include ++#endif ++ + #include + #ifdef DIG_SIGCHASE + #include +@@ -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 +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 ++.\" 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 ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 \n"); ++ fprintf(stderr, " -K : 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 @@ ++]> ++ ++ ++ ++ ++ ++ August 30, 2013 ++ ++ ++ ++ dnssec-importkey ++ 8 ++ BIND9 ++ ++ ++ ++ dnssec-importkey ++ Import DNSKEY records from external systems so they can be managed. ++ ++ ++ ++ ++ 2013 ++ Internet Systems Consortium, Inc. ("ISC") ++ ++ ++ ++ ++ ++ dnssec-importkey ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ DESCRIPTION ++ dnssec-importkey ++ read a DNSKEY record and generated a .key/.private key pair. ++ Publication () and deletions () ++ times can be set for the key. ++ ++ ++ ++ ++ OPTIONS ++ ++ ++ ++ -f filename ++ ++ ++ Filename to read the key from. ++ ++ ++ ++ ++ ++ -K directory ++ ++ ++ Sets the directory in which the key files are to reside. ++ ++ ++ ++ ++ ++ -L ttl ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ -h ++ ++ ++ Emit usage message and exit. ++ ++ ++ ++ ++ ++ -v level ++ ++ ++ Sets the debugging level. ++ ++ ++ ++ ++ ++ ++ ++ ++ TIMING OPTIONS ++ ++ 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 date/offset ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ -D date/offset ++ ++ ++ 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.) ++ ++ ++ ++ ++ ++ ++ ++ ++ SEE ALSO ++ ++ dnssec-keygen8 ++ , ++ ++ dnssec-signzone8 ++ , ++ BIND 9 Administrator Reference Manual, ++ RFC 5011. ++ ++ ++ ++ ++ AUTHOR ++ Internet Systems Consortium ++ ++ ++ ++ +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 @@ ++ ++ ++ ++ ++ ++dnssec-importkey ++ ++ ++
++
++
++

Name

++

dnssec-importkey — Import DNSKEY records from external systems so they can be managed.

++
++
++

Synopsis

++

dnssec-importkey [-f filename] [-K directory] [-P date/offset] [-D date/offset] [-h] [-v level] [keyname]

++
++
++

DESCRIPTION

++

dnssec-importkey ++ read a DNSKEY record and generated a .key/.private key pair. ++ Publication (-P) and deletions (-D) ++ times can be set for the key. ++

++
++
++

OPTIONS

++
++
-f filename
++

++ Filename to read the key from. ++

++
-K directory
++

++ Sets the directory in which the key files are to reside. ++

++
-L ttl
++

++ 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. ++

++
-h
++

++ Emit usage message and exit. ++

++
-v level
++

++ Sets the debugging level. ++

++
++
++
++

TIMING OPTIONS

++

++ 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 date/offset
++

++ 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. ++

++
-D date/offset
++

++ 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.) ++

++
++
++
++

SEE ALSO

++

dnssec-keygen(8), ++ dnssec-signzone(8), ++ BIND 9 Administrator Reference Manual, ++ RFC 5011. ++

++
++
++

AUTHOR

++

Internet Systems Consortium ++

++
++
++ +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 +Date: Thu, 21 May 2015 10:52:03 +0200 +Subject: [PATCH] native PKCS#11 + +Signed-off-by: Tomas Hozza +--- + 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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 \n"); ++ fprintf(stderr, " -f file: read key from zone file\n"); + fprintf(stderr, " -K : 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 \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 @@ + + + dnssec-importkey +- + ++ + + + + +- ++ ++ ++ ++ dnssec-importkey ++ ++ ++ ++ ++ ++ ++ ++ + + + + + DESCRIPTION + dnssec-importkey +- read a DNSKEY record and generated a .key/.private key pair. +- Publication () and deletions () +- 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. ++ ++ ++ The newly-created .private file does not ++ contain private key data, and cannot be used for signing. ++ However, having a .private file makes it possible to set ++ publication () and deletion ++ () 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. + + + +@@ -70,9 +93,16 @@ + + -f filename + +- +- Filename to read the key from. +- ++ ++ 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 . If the domain name is the same as ++ , then it may be omitted. ++ ++ ++ If is set to "-", then ++ the zone data is read from the standard input. ++ + + + +@@ -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 + 0 or none removes it. + + +@@ -160,6 +190,16 @@ + + + ++ FILES ++ ++ A keyfile can be designed by the key identification ++ Knnnn.+aaa+iiiii or the full file name ++ Knnnn.+aaa+iiiii.key as generated by ++ dnssec-keygen8. ++ ++ ++ ++ + SEE ALSO + + dnssec-keygen8 +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 :\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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +@@ -143,9 +150,32 @@ + -l label + + +- 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. ++ ++ ++ When BIND 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:keylabel". ++ ++ ++ When BIND 9 is built with native PKCS#11 ++ support, the label is a PKCS#11 URI string in the format ++ "pkcs11:=value;=value;..." ++ 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. ++ ++ ++ If the label contains a ++ 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. + + + +@@ -429,7 +459,8 @@ + dnssec-signzone8 + , + BIND 9 Administrator Reference Manual, +- RFC 4034. ++ RFC 4034, ++ The PKCS#11 URI Scheme (draft-pechanec-pkcs11uri-13). + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 : (default: IN)\n"); + fprintf(stderr, " -d (0 => max, default)\n"); +-#ifdef USE_PKCS11 +- fprintf(stderr, " -E (default \"pkcs11\")\n"); ++ fprintf(stderr, " -E :\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 \n"); ++ fprintf(stderr, " name of an OpenSSL engine to use\n"); + #endif + fprintf(stderr, " -f : KSK | REVOKE\n"); + fprintf(stderr, " -g : use specified generator " +@@ -134,7 +143,6 @@ usage(void) { + "records with (default: 0)\n"); + fprintf(stderr, " -T : DNSKEY | KEY (default: DNSKEY; " + "use KEY for SIG(0))\n"); +- fprintf(stderr, " ECCGOST:\tignored\n"); + fprintf(stderr, " -t : " + "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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + -E engine + + +- 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. ++ ++ ++ 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". + + + +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 + ++#ifdef PKCS11CRYPTO ++#include ++#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 @@ + + + ++ -E engine ++ ++ ++ Specifies the cryptographic hardware to use, when applicable. ++ ++ ++ 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". ++ ++ ++ ++ ++ + -I input-format + + +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 + + #include ++#ifdef PKCS11CRYPTO ++#include ++#endif + + #include + +@@ -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 @@ + -E engine-name + + +- 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 +- engine-name +- 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. ++ ++ ++ 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". + + + +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 + #include + #include +-#include "cryptoki.h" + +-#ifdef WIN32 +-#define sleep(x) Sleep(x) +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include ++#include ++#include ++ ++#include ++#include + + #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 @@ + + + 2009 ++ 2014 + Internet Systems Consortium, Inc. ("ISC") + + +@@ -51,6 +52,7 @@ + -l label + + ++ + + + +@@ -62,9 +64,9 @@ + . + + +- 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. + + + +@@ -119,6 +121,17 @@ + + + ++ ++ ++ -w seconds ++ ++ ++ Specify how long to pause before carrying out key destruction. ++ The default is five seconds. If set to 0, ++ destruction will be immediate. ++ ++ ++ + + + +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 @@ + +
+

Synopsis

+-

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 seconds]

+
+
+-

DESCRIPTION

++

DESCRIPTION

+

+ pkcs11-destroy destroys keys stored in a + PKCS#11 device, identified by their ID or + label. +

+

+- 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. +

+
+
+-

ARGUMENTS

++

ARGUMENTS

+
+
-m module
+

+@@ -71,17 +71,23 @@ + Specify the PIN for the device. If no PIN is provided on the + command line, pkcs11-destroy will prompt for it. +

++
-w seconds
++

++ Specify how long to pause before carrying out key destruction. ++ The default is five seconds. If set to 0, ++ destruction will be immediate. ++

+
+
+
+-

SEE ALSO

++

SEE ALSO

+

+ pkcs11-list(3), + pkcs11-keygen(3) +

+
+
+-

AUTHOR

++

AUTHOR

+

Internet Systems Consortium +

+
+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 + #include + #include +-#include "cryptoki.h" + +-#ifdef WIN32 +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include ++#include ++#include ++ ++#include ++#include ++#define WANT_DH_PRIMES ++#define WANT_ECC_CURVES ++#include + + #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 @@ + --> + + +- ++ + +- Sep 18, 2009 ++ Feb 30, 2012 + + + +- pkcs11-keygen ++ pkcs11-ecgen + 8 + BIND9 + + + + pkcs11-keygen +- generate RSA keys on a PKCS#11 device ++ generate keys on a PKCS#11 device + + + + + 2009 ++ 2014 + Internet Systems Consortium, Inc. ("ISC") + + +@@ -44,14 +45,17 @@ + + + pkcs11-keygen +- +- +- ++ -a algorithm ++ + +- -b keysize +- -l label + ++ ++ + ++ ++ ++ ++ label + + + +@@ -59,8 +63,8 @@ + DESCRIPTION + + pkcs11-keygen causes a PKCS#11 device to generate +- a new RSA key pair with the specified and +- with bits of modulus. ++ a new key pair with the given (which must be ++ unique) and with bits of prime. + + + +@@ -68,83 +72,109 @@ + ARGUMENTS + + +- -P ++ -a algorithm + + +- 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 ++ 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". + + + + + +- -m module ++ -b keysize + + +- 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 bits of ++ prime. For ECC keys, the only valid values are 256 and 384, ++ and the default is 256. + + + + + +- -s slot ++ -e + + +- Open the session with the given PKCS#11 slot. The default is +- slot 0. ++ For RSA keys only, use a large exponent. + + + + + +- -e ++ -i id + + +- 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. + + + + + +- -b keysize ++ -m module + + +- Create the key pair with 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. ++ ++ ++ ++ ++ ++ -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. + + + + + +- -l label ++ -p PIN + + +- 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, pkcs11-ecgen will ++ prompt for it. + + + + + +- -i id ++ -q + + +- 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. ++ ++ ++ ++ ++ ++ -S ++ ++ ++ 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 PIN ++ -s slot + + +- Specify the PIN for the device. If no PIN is provided on the +- command line, pkcs11-keygen will prompt for it. ++ Open the session with the given PKCS#11 slot. The default is ++ slot 0. + + + +@@ -155,6 +185,12 @@ + SEE ALSO + + ++ pkcs11-rsagen3 ++ , ++ ++ pkcs11-dsagen3 ++ , ++ + pkcs11-list3 + , + +@@ -167,11 +203,6 @@ + + + +- CAVEAT +- Some PKCS#11 providers crash with big public exponent. +- +- +- + AUTHOR + Internet Systems Consortium + +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 @@ + + + +-pkcs11-keygen ++pkcs11-ecgen + + +
+-
++
+
+

Name

+-

pkcs11-keygen — generate RSA keys on a PKCS#11 device

++

pkcs11-keygen — generate keys on a PKCS#11 device

+
+
+

Synopsis

+-

pkcs11-keygen [-P] [-m module] [-s slot] [-e] {-b keysize} {-l label} [-i id] [-p PIN]

++

pkcs11-keygen {-a algorithm} [-b keysize] [-e] [-i id] [-m module] [-P] [-p PIN] [-q] [-S] [-s slot] {label}

+
+
+-

DESCRIPTION

++

DESCRIPTION

+

+ pkcs11-keygen causes a PKCS#11 device to generate +- a new RSA key pair with the specified label and +- with keysize bits of modulus. ++ a new key pair with the given label (which must be ++ unique) and with keysize bits of prime. +

+
+
+-

ARGUMENTS

++

ARGUMENTS

+
+-
-P
++
-a algorithm
+

+- 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 ++ algorithm 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". ++

++
-b keysize
++

++ Create the key pair with keysize bits of ++ prime. For ECC keys, the only valid values are 256 and 384, ++ and the default is 256. ++

++
-e
++

++ For RSA keys only, use a large exponent. ++

++
-i id
++

++ Create key objects with id. The id is either ++ an unsigned short 2 byte or an unsigned long 4 byte number. +

+
-m module
+

+@@ -55,51 +72,48 @@ + path to a shared library object implementing the PKCS#11 API + for the device. +

+-
-s slot
+-

+- Open the session with the given PKCS#11 slot. The default is +- slot 0. +-

+-
-e
++
-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. +

+-
-b keysize
++
-p PIN
+

+- Create the key pair with keysize bits of +- modulus. ++ Specify the PIN for the device. If no PIN is provided on ++ the command line, pkcs11-ecgen will ++ prompt for it. +

+-
-l label
++
-q
+

+- Create key objects with the given label. +- This name must be unique. ++ Quiet mode: suppress unnecessary output. +

+-
-i id
++
-S
+

+- 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 PIN
++
-s slot
+

+- Specify the PIN for the device. If no PIN is provided on the +- command line, pkcs11-keygen will prompt for it. ++ Open the session with the given PKCS#11 slot. The default is ++ slot 0. +

+
+
+
+-

SEE ALSO

++

SEE ALSO

+

++ pkcs11-rsagen(3), ++ pkcs11-dsagen(3), + pkcs11-list(3), + pkcs11-destroy(3), + dnssec-keyfromlabel(3), +

+
+
+-

CAVEAT

+-

Some PKCS#11 providers crash with big public exponent.

+-
+-
+-

AUTHOR

++

AUTHOR

+

Internet Systems Consortium +

+
+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 + #include + #include +-#include "cryptoki.h" + +-#ifdef WIN32 +-#include "win32.c" +-#else +-#ifndef FORCE_STATIC_PROVIDER +-#include "unix.c" +-#endif +-#endif ++#include ++#include ++#include ++ ++#include ++#include + + #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 ++.\" 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++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 @@ ++]> ++ ++ ++ ++ ++ ++ August 25, 2013 ++ ++ ++ ++ pkcs11-tokens ++ 8 ++ BIND9 ++ ++ ++ ++ pkcs11-tokens ++ list PKCS#11 available tokens ++ ++ ++ ++ ++ 2013 ++ Internet Systems Consortium, Inc. ("ISC") ++ ++ ++ ++ ++ ++ pkcs11-tokens ++ ++ ++ ++ ++ ++ DESCRIPTION ++ ++ pkcs11-tokens ++ lists the PKCS#11 available tokens with defaults from the slot/token ++ scan performed at application initialization. ++ ++ ++ ++ ++ ARGUMENTS ++ ++ ++ -m module ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ ++ ++ AUTHOR ++ Internet Systems Consortium ++ ++ ++ ++ +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 @@ ++ ++ ++ ++ ++ ++pkcs11-tokens ++ ++ ++
++
++
++

Name

++

pkcs11-tokens — list PKCS#11 available tokens

++
++
++

Synopsis

++

pkcs11-tokens [-m module]

++
++
++

DESCRIPTION

++

++ pkcs11-tokens ++ lists the PKCS#11 available tokens with defaults from the slot/token ++ scan performed at application initialization. ++

++
++
++

ARGUMENTS

++
++
-m module
++

++ 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. ++

++
++
++
++

AUTHOR

++

Internet Systems Consortium ++

++
++
++ +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 /* Required for HP/UX (and others?) */ + + #include ++#include + #include + #include + +@@ -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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 < /dev/null < 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 < 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 + + #include +@@ -44,8 +44,16 @@ + #include + #include + ++#ifdef OPENSSL + #include + #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 + #include + + 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 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 + #include +@@ -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 ++#include ++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 @@ + + + +- PKCS #11 (Cryptoki) support +- 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. +- 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. ++ PKCS#11 (Cryptoki) support ++ ++ 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. ++ ++ ++ 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. ++ ++ ++ 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. ++ ++ ++ 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. ++ + + Prerequisites +- See the HSM vendor documentation for information about +- installing, initializing, testing and troubleshooting the +- HSM. +- 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. +- 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. +- 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: ++ ++ See the documentation provided by your HSM vendor for ++ information about installing, initializing, testing and ++ troubleshooting the HSM. ++ ++ ++ ++ Native PKCS#11 ++ ++ Native PKCS#11 mode will only work with an HSM capable of carrying ++ out every 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.) ++ ++ ++ To build BIND with native PKCS#11, configure as follows: ++ ++ ++$ cd bind9 ++$ ./configure --enable-native-pkcs11 \ ++ --with-pkcs11=provider-library-path ++ ++ ++ This will cause all BIND tools, including named ++ and the dnssec-* and pkcs11-* ++ tools, to use the PKCS#11 provider library specified in ++ provider-library-path for cryptography. ++ (The provider library path can be overridden using the ++ in named and the ++ dnssec-* tools, or the in ++ the pkcs11-* tools.) ++ ++ ++ ++ OpenSSL-based PKCS#11 ++ ++ 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. ++ ++ ++ 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: ++ + + +- 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. ++ ++ 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. ++ + + +- 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. ++ ++ 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. ++ + + +- 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. ++ ++ 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. + + +- 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. ++ is expected to change. ++ + +- 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. +- Obtain OpenSSL 0.9.8s: +- +-$ wget http://www.openssl.org/source/openssl-0.9.8s.tar.gz +- +- Extract the tarball: +- +-$ tar zxf openssl-0.9.8s.tar.gz ++ 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. ++ ++ ++ Patching OpenSSL ++ ++$ wget http://www.openssl.org/source/openssl-0.9.8y.tar.gz ++ ++ Extract the tarball: ++ ++$ tar zxf openssl-0.9.8y.tar.gz + +- Apply the patch from the BIND 9 release: +- +-$ patch -p1 -d openssl-0.9.8s \ +- < bind9/bin/pkcs11/openssl-0.9.8s-patch ++ Apply the patch from the BIND 9 release: ++ ++$ patch -p1 -d openssl-0.9.8y \ ++ < bind9/bin/pkcs11/openssl-0.9.8y-patch + +- (Note that the patch file may not be compatible with the +- "patch" utility on all operating systems. You may need to +- install GNU patch.) +- 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. ++ ++ Note that the patch file may not be compatible with the ++ "patch" utility on all operating systems. You may need to ++ install GNU patch. ++ ++ ++ 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. ++ ++ ++ Later, when building BIND 9, the location of the custom-built ++ OpenSSL library will need to be specified via configure. ++ ++ + + + Building OpenSSL for the AEP Keyper on Linux +- 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. +- The Keyper-specific PKCS #11 provider library is +- delivered with the Keyper software. In this example, we place +- it /opt/pkcs11/usr/lib: ++ ++ 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. ++ ++ ++ The Keyper-specific PKCS#11 provider library is ++ delivered with the Keyper software. In this example, we place ++ it /opt/pkcs11/usr/lib: ++ + + $ cp pkcs11.GCC4.0.2.so.4.05 /opt/pkcs11/usr/lib/libpkcs11.so + +- 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. +- Finally, the Keyper library requires threads, so we +- must specify -pthread. ++ ++ 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. ++ ++ ++ Finally, the Keyper library requires threads, so we ++ must specify -pthread. ++ + +-$ cd openssl-0.9.8s ++$ cd openssl-0.9.8y + $ ./Configure linux-generic32 -m32 -pthread \ + --pk11-libname=/opt/pkcs11/usr/lib/libpkcs11.so \ + --pk11-flavor=sign-only \ + --prefix=/opt/pkcs11/usr + +- After configuring, run "make" +- and "make test". If "make +- test" fails with "pthread_atfork() not found", you forgot to +- add the -pthread above. ++ ++ After configuring, run "make" ++ and "make test". If "make ++ test" fails with "pthread_atfork() not found", you forgot to ++ add the -pthread above. ++ + + + + Building OpenSSL for the SCA 6000 on Solaris +- 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'. +- In this example, we are building on Solaris x86 on an +- AMD64 system. ++ ++ 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'. ++ ++ ++ In this example, we are building on Solaris x86 on an ++ AMD64 system. ++ + +-$ cd openssl-0.9.8s ++$ cd openssl-0.9.8y + $ ./Configure solaris64-x86_64-cc \ + --pk11-libname=/usr/lib/64/libpkcs11.so \ + --pk11-flavor=crypto-accelerator \ + --prefix=/opt/pkcs11/usr + +- (For a 32-bit build, use "solaris-x86-cc" and +- /usr/lib/libpkcs11.so.) +- After configuring, run +- make and +- make test. ++ ++ (For a 32-bit build, use "solaris-x86-cc" and /usr/lib/libpkcs11.so.) ++ ++ ++ After configuring, run ++ make and ++ make test. ++ + + + + Building OpenSSL for SoftHSM +- 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. +- 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: ++ ++ 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. ++ ++ ++ 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: ++ + + $ cd softhsm-1.3.0 + $ configure --prefix=/opt/pkcs11/usr +@@ -185,25 +282,31 @@ $ export SOFTHSM_CONF=/opt/pkcs11/softhsm.conf + $ echo "0:/opt/pkcs11/softhsm.db" > $SOFTHSM_CONF + $ /opt/pkcs11/usr/bin/softhsm --init-token 0 --slot 0 --label softhsm + +- 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. ++ ++ 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. ++ + +-$ cd openssl-0.9.8s ++$ cd openssl-0.9.8y + $ ./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 + +- After configuring, run "make" +- and "make test". ++ ++ After configuring, run "make" ++ and "make test". ++ + +- Once you have built OpenSSL, run +- "apps/openssl engine pkcs11" to confirm +- that PKCS #11 support was compiled in correctly. The output +- should be one of the following lines, depending on the flavor +- selected: ++ ++ Once you have built OpenSSL, run ++ "apps/openssl engine pkcs11" to confirm ++ that PKCS#11 support was compiled in correctly. The output ++ should be one of the following lines, depending on the flavor ++ selected: ++ + + (pkcs11) PKCS #11 engine support (sign only) + +@@ -211,29 +314,31 @@ $ ./Configure linux-x86_64 -pthread \ + + (pkcs11) PKCS #11 engine support (crypto accelerator) + +- Next, run +- "apps/openssl engine pkcs11 -t". This will +- attempt to initialize the PKCS #11 engine. If it is able to +- do so successfully, it will report +- [ available ]. +- If the output is correct, run +- "make install" which will install the +- modified OpenSSL suite to +- /opt/pkcs11/usr. +- +- +- Building BIND 9 with PKCS#11 +- When building BIND 9, the location of the custom-built +- OpenSSL library must be specified via configure. ++ ++ Next, run ++ "apps/openssl engine pkcs11 -t". This will ++ attempt to initialize the PKCS#11 engine. If it is able to ++ do so successfully, it will report ++ [ available ]. ++ ++ ++ If the output is correct, run ++ "make install" which will install the ++ modified OpenSSL suite to /opt/pkcs11/usr. ++ + + + Configuring BIND 9 for Linux with the AEP Keyper +- To link with the PKCS #11 provider, threads must be +- enabled in the BIND 9 build. +- 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. ++ ++ To link with the PKCS#11 provider, threads must be ++ enabled in the BIND 9 build. ++ ++ ++ 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. ++ + + $ cd ../bind9 + $ ./configure CC="gcc -m32" --enable-threads \ +@@ -244,8 +349,10 @@ $ ./configure CC="gcc -m32" --enable-threads \ + + + Configuring BIND 9 for Solaris with the SCA 6000 +- To link with the PKCS #11 provider, threads must be +- enabled in the BIND 9 build. ++ ++ To link with the PKCS#11 provider, threads must be ++ enabled in the BIND 9 build. ++ + + $ cd ../bind9 + $ ./configure CC="cc -xarch=amd64" --enable-threads \ +@@ -253,11 +360,13 @@ $ ./configure CC="cc -xarch=amd64" --enable-threads \ + --with-pkcs11=/usr/lib/64/libpkcs11.so + + (For a 32-bit build, omit CC="cc -xarch=amd64".) +- 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). ++ ++ 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). ++ + + + +@@ -266,63 +375,85 @@ $ ./configure CC="cc -xarch=amd64" --enable-threads \ + $ cd ../bind9 + $ ./configure --enable-threads \ + --with-openssl=/opt/pkcs11/usr \ +- --with-pkcs11=/opt/pkcs11/usr/lib/libpkcs11.so ++ --with-pkcs11=/opt/pkcs11/usr/lib/libsofthsm.so + + +- After configuring, run +- "make", +- "make test" and +- "make install". +- (Note: If "make test" fails in the "pkcs11" system test, you may +- have forgotten to set the SOFTHSM_CONF environment variable.) ++ ++ After configuring, run ++ "make", ++ "make test" and ++ "make install". ++ ++ ++ (Note: If "make test" fails in the "pkcs11" system test, you may ++ have forgotten to set the SOFTHSM_CONF environment variable.) ++ + + +- PKCS #11 Tools +- BIND 9 includes a minimal set of tools to operate the +- HSM, including +- pkcs11-keygen to generate a new key pair +- within the HSM, +- pkcs11-list to list objects currently +- available, and +- pkcs11-destroy to remove objects. +- 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.) ++ PKCS#11 Tools ++ ++ BIND 9 includes a minimal set of tools to operate the ++ HSM, including ++ pkcs11-keygen to generate a new key pair ++ within the HSM, ++ pkcs11-list to list objects currently ++ available, ++ pkcs11-destroy to remove objects, and ++ pkcs11-tokens to list available tokens. ++ ++ ++ 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.) ++ + + + Using the HSM +- First, we must set up the runtime environment so the +- OpenSSL and PKCS #11 libraries can be loaded: ++ ++ For OpenSSL-based PKCS#11, we must first set up the runtime ++ environment so the OpenSSL and PKCS#11 libraries can be loaded: ++ + + $ export LD_LIBRARY_PATH=/opt/pkcs11/usr/lib:${LD_LIBRARY_PATH} + +- 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 +- /opt/Keyper/PKCS11Provider/machine, +- use: ++ ++ This causes named and other binaries to load ++ the OpenSSL library from /opt/pkcs11/usr/lib ++ rather than from the default location. This step is not necessary ++ when using native PKCS#11. ++ ++ ++ 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 ++ /opt/Keyper/PKCS11Provider/machine, ++ use: ++ + + $ export KEYPER_LIBRARY_PATH=/opt/Keyper/PKCS11Provider + +- +- These environment variables must be set whenever running +- any tool that uses the HSM, including +- pkcs11-keygen, +- pkcs11-list, +- pkcs11-destroy, +- dnssec-keyfromlabel, +- dnssec-signzone, +- dnssec-keygen(which will use the HSM for +- random number generation), and +- named. +- 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": ++ ++ Such environment variables must be set whenever running ++ any tool that uses the HSM, including ++ pkcs11-keygen, ++ pkcs11-list, ++ pkcs11-destroy, ++ dnssec-keyfromlabel, ++ dnssec-signzone, ++ dnssec-keygen, and ++ named. ++ ++ ++ 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": ++ + + $ pkcs11-keygen -b 2048 -l sample-ksk + +@@ -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] + +- 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": ++ ++ 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": ++ + + $ dnssec-keyfromlabel -l sample-ksk -f KSK example.net + +- 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. +- 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: ++ ++ 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. ++ ++ ++ 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: ++ + + $ pkcs11-keygen -b 1024 -l sample-zsk + $ dnssec-keyfromlabel -l sample-zsk example.net + +- Alternatively, you may prefer to generate a conventional +- on-disk key, using dnssec-keygen: ++ ++ Alternatively, you may prefer to generate a conventional ++ on-disk key, using dnssec-keygen: ++ + + $ dnssec-keygen example.net + +- 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. +- Now you can sign the zone. (Note: If not using the -S +- option to +- dnssec-signzone, it will be necessary to add +- the contents of both +- K*.key files to the zone master file before +- signing it.) ++ ++ 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.) ++ ++ ++ Now you can sign the zone. (Note: If not using the -S ++ option to dnssec-signzone, it will be ++ necessary to add the contents of both K*.key ++ files to the zone master file before signing it.) ++ + + $ dnssec-signzone -S example.net + Enter PIN: +@@ -383,36 +526,50 @@ example.net.signed + + + Specifying the engine on the command line +- The OpenSSL engine can be specified in +- named and all of the BIND +- dnssec-* 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. +- 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: ++ ++ When using OpenSSL-based PKCS#11, the "engine" to be used by ++ OpenSSL can be specified in named and all of ++ the BIND dnssec-* 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. ++ ++ ++ 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: ++ + + $ dnssec-signzone -E '' -S example.net + +- This causes +- dnssec-signzone to run as if it were compiled +- without the --with-pkcs11 option. ++ ++ This causes ++ dnssec-signzone to run as if it were compiled ++ without the --with-pkcs11 option. ++ ++ ++ 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. ++ + + + Running named with automatic zone re-signing +- If you want +- named 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, +- /opt/pkcs11/usr/ssl/openssl.cnf). +- The location of the openssl.cnf file can be overridden by +- setting the OPENSSL_CONF environment variable before running +- named. ++ ++ If you want named 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, ++ /opt/pkcs11/usr/ssl/openssl.cnf). ++ ++ ++ The location of the openssl.cnf file can be overridden by ++ setting the OPENSSL_CONF environment variable before running ++ named. ++ + Sample openssl.cnf: + + openssl_conf = openssl_def +@@ -423,22 +580,25 @@ $ dnssec-signzone -E '' -S example.net + [ pkcs11_section ] + PIN = <PLACE PIN HERE> + +- 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.) +- ++ ++ 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.) ++ ++ ++ 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 ++ pkcs11:object=local-zsk;pin-source=/etc/hsmpin", ++ then the PIN would be read from the file ++ /etc/hsmpin. ++ + +- 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. ++ ++ 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. ++ + + +- +- + +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 + +-#ifdef HAVE_OPENSSL_GOST +-#include +-#include +- +-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 ++#include ++#include ++ ++#define ISC_GOST_DIGESTLENGTH 32U ++ ++#ifdef HAVE_OPENSSL_GOST ++#include ++ ++typedef EVP_MD_CTX isc_gost_t; ++#endif ++#ifdef HAVE_PKCS11_GOST ++#include ++ ++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 ++#include ++#include ++ ++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 + +-#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 + #include +@@ -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 ++ ++#include ++#include ++ ++#include ++#include ++ ++#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 ++ ++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 ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++#include ++#define WANT_DH_PRIMES ++#include ++ ++#include ++ ++/* ++ * 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 ++ ++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 ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++ ++/* ++ * 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 ++ ++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 ++ ++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_ECDSA) ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++#include ++#define WANT_ECC_CURVES ++#include ++ ++#include ++ ++/* ++ * 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) ++ */ ++ ++#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 ++ ++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 ++ ++#if defined(PKCS11CRYPTO) && defined(HAVE_PKCS11_GOST) ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++#include "dst_gost.h" ++ ++#include ++#include ++#define WANT_GOST_PARAMS ++#include ++ ++#include ++ ++/* ++ * 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: (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 ++ ++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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include "dst_internal.h" ++#include "dst_parse.h" ++#include "dst_pkcs11.h" ++ ++#include ++ ++/* ++ * 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 ++ ++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 + ++#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 + ++#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 ++ ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#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 + #include + ++#include "dst_internal.h" ++ + #define TKEY_RANDOM_AMOUNT 16 + ++#ifdef PKCS11CRYPTO ++#include ++#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 + #include + ++#ifdef PKCS11CRYPTO ++#include ++#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 + #include + ++#if PKCS11CRYPTO || PKCS11CRYPTOWITHHMAC ++#include ++#include ++#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 + #include + ++#if PKCS11CRYPTO ++#include ++#include ++#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 ++ ++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 ++ ++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 ++ ++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 ++ ++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 ++ ++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 ++#include ++#include ++ ++#define PK11_FATALCHECK(func, args) \ ++ ((void) (((rv = (func) args) == CKR_OK) || \ ++ ((pk11_error_fatalcheck)(__FILE__, __LINE__, #func, rv), 0))) ++ ++#include ++ ++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 ++#include ++ ++/* ++ * Nothing in this file truly depends on , 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 /* 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 + #include + #include ++ ++#if PKCS11CRYPTO ++#include ++#include ++#endif ++ + #include + + #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 ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#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 ++#include ++ ++#include ++#include ++#include ++ ++#include ++ ++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 + #include + +-#ifdef ISC_PLATFORM_OPENSSLHASH ++#if PKCS11CRYPTO ++#include ++#include ++#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 + #include + ++#if PKCS11CRYPTO ++#include ++#include ++#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 ++#define NULL_PTR NULL ++ ++#undef CK_PKCS11_FUNCTION_INFO ++ ++#include ++ ++#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 ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#define KEEP_PKCS11_NAMES ++#include ++#include ++ ++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 +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 + #include + #include 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/bind93-rh726120.patch b/SOURCES/bind93-rh726120.patch new file mode 100644 index 0000000..5eb11ee --- /dev/null +++ b/SOURCES/bind93-rh726120.patch @@ -0,0 +1,26 @@ +From 23c33ea76e916cc16e354faa218b6a0ca6385d00 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Tue, 5 Dec 2017 16:33:08 +0100 +Subject: [PATCH] Fix bug #726120 + +--- + bin/dig/dighost.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c +index 42a2fe2..3a066c6 100644 +--- a/bin/dig/dighost.c ++++ b/bin/dig/dighost.c +@@ -3416,7 +3416,8 @@ recv_done(isc_task_t *task, isc_event_t *event) { + 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) +-- +2.9.5 + 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 + #include + ++/* 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 + #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] + max-acache-size size_spec ; + clients-per-query number ; + max-clients-per-query number ; ++ max-recursion-depth number ; ++ max-recursion-queries number ; + masterfile-format (text|raw) ; + empty-server name ; + empty-contact name ; +@@ -8623,6 +8625,35 @@ avoid-v6-udp-ports { 40000; range 50000 + + + ++ ++ ++ max-recursion-depth ++ ++ ++ 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. ++ ++ ++ ++ ++ ++ max-recursion-queries ++ ++ ++ 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. ++ ++ ++ + + + notify-delay +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 ; // obsolete + max-journal-size ; + max-ncache-ttl ; ++ max-recursion-depth ; ++ max-recursion-queries ; + max-refresh-time ; + max-retry-time ; + max-rsa-exponent-size ; +@@ -385,6 +387,8 @@ view { + max-ixfr-log-size ; // obsolete + max-journal-size ; + max-ncache-ttl ; ++ max-recursion-depth ; ++ max-recursion-queries ; + max-refresh-time ; + max-retry-time ; + max-transfer-idle-in ; +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 + ++#include + #include + #include + #include +@@ -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 ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++ ++/***** ++ ***** 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 +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 +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?= +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?= +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-CVE-2017-3145.patch b/SOURCES/bind99-CVE-2017-3145.patch new file mode 100644 index 0000000..167f277 --- /dev/null +++ b/SOURCES/bind99-CVE-2017-3145.patch @@ -0,0 +1,124 @@ +From 4d73fed57703f561aefd545eda0f3f2c5e69a547 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Petr=20Men=C5=A1=C3=ADk?= +Date: Tue, 16 Jan 2018 09:50:45 +0100 +Subject: [PATCH] 4858. [security] Addresses could be referenced after + being freed in resolver.c, causing an assertion failure. + (CVE-2017-3145) [RT #46839] + +--- + lib/dns/resolver.c | 37 +++++++++++++++++++++++-------------- + 1 file changed, 23 insertions(+), 14 deletions(-) + +diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c +index 860a792..619646f 100644 +--- a/lib/dns/resolver.c ++++ b/lib/dns/resolver.c +@@ -751,7 +751,7 @@ fctx_stoptimer(fetchctx_t *fctx) { + * cannot fail in that case. + */ + result = isc_timer_reset(fctx->timer, isc_timertype_inactive, +- NULL, NULL, ISC_TRUE); ++ NULL, NULL, ISC_TRUE); + if (result != ISC_R_SUCCESS) { + UNEXPECTED_ERROR(__FILE__, __LINE__, + "isc_timer_reset(): %s", +@@ -759,7 +759,6 @@ fctx_stoptimer(fetchctx_t *fctx) { + } + } + +- + static inline isc_result_t + fctx_startidletimer(fetchctx_t *fctx, isc_interval_t *interval) { + /* +@@ -992,7 +991,8 @@ fctx_cleanupfinds(fetchctx_t *fctx) { + + for (find = ISC_LIST_HEAD(fctx->finds); + find != NULL; +- find = next_find) { ++ find = next_find) ++ { + next_find = ISC_LIST_NEXT(find, publink); + ISC_LIST_UNLINK(fctx->finds, find, publink); + dns_adb_destroyfind(&find); +@@ -1008,7 +1008,8 @@ fctx_cleanupaltfinds(fetchctx_t *fctx) { + + for (find = ISC_LIST_HEAD(fctx->altfinds); + find != NULL; +- find = next_find) { ++ find = next_find) ++ { + next_find = ISC_LIST_NEXT(find, publink); + ISC_LIST_UNLINK(fctx->altfinds, find, publink); + dns_adb_destroyfind(&find); +@@ -1024,7 +1025,8 @@ fctx_cleanupforwaddrs(fetchctx_t *fctx) { + + for (addr = ISC_LIST_HEAD(fctx->forwaddrs); + addr != NULL; +- addr = next_addr) { ++ addr = next_addr) ++ { + next_addr = ISC_LIST_NEXT(addr, publink); + ISC_LIST_UNLINK(fctx->forwaddrs, addr, publink); + dns_adb_freeaddrinfo(fctx->adb, &addr); +@@ -1039,7 +1041,8 @@ fctx_cleanupaltaddrs(fetchctx_t *fctx) { + + for (addr = ISC_LIST_HEAD(fctx->altaddrs); + addr != NULL; +- addr = next_addr) { ++ addr = next_addr) ++ { + next_addr = ISC_LIST_NEXT(addr, publink); + ISC_LIST_UNLINK(fctx->altaddrs, addr, publink); + dns_adb_freeaddrinfo(fctx->adb, &addr); +@@ -1047,14 +1050,18 @@ fctx_cleanupaltaddrs(fetchctx_t *fctx) { + } + + static inline void +-fctx_stopeverything(fetchctx_t *fctx, isc_boolean_t no_response) { +- FCTXTRACE("stopeverything"); ++fctx_stopqueries(fetchctx_t *fctx, isc_boolean_t no_response) { ++ FCTXTRACE("stopqueries"); + fctx_cancelqueries(fctx, no_response); ++ fctx_stoptimer(fctx); ++} ++ ++static inline void ++fctx_cleanupall(fetchctx_t *fctx) { + fctx_cleanupfinds(fctx); + fctx_cleanupaltfinds(fctx); + fctx_cleanupforwaddrs(fctx); + fctx_cleanupaltaddrs(fctx); +- fctx_stoptimer(fctx); + } + + static inline void +@@ -1184,7 +1191,8 @@ fctx_done(fetchctx_t *fctx, isc_result_t result, int line) { + no_response = ISC_FALSE; + + fctx->reason = NULL; +- fctx_stopeverything(fctx, no_response); ++ ++ fctx_stopqueries(fctx, no_response); + + LOCK(&res->buckets[fctx->bucketnum].lock); + +@@ -3336,11 +3344,12 @@ fctx_doshutdown(isc_task_t *task, isc_event_t *event) { + dns_resolver_cancelfetch(fctx->nsfetch); + + /* +- * Shut down anything that is still running on behalf of this +- * fetch. To avoid deadlock with the ADB, we must do this +- * before we lock the bucket lock. ++ * Shut down anything still running on behalf of this ++ * fetch, and clean up finds and addresses. To avoid deadlock ++ * with the ADB, we must do this before we lock the bucket lock. + */ +- fctx_stopeverything(fctx, ISC_FALSE); ++ fctx_stopqueries(fctx, ISC_FALSE); ++ fctx_cleanupall(fctx); + + LOCK(&res->buckets[bucketnum].lock); + +-- +2.14.3 + 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 +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 +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 +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 +--- + 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 + #include + #include ++#include ++ ++#ifdef HAVE_NET_ROUTE_H ++#include ++#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 ++#include ++#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 boolean; + zero-no-soa-ttl-cache boolean; + dnssec-secure-to-insecure boolean; ++ automatic-interface-scan boolean; + deny-answer-addresses { + address_match_list + } except-from { namelist } ; +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 @@ + + + ++ scan ++ ++ ++ Scan the list of available network interfaces ++ for changes, without performing a full ++ reconfig or waiting for the ++ interface-interval timer. ++ ++ ++ ++ ++ + sync -clean zone class view + + +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 header file. */ + #undef HAVE_LINUX_CAPABILITY_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_LINUX_NETLINK_H ++ ++/* Define to 1 if you have the header file. */ ++#undef HAVE_LINUX_RTNETLINK_H ++ + /* Define to 1 if you have the 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 header file. */ + #undef HAVE_NET_IF6_H + ++/* Define to 1 if you have the 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 header file. */ + #undef HAVE_SYS_SELECT_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_SOCKET_H ++ + /* Define to 1 if you have the 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 + #endif ++#ifdef HAVE_SYS_SOCKET_H ++# include ++#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] + policy given | disabled | passthru | nxdomain | nodata | cname domain + recursive-only yes_or_no max-policy-ttl number ; + } recursive-only yes_or_no max-policy-ttl number +- break-dnssec yes_or_no min-ns-dots number ; ++ break-dnssec yes_or_no min-ns-dots number ++ automatic-interface-scan yes_or_no ++ ; + }; + + +@@ -5726,6 +5728,23 @@ options { + + + ++ automatic-interface-scan ++ ++ ++ If yes and supported by the OS, ++ automatically rescan network interfaces when the interface ++ addresses are added or removed. The default is ++ yes. ++ ++ ++ Currently the OS needs to support routing sockets for ++ automatic-interface-scan to be ++ supported. ++ ++ ++ ++ ++ + allow-new-zones + + +@@ -10494,6 +10513,7 @@ zone zone_name class allow-query-on { address_match_list }; + allow-transfer { address_match_list }; + allow-update-forwarding { address_match_list }; ++ automatic-interface-scan { yes_or_no }; + dnssec-update-mode ( maintain | no-resign ); + update-check-ksk yes_or_no; + dnssec-dnskey-kskonly yes_or_no; +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 + #include + ++#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) ++#include ++#include ++#endif ++ + #include + #include + #include +@@ -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 +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 +--- + 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 + #include + +-#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 +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 +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 +--- + 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 + + #include ++#include + #include + #include + #include +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 + #include ++#include + #include + #include + #include +@@ -64,6 +65,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -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 ++Jiri Kuncar ++Martin Nagy ++Petr Spacek +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 ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 {} 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 ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#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 ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++#include ++#include ++ ++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 ++ ++#include ++#include ++ ++#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 ++ ++#include ++ ++#include ++ ++#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 ++#include ++#include ++ ++#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 ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#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 ++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 ++#include ++ ++#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 ++ ++#include ++ ++#include ++#include ++#include ++ ++#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 < 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 < 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 { + + + ++ ++ + + IPv6 Support in <acronym>BIND</acronym> 9 + +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 @@ ++ ++ ++ ++ ++ DynDB (Dynamic Database) ++ ++ DynDB is an extension to BIND 9 which, like DLZ ++ (see ), 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. ++ ++ ++ A DynDB module supporting LDAP has been created by Red Hat ++ and is available from ++ https://fedorahosted.org/bind-dyndb-ldap/. ++ ++ ++ A sample DynDB module for testing and developer guidance ++ is included with the BIND source code, in the directory ++ bin/tests/system/dyndb/driver. ++ ++ ++ ++ Configuring DynDB ++ ++ A DynDB database is configured with a dyndb ++ statement in named.conf: ++ ++ ++ dyndb example "driver.so" { ++ parameters ++ }; ++ ++ ++ The file driver.so is a DynDB module which ++ implements the full DNS database API. Multiple ++ dyndb 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. ++ ++ ++ The parameters are passed as an opaque ++ string to the DynDB module's initialization routine. Configuration ++ syntax will differ depending on the driver. ++ ++ ++ ++ Sample DynDB Module ++ ++ For guidance in implementation of DynDB modules, the directory ++ bin/tests/system/dyndb/driver. ++ contains a basic DynDB module. ++ The example sets up two zones, whose names are passed ++ to the module as arguments in the dyndb ++ statement: ++ ++ ++ dyndb sample "sample.so" { example.nil. arpa. }; ++ ++ ++ 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: ++ ++ ++ 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 ++ ++ ++ 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.) ++ ++ ++ +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 ++#include + #include + #include + #include +@@ -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 ++ ++#if HAVE_DLFCN_H ++#include ++#elif _WIN32 ++#include ++#endif ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#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 ++ ++#include ++ ++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 + + #include ++#include + #include + #include + #include +@@ -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 + #include + #include ++#include + + /*% 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_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 ++ ++#include ++#include ++ ++#include ++ ++#include ++#include ++ ++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 ++ ++#include ++#include ++ ++#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 ++ ++#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, "{ }"); ++} ++ ++ + 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 + dig 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 IDN_DISABLE environment variable. ++ If you'd like to turn off the IDN support for some reason, define ++ the CHARSET=ASCII environment variable. + The IDN support is disabled if the variable is set when + dig runs. + 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 +Date: Thu, 20 Feb 2014 11:01:00 +0100 +Subject: [PATCH] check TSIG key ID when receiving NOTIFY + +Signed-off-by: Tomas Hozza +--- + 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 +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 string optional_class; + search { string; ... }; + ndots integer; ++ lwres-tasks integer; ++ lwres-clients integer; + }; + + +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 + lwres statement in named.conf. + +- ++ ++ The number of client queries that the lwresd ++ daemon is able to serve can be set using the ++ and ++ statements in the configuration. ++ + + + +@@ -4959,6 +4964,8 @@ badresp:1,adberr:0,findfail:0,valfail:0] + view view_name; + search { domain_name ; domain_name ; ... }; + ndots number; ++ lwres-tasks number; ++ lwres-clients number; + }; + + +@@ -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. + ++ ++ The 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 ++ command line option when starting the server. ++ ++ ++ The 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 named, 256 client objects are ++ created for each task; if it runs as lwresd, ++ 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. ++ ++ ++ The maximum number of client queries that the lightweight ++ resolver can handle at any one time equals ++ times . ++ + + + <command>masters</command> Statement Grammar +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 +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 +--- + 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 @@ + + + When using GSS-TSIG use realm_name rather +- than the default realm in krb5.conf. If no ++ than leaving the realm detection up to GSSAPI. If no + realm is specified the saved realm is cleared. + + +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 @@ + +

+ When using GSS-TSIG use realm_name rather +- than the default realm in krb5.conf. If no ++ than leaving the realm detection up to GSSAPI. If no + realm is specified the saved realm is cleared. +

+
+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 @@ + -T mode + + +- 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 +- "warn" (default), "ignore". ++ 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 "warn" ++ (default), "ignore". + + + +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] + check-mx-cname ( warn | fail | ignore ); + check-srv-cname ( warn | fail | ignore ); + check-sibling yes_or_no; +- check-spf ( warn | fail | ignore ); ++ check-spf ( warn | ignore ); + allow-new-zones { yes_or_no }; + allow-notify { address_match_list }; + allow-query { address_match_list }; +@@ -6573,10 +6573,13 @@ options { + The default is yes. + + +- 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 + check-spf. + + +@@ -6618,11 +6621,11 @@ options { + check-spf + + +- 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 warn. ++ If check-integrity 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 ++ warn. + + + +@@ -10372,7 +10375,7 @@ view "external" { + check-names (warn|fail|ignore) ; + check-mx (warn|fail|ignore) ; + check-wildcard yes_or_no; +- check-spf ( warn | fail | ignore ); ++ check-spf ( warn | ignore ); + check-integrity yes_or_no ; + dialup dialup_option ; + file string ; +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 +Date: Wed, 13 Apr 2016 09:57:31 +0200 +Subject: [PATCH] Added support for GeoIP + +Signed-off-by: Tomas Hozza +--- + 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 ++ ++#include ++ ++#include ++#include ++ ++#include ++ ++#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 ++#include ++#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 + #include + ++#include + #include + + #include +@@ -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 + #include + #include ++#include + #include + #include + #include +@@ -114,6 +115,9 @@ + #include + #include + #endif ++#ifdef HAVE_GEOIP ++#include ++#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 ++#include ++ ++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 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 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 ++ #include ++ ], [ ++ 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 ++ #include ++ #include ++ ], [ ++ 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. + + + ++ ++ When BIND 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: ++ geoip db database field value ++ ++ ++ The field 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". ++ ++ ++ value 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. ++ ++ ++ The database 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 database ++ will force the query to be answered from that database and no ++ other. If database 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. ++ ++ ++ Some example GeoIP ACLs: ++ ++ 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"; ++ ++ ++ + + + <command>controls</command> Statement Grammar +@@ -4692,6 +4748,7 @@ badresp:1,adberr:0,findfail:0,valfail:0] + hostname hostname_string; + server-id server_id_string; + directory path_name; ++ geoip-directory path_name; + key-directory path_name; + managed-keys-directory path_name; + named-xfer path_name; +@@ -5048,6 +5105,21 @@ badresp:1,adberr:0,findfail:0,valfail:0] + + + ++ geoip-directory ++ ++ ++ Specifies the directory containing GeoIP ++ .dat 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 about the ++ geoip ACL.) ++ ++ ++ ++ ++ + key-directory + + +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 + #include + ++ + /* + * 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 ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#ifdef HAVE_GEOIP ++#include ++#include ++ ++/* ++ * 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 + #include + ++#ifdef HAVE_GEOIP ++#include ++#endif + #include + #include + #include + ++#ifdef HAVE_GEOIP ++#include ++#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 ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#ifdef HAVE_GEOIP ++#include ++#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 ++ ++#include ++ ++#include ++ ++#include ++ ++#include ++ ++#include "dnstest.h" ++ ++#ifdef HAVE_GEOIP ++#include ++ ++/* 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 + #include + ++#ifdef HAVE_GEOIP ++#include ++#include ++#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 + ++#ifdef HAVE_GEOIP ++#include ++#endif + #include + + 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 ] search-type ++ */ ++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, ""); ++} ++#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 +Date: Fri, 1 Apr 2016 15:20:27 +0200 +Subject: [PATCH] Added support for CAA records + +Signed-off-by: Tomas Hozza +--- + 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 + + #include +@@ -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 [; = ]* : The issue property ++ entry authorizes the holder of the 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 [; = ]* : The issuewild ++ property entry authorizes the holder of the 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 : 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 ++ ++ 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 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 +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 + #include ++#include + #include + #include + +@@ -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 +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 +--- + 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-rh1464850-2.patch b/SOURCES/bind99-rh1464850-2.patch new file mode 100644 index 0000000..6c4d07c --- /dev/null +++ b/SOURCES/bind99-rh1464850-2.patch @@ -0,0 +1,102 @@ +From a58f31659a924c59f6342d79d2c19ee956453d82 Mon Sep 17 00:00:00 2001 +From: Mark Andrews +Date: Sat, 18 Oct 2014 12:40:13 +1100 +Subject: [PATCH 2/2] 3980. [bug] Improve --with-tuning=large by + self tuning of SO_RCVBUF size. [RT #37187] + +(cherry picked from commit 871f3c8beeb2134b17414ec167b90a57adb8e122) +--- + lib/isc/unix/socket.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 61 insertions(+), 5 deletions(-) + +diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c +index af0c3bc..90953ff 100644 +--- a/lib/isc/unix/socket.c ++++ b/lib/isc/unix/socket.c +@@ -2245,6 +2245,62 @@ free_socket(isc__socket_t **socketp) { + *socketp = NULL; + } + ++#ifdef SO_RCVBUF ++static isc_once_t rcvbuf_once = ISC_ONCE_INIT; ++static int rcvbuf = RCVBUFSIZE; ++ ++static void ++set_rcvbuf(void) { ++ int fd; ++ int max = rcvbuf, min; ++ ISC_SOCKADDR_LEN_T len; ++ ++ fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++#if defined(ISC_PLATFORM_HAVEIPV6) ++ if (fd == -1) { ++ switch (errno) { ++ case EPROTONOSUPPORT: ++ case EPFNOSUPPORT: ++ case EAFNOSUPPORT: ++ /* ++ * Linux 2.2 (and maybe others) return EINVAL instead of ++ * EAFNOSUPPORT. ++ */ ++ case EINVAL: ++ fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); ++ break; ++ } ++ } ++#endif ++ if (fd == -1) ++ return; ++ ++ len = sizeof(min); ++ if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&min, &len) >= 0 && ++ min < rcvbuf) { ++ again: ++ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *)&rcvbuf, ++ sizeof(rcvbuf)) == -1) { ++ if (errno == ENOBUFS && rcvbuf > min) { ++ max = rcvbuf - 1; ++ rcvbuf = (rcvbuf + min) / 2; ++ goto again; ++ } else { ++ rcvbuf = min; ++ goto cleanup; ++ } ++ } else ++ min = rcvbuf; ++ if (min != max) { ++ rcvbuf = max; ++ goto again; ++ } ++ } ++ cleanup: ++ close (fd); ++} ++#endif ++ + #ifdef SO_BSDCOMPAT + /* + * This really should not be necessary to do. Having to workout +@@ -2609,15 +2665,15 @@ opensocket(isc__socketmgr_t *manager, isc__socket_t *sock, + #if defined(SO_RCVBUF) + optlen = sizeof(size); + if (getsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, +- (void *)&size, &optlen) >= 0 && +- size < RCVBUFSIZE) { +- size = RCVBUFSIZE; ++ (void *)&size, &optlen) >= 0 && size < rcvbuf) { ++ RUNTIME_CHECK(isc_once_do(&rcvbuf_once, ++ set_rcvbuf) == ISC_R_SUCCESS); + if (setsockopt(sock->fd, SOL_SOCKET, SO_RCVBUF, +- (void *)&size, sizeof(size)) == -1) { ++ (void *)&rcvbuf, sizeof(rcvbuf)) == -1) { + isc__strerror(errno, strbuf, sizeof(strbuf)); + UNEXPECTED_ERROR(__FILE__, __LINE__, + "setsockopt(%d, SO_RCVBUF, %d) %s: %s", +- sock->fd, size, ++ sock->fd, rcvbuf, + isc_msgcat_get(isc_msgcat, + ISC_MSGSET_GENERAL, + ISC_MSG_FAILED, +-- +2.9.5 + diff --git a/SOURCES/bind99-rh1464850.patch b/SOURCES/bind99-rh1464850.patch new file mode 100644 index 0000000..f96db9a --- /dev/null +++ b/SOURCES/bind99-rh1464850.patch @@ -0,0 +1,1849 @@ +From b154e9fd7a4acc87435f858d43b8c234885a8763 Mon Sep 17 00:00:00 2001 +From: Evan Hunt +Date: Tue, 18 Feb 2014 22:36:14 -0800 +Subject: [PATCH 1/2] add "--with-tuning=large" option + +3745. [func] "configure --with-tuning=large" adjusts various + compiled-in constants and default settings to + values suited to large servers with abundant + memory. [RT #29538] + +(cherry picked from commit 6a3fa181d1253db5191139e20231512eebaddeeb) +--- + README | 8 + + bin/named/bind9.ver3.xsl.h | 6 +- + bin/named/interfacemgr.c | 9 +- + bin/named/named.docbook | 3 + + bin/named/server.c | 21 +- + bin/named/update.c | 2 +- + config.h.in | 3 + + configure | 1064 ++++++++++++++++++++++++++++++++++++-------- + configure.in | 25 ++ + lib/dns/client.c | 8 +- + lib/isc/unix/socket.c | 12 + + 11 files changed, 975 insertions(+), 186 deletions(-) + +diff --git a/README b/README +index b22e9ce..7451acb 100644 +--- a/README ++++ b/README +@@ -221,6 +221,14 @@ Building + To build shared libraries, specify "--with-libtool" on the + configure command line. + ++ Certain compiled-in constants and default settings can be ++ increased to values better suited to large servers with abundant ++ memory resources (e.g, 64-bit servers with 12G or more of memory) ++ by specifying "--with-tuning=large" on the configure command ++ line. This can improve performance on big servers, but will ++ consume more memory and may degrade performance on smaller ++ systems. ++ + For the server to support DNSSEC, you need to build it + with crypto support. You must have OpenSSL 0.9.5a + or newer installed and specify "--with-openssl" on the +diff --git a/bin/named/bind9.ver3.xsl.h b/bin/named/bind9.ver3.xsl.h +index c55714a..8c0a4a9 100644 +--- a/bin/named/bind9.ver3.xsl.h ++++ b/bin/named/bind9.ver3.xsl.h +@@ -210,7 +210,7 @@ static char xslmsg[] = + "

Incoming Requests

\n" + " \n" + " \n" +- "
[graph incoming requests]
\n" ++ "
[no incoming requests]
\n" + "
\n" + " \n" + " \n" +@@ -235,7 +235,7 @@ static char xslmsg[] = + "

Incoming Queries by Type

\n" + " \n" + " \n" +- "
[graph incoming qtypes]
\n" ++ "
[no incoming queries]
\n" + "
\n" + "
\n" + " \n" +@@ -307,7 +307,7 @@ static char xslmsg[] = + " \n" + "