From wk at gnupg.org Wed Feb 1 09:43:16 2006 From: wk at gnupg.org (Werner Koch) Date: Wed, 01 Feb 2006 09:43:16 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: <20060131183029.GA3568@downhill.aus.cc> (Andreas Metzler's message of "Tue, 31 Jan 2006 19:30:29 +0100") References: <20060131183029.GA3568@downhill.aus.cc> Message-ID: <87ek2nwjtn.fsf@wheatstone.g10code.de> On Tue, 31 Jan 2006 19:30:29 +0100, Andreas Metzler said: > For bug #2 /dev/urandom is used, therefore there is no blocking in Who is using /dev/urandom: Exim proper or gnutls/libgcrypt? > exim, just the fact that anything using /dev/random will block, as > there is no entropy left. For my understanding, will someone be so kind to answer these questions: 1. Does gnutls use GCRY_VERY_STRONG_RANDOM? 2. Does gnutls save the random seed file? gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, filename); atexit: gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); 3. Does the problem only occur for inetd invoked exims? Thanks, Werner From jas at extundo.com Wed Feb 1 12:58:55 2006 From: jas at extundo.com (Simon Josefsson) Date: Wed, 01 Feb 2006 12:58:55 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: <20060131183029.GA3568@downhill.aus.cc> (Andreas Metzler's message of "Tue, 31 Jan 2006 19:30:29 +0100") References: <20060131183029.GA3568@downhill.aus.cc> Message-ID: Andreas Metzler writes: > On 2006-01-31 Simon Josefsson wrote: >> Jason Lunz writes: >> > Are the gnutls developers aware of the ongoing entropy-pool-draining >> > problems with gnutls in exim4? For example: > >> > http://article.gmane.org/gmane.linux.debian.devel.exim4.user/477 > >> > Is this a known problem? Can something be done about it? > >> We are working on it, please see the other current threads on the >> mailing list. > >> I believe we have identified the problem, and proposed a solution, so >> a exim developer could probably implement it. Any exim developers >> following this? > > Hello, > As far as I gather from reading http://bugs.debian.org/343085 and the > thread "Feature request: not really random session keys" on gnutls-dev > there are two problems. > > #1: Online, blocking generation of RSA-params and DH-params in exim. > This is already fixed for quite some time in exim (thanks Nikos > Mavrogiannopoulos), it switched to using a certtool-compatible > fileformat for these parameters and certtool can be used for > generating them offline. Right. > #2: Florian Weimer wrote in http://bugs.debian.org/343085 > | As a side note: With GNU TLS, every _single_ encrypted mail > | transmission _totally_ depletes my entropy pool (going from ~3500 to > | ~150), but after recompiling Exim4 with OpenSSL, only about 200 bits > | (the number is difficult to measure, but it is way less than with GNU > | TLS) are used. > > For bug #2 /dev/urandom is used, therefore there is no blocking in > exim, just the fact that anything using /dev/random will block, as > there is no entropy left. > > The issue Jason is refereing to is #2, which is not fixed /yet/ but > known. Agreed. I believe /dev/urandom is poorly designed if reading from it make /dev/random unusable. I think this should be raised with the kernel developers. I believe we can, and probably should, implement some workaround for this. Until GnuTLS supports other crypto libraries than libgcrypt, solving that problem should likely be done in libgcrypt, or possibly by improving GnuTLS's use of libgcrypt (like saving the seed). Thanks. From jas at extundo.com Wed Feb 1 13:05:34 2006 From: jas at extundo.com (Simon Josefsson) Date: Wed, 01 Feb 2006 13:05:34 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: <87ek2nwjtn.fsf@wheatstone.g10code.de> (Werner Koch's message of "Wed, 01 Feb 2006 09:43:16 +0100") References: <20060131183029.GA3568@downhill.aus.cc> <87ek2nwjtn.fsf@wheatstone.g10code.de> Message-ID: Werner Koch writes: > On Tue, 31 Jan 2006 19:30:29 +0100, Andreas Metzler said: > >> For bug #2 /dev/urandom is used, therefore there is no blocking in > > Who is using /dev/urandom: Exim proper or gnutls/libgcrypt? > >> exim, just the fact that anything using /dev/random will block, as >> there is no entropy left. > > For my understanding, will someone be so kind to answer these > questions: > > 1. Does gnutls use GCRY_VERY_STRONG_RANDOM? Yes, in gc_random() which is used by RAND_bytes in libextra/gnutls_openssl.c. Otherwise, no, as far as I can see. Is exim using the OpenSSL compatibility interface? Does it invoke RAND_bytes? GnuTLS calls gnutls_mpi_randomize in a few places, but only with GCRY_STRONG_RANDOM. > 2. Does gnutls save the random seed file? > gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, filename); > atexit: > gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); No. Should it? What should we use as the filename? > 3. Does the problem only occur for inetd invoked exims? I don't know. Thanks. From n.mavrogiannopoulos at gmail.com Wed Feb 1 13:14:06 2006 From: n.mavrogiannopoulos at gmail.com (Nikos Mavrogiannopoulos) Date: Wed, 1 Feb 2006 13:14:06 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: References: <20060131183029.GA3568@downhill.aus.cc> <87ek2nwjtn.fsf@wheatstone.g10code.de> Message-ID: On 2/1/06, Simon Josefsson wrote: > > 1. Does gnutls use GCRY_VERY_STRONG_RANDOM? > Yes, in gc_random() which is used by RAND_bytes in > libextra/gnutls_openssl.c. Otherwise, no, as far as I can see. Indirectly it is used during key generation. I believe libgcrypt uses GCRY_VERY_STRONG_RANDOM to generate an RSA key. This is the reason exim was blocking. It was creating an RSA key per connection (which is not really needed). > Is exim using the OpenSSL compatibility interface? Does it invoke > RAND_bytes? no, it uses a direct implementation. > > 2. Does gnutls save the random seed file? > > gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, filename); > > atexit: > > gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); > No. Should it? What should we use as the filename? I also don't think we should use it. gnutls doesn't need to know about that. It could be used by exim though because of the way it works. > > 3. Does the problem only occur for inetd invoked exims? > I don't know. It occurs for any way you run exim. The problem is that exim is forking and then initializing gnutls and everything else after every fork. As far as I was told, there is no other way to do that. However a fork happens really often in exim, thus is causes that problem. From wk at gnupg.org Wed Feb 1 15:48:59 2006 From: wk at gnupg.org (Werner Koch) Date: Wed, 01 Feb 2006 15:48:59 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: (Nikos Mavrogiannopoulos's message of "Wed, 1 Feb 2006 13:14:06 +0100") References: <20060131183029.GA3568@downhill.aus.cc> <87ek2nwjtn.fsf@wheatstone.g10code.de> Message-ID: <87y80vuobo.fsf@wheatstone.g10code.de> On Wed, 1 Feb 2006 13:14:06 +0100, Nikos Mavrogiannopoulos said: > Indirectly it is used during key generation. I believe libgcrypt > uses GCRY_VERY_STRONG_RANDOM to generate an RSA key. This > is the reason exim was blocking. It was creating an RSA key per > connection (which is not really needed). Well, we could add an extra flag to use reduced quality random. But if you say it is not needed, we will postpone this. > no, it uses a direct implementation. >> > 2. Does gnutls save the random seed file? >> > gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, filename); >> > atexit: >> > gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); >> No. Should it? What should we use as the filename? > I also don't think we should use it. gnutls doesn't need to know about that. > It could be used by exim though because of the way it works. Saving the random state is really needed if you want to avoid reading /dev/random. There is a minor bug to to a race condition in writing, reading the file which will trigger a read from /dev/random. That is however easy to fix - we have to do this for GnuPG anyway. > As far as I was told, there is no other way to do that. However a fork > happens really often in exim, thus is causes that problem. Actually I assumed that. So the easiest way to fix it is by having Exim initialize libgcrypt and initializing, saving a random seed file. I'll add an internal flock call to protect against the above race conditions. But even without that it should really help to use a random seed. Another way to help forking servers is a function to declare the internal random pool initialized; that would be called right after the fork and avoids the extrs seeding libgcrypt requires when no random seed file has been loaded; thus it would be a kind of temporary seed file. Shalom-Salam, Werner From max at duempel.org Wed Feb 1 14:38:49 2006 From: max at duempel.org (Max Kellermann) Date: Wed, 1 Feb 2006 14:38:49 +0100 Subject: [gnutls-dev] more than one trusted certificate - buffer overflow Message-ID: <20060201133849.GA312@roonstrasse.net> Hi, I'm getting bus errors when I try to add more than one certificate with gnutls_certificate_set_x509_trust(). Backtrace: #0 _gnutls_x509_crt_get_raw_dn2 (cert=0x4449657571696e, whom=0x2aaaaac2a127 "issuer", start=0x7fffffe93940) at x509.c:1148 #1 0x00002aaaaabfe773 in generate_rdn_seq (res=0x53ac20) at gnutls_x509.c:1030 #2 0x00002aaaaabfed3d in gnutls_certificate_set_x509_trust (res=0x53ac20, ca_list=0x7fffffe93d60, ca_list_size=2) at gnutls_x509.c:1344 #3 0x000000000040371c in reload_credentials (instance=0x7fffffe93d20) at server/wrapper.c:458 [...] I'm using libgnutls12 1.2.9-1 (Debian) on AMD64. CVS HEAD still carries this bug. I found strange code in this function, see gnutls_x509.c lines 1312+: for (i = 0; i < ca_list_size; i++) { ret = gnutls_x509_crt_init(&res->x509_ca_list[i + res->x509_ncas]); [..] res->x509_ncas++; } Both "i" and "res->x509_ncas" are incremented in every iteration, that means, only even indices are being initialized - and it will overflow the "res->x509_ca_list" buffer. The same bug is present in gnutls_certificate_set_x509_crl(). Valgrind confirmed my theory: Invalid write of size 8 at 0x4B69C3F: gnutls_x509_crt_init (x509.c:54) by 0x4B5ACF4: gnutls_certificate_set_x509_trust (gnutls_x509.c:1328) by 0x40371B: reload_credentials (wrapper.c:458) by 0x40392C: init_tls (wrapper.c:523) by 0x404D25: main (wrapper.c:1118) Solution: don't add "i" and "res->x509_ncas", just "res->x509_ncas" gives us the correct index. See patch. You might need a lot of fantasy to imagine a remote exploit for this buffer overflow, but the fact that this bug exists, shows that nobody has ever tried to load more than one trusted certificate into libgnutls... Max -------------- next part -------------- --- gnutls12-1.2.9/lib/gnutls_x509.c.orig 2006-02-01 14:24:37.778492250 +0100 +++ gnutls12-1.2.9/lib/gnutls_x509.c 2006-02-01 14:24:59.971879250 +0100 @@ -1325,17 +1325,17 @@ } for (i = 0; i < ca_list_size; i++) { - ret = gnutls_x509_crt_init(&res->x509_ca_list[i + res->x509_ncas]); + ret = gnutls_x509_crt_init(&res->x509_ca_list[res->x509_ncas]); if (ret < 0) { gnutls_assert(); return ret; } - ret = _gnutls_x509_crt_cpy(res->x509_ca_list[i + res->x509_ncas], + ret = _gnutls_x509_crt_cpy(res->x509_ca_list[res->x509_ncas], ca_list[i]); if (ret < 0) { gnutls_assert(); - gnutls_x509_crt_deinit(res->x509_ca_list[i + res->x509_ncas]); + gnutls_x509_crt_deinit(res->x509_ca_list[res->x509_ncas]); return ret; } res->x509_ncas++; @@ -1615,7 +1615,7 @@ } for (i = 0; i < crl_list_size; i++) { - ret = _gnutls_x509_crl_cpy(res->x509_crl_list[i + res->x509_ncrls], + ret = _gnutls_x509_crl_cpy(res->x509_crl_list[res->x509_ncrls], crl_list[i]); if (ret < 0) { gnutls_assert(); From nmav at gnutls.org Wed Feb 1 16:53:21 2006 From: nmav at gnutls.org (Nikos Mavrogiannopoulos) Date: Wed, 1 Feb 2006 16:53:21 +0100 Subject: [gnutls-dev] more than one trusted certificate - buffer overflow In-Reply-To: <20060201133849.GA312@roonstrasse.net> References: <20060201133849.GA312@roonstrasse.net> Message-ID: <200602011653.22022.nmav@gnutls.org> On Wednesday 01 February 2006 14:38, Max Kellermann wrote: > Hi, > I'm getting bus errors when I try to add more than one certificate > with gnutls_certificate_set_x509_trust(). Backtrace: Thanks for reporting it. I've applied a patch in the cvs for both the development and the stable version. regards, Nikos Mavrogiannopoulos From nmav at gnutls.org Wed Feb 1 17:36:12 2006 From: nmav at gnutls.org (Nikos Mavrogiannopoulos) Date: Wed, 1 Feb 2006 17:36:12 +0100 Subject: [gnutls-dev] more than one trusted certificate - buffer overflow In-Reply-To: <20060201133849.GA312@roonstrasse.net> References: <20060201133849.GA312@roonstrasse.net> Message-ID: <200602011736.12429.nmav@gnutls.org> On Wednesday 01 February 2006 14:38, Max Kellermann wrote: > You might need a lot of fantasy to imagine a remote exploit for this > buffer overflow, but the fact that this bug exists, shows that nobody > has ever tried to load more than one trusted certificate into > libgnutls... That's not true :) The most uses of gnutls use the _file() function which uses the pem parser. That one seems to work. -- Nikos Mavrogiannopoulos From nmav at gnutls.org Thu Feb 2 09:19:21 2006 From: nmav at gnutls.org (Nikos Mavrogiannopoulos) Date: Thu, 2 Feb 2006 09:19:21 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: <87y80vuobo.fsf@wheatstone.g10code.de> References: <20060131183029.GA3568@downhill.aus.cc> <87ek2nwjtn.fsf@wheatstone.g10code.de> <87y80vuobo.fsf@wheatstone.g10code.de> Message-ID: On 2/1/06, Werner Koch wrote: > Actually I assumed that. So the easiest way to fix it is by having > Exim initialize libgcrypt and initializing, saving a random seed > file. > I'll add an internal flock call to protect against the above race > conditions. But even without that it should really help to use a > random seed. But would this protect from two children accessing the same random seed? From wk at gnupg.org Thu Feb 2 09:36:17 2006 From: wk at gnupg.org (Werner Koch) Date: Thu, 02 Feb 2006 09:36:17 +0100 Subject: [gnutls-dev] Re: ongoing entropy problems In-Reply-To: (Nikos Mavrogiannopoulos's message of "Thu, 2 Feb 2006 09:19:21 +0100") References: <20060131183029.GA3568@downhill.aus.cc> <87ek2nwjtn.fsf@wheatstone.g10code.de> <87y80vuobo.fsf@wheatstone.g10code.de> Message-ID: <8764nytawu.fsf@wheatstone.g10code.de> On Thu, 2 Feb 2006 09:19:21 +0100, Nikos Mavrogiannopoulos said: > But would this protect from two children accessing the same random > seed? This is not required. After reading some data gets mixed into the pool, one item is the pid another are 16 bytes from /dev/urandom. So you will never get the same pool and due to /dev/urandom even a sibling process won't be able to predict the pool's state. Shalom-Salam, Werner From jas at extundo.com Thu Feb 9 16:38:35 2006 From: jas at extundo.com (Simon Josefsson) Date: Thu, 09 Feb 2006 16:38:35 +0100 Subject: [gnutls-dev] Libtasn1 0.2.18 - Tiny ASN.1 Library - Security release Message-ID: All, this release fixes several serious bugs that would make the DER decoder in libtasn1 crash on invalid input. The problems were reported by Evgeny Legerov on the 31th of January. New releases of GnuTLS will follow later today. We invite more detailed analysis of the problem, following our general security advisory approach explained on: http://www.gnu.org/software/gnutls/security.html Particularly, it would be useful to answer the question of whether these bugs are possible to exploit remotely. It is certainly possible to cause the server to crash. We don't have resources to investigate this problem more ourselves currently. To make it easier for you to review this problem, I have prepared a self test that trigger three bugs in the old libtasn1. It will be part of GnuTLS 1.3.4, in tests/certder.c. I have also created a diff between libtasn1 0.2.17 and libtasn1 0.2.18. I contains unrelated fixes too, but it is not too large. It is available from: http://josefsson.org/gnutls/releases/libtasn1/libtasn1-0.2.18-from-0.2.17.patch Please send your analysis to gnutls-dev at gnupg.org and I'll update the security advisory web page pointing to it. Libtasn1 is a standalone library written in C for manipulating ASN.1 objects including DER encoding and DER decoding. It is used by GnuTLS to manipulate X.509 objects and by GNU Shishi to handle Kerberos packets. Version 0.2.18 - Fix out-of-bounds access in DER decoding, reported by Evgeny Legerov. - Add 'const' keyword to some prototypes, thanks to Frediano ZIGLIO. - Fixed typo in src/Makefile.am to make it build with objdir != srcdir, thanks to Bernard Leak. - Update of gnulib files. - Typo fixes in comments, e.g. finish libasn1 to libtasn1 renaming, use LGPL boiler plate on some files in lib/. Commercial support contracts for Libtasn1 are available, and they help finance continued maintenance. Simon Josefsson Datakonsult, a Stockholm based privately held company, is currently funding Libtasn1 maintenance. We are always looking for interesting development projects. If you need help to use Libtasn1, or want to help others, you are invited to join our help-gnutls mailing list, see: . Homepage: http://josefsson.org/libtasn1/ Manual in many formats: http://josefsson.org/gnutls/manual/libtasn1/ Here are the compressed sources: ftp://ftp.gnutls.org/pub/gnutls/libtasn1/libtasn1-0.2.18.tar.gz (888KB) http://josefsson.org/gnutls/releases/libtasn1/libtasn1-0.2.18.tar.gz Here are GPG detached signatures using key 0xB565716F: ftp://ftp.gnutls.org/pub/gnutls/libtasn1/libtasn1-0.2.18.tar.gz.sig http://josefsson.org/gnutls/releases/libtasn1/libtasn1-0.2.18.tar.gz.sig Here are the SHA-1 checksums: 4f9c1be1586083cd605e17c7948f94deed63b024 libtasn1-0.2.18.tar.gz 08d625e5fbabee2710f9789c8508397e481b048b libtasn1-0.2.18.tar.gz.sig Enjoy, Nikos and Simon -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 423 bytes Desc: not available URL: From jas at extundo.com Thu Feb 9 16:46:28 2006 From: jas at extundo.com (Simon Josefsson) Date: Thu, 09 Feb 2006 16:46:28 +0100 Subject: [gnutls-dev] GnuTLS 1.2.10 - Security release Message-ID: We are pleased to announce the availability of GnuTLS version 1.2.10, a security bug-fix release on the stable 1.2.x branch. This release fixes several serious bugs that would make the DER decoder in libtasn1 crash on invalid input. The problems were reported by Evgeny Legerov on the 31th of January. We invite more detailed analysis of the problem, following our general security advisory approach explained on: http://www.gnu.org/software/gnutls/security.html Particularly, it would be useful to answer the question of whether these bugs are possible to exploit remotely. It is certainly possible to cause the server to crash. We don't have resources to investigate this problem more ourselves currently. To make it easier for you to review this problem, I have prepared a self test that trigger three bugs in the old libtasn1. It will be part of GnuTLS 1.3.4, in tests/certder.c. A diff between libtasn1 0.2.17 and libtasn1 0.2.18 is also available, for those wishing to analyze the changes made to address the problems. It contains a few unrelated fixes too, but it is not too large. It is available from: http://josefsson.org/gnutls/releases/libtasn1/libtasn1-0.2.18-from-0.2.17.patch Please send your analysis to gnutls-dev at gnupg.org and I'll update the security advisory web page pointing to it. GnuTLS is a modern C library that implement the standard network security protocol Transport Layer Security (TLS), for use by network applications. Noteworthy changes since version 1.2.9: - Fix read out bounds bug in DER parser. Reported by Evgeny Legerov , and debugging help from Protover SSL. - Libtasn1 0.2.18 is now required (contains the previous bug fix). The included version has been updated too. - Fix gnutls-cli STARTTLS hang when SIGINT is sent too quickly, thanks to Otto Maddox and Nozomu Ando . - Corrected a bug in certtool for 64 bit machines. Reported by Max Kellermann . - Corrected bugs in gnutls_certificate_set_x509_crl() and gnutls_certificate_set_x509_trust(), that caused memory corruption if more than one certificates were added. Report and patch by Max Kellermann. - Fixed bug in non-blocking gnutls_bye(). gnutls_record_send() will no longer invalidate a session if the underlying send fails, but it will prevent future writes. That is to allow reading the already received data. Patches and bug reports by Yoann Vandoorselaere Improving GnuTLS is costly, but you can help! We are looking for organizations that find GnuTLS useful and wish to contribute back. You can contribute by reporting bugs, improve the software, or donate money or equipment. Commercial support contracts for GnuTLS are available, and they help finance continued maintenance. Simon Josefsson Datakonsult, a Stockholm based privately held company, is currently funding GnuTLS maintenance. We are always looking for interesting development projects. If you need help to use GnuTLS, or want to help others, you are invited to join our help-gnutls mailing list, see: . The project page of the library is available at: http://www.gnutls.org/ http://www.gnu.org/software/gnutls/ http://josefsson.org/gnutls/ (updated fastest) Here are the compressed sources: http://josefsson.org/gnutls/releases/gnutls-1.2.10.tar.bz2 (2.7MB) ftp://ftp.gnutls.org/pub/gnutls/gnutls-1.2.10.tar.bz2 Here are GPG detached signatures signed using key 0xB565716F: http://josefsson.org/gnutls/releases/gnutls-1.2.10.tar.bz2.sig ftp://ftp.gnutls.org/pub/gnutls/gnutls-1.2.10.tar.bz2.sig The software is cryptographically signed by the author using an OpenPGP key identified by the following information: 1280R/B565716F 2002-05-05 [expires: 2006-02-28] Key fingerprint = 0424 D4EE 81A0 E3D1 19C6 F835 EDA2 1E94 B565 716F The key is available from: http://josefsson.org/key.txt dns:b565716f.josefsson.org?TYPE=CERT Here are the build reports for various platforms: http://josefsson.org/autobuild-logs/gnutls.html Here are the SHA-1 checksums: 18140bebae006e019deb77962836bcd775256aab gnutls-1.2.10.tar.bz2 19d200ce04dc54b55d609a091500d1a2aee6e368 gnutls-1.2.10.tar.bz2.sig Enjoy, Nikos and Simon -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 423 bytes Desc: not available URL: From jas at extundo.com Thu Feb 9 16:51:12 2006 From: jas at extundo.com (Simon Josefsson) Date: Thu, 09 Feb 2006 16:51:12 +0100 Subject: [gnutls-dev] GnuTLS 1.3.4 - Experimental - Security release Message-ID: This release solves the DER security issue on the experimental branch too. It contains a few other fixes too. GnuTLS is a modern C library that implement the standard network security protocol Transport Layer Security (TLS), for use by network applications. Noteworthy changes since version 1.3.3: - Fix read of out bounds bug in DER parser. Reported by Evgeny Legerov , and debugging help from Protover SSL. Libtasn1 0.2.18 is now required, which contains the previous bug fix. The included libtasn1 version in GnuTLS has been updated. - Fixed bug in non-blocking gnutls_bye(). gnutls_record_send() will no longer invalidate a session if the underlying send fails, but it will prevent future writes. That is to allow reading the already received data. Patches and bug reports by Yoann Vandoorselaere - Corrected bugs in gnutls_certificate_set_x509_crl() and gnutls_certificate_set_x509_trust(), that caused memory corruption if more than one certificates were added. Report and patch by Max Kellermann. - Fix build problems of OpenCDK on AIX. Thanks to "Heiden, John" . - API and ABI modifications: No changes since last version. Improving GnuTLS is costly, but you can help! We are looking for organizations that find GnuTLS useful and wish to contribute back. You can contribute by reporting bugs, improve the software, or donate money or equipment. Commercial support contracts for GnuTLS are available, and they help finance continued maintenance. Simon Josefsson Datakonsult, a Stockholm based privately held company, is currently funding GnuTLS maintenance. We are always looking for interesting development projects. If you need help to use GnuTLS, or want to help others, you are invited to join our help-gnutls mailing list, see: . The project page of the library is available at: http://www.gnutls.org/ http://www.gnu.org/software/gnutls/ http://josefsson.org/gnutls/ (updated fastest) Here are the compressed sources: http://josefsson.org/gnutls/releases/gnutls-1.3.4.tar.bz2 (3.1MB) ftp://ftp.gnutls.org/pub/gnutls/gnutls-1.3.4.tar.bz2 Here are GPG detached signatures signed using key 0xB565716F: http://josefsson.org/gnutls/releases/gnutls-1.3.4.tar.bz2.sig ftp://ftp.gnutls.org/pub/gnutls/gnutls-1.3.4.tar.bz2.sig The software is cryptographically signed by the author using an OpenPGP key identified by the following information: 1280R/B565716F 2002-05-05 [expires: 2006-02-28] Key fingerprint = 0424 D4EE 81A0 E3D1 19C6 F835 EDA2 1E94 B565 716F The key is available from: http://josefsson.org/key.txt dns:b565716f.josefsson.org?TYPE=CERT Here are the build reports for various platforms: http://josefsson.org/autobuild-logs/gnutls.html Here are the SHA-1 checksums: f412262ab6299f6e4603c3f524551ae0357ff983 gnutls-1.3.4.tar.bz2 3c9ac687440b5e36b4d41eaf15fc6ea98a199a06 gnutls-1.3.4.tar.bz2.sig Enjoy, Nikos and Simon -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 423 bytes Desc: not available URL: From max at duempel.org Fri Feb 10 12:45:17 2006 From: max at duempel.org (Max Kellermann) Date: Fri, 10 Feb 2006 12:45:17 +0100 Subject: [gnutls-dev] more than one trusted certificate - buffer overflow In-Reply-To: <200602011736.12429.nmav@gnutls.org> References: <20060201133849.GA312@roonstrasse.net> <200602011736.12429.nmav@gnutls.org> Message-ID: <20060210114517.GA8168@roonstrasse.net> On 2006/02/01 17:36, Nikos Mavrogiannopoulos wrote: > On Wednesday 01 February 2006 14:38, Max Kellermann wrote: > > > You might need a lot of fantasy to imagine a remote exploit for this > > buffer overflow, but the fact that this bug exists, shows that nobody > > has ever tried to load more than one trusted certificate into > > libgnutls... > > That's not true :) The most uses of gnutls use the _file() function > which uses the pem parser. That one seems to work. Which of the two cited statements did you mean with "not true"? The _file() functions do not allow to add two .pem files, which renders them useless for my application. Max From jas at extundo.com Sat Feb 11 11:19:56 2006 From: jas at extundo.com (Simon Josefsson) Date: Sat, 11 Feb 2006 11:19:56 +0100 Subject: [gnutls-dev] Re: Libtasn1 0.2.18 - Tiny ASN.1 Library - Security release In-Reply-To: (Simon Josefsson's message of "Thu, 09 Feb 2006 16:38:35 +0100") References: Message-ID: On popular demand, we have prepared a minimal set of patches against 0.2.17 that will fix the security problem. There is a branch in CVS called "libtasn1_0_2_17_security" that also contain the minimal fixes for 0.2.17 you'll have to apply to get a security libtasn1. I'm including the patch below. Please review it. Astute readers may recognize that some _asn1* APIs have changed their signature. Those APIs are not exported, and are not intended to be used by external applications. Unfortunately, GnuTLS did use them. We are considering to bump the so version in libtasn1_0_2_17_security and in a new libtasn1 0.3.0. We would then also have to deprecate 0.2.18 because it didn't bump the so version. Comments on this approach are appreciated. Regards, Simon Index: lib/coding.c =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/coding.c,v retrieving revision 1.16 retrieving revision 1.16.2.1 diff -u -p -r1.16 -r1.16.2.1 --- lib/coding.c 16 Jul 2005 11:25:32 -0000 1.16 +++ lib/coding.c 11 Feb 2006 10:00:11 -0000 1.16.2.1 @@ -1,22 +1,23 @@ /* + * Copyright (C) 2004, 2006 Free Software Foundation * Copyright (C) 2002 Fabio Fiorina - * Copyright (C) 2004 Simon Josefsson * - * This file is part of LIBASN1. + * This file is part of LIBTASN1. * - * The LIBTASN1 library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA */ @@ -148,7 +149,7 @@ _asn1_octet_der(const unsigned char *str { int len_len; - if(der==NULL) return; + if(der==NULL || str_len <= 0) return; _asn1_length_der(str_len,der,&len_len); memcpy(der+len_len,str,str_len); *der_len=str_len+len_len; @@ -196,7 +197,8 @@ _asn1_get_utctime_der(unsigned char *der char temp[20]; if(str==NULL) return; - str_len=_asn1_get_length_der(der,&len_len); + str_len=_asn1_get_length_der(der,*der_len,&len_len); + if (str_len<0) return; memcpy(temp,der+len_len,str_len); *der_len=str_len+len_len; switch(str_len){ @@ -534,7 +536,7 @@ _asn1_insert_tag_der(node_asn *node,unsi /* Return: */ /******************************************************/ void -_asn1_ordering_set(unsigned char *der,node_asn *node) +_asn1_ordering_set(unsigned char *der, int der_len, node_asn *node) { struct vet{ int end; @@ -569,12 +571,14 @@ _asn1_ordering_set(unsigned char *der,no last=p_vet; /* tag value calculation */ - tag=_asn1_get_tag_der(der+counter,&class,&len2); + if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2, &tag)!=ASN1_SUCCESS) + return; p_vet->value=(class<<24)|tag; counter+=len2; /* extraction and length */ - len2=_asn1_get_length_der(der+counter,&len); + len2=_asn1_get_length_der(der+counter,der_len-counter,&len); + if (len2<0) return; counter+=len+len2; p_vet->end=counter; @@ -626,7 +630,7 @@ _asn1_ordering_set(unsigned char *der,no /* Return: */ /******************************************************/ void -_asn1_ordering_set_of(unsigned char *der,node_asn *node) +_asn1_ordering_set_of(unsigned char *der, int der_len, node_asn *node) { struct vet{ int end; @@ -661,10 +665,16 @@ _asn1_ordering_set_of(unsigned char *der last=p_vet; /* extraction of tag and length */ - _asn1_get_tag_der(der+counter,&class,&len); - counter+=len; - len2=_asn1_get_length_der(der+counter,&len); - counter+=len+len2; + if (der_len-counter > 0) { + + if (_asn1_get_tag_der(der+counter, der_len - counter, &class,&len,NULL)!=ASN1_SUCCESS) + return; + counter+=len; + + len2=_asn1_get_length_der(der+counter,der_len-counter,&len); + if (len2<0) return; + counter+=len+len2; + } p_vet->end=counter; p=p->right; @@ -804,7 +814,8 @@ asn1_der_coding(ASN1_TYPE element,const _asn1_error_description_value_not_found(p,ErrorDescription); return ASN1_VALUE_NOT_FOUND; } - len2=_asn1_get_length_der(p->value,&len3); + len2=_asn1_get_length_der(p->value,p->value_len, &len3); + if (len2<0) return ASN1_DER_ERROR; max_len -= len2+len3; if(max_len>=0) memcpy(der+counter,p->value,len3+len2); @@ -846,7 +857,8 @@ asn1_der_coding(ASN1_TYPE element,const _asn1_error_description_value_not_found(p,ErrorDescription); return ASN1_VALUE_NOT_FOUND; } - len2=_asn1_get_length_der(p->value,&len3); + len2=_asn1_get_length_der(p->value,p->value_len,&len3); + if (len2<0) return ASN1_DER_ERROR; max_len-=len2+len3; if(max_len>=0) memcpy(der+counter,p->value,len3+len2); @@ -858,7 +870,8 @@ asn1_der_coding(ASN1_TYPE element,const _asn1_error_description_value_not_found(p,ErrorDescription); return ASN1_VALUE_NOT_FOUND; } - len2=_asn1_get_length_der(p->value,&len3); + len2=_asn1_get_length_der(p->value,p->value_len,&len3); + if (len2<0) return ASN1_DER_ERROR; max_len-=len2+len3; if(max_len>=0) memcpy(der+counter,p->value,len3+len2); @@ -870,7 +883,8 @@ asn1_der_coding(ASN1_TYPE element,const _asn1_error_description_value_not_found(p,ErrorDescription); return ASN1_VALUE_NOT_FOUND; } - len2=_asn1_get_length_der(p->value,&len3); + len2=_asn1_get_length_der(p->value,p->value_len,&len3); + if (len2<0) return ASN1_DER_ERROR; max_len-=len2+len3; if(max_len>=0) memcpy(der+counter,p->value,len3+len2); @@ -903,7 +917,7 @@ asn1_der_coding(ASN1_TYPE element,const len2=strtol(p->value,NULL,10); _asn1_set_value(p,NULL,0); if((type_field(p->type)==TYPE_SET) && (max_len>=0)) - _asn1_ordering_set(der+len2,p); + _asn1_ordering_set(der+len2, max_len-len2,p); _asn1_length_der(counter-len2,temp,&len3); max_len-=len3; if(max_len>=0){ @@ -934,8 +948,9 @@ asn1_der_coding(ASN1_TYPE element,const if(move==UP){ len2=strtol(p->value,NULL,10); _asn1_set_value(p,NULL,0); - if((type_field(p->type)==TYPE_SET_OF) && (max_len>=0)) - _asn1_ordering_set_of(der+len2,p); + if((type_field(p->type)==TYPE_SET_OF) && (max_len-len2>0)) { + _asn1_ordering_set_of(der+len2, max_len-len2,p); + } _asn1_length_der(counter-len2,temp,&len3); max_len-=len3; if(max_len>=0){ @@ -951,7 +966,8 @@ asn1_der_coding(ASN1_TYPE element,const _asn1_error_description_value_not_found(p,ErrorDescription); return ASN1_VALUE_NOT_FOUND; } - len2=_asn1_get_length_der(p->value,&len3); + len2=_asn1_get_length_der(p->value,p->value_len,&len3); + if (len2<0) return ASN1_DER_ERROR; max_len-=len2; if(max_len>=0) memcpy(der+counter,p->value+len3,len2); Index: lib/decoding.c =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/decoding.c,v retrieving revision 1.26 retrieving revision 1.26.2.1 diff -u -p -r1.26 -r1.26.2.1 --- lib/decoding.c 16 Jul 2005 11:25:32 -0000 1.26 +++ lib/decoding.c 11 Feb 2006 10:00:11 -0000 1.26.2.1 @@ -1,22 +1,23 @@ /* + * Copyright (C) 2004, 2006 Free Software Foundation * Copyright (C) 2002 Fabio Fiorina - * Copyright (C) 2004 Simon Josefsson * - * This file is part of LIBASN1. + * This file is part of LIBTASN1. * - * The LIBTASN1 library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA */ @@ -47,11 +48,14 @@ _asn1_error_description_tag_error(node_a signed long -_asn1_get_length_der(const unsigned char *der,int *len) +_asn1_get_length_der(const unsigned char *der, int der_len, int *len) { unsigned long ans; int k,punt; + *len = 0; + if (der_len <= 0) return 0; + if(!(der[0]&128)){ /* short form */ *len=1; @@ -63,7 +67,13 @@ _asn1_get_length_der(const unsigned char punt=1; if(k){ /* definite length method */ ans=0; - while(punt<=k) ans=ans*256+der[punt++]; + while(punt<=k && punt < der_len) { + unsigned long last = ans; + ans=ans*256+der[punt++]; + if (ans < last) + /* we wrapped around, no bignum support... */ + return -2; + } } else{ /* indefinite length method */ ans=-1; @@ -77,12 +87,14 @@ _asn1_get_length_der(const unsigned char -unsigned int -_asn1_get_tag_der(const unsigned char *der,unsigned char *class,int *len) +int +_asn1_get_tag_der(const unsigned char *der, int der_len, + unsigned char *class,int *len, unsigned long *tag) { int punt,ris; - if (der==NULL || len == NULL) return ASN1_DER_ERROR; + if (der==NULL || der_len <= 0 || len == NULL) return ASN1_DER_ERROR; + *class=der[0]&0xE0; if((der[0]&0x1F)!=0x1F){ /* short form */ @@ -93,25 +105,46 @@ _asn1_get_tag_der(const unsigned char *d /* Long form */ punt=1; ris=0; - while(der[punt]&128) ris=ris*128+(der[punt++]&0x7F); - ris=ris*128+(der[punt++]&0x7F); + while(punt <= der_len && der[punt]&128) + { + int last = ris; + ris=ris*128+(der[punt++]&0x7F); + if (ris < last) + /* wrapper around, and no bignums... */ + return ASN1_DER_ERROR; + } + if (punt >= der_len) + return ASN1_DER_ERROR; + { + int last = ris; + ris=ris*128+(der[punt++]&0x7F); + if (ris < last) + /* wrapper around, and no bignums... */ + return ASN1_DER_ERROR; + } *len=punt; } - return ris; + if (tag) *tag = ris; + return ASN1_SUCCESS; } int -_asn1_get_octet_der(const unsigned char *der,int *der_len,unsigned char *str,int str_size, int *str_len) +_asn1_get_octet_der(const unsigned char *der, int der_len, int *ret_len,unsigned char *str,int str_size, int *str_len) { int len_len; + if (der_len <= 0) return ASN1_GENERIC_ERROR; + /* if(str==NULL) return ASN1_SUCCESS; */ - *str_len=_asn1_get_length_der(der,&len_len); + *str_len=_asn1_get_length_der(der, der_len, &len_len); + + if (*str_len < 0) + return ASN1_DER_ERROR; - *der_len=*str_len+len_len; + *ret_len=*str_len+len_len; if ( str_size >= *str_len) memcpy(str,der+len_len,*str_len); else { @@ -126,17 +159,17 @@ _asn1_get_octet_der(const unsigned char /* Returns ASN1_SUCCESS on success or an error code on error. */ int -_asn1_get_time_der(const unsigned char *der,int *der_len,unsigned char *str,int str_size) +_asn1_get_time_der(const unsigned char *der, int der_len, int *ret_len,unsigned char *str,int str_size) { int len_len,str_len; - if(str==NULL) return ASN1_DER_ERROR; - str_len=_asn1_get_length_der(der,&len_len); + if(der_len <=0 || str==NULL) return ASN1_DER_ERROR; + str_len=_asn1_get_length_der(der, der_len, &len_len); if (str_len < 0 || str_size < str_len) return ASN1_DER_ERROR; memcpy(str,der+len_len,str_len); str[str_len]=0; - *der_len=str_len+len_len; + *ret_len=str_len+len_len; return ASN1_SUCCESS; } @@ -144,14 +177,19 @@ _asn1_get_time_der(const unsigned char * void -_asn1_get_objectid_der(const unsigned char *der,int *der_len,unsigned char *str, int str_size) +_asn1_get_objectid_der(const unsigned char *der,int der_len, int *ret_len,unsigned char *str, int str_size) { int len_len,len,k; char temp[20]; unsigned long val,val1; - if(str==NULL) return; - len=_asn1_get_length_der(der,&len_len); + *ret_len = 0; + if (str && str_size > 0) str[0] = 0; /* no oid */ + + if(str==NULL || der_len <= 0) return; + len=_asn1_get_length_der(der,der_len, &len_len); + + if (len < 0 || len > der_len || len_len > der_len) return; val1=der[len_len]/40; val=der[len_len]-val1*40; @@ -170,20 +208,24 @@ _asn1_get_objectid_der(const unsigned ch val=0; } } - *der_len=len+len_len; + *ret_len=len+len_len; } int -_asn1_get_bit_der(const unsigned char *der,int *der_len,unsigned char *str, int str_size, int *bit_len) +_asn1_get_bit_der(const unsigned char *der, int der_len, + int *ret_len,unsigned char *str, int str_size, int *bit_len) { int len_len,len_byte; - len_byte=_asn1_get_length_der(der,&len_len)-1; + if (der_len <=0) return ASN1_GENERIC_ERROR; + len_byte=_asn1_get_length_der(der,der_len,&len_len)-1; + if (len_byte < 0) + return ASN1_DER_ERROR; - *der_len=len_byte+len_len+1; + *ret_len=len_byte+len_len+1; *bit_len=len_byte*8-der[len_len]; if (str_size >= len_byte) @@ -199,14 +241,15 @@ _asn1_get_bit_der(const unsigned char *d int -_asn1_extract_tag_der(node_asn *node,const unsigned char *der,int *der_len) +_asn1_extract_tag_der(node_asn *node,const unsigned char *der, int der_len,int *ret_len) { node_asn *p; int counter,len2,len3,is_tag_implicit; unsigned long tag,tag_implicit=0; unsigned char class,class2,class_implicit=0; - + if (der_len <= 0) return ASN1_GENERIC_ERROR; + counter=is_tag_implicit=0; if(node->type&CONST_TAG){ @@ -219,9 +262,14 @@ _asn1_extract_tag_der(node_asn *node,con else class2=CONTEXT_SPECIFIC; if(p->type&CONST_EXPLICIT){ - tag=_asn1_get_tag_der(der+counter,&class,&len2); + if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2, &tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > der_len) + return ASN1_DER_ERROR; counter+=len2; - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,der_len-counter, &len2); + if (len3 < 0) + return ASN1_DER_ERROR; counter+=len2; if(!is_tag_implicit){ if((class!=(class2|STRUCTURED)) || (tag!=strtoul(p->value,NULL,10))) @@ -251,7 +299,11 @@ _asn1_extract_tag_der(node_asn *node,con } if(is_tag_implicit){ - tag=_asn1_get_tag_der(der+counter,&class,&len2); + if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2, &tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > der_len) + return ASN1_DER_ERROR; + if((class!=class_implicit) || (tag!=tag_implicit)){ if(type_field(node->type)==TYPE_OCTET_STRING){ class_implicit |= STRUCTURED; @@ -265,11 +317,15 @@ _asn1_extract_tag_der(node_asn *node,con else{ if(type_field(node->type)==TYPE_TAG){ counter=0; - *der_len=counter; + *ret_len=counter; return ASN1_SUCCESS; } - tag=_asn1_get_tag_der(der+counter,&class,&len2); + if (_asn1_get_tag_der(der+counter, der_len-counter,&class,&len2,&tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > der_len) + return ASN1_DER_ERROR; + switch(type_field(node->type)){ case TYPE_NULL: if((class!=UNIVERSAL) || (tag!=TAG_NULL)) return ASN1_DER_ERROR; @@ -323,7 +379,7 @@ _asn1_extract_tag_der(node_asn *node,con } counter+=len2; - *der_len=counter; + *ret_len=counter; return ASN1_SUCCESS; } @@ -375,7 +431,7 @@ _asn1_delete_not_used(node_asn *node) asn1_retCode -_asn1_get_octet_string(const unsigned char* der,node_asn *node,int* len) +_asn1_get_octet_string(const unsigned char* der, node_asn *node,int* len) { int len2,len3,counter,counter2,counter_end,tot_len,indefinite; char *temp,*temp2; @@ -384,7 +440,9 @@ _asn1_get_octet_string(const unsigned ch if(*(der-1) & STRUCTURED){ tot_len=0; - indefinite=_asn1_get_length_der(der,&len3); + indefinite=_asn1_get_length_der(der, *len, &len3); + if (indefinite < -1) + return ASN1_DER_ERROR; counter+=len3; if(indefinite>=0) indefinite+=len3; @@ -404,7 +462,7 @@ _asn1_get_octet_string(const unsigned ch counter++; - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,*len-counter, &len3); if(len2 <= 0) return ASN1_DER_ERROR; counter+=len3+len2; @@ -422,24 +480,33 @@ _asn1_get_octet_string(const unsigned ch _asn1_length_der(tot_len,temp,&len2); tot_len+=len2; temp2=temp+len2; - len2=_asn1_get_length_der(der,&len3); + len2=_asn1_get_length_der(der,*len,&len3); + if(len2 < -1) return ASN1_DER_ERROR; counter2=len3+1; if(indefinite==-1) counter_end=counter-2; else counter_end=counter; while(counter2 *len) return ASN1_DER_ERROR; if(node) _asn1_set_value(node,der,len3+len2); counter=len3+len2; @@ -452,10 +519,10 @@ _asn1_get_octet_string(const unsigned ch asn1_retCode -_asn1_get_indefinite_length_string(const unsigned char* der,int* len) +_asn1_get_indefinite_length_string(const unsigned char* der, int* len) { int len2,len3,counter,indefinite; - unsigned int tag; + unsigned long tag; unsigned char class; counter=indefinite=0; @@ -470,9 +537,13 @@ _asn1_get_indefinite_length_string(const else continue; } - tag=_asn1_get_tag_der(der+counter,&class,&len2); + if(_asn1_get_tag_der(der+counter, *len-counter,&class,&len2,&tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > *len) + return ASN1_DER_ERROR; counter+=len2; - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter, *len-counter,&len3); + if(len2 < -1) return ASN1_DER_ERROR; if(len2 == -1){ indefinite++; counter+=1; @@ -520,7 +591,7 @@ asn1_der_decoding(ASN1_TYPE *element,con char temp[128]; int counter,len2,len3,len4,move,ris,tlen; unsigned char class,*temp2; - unsigned int tag; + unsigned long tag; int indefinite, result; const unsigned char* der = ider; @@ -563,11 +634,11 @@ asn1_der_decoding(ASN1_TYPE *element,con while(p2){ if((p2->type&CONST_SET) && (p2->type&CONST_NOT_USED)){ if(type_field(p2->type)!=TYPE_CHOICE) - ris=_asn1_extract_tag_der(p2,der+counter,&len2); + ris=_asn1_extract_tag_der(p2,der+counter,len-counter, &len2); else{ p3=p2->down; while(p3){ - ris=_asn1_extract_tag_der(p3,der+counter,&len2); + ris=_asn1_extract_tag_der(p3,der+counter,len-counter, &len2); if(ris==ASN1_SUCCESS) break; p3=p3->right; } @@ -606,7 +677,7 @@ asn1_der_decoding(ASN1_TYPE *element,con if(type_field(p->type)==TYPE_CHOICE){ while(p->down){ if(counterdown,der+counter,&len2); + ris=_asn1_extract_tag_der(p->down,der+counter,len-counter,&len2); else ris=ASN1_DER_ERROR; if(ris==ASN1_SUCCESS){ @@ -642,7 +713,7 @@ asn1_der_decoding(ASN1_TYPE *element,con if((len2!=-1) && (counter>len2)) ris=ASN1_TAG_ERROR; } - if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,&len2); + if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2); if(ris!=ASN1_SUCCESS){ if(p->type&CONST_OPTION){ p->type|=CONST_NOT_USED; @@ -683,13 +754,15 @@ asn1_der_decoding(ASN1_TYPE *element,con move=RIGHT; break; case TYPE_INTEGER: case TYPE_ENUMERATED: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter, &len3); + if(len2 < 0) return ASN1_DER_ERROR; + if (len2+len3 > len-counter) return ASN1_DER_ERROR; _asn1_set_value(p,der+counter,len3+len2); counter+=len3+len2; move=RIGHT; break; case TYPE_OBJECT_ID: - _asn1_get_objectid_der(der+counter,&len2, temp, sizeof(temp)); + _asn1_get_objectid_der(der+counter,len-counter,&len2, temp, sizeof(temp)); tlen = strlen(temp); if( tlen > 0) _asn1_set_value(p,temp,tlen+1); @@ -697,7 +770,7 @@ asn1_der_decoding(ASN1_TYPE *element,con move=RIGHT; break; case TYPE_TIME: - result = _asn1_get_time_der(der+counter,&len2,temp,sizeof(temp)-1); + result = _asn1_get_time_der(der+counter,len-counter,&len2,temp,sizeof(temp)-1); if (result != ASN1_SUCCESS) { asn1_delete_structure(element); return result; @@ -716,14 +789,18 @@ asn1_der_decoding(ASN1_TYPE *element,con move=RIGHT; break; case TYPE_GENERALSTRING: - len2=_asn1_get_length_der(der+counter,&len3); - _asn1_set_value(p,der+counter,len3+len2); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; + if (len3+len2 > len-counter) return ASN1_DER_ERROR; + _asn1_set_value(p,der+counter,len3+len2); counter+=len3+len2; move=RIGHT; break; case TYPE_BIT_STRING: - len2=_asn1_get_length_der(der+counter,&len3); - _asn1_set_value(p,der+counter,len3+len2); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; + if (len3+len2 > len-counter) return ASN1_DER_ERROR; + _asn1_set_value(p,der+counter,len3+len2); counter+=len3+len2; move=RIGHT; break; @@ -732,10 +809,12 @@ asn1_der_decoding(ASN1_TYPE *element,con len2=strtol(p->value,NULL,10); _asn1_set_value(p,NULL,0); if(len2==-1){ /* indefinite length method */ - if((der[counter]) || der[counter+1]){ - asn1_delete_structure(element); - return ASN1_DER_ERROR; - } + if (len-counter+1 > 0) { + if((der[counter]) || der[counter+1]){ + asn1_delete_structure(element); + return ASN1_DER_ERROR; + } + } else return ASN1_DER_ERROR; counter+=2; } else{ /* definite length method */ @@ -747,7 +826,8 @@ asn1_der_decoding(ASN1_TYPE *element,con move=RIGHT; } else{ /* move==DOWN || move==RIGHT */ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < -1) return ASN1_DER_ERROR; counter+=len2; if(len3>0){ _asn1_ltostr(counter+len3,temp); @@ -806,7 +886,8 @@ asn1_der_decoding(ASN1_TYPE *element,con } } else{ /* move==DOWN || move==RIGHT */ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < -1) return ASN1_DER_ERROR; counter+=len2; if(len3){ if(len3>0){ /* definite length method */ @@ -828,9 +909,13 @@ asn1_der_decoding(ASN1_TYPE *element,con move=RIGHT; break; case TYPE_ANY: - tag=_asn1_get_tag_der(der+counter,&class,&len2); - len4=_asn1_get_length_der(der+counter+len2,&len3); - + if(_asn1_get_tag_der(der+counter,len-counter,&class,&len2,&tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > len) + return ASN1_DER_ERROR; + len4=_asn1_get_length_der(der+counter+len2,len-counter-len2,&len3); + if(len4 < -1) return ASN1_DER_ERROR; + if(len4 > len-counter+len2+len3) return ASN1_DER_ERROR; if(len4 != -1){ len2+=len4; _asn1_length_der(len2+len3,NULL,&len4); @@ -955,7 +1040,7 @@ asn1_der_decoding_element(ASN1_TYPE *str int nameLen=MAX_NAME_SIZE*10-1,state; int counter,len2,len3,len4,move,ris, tlen; unsigned char class,*temp2; - unsigned int tag; + unsigned long tag; int indefinite, result; const unsigned char* der = ider; @@ -1024,11 +1109,11 @@ asn1_der_decoding_element(ASN1_TYPE *str while(p2){ if((p2->type&CONST_SET) && (p2->type&CONST_NOT_USED)){ if(type_field(p2->type)!=TYPE_CHOICE) - ris=_asn1_extract_tag_der(p2,der+counter,&len2); + ris=_asn1_extract_tag_der(p2,der+counter,len-counter,&len2); else{ p3=p2->down; while(p3){ - ris=_asn1_extract_tag_der(p3,der+counter,&len2); + ris=_asn1_extract_tag_der(p3,der+counter,len-counter,&len2); if(ris==ASN1_SUCCESS) break; p3=p3->right; } @@ -1067,7 +1152,7 @@ asn1_der_decoding_element(ASN1_TYPE *str if(type_field(p->type)==TYPE_CHOICE){ while(p->down){ if(counterdown,der+counter,&len2); + ris=_asn1_extract_tag_der(p->down,der+counter,len-counter,&len2); else ris=ASN1_DER_ERROR; if(ris==ASN1_SUCCESS){ @@ -1103,7 +1188,7 @@ asn1_der_decoding_element(ASN1_TYPE *str if(counter>len2) ris=ASN1_TAG_ERROR; } - if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,&len2); + if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2); if(ris!=ASN1_SUCCESS){ if(p->type&CONST_OPTION){ p->type|=CONST_NOT_USED; @@ -1156,8 +1241,10 @@ asn1_der_decoding_element(ASN1_TYPE *str move=RIGHT; break; case TYPE_INTEGER: case TYPE_ENUMERATED: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; if(state==FOUND){ + if (len3+len2 > len-counter) return ASN1_DER_ERROR; _asn1_set_value(p,der+counter,len3+len2); if(p==nodeFound) state=EXIT; @@ -1167,7 +1254,7 @@ asn1_der_decoding_element(ASN1_TYPE *str break; case TYPE_OBJECT_ID: if(state==FOUND){ - _asn1_get_objectid_der(der+counter,&len2, temp, sizeof(temp)); + _asn1_get_objectid_der(der+counter,len-counter,&len2, temp, sizeof(temp)); tlen = strlen(temp); if (tlen > 0) @@ -1176,7 +1263,8 @@ asn1_der_decoding_element(ASN1_TYPE *str if(p==nodeFound) state=EXIT; } else{ - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; len2+=len3; } @@ -1185,7 +1273,7 @@ asn1_der_decoding_element(ASN1_TYPE *str break; case TYPE_TIME: if(state==FOUND){ - result = _asn1_get_time_der(der+counter,&len2,temp,sizeof(temp)-1); + result = _asn1_get_time_der(der+counter,len-counter,&len2,temp,sizeof(temp)-1); if (result != ASN1_SUCCESS) { asn1_delete_structure(structure); return result; @@ -1198,7 +1286,8 @@ asn1_der_decoding_element(ASN1_TYPE *str if(p==nodeFound) state=EXIT; } else{ - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; len2+=len3; } @@ -1219,8 +1308,10 @@ asn1_der_decoding_element(ASN1_TYPE *str move=RIGHT; break; case TYPE_GENERALSTRING: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; if(state==FOUND){ + if (len3+len2 > len-counter) return ASN1_DER_ERROR; _asn1_set_value(p,der+counter,len3+len2); if(p==nodeFound) state=EXIT; @@ -1229,8 +1320,10 @@ asn1_der_decoding_element(ASN1_TYPE *str move=RIGHT; break; case TYPE_BIT_STRING: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; if(state==FOUND){ + if (len3+len2 > len-counter) return ASN1_DER_ERROR; _asn1_set_value(p,der+counter,len3+len2); if(p==nodeFound) state=EXIT; @@ -1260,12 +1353,14 @@ asn1_der_decoding_element(ASN1_TYPE *str } else{ /* move==DOWN || move==RIGHT */ if(state==OTHER_BRANCH){ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < 0) return ASN1_DER_ERROR; counter+=len2+len3; move=RIGHT; } else { /* state==SAME_BRANCH or state==FOUND */ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < 0) return ASN1_DER_ERROR; counter+=len2; if(len3>0){ _asn1_ltostr(counter+len3,temp); @@ -1315,12 +1410,14 @@ asn1_der_decoding_element(ASN1_TYPE *str } else{ /* move==DOWN || move==RIGHT */ if(state==OTHER_BRANCH){ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < 0) return ASN1_DER_ERROR; counter+=len2+len3; move=RIGHT; } else{ /* state==FOUND or state==SAME_BRANCH */ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < 0) return ASN1_DER_ERROR; counter+=len2; if(len3){ _asn1_ltostr(counter+len3,temp); @@ -1339,9 +1436,14 @@ asn1_der_decoding_element(ASN1_TYPE *str break; case TYPE_ANY: - tag=_asn1_get_tag_der(der+counter,&class,&len2); - len4=_asn1_get_length_der(der+counter+len2,&len3); - + if(_asn1_get_tag_der(der+counter, len-counter,&class,&len2,&tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > len) + return ASN1_DER_ERROR; + + len4=_asn1_get_length_der(der+counter+len2,len-counter-len2,&len3); + if(len4 < -1) return ASN1_DER_ERROR; + if(len4 != -1){ len2+=len4; if(state==FOUND){ @@ -1549,7 +1651,7 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele node_asn *node,*node_to_find,*p,*p2,*p3; int counter,len2,len3,len4,move,ris; unsigned char class; - unsigned int tag; + unsigned long tag; int indefinite; const unsigned char* der = ider; @@ -1597,10 +1699,10 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele while(p2){ if((p2->type&CONST_SET) && (p2->type&CONST_NOT_USED)){ /* CONTROLLARE */ if(type_field(p2->type)!=TYPE_CHOICE) - ris=_asn1_extract_tag_der(p2,der+counter,&len2); + ris=_asn1_extract_tag_der(p2,der+counter,len-counter,&len2); else{ p3=p2->down; - ris=_asn1_extract_tag_der(p3,der+counter,&len2); + ris=_asn1_extract_tag_der(p3,der+counter,len-counter,&len2); } if(ris==ASN1_SUCCESS){ p2->type&=~CONST_NOT_USED; @@ -1617,11 +1719,11 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele if(type_field(p->type)==TYPE_CHOICE){ p=p->down; - ris=_asn1_extract_tag_der(p,der+counter,&len2); + ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2); if(p==node_to_find) *start=counter; } - if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,&len2); + if(ris==ASN1_SUCCESS) ris=_asn1_extract_tag_der(p,der+counter,len-counter,&len2); if(ris!=ASN1_SUCCESS){ if(p->type&CONST_OPTION){ p->type|=CONST_NOT_USED; @@ -1650,17 +1752,20 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele move=RIGHT; break; case TYPE_INTEGER: case TYPE_ENUMERATED: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; counter+=len3+len2; move=RIGHT; break; case TYPE_OBJECT_ID: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; counter+=len2+len3; move=RIGHT; break; case TYPE_TIME: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; counter+=len2+len3; move=RIGHT; break; @@ -1672,18 +1777,21 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele move=RIGHT; break; case TYPE_GENERALSTRING: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; counter+=len3+len2; move=RIGHT; break; case TYPE_BIT_STRING: - len2=_asn1_get_length_der(der+counter,&len3); + len2=_asn1_get_length_der(der+counter,len-counter,&len3); + if(len2 < 0) return ASN1_DER_ERROR; counter+=len3+len2; move=RIGHT; break; case TYPE_SEQUENCE: case TYPE_SET: if(move!=UP){ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < -1) return ASN1_DER_ERROR; counter+=len2; if(len3==0) move=RIGHT; else move=DOWN; @@ -1696,7 +1804,8 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele break; case TYPE_SEQUENCE_OF: case TYPE_SET_OF: if(move!=UP){ - len3=_asn1_get_length_der(der+counter,&len2); + len3=_asn1_get_length_der(der+counter,len-counter,&len2); + if(len3 < -1) return ASN1_DER_ERROR; counter+=len2; if((len3==-1) && !der[counter] && !der[counter+1]) counter+=2; @@ -1714,9 +1823,14 @@ asn1_der_decoding_startEnd(ASN1_TYPE ele move=RIGHT; break; case TYPE_ANY: - tag=_asn1_get_tag_der(der+counter,&class,&len2); - len4=_asn1_get_length_der(der+counter+len2,&len3); - + if (_asn1_get_tag_der(der+counter, len-counter,&class,&len2,&tag)!=ASN1_SUCCESS) + return ASN1_DER_ERROR; + if (counter+len2 > len) + return ASN1_DER_ERROR; + + len4=_asn1_get_length_der(der+counter+len2,len-counter-len2,&len3); + if(len4 < -1) return ASN1_DER_ERROR; + if(len4 != -1){ counter+=len2+len4+len3; } @@ -1887,8 +2001,9 @@ asn1_expand_any_defined_by(ASN1_TYPE def result=asn1_create_element(definitions,name,&aux); if(result == ASN1_SUCCESS){ _asn1_set_name(aux,p->name); - len2=_asn1_get_length_der(p->value,&len3); - + len2=_asn1_get_length_der(p->value,p->value_len,&len3); + if(len2 < 0) return ASN1_DER_ERROR; + result=asn1_der_decoding(&aux,p->value+len3,len2, errorDescription); if(result == ASN1_SUCCESS){ @@ -2051,8 +2166,9 @@ asn1_expand_octet_string(ASN1_TYPE defin result=asn1_create_element(definitions,name,&aux); if(result == ASN1_SUCCESS){ _asn1_set_name(aux,octetNode->name); - len2=_asn1_get_length_der(octetNode->value,&len3); - + len2=_asn1_get_length_der(octetNode->value,octetNode->value_len,&len3); + if(len2 < 0) return ASN1_DER_ERROR; + result=asn1_der_decoding(&aux,octetNode->value+len3,len2, errorDescription); if(result == ASN1_SUCCESS){ Index: lib/der.h =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/der.h,v retrieving revision 1.6 retrieving revision 1.6.2.1 diff -u -p -r1.6 -r1.6.2.1 --- lib/der.h 30 Jul 2003 19:52:56 -0000 1.6 +++ lib/der.h 11 Feb 2006 10:00:11 -0000 1.6.2.1 @@ -28,23 +28,23 @@ #define TAG_NULL 0x05 #define TAG_GENERALSTRING 0x1B -unsigned int _asn1_get_tag_der(const unsigned char *der, - unsigned char *class,int *len); +int _asn1_get_tag_der(const unsigned char *der, int der_len, + unsigned char *class,int *len, unsigned long *tag); void _asn1_octet_der(const unsigned char *str,int str_len, unsigned char *der,int *der_len); -asn1_retCode _asn1_get_octet_der(const unsigned char *der, - int *der_len,unsigned char *str,int str_size, int *str_len); +asn1_retCode _asn1_get_octet_der(const unsigned char *der, int der_len, + int *ret_len,unsigned char *str,int str_size, int *str_len); void _asn1_bit_der(const unsigned char *str,int bit_len, unsigned char *der,int *der_len); -asn1_retCode _asn1_get_bit_der(const unsigned char *der, - int *der_len,unsigned char *str, int str_size, +asn1_retCode _asn1_get_bit_der(const unsigned char *der, int der_len, + int *ret_len,unsigned char *str, int str_size, int *bit_len); -signed long _asn1_get_length_der(const unsigned char *der,int *len); +signed long _asn1_get_length_der(const unsigned char *der,int der_len, int *len); void _asn1_length_der(unsigned long len,unsigned char *ans,int *ans_len); Index: lib/element.c =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/element.c,v retrieving revision 1.22 retrieving revision 1.22.2.1 diff -u -p -r1.22 -r1.22.2.1 --- lib/element.c 16 Jul 2005 11:25:32 -0000 1.22 +++ lib/element.c 11 Feb 2006 10:00:11 -0000 1.22.2.1 @@ -1,22 +1,23 @@ /* + * Copyright (C) 2004, 2006 Free Software Foundation * Copyright (C) 2000, 2001, 2002, 2003 Fabio Fiorina - * Copyright (C) 2004 Simon Josefsson * - * This file is part of LIBASN1. + * This file is part of LIBTASN1. * - * The LIBTASN1 library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA */ /*****************************************************/ @@ -677,7 +678,7 @@ asn1_read_value(ASN1_TYPE root,const cha } else{ len2=-1; - if (_asn1_get_octet_der(node->value,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; + if (_asn1_get_octet_der(node->value,node->value_len,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; } break; case TYPE_OBJECT_ID: @@ -709,22 +710,23 @@ asn1_read_value(ASN1_TYPE root,const cha break; case TYPE_OCTET_STRING: len2=-1; - if (_asn1_get_octet_der(node->value,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; + if (_asn1_get_octet_der(node->value,node->value_len,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; break; case TYPE_GENERALSTRING: len2=-1; - if (_asn1_get_octet_der(node->value,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; + if (_asn1_get_octet_der(node->value,node->value_len,&len2,value, value_size, len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; break; case TYPE_BIT_STRING: len2=-1; - if (_asn1_get_bit_der(node->value,&len2,value,value_size,len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; + if (_asn1_get_bit_der(node->value,node->value_len,&len2,value,value_size,len)!=ASN1_SUCCESS) return ASN1_MEM_ERROR; break; case TYPE_CHOICE: PUT_STR_VALUE( value, value_size, node->down->name); break; case TYPE_ANY: len3=-1; - len2=_asn1_get_length_der(node->value,&len3); + len2=_asn1_get_length_der(node->value,node->value_len,&len3); + if (len2 < 0) return ASN1_DER_ERROR; PUT_VALUE( value, value_size, node->value+len3, len2); break; default: Index: lib/libtasn1.h =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/libtasn1.h,v retrieving revision 1.30 retrieving revision 1.30.2.1 diff -u -p -r1.30 -r1.30.2.1 --- lib/libtasn1.h 31 Aug 2005 13:17:47 -0000 1.30 +++ lib/libtasn1.h 11 Feb 2006 10:00:11 -0000 1.30.2.1 @@ -1,6 +1,6 @@ /* + * Copyright (C) 2004, 2005, 2006 Free Software Foundation * Copyright (C) 2002 Fabio Fiorina - * Copyright (C) 2004, 2005 Simon Josefsson * * This file is part of LIBTASN1. * @@ -108,6 +108,7 @@ typedef struct node_asn_struct{ char *name; /* Node name */ unsigned int type; /* Node type */ unsigned char *value; /* Node value */ + int value_len; struct node_asn_struct *down; /* Pointer to the son node */ struct node_asn_struct *right; /* Pointer to the brother node */ struct node_asn_struct *left; /* Pointer to the next list element */ Index: lib/parser_aux.c =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/parser_aux.c,v retrieving revision 1.13 retrieving revision 1.13.2.1 diff -u -p -r1.13 -r1.13.2.1 --- lib/parser_aux.c 16 Jul 2005 11:25:32 -0000 1.13 +++ lib/parser_aux.c 11 Feb 2006 10:00:11 -0000 1.13.2.1 @@ -1,22 +1,23 @@ /* + * Copyright (C) 2004, 2006 Free Software Foundation * Copyright (C) 2000,2001 Fabio Fiorina - * Copyright (C) 2004 Simon Josefsson * - * This file is part of LIBASN1. + * This file is part of LIBTASN1. * - * The LIBTASN1 library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA */ #include @@ -187,10 +188,12 @@ _asn1_set_value(node_asn *node,const uns if(node->value){ _asn1_free(node->value); node->value=NULL; + node->value_len = 0; } if(!len) return node; node->value=(unsigned char *) _asn1_malloc(len); if (node->value==NULL) return NULL; + node->value_len = len; memcpy(node->value,value,len); return node; Index: lib/structure.c =================================================================== RCS file: /cvs/gnutls/libtasn1/lib/structure.c,v retrieving revision 1.21 retrieving revision 1.21.2.1 diff -u -p -r1.21 -r1.21.2.1 --- lib/structure.c 16 Jul 2005 11:25:32 -0000 1.21 +++ lib/structure.c 11 Feb 2006 10:00:11 -0000 1.21.2.1 @@ -1,22 +1,23 @@ /* + * Copyright (C) 2004, 2006 Free Software Foundation * Copyright (C) 2002 Fabio Fiorina - * Copyright (C) 2004 Simon Josefsson * - * This file is part of LIBASN1. + * This file is part of LIBTASN1. * - * The LIBTASN1 library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public + * The LIBTASN1 library is free software; you can redistribute it + * and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA */ @@ -362,7 +363,8 @@ _asn1_copy_structure3(node_asn *source_n case TYPE_OCTET_STRING: case TYPE_BIT_STRING: case TYPE_GENERALSTRING: case TYPE_INTEGER: len2=-1; - len=_asn1_get_length_der(p_s->value,&len2); + len=_asn1_get_length_der(p_s->value,p_s->value_len,&len2); + if (len < 0) return NULL; _asn1_set_value(p_d,p_s->value,len+len2); break; default: @@ -726,17 +728,19 @@ asn1_print_structure(FILE *out,ASN1_TYPE case TYPE_INTEGER: if(p->value){ len2=-1; - len=_asn1_get_length_der(p->value,&len2); + len=_asn1_get_length_der(p->value,p->value_len,&len2); fprintf(out," value:0x"); - for(k=0;kvalue)[k+len2]); + if (len > 0) + for(k=0;kvalue)[k+len2]); } break; case TYPE_ENUMERATED: if(p->value){ len2=-1; - len=_asn1_get_length_der(p->value,&len2); + len=_asn1_get_length_der(p->value,p->value_len,&len2); fprintf(out," value:0x"); - for(k=0;kvalue)[k+len2]); + if (len > 0) + for(k=0;kvalue)[k+len2]); } break; case TYPE_TIME: @@ -751,25 +755,30 @@ asn1_print_structure(FILE *out,ASN1_TYPE case TYPE_BIT_STRING: if(p->value){ len2=-1; - len=_asn1_get_length_der(p->value,&len2); - fprintf(out," value(%i):",(len-1)*8-(p->value[len2])); - for(k=1;kvalue)[k+len2]); + len=_asn1_get_length_der(p->value,p->value_len,&len2); + if (len>0) + { + fprintf(out," value(%i):",(len-1)*8-(p->value[len2])); + for(k=1;kvalue)[k+len2]); + } } break; case TYPE_OCTET_STRING: if(p->value){ len2=-1; - len=_asn1_get_length_der(p->value,&len2); + len=_asn1_get_length_der(p->value,p->value_len,&len2); fprintf(out," value:"); - for(k=0;kvalue)[k+len2]); + if (len>0) + for(k=0;kvalue)[k+len2]); } break; case TYPE_GENERALSTRING: if(p->value){ len2=-1; - len=_asn1_get_length_der(p->value,&len2); + len=_asn1_get_length_der(p->value,p->value_len,&len2); fprintf(out," value:"); - for(k=0;kvalue)[k+len2]); + if (len>0) + for(k=0;kvalue)[k+len2]); } break; case TYPE_OBJECT_ID: @@ -778,9 +787,10 @@ asn1_print_structure(FILE *out,ASN1_TYPE case TYPE_ANY: if(p->value){ len3=-1; - len2=_asn1_get_length_der(p->value,&len3); + len2=_asn1_get_length_der(p->value,p->value_len,&len3); fprintf(out," value:"); - for(k=0;kvalue)[k+len3]); + if (len2>0) + for(k=0;kvalue)[k+len3]); } break; case TYPE_SET: From jas at extundo.com Sat Feb 11 11:36:16 2006 From: jas at extundo.com (Simon Josefsson) Date: Sat, 11 Feb 2006 11:36:16 +0100 Subject: [gnutls-dev] Re: GnuTLS 1.2.10 - Security release In-Reply-To: (Simon Josefsson's message of "Thu, 09 Feb 2006 16:46:28 +0100") References: Message-ID: The patch against GnuTLS 1.2.9 to solve the security problem is below. Actually, it merely fix the calls to the internal libtasn1 APIs that changed with the security fixes for libtasn1. In the future, GnuTLS will not rely on libtasn1 internal functions. We will export _asn1_get_tag_der, _asn1_get_octet_der, _asn1_get_bit_der and _asn1_get_length_der (after removing the leading '_') because these functions have proved useful outside of the library. Note that you'll want to make sure a GnuTLS 1.2.9 built with this patch really uses the new libtasn1, or it will break. Regards, Simon Index: lib/x509/xml.c =================================================================== RCS file: /cvs/gnutls/gnutls/lib/x509/xml.c,v retrieving revision 1.14 retrieving revision 1.14.10.1 diff -u -p -r1.14 -r1.14.10.1 --- lib/x509/xml.c 26 May 2005 15:27:24 -0000 1.14 +++ lib/x509/xml.c 11 Feb 2006 10:28:55 -0000 1.14.10.1 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation + * Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation * * Author: Nikos Mavroyanopoulos * @@ -344,7 +344,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE if (p->type == TYPE_BIT_STRING) { len2 = -1; - len = _asn1_get_length_der(p->value, &len2); + len = _asn1_get_length_der(p->value, p->value_len, &len2); snprintf(tmp, sizeof(tmp), " length=\"%i\"", (len - 1) * 8 - (p->value[len2])); STR_APPEND(tmp); @@ -374,7 +374,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE case TYPE_INTEGER: if (value) { len2 = -1; - len = _asn1_get_length_der(value, &len2); + len = _asn1_get_length_der(value, p->value_len, &len2); for (k = 0; k < len; k++) { snprintf(tmp, sizeof(tmp), @@ -387,7 +387,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE case TYPE_ENUMERATED: if (value) { len2 = -1; - len = _asn1_get_length_der(value, &len2); + len = _asn1_get_length_der(value, p->value_len, &len2); for (k = 0; k < len; k++) { snprintf(tmp, sizeof(tmp), @@ -412,7 +412,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE case TYPE_BIT_STRING: if (value) { len2 = -1; - len = _asn1_get_length_der(value, &len2); + len = _asn1_get_length_der(value, p->value_len, &len2); for (k = 1; k < len; k++) { snprintf(tmp, sizeof(tmp), @@ -424,7 +424,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE case TYPE_OCTET_STRING: if (value) { len2 = -1; - len = _asn1_get_length_der(value, &len2); + len = _asn1_get_length_der(value, p->value_len, &len2); for (k = 0; k < len; k++) { snprintf(tmp, sizeof(tmp), "%02X", (value)[k + len2]); @@ -440,7 +440,7 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE if (!p->down) { if (value) { len3 = -1; - len2 = _asn1_get_length_der(value, &len3); + len2 = _asn1_get_length_der(value, p->value_len, &len3); for (k = 0; k < len2; k++) { snprintf(tmp, sizeof(tmp), "%02X", (value)[k + len3]); @@ -456,10 +456,10 @@ _gnutls_asn1_get_structure_xml(ASN1_TYPE up->left && up->left->value && up->type & CONST_DEFINED_BY && type_field(up->left->type) == TYPE_OBJECT_ID) { + len2 = _asn1_get_length_der(up->value, + up->value_len, &len3); - len2 = _asn1_get_length_der(up->value, &len3); - - if (len2 > 0 && strcmp(p->name, "type") == 0) { + if (len2 > 0 && strcmp(p->name, "type") == 0) { size_t tmp_len = sizeof(tmp); ret = _gnutls_x509_oid_data2string(up->left-> From solinym at gmail.com Wed Feb 15 15:23:01 2006 From: solinym at gmail.com (Travis H.) Date: Wed, 15 Feb 2006 08:23:01 -0600 Subject: [gnutls-dev] redesign of Linux/Unix /dev/random Message-ID: Quoting: "We've made some progress on the RNG issue on the GnuTLS discussion list. I think the Linux /dev/urandom implementation is sub-optimal. When used heavily, it depletes the /dev/random pool, causing applications that access /dev/random to stall. I believe /dev/urandom should be changed, to be a PRNG (re-)seeded with strong randomness from the /dev/random pool, rather than simply taking entropy from the /dev/random pool directly. The source code for the /dev/random interface in Linux is rather unreadable IMHO. The code for it should not be as complicated it is today." I concur, and brought this point up on the cryptography mailing list a while ago. You can read my gripes at the end of this email if so inclined. In particular, I'd like to have fortuna (an evolution of yarrow described only in "Practical Cryptography" to my knowledge) as the /dev/urandom, only stealing enough entropy to reseed itself, and maybe only doing that under certain constraints (nobody waiting on /dev/random). It merits further discussion and exploration. BTW, FreeBSD has yarrow as its /dev/random! That's right, there's no "real random bits" in FreeBSD, except potentially as seeds to yarrow internally. Perhaps it could return "real random" bits iff there are no processes reading /dev/random. Sounds like a good thing to control via sysctl. See also: http://www.aculei.net/~shardy/bcard/talks/bhe04-paper.pdf In this paper Seth describes extractors, which can transform "weakly random" bits into "arbitrarily close to uniform" bits via a few "uniformly random" bits. I had an idea which involves a userland process which hashes "possibly unpredictable" bits with the pool without updating the entropy count. For example, it could get them from one of the various "free random number" web sites, and if they are not observed by the attacker, they can help recover from a seed compromise. If they are observed, or worse yet controlled, there's no discernable drawback, given standard assumptions about cryptographic one-way functions between the source and eventual use. One subtle attack that Schneier mentions in PC is the state compromise followed by tracking; that is, if the attacker gets the PRNG state somehow and has access to its outputs, then if we only update it incrementally, he can guess the added bits and compare them with his model, thereby "tracking" the state changes. To deal with this, we must update the seed with a large amount of unpredictable bits at once, not incrementally like the current Linux /dev/urandom. Also, there's a speed issue; /dev/urandom does one SHA-1 computation over the whole pool for each 160 bits of output. On one of my old boxes, that's under 1MB/s, which is too slow for some applications (e.g. wiping a 100GB disk partition with pseudorandom data, or filling a gigabit ethernet link with random bits between actual transmissions to prevent traffic analysis). Another thing I wish to explore is securely combining random bits from different sources and the relation between how you combine them, efficiency, and how much you trust the sources. That is, can we make use of a HWRNG that we don't trust entirely by combining it with a slower source we trust more? I'd also like some kind of statistical sanity checks on the various entropy sources, so that I can be protected (or at least warned) if they fail. I will obviously have to define some kinds of failure modes and test for them, as unpredictability cannot be tested for. Nevertheless, some people want to know if their HWRNG produces 1kB of nulls all of a sudden. I would also like *writing* to /dev/random to block when the pool is full, under the assumption that getting random bits from a HWRNG may be expensive in terms of some resource, and so you don't necessarily want to be pulling them all the time if nobody is using them. One interesting suggestion Terry Ritter had was to provide the available random bits in a buffer, and tell the application that you could only fulfill part of its request immediately, giving the application the opportunity to decide what to do. I'm not sure how this would fit into the Unix I/O model, but I suspect something could be done (poll/select perhaps?). Due to the number of changes, I'd like to pull some/all of it out of the kernel for experimentation, and then maybe integrate it back into the kernel if necessary. For example, a .png chart of a distribution of values can convey much more information than statistics, and besides all that you can't do floating point in the kernel, which makes doing Shannon entropy or chi-square calculations there, uh, challenging. ===prior /dev/random email=== So far I haven't seen any userland tools for updating the entropy count (NetBSD, OpenBSD, Linux). This is unfortunate, because sometimes I generate entropy on one machine and want to pipe it into the /dev/random pool (currently it stirs the pool but doesn't update estimated entropy count). However, I cannot update entropy counts without writing programs that can do ioctl (meaning C or C++). This is no good. Can't we make writes to /dev/random take some kind of structured form that's easy to do from a shell script so that we don't have to use ioctls? Failing that, could we have a userland tool that can make the requisite ioctls? The entropy harvesting and estimation code is bound too tightly to the entropy pool (Linux). It is in kernelspace so cannot do floating point, like measuring chi-square or Shannon entropy to estimate the amount of randomness. Reading from /dev/urandom empties the entropy pool immediately; this is unfriendly to people who need real random numbers. In Linux, writing to /dev/random and /dev/urandom is absolutely identical; the data gets mixed in, but the entropy count isn't updated. The random_write_wakeup_thresh is almost worthless as any woken processes will probably not be able to update the entropy count, unless they are specially coded for this purpose. The write interface isn't exploited thoroughly enough. If writes to /dev/random were to block when the entropy pool is full, and writes to /dev/urandom never blocks. then it greatly simplifies the design of userland programs that harvest entropy from sources of non-zero cost; they merely write(2) to /dev/random, and if it doesn't need any more entropy, then it simply blocks until more is needed. This way it doesn't have to pool the entropy pool using ioctl(2). If we change the semantics, they should be queryable in some way, because currently the source code or experimentation is the only way of discerning them. Getting good randomness shouldn't be platform-specific, and shouldn't fail in silent or unsafe ways at runtime. -- "Cryptography is nothing more than a mathematical framework for discussing various paranoid delusions." -- Don Alvarez http://www.lightconsulting.com/~travis/ -><- GPG fingerprint: 50A1 15C5 A9DE 23B9 ED98 C93E 38E9 204A 94C2 641B From smurf at smurf.noris.de Tue Feb 21 10:15:45 2006 From: smurf at smurf.noris.de (Matthias Urlichs) Date: Tue, 21 Feb 2006 10:15:45 +0100 Subject: [gnutls-dev] Re: redesign of Linux/Unix /dev/random References: Message-ID: Hi, Travis H. wrote: > One interesting suggestion Terry Ritter had was to provide the > available random bits in a buffer, and tell the application that you > could only fulfill part of its request immediately, giving the > application the opportunity to decide what to do. I'm not sure how > this would fit into the Unix I/O model, but I suspect something could > be done (poll/select perhaps?). Just do a short read (i.e. return less than requested). Presumably the application would then select/poll for more bits if it needs them. -- Matthias Urlichs From nmav at gnutls.org Tue Feb 28 12:48:59 2006 From: nmav at gnutls.org (Nikos Mavrogiannopoulos) Date: Tue, 28 Feb 2006 12:48:59 +0100 Subject: [gnutls-dev] alternative /dev/random Message-ID: Hello, based on the last discussions on the list about the Linux /dev/random and urandom, we decided to look on this issue further. For many reasons that have to do with the gathering of random events and functionality (i.e. it is not trivial to create a thread safe random number implementation), we believe that the random generator should be part of the operating system. Unfortunately the Linux' random generator is less than optimal. Some reasons: 1. It is way too slow and does not offer a faster but lower quality prng (for less important stuff such as IV's, padding etc) 2. /dev/random is blocking that may cause denial of service if you use it. 3. Using /dev/urandom will depleat the entropy of /dev/random as well, thus although we don't block other applications will. 4. Cannot use random events that may be known to attackers such as the network events. What would we like from a kernel implemented random generator? At least for gnutls two devices would be sufficient. /dev/urandom: to generate session and private keys /dev/arandom: to generate anything else (such as IV's) The primary concern of the first should be to be unpredictable, whilst the second should focus on being fast. A question might be why do we need /dev/arandom? There are non cryptographic uses of random numbers (IV's, some padding data) that have different requirements and thus should not depleat the kernel's entropy the same way as a key generation. There are also non-cryptographic applications, that could use that instead. We initially implemented an AES-CTR based prng based on the idea of /dev/arandom of OpenBSD to overcome some of these limitations. But then we came across the fortuna implementation for the Linux kernel: http://jlcooke.ca/random/ Although we haven't checked the implementation, the fortuna algorithm seems an ideal algorithm to be used as a kernel prng. It is about 10 times faster of the current prng and does not have the limitations discussed above. Thus if your system had one of the previously discussed problems, we'd like to suggest you to try this kernel prng implementation and discuss it in this list. regards, Nikos and Simon From jas at extundo.com Tue Feb 28 13:49:42 2006 From: jas at extundo.com (Simon Josefsson) Date: Tue, 28 Feb 2006 13:49:42 +0100 Subject: [gnutls-dev] Libtasn1 0.3.0 Message-ID: The main focus of this release is a native port to Microsoft Windows. The project files for Visual Studio 2005 are included in the windows/ directory. With them, you can build the library, the self-tests and command line ASN.1 parser tool. This build pass self tests and appear to work, but is still experimental. The Windows port is the first step towards a more fully functional port of GnuTLS to Windows with, e.g., support for Windows CAPI CA certificates. It is not yet clear how, when or if that port will be finished, we invite feedback, support and any monetary donations. This work is done in an co-operation with Simon Josefsson Datakonsult, Lumiad and E-advies. This release export the functions that GnuTLS need internally, so that GnuTLS and other projects can use them without problem. Below is your regular release announcement... Libtasn1 is a standalone library written in C for manipulating ASN.1 objects including DER/BER encoding and DER/BER decoding. Libtasn1 is used by GnuTLS to manipulate X.509 objects and by GNU Shishi to handle Kerberos V5 packets. Version 0.3.0 - Export DER utility functions, mostly so that GnuTLS can avoid using libtasn1 internals. - The _asn1* symbols are not exported in the shared library file (when using GNU ld). - The library can now be built using Visual Studio, and the project files are included in windows/. - New public APIs: asn1_get_tag_der asn1_octet_der asn1_get_octet_der asn1_bit_der asn1_get_bit_der asn1_get_length_der asn1_length_der Commercial support contracts for Libtasn1 are available, and they help finance continued maintenance. Simon Josefsson Datakonsult, a Stockholm based privately held company, is currently funding Libtasn1 maintenance. We are always looking for interesting development projects. If you need help to use Libtasn1, or want to help others, you are invited to join our help-gnutls mailing list, see: . Homepage: http://josefsson.org/libtasn1/ Manual in many formats: http://josefsson.org/gnutls/manual/libtasn1/ Here are the compressed sources: ftp://ftp.gnutls.org/pub/gnutls/libtasn1/libtasn1-0.3.0.tar.gz (1.2MB) http://josefsson.org/gnutls/releases/libtasn1/libtasn1-0.3.0.tar.gz Here are GPG detached signatures using key 0xB565716F: ftp://ftp.gnutls.org/pub/gnutls/libtasn1/libtasn1-0.3.0.tar.gz.sig http://josefsson.org/gnutls/releases/libtasn1/libtasn1-0.3.0.tar.gz.sig Here are the SHA-1 checksums: 944117dfa77550ac425121f8aa1489be97a6b522 libtasn1-0.3.0.tar.gz 0f38814e0eebe0ccd6ed165c286d1e2e9ea6c82c libtasn1-0.3.0.tar.gz.sig Enjoy, Simon -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 422 bytes Desc: not available URL: