Hello,
* gcm.h:
The GCM_SET_KEY macro uses key both as input and to access a ctx element, and thus requires the last parameter to be called "key" as well.
#define GCM_SET_KEY(ctx, set_key, encrypt, key) \ do { \ (set_key)(&(ctx)->cipher, (key)); \ if (0) (encrypt)(&(ctx)->cipher, 0, (void *)0, (void *)0); \ gcm_set_key(&(ctx)->key, &(ctx)->cipher, \ (nettle_cipher_func *) (encrypt)); \ } while (0)
* cbc.h: cbc_encrypt and decrypt use const void* as first parameter. That is, it cannot be wrapped over a function that works for cbc_encrypt as well as gcm_aes_encrypt (the latter doesn't use const). Without casts that is.
Overall, what I didn't like it that the new cipher API required more code to wrap around it.
* macros.h: The MD_INCR(ctx) macro is now only applicable for sha512.
* nettle-types.h: There is still nettle_crypt_func which is identical to nettle_cipher_func. Is that intentional? I was wondering what was its use.
* dsa_verify() Note sure if this is a regression, but this function will now succeed verifying data signed with a DSA-2048 key and SHA1 as hash.
* libhogweed soname: libhogweed has the same soname with 2.7.1, so applications crash if they are linked against nettle 2.7.1 and 3.0 is installed (that is because hogweed links against libnettle.so.5). It may make sense for both libraries to share the same so version.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
Thanks for the comments.
- gcm.h:
The GCM_SET_KEY macro uses key both as input and to access a ctx element, and thus requires the last parameter to be called "key" as well.
#define GCM_SET_KEY(ctx, set_key, encrypt, key) \ do { \ (set_key)(&(ctx)->cipher, (key)); \ if (0) (encrypt)(&(ctx)->cipher, 0, (void *)0, (void *)0); \ gcm_set_key(&(ctx)->key, &(ctx)->cipher, \ (nettle_cipher_func *) (encrypt)); \ } while (0)
Fixed, good catch. I renamed the macro argument to gcm_key.
- cbc.h:
cbc_encrypt and decrypt use const void* as first parameter. That is, it cannot be wrapped over a function that works for cbc_encrypt as well as gcm_aes_encrypt (the latter doesn't use const). Without casts that is.
Overall, what I didn't like it that the new cipher API required more code to wrap around it.
Can you give some example of what you're doing?
gcm_encrypt uses const void * and nettle_cipher_func, just like cbc_encrypt.
While the struct gcm_aes_ctx contains both the aes key (constant after key schedule) and per message state, and hence has to be non-const. And it's not much different to if you use
struct cbc_aes_ctx CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE);
- macros.h:
The MD_INCR(ctx) macro is now only applicable for sha512.
For hashes where the count is stored in a scalar variable (typically an uint64_t), you should use "ctx->count++" instead of MD_INCR (ctx). I didn't see any need for a macro for that.
- nettle-types.h:
There is still nettle_crypt_func which is identical to nettle_cipher_func. Is that intentional? I was wondering what was its use.
The differ in const-ness... The idea is that nettle_cipher_func is for block ciphers where encrypt and decrypt doesn't change the cipher state. nettle_crypt_func is used for stateful operations, such as stream-ciphers and aead constructions.
- dsa_verify()
Note sure if this is a regression, but this function will now succeed verifying data signed with a DSA-2048 key and SHA1 as hash.
Right, one can use dsa (and ecdsa) with any hash function, with arbitrary digest size. I think that's according to spec (even if not all combinations are recommended or make sense).
- libhogweed soname:
libhogweed has the same soname with 2.7.1, so applications crash if they are linked against nettle 2.7.1 and 3.0 is installed (that is because hogweed links against libnettle.so.5).
He intention was that nettle-2.7.1 uses the sonames "libnettle.so.4" and "libhogweed.so.2", and that nettle-3.0 bumped both numbers, to libnettle.s0.5 and libhogweed.so.3. Was that somehow messed up in the release?
As far as I understand, the versions symbols thing should help. I guess sonames have to be bumped again when version symbols are introduced?
It may make sense for both libraries to share the same so version.
I think it is likely that there maybe incompatible changes affecting only nettle or only hogweed. So I think it's best to keep them independent.
Regards, /Niels
On Mon, 2014-11-24 at 21:39 +0100, Niels Möller wrote:
- cbc.h:
cbc_encrypt and decrypt use const void* as first parameter. That is, it cannot be wrapped over a function that works for cbc_encrypt as well as gcm_aes_encrypt (the latter doesn't use const). Without casts that is.
Overall, what I didn't like it that the new cipher API required more code to wrap around it.
Can you give some example of what you're doing?
I provide an API such as: ctx=cipher_init(cipherno, key) cipher_encrypt(ctx, data) cipher_decrypt(ctx, data) cipher_deinit()
So within the cipher_init I am using a big switch() to the various algorithms. With the split I need more switch cases for the different algorithms (camellia128,camellia192,camellia256) rather than one for camellia.
gcm_encrypt uses const void * and nettle_cipher_func, just like cbc_encrypt. While the struct gcm_aes_ctx contains both the aes key (constant after key schedule) and per message state, and hence has to be non-const. And it's not much different to if you use struct cbc_aes_ctx CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE);
Does it really matter to differentiate? I mean in my code I wrap stream aead, and block ciphers equally, and having a different function pointer for each would mean that I will use function casts (which are horribly dangerous if the API changes and I don't notice).
(said that I think I'll separate the AEAD ciphers after having seen the horrible CCM mode, and may only allow packet encryption with them).
- libhogweed soname:
libhogweed has the same soname with 2.7.1, so applications crash if they are linked against nettle 2.7.1 and 3.0 is installed (that is because hogweed links against libnettle.so.5).
He intention was that nettle-2.7.1 uses the sonames "libnettle.so.4" and "libhogweed.so.2", and that nettle-3.0 bumped both numbers, to libnettle.s0.5 and libhogweed.so.3. Was that somehow messed up in the release?
I was mistaken it seems. It is indeed libhogweed.so.3 that I see in 3.0. For some reason evolution was linking with it though and wouldn't run after installing it.
As far as I understand, the versions symbols thing should help. I guess sonames have to be bumped again when version symbols are introduced?
Not needed. But the version with the symbols will be binary incompatible with the previous one, so it may make sense to bump the soversion again to make that clear that they are incompatible.
It may make sense for both libraries to share the same so version.
I think it is likely that there maybe incompatible changes affecting only nettle or only hogweed. So I think it's best to keep them independent.
Would that independence work in practice given that lighoweed is linked with libnettle? I mean if you only bump only nettle, there will be a competing libhogweed with the previous version of nettle if both are installed. Symbol versioning would save the day there too though :)
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
Can you give some example of what you're doing?
I provide an API such as: ctx=cipher_init(cipherno, key) cipher_encrypt(ctx, data) cipher_decrypt(ctx, data) cipher_deinit()
And what does cipherno represent here? Just "AES", or does it imply a key size and/or a mode of operation too?
Does it really matter to differentiate? I mean in my code I wrap stream aead, and block ciphers equally,
With "block ciphers", I imagine you include ECB mode, not just CBC and CTR and the like?
In that case I think you need to pass contexts around as always non-const. It's not entirely clear to me how much casting there will be of the function pointers, hopefully it can be isolated.
But some casting is needed somwehere, if one is going to assign both aes128_encrypt and camellia128_crypt to variables of the same type. Within nettle, that casting is done in the initializers for the various nettle_cipher structs.
And the way I recommend (but maybe that doesn't work for you?) is to use an array of constant structs, similar in spirit to struct nettle_cipher and struct nettle_aead, rather than a big switch.
As far as I understand, the versions symbols thing should help. I guess sonames have to be bumped again when version symbols are introduced?
Not needed. But the version with the symbols will be binary incompatible with the previous one, so it may make sense to bump the soversion again to make that clear that they are incompatible.
Can a program linked with nettle-3.0 use a nettle-3.1 library with versioned symbols at runtime? If not, we must have another soname bump.
Would that independence work in practice given that lighoweed is linked with libnettle? I mean if you only bump only nettle, there will be a competing libhogweed with the previous version of nettle if both are installed.
I don't understand all possible cases. But I think it's nice if you don't have to upgrade a program using only interfaces from one of the libraries, just because you upgraded to a newer version of the nettle packages, and the other library had an incompatible change.
Symbol versioning would save the day there too though :)
If we introduce symbol versioning, it seems good to do it for both libraries at the same time.
Regards, /Niels
On Tue, 2014-11-25 at 07:28 +0100, Niels Möller wrote:
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
Can you give some example of what you're doing?
I provide an API such as: ctx=cipher_init(cipherno, key) cipher_encrypt(ctx, data) cipher_decrypt(ctx, data) cipher_deinit()
And what does cipherno represent here? Just "AES", or does it imply a key size and/or a mode of operation too?
Yes, something like AES-128-CBC.
Does it really matter to differentiate? I mean in my code I wrap stream aead, and block ciphers equally,
With "block ciphers", I imagine you include ECB mode, not just CBC and CTR and the like?
I don't have ecb mode at all since it is not used by TLS (or any other protocol). Just cbc, and gcm for now.
And the way I recommend (but maybe that doesn't work for you?) is to use an array of constant structs, similar in spirit to struct nettle_cipher and struct nettle_aead, rather than a big switch.
That looks like a nice approach. I may even be able to re-use some of the structures already in nettle to save some memory.
As far as I understand, the versions symbols thing should help. I guess sonames have to be bumped again when version symbols are introduced?
Not needed. But the version with the symbols will be binary incompatible with the previous one, so it may make sense to bump the soversion again to make that clear that they are incompatible.
Can a program linked with nettle-3.0 use a nettle-3.1 library with versioned symbols at runtime? If not, we must have another soname bump.
No it will not.
Symbol versioning would save the day there too though :)
If we introduce symbol versioning, it seems good to do it for both libraries at the same time.
I think my patch addresses that for both. What I now realize is that that mini-gmp mpz_*, gmp_* and mpn_* symbols are not exported in the script that I sent. They could be put unconditionally there, or via a configure variable.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
On Tue, 2014-11-25 at 07:28 +0100, Niels Möller wrote:
And what does cipherno represent here? Just "AES", or does it imply a key size and/or a mode of operation too?
Yes, something like AES-128-CBC.
I see. Makes sense.
I don't have ecb mode at all since it is not used by TLS (or any other protocol). Just cbc, and gcm for now.
Also makes sense. Then you probably should use the nettle_cipher_func type as little as possible. Rather, something like
struct aes128_cbc_ctx CBC_CTX(struct aes128); nettle_crypt_func aes128_cbc_encrypt;
/* If you're going to call this function via a generic function pointer only, there's no gain to have a precise context type, it can just as well take a void * argument and cast internally. */ void aes128_cbc_encrypt (void *p...) { struct aes128_cbc_ctx *ctx = (struct aes128_cbc_ctx *) p; CBC_ENCRYPT (ctx, ...); }
const struct gnutls_cipher aes128_cbc = { .name = "aes128-cbc", .size = sizeof(aes128_cbc_ctx), .encrypt = aes128_cbc_encrypt, ... };
And to make the contexts structs exposed to library users more self-contained, they can have as first element an "is_a"-pointer to the corresponding gnutls_cipher, followed (pointer, or directly in the same object) by the internal cipher-specific context. I guess you already do something a bit like that?
Can a program linked with nettle-3.0 use a nettle-3.1 library with versioned symbols at runtime? If not, we must have another soname bump.
No it will not.
So nettle-3.1 must have a new soname, if it's going to use versioned symbols (which I'm leaning towards doing).
I think my patch addresses that for both.
I think it lacked a linker script for hogweed, with symbol version tracking libhogweed's major version rather than libnettle's.
What I now realize is that that mini-gmp mpz_*, gmp_* and mpn_* symbols are not exported in the script that I sent. They could be put unconditionally there, or via a configure variable.
I think it's generally a bit dangerous to make shared libraries with mini-gmp (the result is not promised to be binary compatible with regular builds). Anyone trying that really needs to know what he/she is doing. So I think a sensible default is to disable hogweed symbol versioning in that case, and possibly have a configure option to explicitly specify the linker script to use for each library.
Regards, /Niels
On Tue, Nov 25, 2014 at 10:36 AM, Niels Möller nisse@lysator.liu.se wrote:
I don't have ecb mode at all since it is not used by TLS (or any other protocol). Just cbc, and gcm for now.
Also makes sense. Then you probably should use the nettle_cipher_func type as little as possible. Rather, something like struct aes128_cbc_ctx CBC_CTX(struct aes128); nettle_crypt_func aes128_cbc_encrypt;
/* If you're going to call this function via a generic function pointer only, there's no gain to have a precise context type, it can just as well take a void * argument and cast internally. */ void aes128_cbc_encrypt (void *p...) { struct aes128_cbc_ctx *ctx = (struct aes128_cbc_ctx *) p; CBC_ENCRYPT (ctx, ...); } const struct gnutls_cipher aes128_cbc = { .name = "aes128-cbc", .size = sizeof(aes128_cbc_ctx), .encrypt = aes128_cbc_encrypt, ... };
The disadvantage here is that I need to define encrypt and decrypt functions for each possible cipher and mode. That was the reason for the usage of cbc_encrypt() and decrypt. Anyway I'll look to it.
btw. I realized that nettle-meta.h lacks definitions for 3des, des and salsa20.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
The disadvantage here is that I need to define encrypt and decrypt functions for each possible cipher and mode. That was the reason for the usage of cbc_encrypt() and decrypt.
Maybe it's possible with some trickery.
For cbc modes, you could allocate a context which is a pointer to the nettle_cipher struct followed by a CBC_CTX with cipher context and iv. Then you could do
nettle_crypt_func gnutls_cbc_encrypt;
struct gnutls_cbc_ctx { const struct nettle_cipher *cipher;
/* A cipher specific context, followed by iv. Use unsigned long as an alignment hack (or use pointers and additional memory blocks). Total allocation size:
offsetof (struct gnutls_cbc_ctx, buf) + cipher->context_size + cipher->block_size. */ unsigned long buf[1]; };
void gnutls_cbc_encrypt (void *p, ...) { struct gnutls_cbc_ctx *ctx = (struct gnutls_cbc_ctx *) p; void *cipher_ctx = ctx->buf; uint8_t *iv = (uint8_t *) cipher_ctx + ctx->cipher->context_size; cbc_encrypt (cipher_ctx, ctx->cipher->encrypt, ctx->cipher->block_size, iv, ...); }
and use the same encrypt function for all ciphers in cbc mode. Not sure what's best, to go this route, or generate boilerplate code for each algorithm.
And note that the only casting above is for packing everything into the same memory block, otherwise the cbc_encrypt call needs no casts at all. (The essential casts are hidden in the initialization of the various nettle_cipher instances).
btw. I realized that nettle-meta.h lacks definitions for 3des, des and salsa20.
des and des3 (and blowfish) are missing, because their set_key functions have a return value indicating weak keys. Maybe they should be added anyway? Either relying on casting betwen function pointers being safe with and without return value, or using a wrapper function to explicitly remove it.
Unfortunately, I don't think a C compiler can optimize
int bar (int x); void foo(int x) { (void) bar(x); /* Ignore return value */ }
to make foo simply an alias of bar (assuming the ABI calling ocnventions allow that). As far as I understand, the C standard requires that &bar != &foo, so at best foo wil be compiled into a single jmp instruction.
And salsa20 is missing because there is no nettle-meta abstraction for stream ciphers. Internally, I use nettle_aead with NULL ->update and ->digest methods to represent stream ciphers, but I'm not sure if that's suitable for a public interface. BTW, it's of course possible to represent CBC and CTR mode in the same way, as nettle_aead without authentication.
Regards, /Niels
On Tue, Nov 25, 2014 at 3:49 PM, Niels Möller nisse@lysator.liu.se wrote:
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
The disadvantage here is that I need to define encrypt and decrypt functions for each possible cipher and mode. That was the reason for the usage of cbc_encrypt() and decrypt.
Maybe it's possible with some trickery. For cbc modes, you could allocate a context which is a pointer to the nettle_cipher struct followed by a CBC_CTX with cipher context and iv. Then you could do
I've done something similar at: https://gitorious.org/gnutls/gnutls/source/0a1102311e443720fc0eb7a83f7dc1b58...
The plan is to integrate that to gnutls master once there is a functioning chacha-poly.
btw. I realized that nettle-meta.h lacks definitions for 3des, des and salsa20.
des and des3 (and blowfish) are missing, because their set_key functions have a return value indicating weak keys. Maybe they should be added anyway? Either relying on casting betwen function pointers being safe with and without return value, or using a wrapper function to explicitly remove it.
If the purpose of these structures are to allow uniform access to ciphers, they should apply to all ciphers. In any case I also saw that rc4 was also missing so I avoided using them.
And salsa20 is missing because there is no nettle-meta abstraction for stream ciphers. Internally, I use nettle_aead with NULL ->update and ->digest methods to represent stream ciphers, but I'm not sure if that's suitable for a public interface. BTW, it's of course possible to represent CBC and CTR mode in the same way, as nettle_aead without authentication.
For my purposes I didn't care to differentiate between cbc_encrypt() and stream_encrypt() so I handled them equally. My impression is that there are two high level abstractions: AEAD ciphers (cipher+mode+tag), and non-aead cipher+mode (just encryption). Stream ciphers are simply ciphers with a fixed mode.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
I've done something similar at: https://gitorious.org/gnutls/gnutls/source/0a1102311e443720fc0eb7a83f7dc1b58...
Looks reasonable. You get a pretty large nettle_cipher_st to support all variations, I see. Some comments:
_ccm_aes_encrypt looks like it supports ccm with any cipher, right?
If the aead_*crypt_func functions are intended as the primary interface for aead, I guess you'd want to either retire the auth and tag functions (and you may want additonal helper functions in nettle to make that easy?). Or implement the aead_*crypt functions in terms of the auth and tag functions for everything but ccm.
For the _gcm functions, do you see any obstacles to implementing generic _gcm functions (like you do with cbc), which passes the encrypt_block function to nettle's general gcm functions? Note that GCM_CTX intentionally puts the cipher-specific context last, so the offset should always be the same.
For function typedefs, in nettle I've chosen to let these types be non-pointers. This is a question of style, of course. If you did the same, you would be able do use them to declare functions like
static encrypt_func _cbc_encrypt;
and then the compiler will check that the definition of _cbc_encrypt matches the declaration. Which I think is nice.
Your auth_func, tag_func, set_key_func and setiv_func seem to duplicate nettle_hash_update, nettle_set_key_func and nettle_hash_digest_func. If they are intended to work with nettle's context structs (which they are, I think?), maybe it's clearer to use nettle's names for these types, to differentiate them from the function types which work with your more abstract nettle_cipher_ctx.
My impression is that there are two high level abstractions: AEAD ciphers (cipher+mode+tag), and non-aead cipher+mode (just encryption). Stream ciphers are simply ciphers with a fixed mode.
And nettle currently lacks an abstraction (of the nette-meta.h style) for the second type. nettle_cipher is for "raw" block ciphers, ECB-mode, no state.
Using struct nettle_aead could work. The update and digest methods would be NULL. The set_nonce method would be NULL for arcfour and any other traditional stream cipher, and non-NULL for block cipher modes like cbc and ctr, as well as for salsa20 and chacha. (Supporting cbc in this way has padding issues, though, not sure how to deal with that).
But using nettle_aead is not ideal naming. Maybe it should be done differently.
(And I don't think nettle should include meta objects for all possible combinations of ciphers and modes, but it could include the most important ones, and make it easy for an application to define additional combinations).
Regards, /Niels
On Wed, Nov 26, 2014 at 1:32 PM, Niels Möller nisse@lysator.liu.se wrote:
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
I've done something similar at: https://gitorious.org/gnutls/gnutls/source/0a1102311e443720fc0eb7a83f7dc1b58...
Looks reasonable. You get a pretty large nettle_cipher_st to support all variations, I see. Some comments: _ccm_aes_encrypt looks like it supports ccm with any cipher, right?
Nice catch. Indeed, it is not restricted to AES.
If the aead_*crypt_func functions are intended as the primary interface for aead, I guess you'd want to either retire the auth and tag functions (and you may want additonal helper functions in nettle to make that easy?). Or implement the aead_*crypt functions in terms of the auth and tag functions for everything but ccm.
My plan is to provide a minimal AEAD API such as: https://gitorious.org/gnutls/gnutls/source/0a1102311e443720fc0eb7a83f7dc1b58...
The old auth and tag will be kept for backwards compatibility in AES-GCM, but will not be offered by all AEAD ciphers.
For the _gcm functions, do you see any obstacles to implementing generic _gcm functions (like you do with cbc), which passes the encrypt_block function to nettle's general gcm functions? Note that GCM_CTX intentionally puts the cipher-specific context last, so the offset should always be the same.
Do you mean something like: struct gcm_cast_st { struct gcm_key key; struct gcm_ctx gcm; char xx[1]; }; #define GCM_CTX_GET_KEY(ptr) (&((struct gcm_cast_st*)ptr)->key) #define GCM_CTX_GET_CTX(ptr) (&((struct gcm_cast_st*)ptr)->gcm) #define GCM_CTX_GET_CIPHER(ptr) ((void*)&((struct gcm_cast_st*)ptr)->xx)
It looks indeed simpler. Not sure how valid is the GCM_CTX_GET_CIPHER cast though. It would be nice if nettle's gcm.h provided such macros.
Your auth_func, tag_func, set_key_func and setiv_func seem to duplicate nettle_hash_update, nettle_set_key_func and nettle_hash_digest_func.
Thanks, I should use them.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
Do you mean something like: struct gcm_cast_st { struct gcm_key key; struct gcm_ctx gcm; char xx[1]; }; #define GCM_CTX_GET_KEY(ptr) (&((struct gcm_cast_st*)ptr)->key) #define GCM_CTX_GET_CTX(ptr) (&((struct gcm_cast_st*)ptr)->gcm) #define GCM_CTX_GET_CIPHER(ptr) ((void*)&((struct gcm_cast_st*)ptr)->xx)
It looks indeed simpler. Not sure how valid is the GCM_CTX_GET_CIPHER cast though. It would be nice if nettle's gcm.h provided such macros.
Only potential problem I see is alignment. You could make it an unsigned long array rather than a char array. And I'd drop the GET_KEY and GET_CTX macros; they're perfectly normal struct accesses.
You could perhaps use GCM_CTX, from nettle/gcm.h, with a generic cipher type, say
struct gcm_st GCM_CTX(unsigned long);
but I'm not sure that's better than making your own. Of the other GCM_* macros in nettle/gcm.h, I think they might work with the above context, provided that the passed in encrypt function takes a void * (or const void *) as the first argument.
Regards, /Niels
On Fri, 2014-11-28 at 19:20 +0100, Niels Möller wrote:
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
Do you mean something like: struct gcm_cast_st { struct gcm_key key; struct gcm_ctx gcm; char xx[1]; }; #define GCM_CTX_GET_KEY(ptr) (&((struct gcm_cast_st*)ptr)->key) #define GCM_CTX_GET_CTX(ptr) (&((struct gcm_cast_st*)ptr)->gcm) #define GCM_CTX_GET_CIPHER(ptr) ((void*)&((struct gcm_cast_st*)ptr)->xx)
It looks indeed simpler. Not sure how valid is the GCM_CTX_GET_CIPHER cast though. It would be nice if nettle's gcm.h provided such macros.
Only potential problem I see is alignment.
Indeed, and that's why I'd prefer for the library to provide such macros. Maybe changing the GCM structure to something like { struct gcm_key key; struct gcm_ctx gcm; void *c; type cipher; }
Where c will be set by GCM_SET_KEY to point to cipher?
You could make it an unsigned long array rather than a char array. And I'd drop the GET_KEY and GET_CTX macros; they're perfectly normal struct accesses.
They are needed as I cast from void*.
regards, Nikos
On Tue, Nov 25, 2014 at 10:36 AM, Niels Möller nisse@lysator.liu.se wrote:
I think it lacked a linker script for hogweed, with symbol version tracking libhogweed's major version rather than libnettle's.
Attached a patch which separates the .map files.
What I now realize is that that mini-gmp mpz_*, gmp_* and mpn_* symbols are not exported in the script that I sent. They could be put unconditionally there, or via a configure variable.
I think it's generally a bit dangerous to make shared libraries with mini-gmp (the result is not promised to be binary compatible with regular builds). Anyone trying that really needs to know what he/she is doing. So I think a sensible default is to disable hogweed symbol versioning in that case, and possibly have a configure option to explicitly specify the linker script to use for each library.
I'm not sure what is the correct path. Disabling the linker script would mean that more symbols will be exported than normally (all internal symbols) and there can be clashes that wouldn't be with the normal library. In any case this is not really related to the version script, it is mostly an issue of having a different soname when nettle-mini is used.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
On Tue, Nov 25, 2014 at 10:36 AM, Niels Möller nisse@lysator.liu.se wrote:
I think it lacked a linker script for hogweed, with symbol version tracking libhogweed's major version rather than libnettle's.
Attached a patch which separates the .map files.
Looks good, thanks. I'll try to do some testing and see if I understand this, and then merge on the master branch.
--- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ core /nettle.tps /nettle.vr /nettle.vrs +*.po +/libhogweed.map +/libnettle.map
I take it adding *.po is not really intended? These files were eliminated a while ago.
+# gl_LD_VERSION_SCRIPT +# -------------------- +# Check if LD supports linker scripts, and define automake conditional +# HAVE_LD_VERSION_SCRIPT if so.
I see no automake-things in here. Right?
+AC_DEFUN([LD_VERSION_SCRIPT], +[
- AC_ARG_ENABLE([ld-version-script],
- AS_HELP_STRING([--enable-ld-version-script],
[enable linker version script (default is enabled when possible)]),
[have_ld_version_script=$enableval], [])
- if test -z "$have_ld_version_script"; then
- AC_MSG_CHECKING([if LD -Wl,--version-script works])
- save_LDFLAGS="$LDFLAGS"
- LDFLAGS="$LDFLAGS -Wl,--version-script=conftest.map"
- cat > conftest.map <<EOF
+foo +EOF
- AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
[accepts_syntax_errors=yes], [accepts_syntax_errors=no])
- if test "$accepts_syntax_errors" = no; then
cat > conftest.map <<EOF
+VERS_1 {
global: sym;
+};
+VERS_2 {
global: sym;
+} VERS_1; +EOF
AC_LINK_IFELSE([AC_LANG_PROGRAM([], [])],
[have_ld_version_script=yes], [have_ld_version_script=no])
- else
have_ld_version_script=no
- fi
- rm -f conftest.map
- LDFLAGS="$save_LDFLAGS"
- AC_MSG_RESULT($have_ld_version_script)
- fi
- if test "$have_ld_version_script" = "yes";then
- EXTRA_LINKER_FLAGS="-Wl,--version-script=$(srcdir)/libnettle.map"
- AC_SUBST(EXTRA_LINKER_FLAGS)
- EXTRA_HOGWEED_LINKER_FLAGS="-Wl,--version-script=$(srcdir)/libhogweed.map"
- AC_SUBST(EXTRA_HOGWEED_LINKER_FLAGS)
- fi
It would in some way be cleaner to have this nettle-specific setup in configure.ac, rather than in aclocal.m4. Maybe the macro could have an optional if-true argument? Or one could just move the test of have_ld_version_script.
Regards, /Niels
On Fri, 2014-11-28 at 19:35 +0100, Niels Möller wrote:
--- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ core /nettle.tps /nettle.vr /nettle.vrs +*.po +/libhogweed.map +/libnettle.map
I take it adding *.po is not really intended? These files were eliminated a while ago.
Indeed, they must be leftovers from old builds in my repository.
It would in some way be cleaner to have this nettle-specific setup in configure.ac, rather than in aclocal.m4. Maybe the macro could have an optional if-true argument? Or one could just move the test of have_ld_version_script.
I didn't make that macro, it was copied from gnulib. Changing the interface would mean that the one who may need to update it with a newer version would have to do quite some porting.
regards, Nikos
Nikos Mavrogiannopoulos nmav@gnutls.org writes:
Attached a patch which separates the .map files.
I've now applied this to a branch named "versioned-symbols". With some additional updates, removing the $(srcdir) when referring to the linker scripts which now are in the build directory, adding ChangeLog entries, and bumping the library version numbers.
Seems to work, but I'm not entirely sure what the symbol table is expected to look like. E.g.,
$ readelf -s libnettle.so |grep sha512_init 17: 000000000001d470 114 FUNC GLOBAL DEFAULT 13 nettle_sha512_init@@NETTLE_6 447: 000000000001d470 114 FUNC GLOBAL DEFAULT 13 nettle_sha512_init
So there are two symbols with the same value, one with and one without the version suffix. Different symbol tables though, the former is in .dynsym, the latter in .symtab. Is that how it's supposed to be?
Further testing appreciated.
Regards, /Niels
nettle-bugs@lists.lysator.liu.se