فهرست منبع

fix SSH string implementation

Steffen Jaeckel 6 سال پیش
والد
کامیت
58254f76e8

+ 1 - 1
src/headers/tomcrypt_private.h

@@ -240,7 +240,7 @@ int ecc_set_curve_by_size(int size, ecc_key *key);
 int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
 
 #ifdef LTC_SSH
-int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
+int ecc_ssh_ecdsa_encode_name(char *buffer, ulong32 *buflen, const ecc_key *key);
 #endif
 
 /* low level functions */

+ 11 - 8
src/misc/ssh/ssh_decode_sequence_multi.c

@@ -20,7 +20,7 @@
   Decode a SSH sequence using a VA list
   @param in     Data to decode
   @param inlen  Length of buffer to decode
-  @remark <...> is of the form <type, data> (int, void*) except for string <type, data, size>
+  @remark <...> is of the form <type, data> (int, void*) except for string <type, data, size> (int, void*, ulong32*)
   @return CRYPT_OK on success
 */
 int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
@@ -33,7 +33,7 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
    char          *sdata;
    ulong32       *u32data;
    ulong64       *u64data;
-   unsigned long bufsize;
+   ulong32       *bufsize;
    ulong32       size;
 
    LTC_ARGCHK(in    != NULL);
@@ -115,17 +115,20 @@ int ssh_decode_sequence_multi(const unsigned char *in, unsigned long inlen, ...)
          case LTC_SSHDATA_STRING:
          case LTC_SSHDATA_NAMELIST:
             sdata = va_arg(args, char*);
-            bufsize = va_arg(args, unsigned long);
-            if (size >= bufsize) {
+            bufsize = va_arg(args, ulong32*);
+            if (bufsize == NULL) {
+               err = CRYPT_INVALID_ARG;
+               goto error;
+            }
+            if (size + 1 >= *bufsize) {
                err = CRYPT_BUFFER_OVERFLOW;
                goto error;
             }
             if (size > 0) {
-               XSTRNCPY(sdata, (const char *)in, size);
-               sdata[size] = '\0'; /* strncpy doesn't NUL-terminate */
-            } else {
-               *sdata = '\0';
+               XMEMCPY(sdata, (const char *)in, size);
             }
+            sdata[size] = '\0';
+            *bufsize = size;
             in += size;
             break;
          case LTC_SSHDATA_MPINT:

+ 7 - 6
src/misc/ssh/ssh_encode_sequence_multi.c

@@ -20,7 +20,7 @@
   Encode a SSH sequence using a VA list
   @param out    [out] Destination for data
   @param outlen [in/out] Length of buffer and resulting length of output
-  @remark <...> is of the form <type, data> (int, void*)
+  @remark <...> is of the form <type, data> (int, void*) except for string <type, data, size> (int, void*, ulong32)
   @return CRYPT_OK on success
 */
 int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
@@ -29,9 +29,10 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
    va_list       args;
    ulong32       size;
    ssh_data_type type;
-   void         *vdata;
-   const char   *sdata;
+   void          *vdata;
+   const char    *sdata;
    int           idata;
+   ulong32       *psize;
    ulong32       u32data;
    ulong64       u64data;
 
@@ -58,9 +59,9 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
             break;
          case LTC_SSHDATA_STRING:
          case LTC_SSHDATA_NAMELIST:
-            sdata = va_arg(args, char*);
+            LTC_UNUSED_PARAM( va_arg(args, char*) );
+            size += va_arg(args, ulong32);
             size += 4;
-            size += strlen(sdata);
             break;
          case LTC_SSHDATA_MPINT:
             vdata = va_arg(args, void*);
@@ -118,7 +119,7 @@ int ssh_encode_sequence_multi(unsigned char *out, unsigned long *outlen, ...)
          case LTC_SSHDATA_STRING:
          case LTC_SSHDATA_NAMELIST:
             sdata = va_arg(args, char*);
-            size = strlen(sdata);
+            size = va_arg(args, ulong32);
             STORE32H(size, out);
             out += 4;
             XMEMCPY(out, sdata, size);

+ 5 - 4
src/pk/ecc/ecc_recover_key.c

@@ -114,19 +114,20 @@ int ecc_recover_key(const unsigned char *sig,  unsigned long siglen,
 #ifdef LTC_SSH
    else if (sigformat == LTC_ECCSIG_RFC5656) {
       char name[64], name2[64];
-      unsigned long namelen = sizeof(name2);
+      ulong32 namelen = sizeof(name);
+      ulong32 name2len = sizeof(name2);
 
       /* Decode as SSH data sequence, per RFC4251 */
       if ((err = ssh_decode_sequence_multi(sig, siglen,
-                                           LTC_SSHDATA_STRING, name, 64,
+                                           LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  s,
                                            LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
 
 
       /* Check curve matches identifier string */
-      if ((err = ecc_ssh_ecdsa_encode_name(name2, &namelen, key)) != CRYPT_OK)                                { goto error; }
-      if (XSTRCMP(name,name2) != 0) {
+      if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK)                                { goto error; }
+      if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
          err = CRYPT_INVALID_ARG;
          goto error;
       }

+ 2 - 2
src/pk/ecc/ecc_sign_hash.c

@@ -159,12 +159,12 @@ int ecc_sign_hash_ex(const unsigned char *in,  unsigned long inlen,
    else if (sigformat == LTC_ECCSIG_RFC5656) {
       /* Get identifier string */
       char name[64];
-      unsigned long namelen = sizeof(name);
+      ulong32 namelen = sizeof(name);
       if ((err = ecc_ssh_ecdsa_encode_name(name, &namelen, key)) != CRYPT_OK) { goto errnokey; }
 
       /* Store as SSH data sequence, per RFC4251 */
       err = ssh_encode_sequence_multi(out, outlen,
-                                      LTC_SSHDATA_STRING, name,
+                                      LTC_SSHDATA_STRING, name, namelen,
                                       LTC_SSHDATA_MPINT,  r,
                                       LTC_SSHDATA_MPINT,  s,
                                       LTC_SSHDATA_EOL,    NULL);

+ 7 - 5
src/pk/ecc/ecc_ssh_ecdsa_encode_name.c

@@ -21,12 +21,11 @@
   @param key       A public or private ECC key
   @return CRYPT_OK if successful
 */
-int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key)
+int ecc_ssh_ecdsa_encode_name(char *buffer, ulong32 *buflen, const ecc_key *key)
 {
    char oidstr[64];
    unsigned long oidlen = sizeof(oidstr);
-   unsigned long size = 0;
-   int err;
+   int err, size = 0;
 
    LTC_ARGCHK(buffer != NULL);
    LTC_ARGCHK(buflen != NULL);
@@ -52,8 +51,11 @@ int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key
       size = snprintf(buffer, *buflen, "ecdsa-sha2-%s", oidstr);
    }
 
-   /* snprintf returns size that would have been written, but limits to buflen-1 chars plus terminator */
-   if (size >= *buflen) {
+   /* snprintf returns a negative value on error
+    * or the size that would have been written, but limits to buflen-1 chars plus terminator */
+   if (size < 0) {
+      err = CRYPT_ERROR;
+   } else if ((unsigned)size >= *buflen) {
       err = CRYPT_BUFFER_OVERFLOW;
    } else {
       err = CRYPT_OK;

+ 5 - 4
src/pk/ecc/ecc_verify_hash.c

@@ -100,19 +100,20 @@ int ecc_verify_hash_ex(const unsigned char *sig,  unsigned long siglen,
 #ifdef LTC_SSH
    else if (sigformat == LTC_ECCSIG_RFC5656) {
       char name[64], name2[64];
-      unsigned long namelen = sizeof(name2);
+      ulong32 namelen = sizeof(name);
+      ulong32 name2len = sizeof(name2);
 
       /* Decode as SSH data sequence, per RFC4251 */
       if ((err = ssh_decode_sequence_multi(sig, siglen,
-                                           LTC_SSHDATA_STRING, name, 64,
+                                           LTC_SSHDATA_STRING, name, &namelen,
                                            LTC_SSHDATA_MPINT,  r,
                                            LTC_SSHDATA_MPINT,  s,
                                            LTC_SSHDATA_EOL,    NULL)) != CRYPT_OK)                      { goto error; }
 
 
       /* Check curve matches identifier string */
-      if ((err = ecc_ssh_ecdsa_encode_name(name2, &namelen, key)) != CRYPT_OK)                                { goto error; }
-      if (XSTRCMP(name,name2) != 0) {
+      if ((err = ecc_ssh_ecdsa_encode_name(name2, &name2len, key)) != CRYPT_OK)                                { goto error; }
+      if ((namelen != name2len) || (XSTRCMP(name, name2) != 0)) {
          err = CRYPT_INVALID_ARG;
          goto error;
       }

+ 22 - 8
tests/ssh_test.c

@@ -61,6 +61,7 @@ static int _ssh_encoding_test(void)
 {
    unsigned char buffer[BUFSIZE];
    unsigned long buflen;
+   ulong32 len;
    void *v, *zero;
    int err;
 
@@ -124,8 +125,9 @@ static int _ssh_encoding_test(void)
    /* string */
    buflen = BUFSIZE;
    zeromem(buffer, BUFSIZE);
+   len = strlen("testing");
    DO(ssh_encode_sequence_multi(buffer, &buflen,
-                                LTC_SSHDATA_STRING, "testing",
+                                LTC_SSHDATA_STRING, "testing", len,
                                 LTC_SSHDATA_EOL,    NULL));
    COMPARE_TESTVECTOR(buffer, buflen, string, sizeof(string), "enc-string", 1);
 
@@ -165,22 +167,25 @@ static int _ssh_encoding_test(void)
    /* name-list */
    buflen = BUFSIZE;
    zeromem(buffer, BUFSIZE);
+   len = strlen("");
    DO(ssh_encode_sequence_multi(buffer, &buflen,
-                                LTC_SSHDATA_NAMELIST, "",
+                                LTC_SSHDATA_NAMELIST, "", len,
                                 LTC_SSHDATA_EOL,      NULL));
    COMPARE_TESTVECTOR(buffer, buflen, nlist1, sizeof(nlist1), "enc-nlist", 1);
 
    buflen = BUFSIZE;
    zeromem(buffer, BUFSIZE);
+   len = strlen("zlib");
    DO(ssh_encode_sequence_multi(buffer, &buflen,
-                                LTC_SSHDATA_NAMELIST, "zlib",
+                                LTC_SSHDATA_NAMELIST, "zlib", len,
                                 LTC_SSHDATA_EOL,      NULL));
    COMPARE_TESTVECTOR(buffer, buflen, nlist2, sizeof(nlist2), "enc-nlist", 2);
 
    buflen = BUFSIZE;
    zeromem(buffer, BUFSIZE);
+   len = strlen("zlib,none");
    DO(ssh_encode_sequence_multi(buffer, &buflen,
-                                LTC_SSHDATA_NAMELIST, "zlib,none",
+                                LTC_SSHDATA_NAMELIST, "zlib,none", len,
                                 LTC_SSHDATA_EOL,      NULL));
    COMPARE_TESTVECTOR(buffer, buflen, nlist3, sizeof(nlist3), "enc-nlist", 3);
 
@@ -195,6 +200,7 @@ static int _ssh_decoding_test(void)
 {
    char strbuf[BUFSIZE];
    void *u, *v;
+   ulong32 size;
    ulong32 tmp32;
    ulong64 tmp64;
    unsigned char tmp8;
@@ -236,9 +242,11 @@ static int _ssh_decoding_test(void)
 
    /* string */
    zeromem(strbuf, BUFSIZE);
+   size = BUFSIZE;
    DO(ssh_decode_sequence_multi(string, sizeof(string),
-                                LTC_SSHDATA_STRING, strbuf, BUFSIZE,
+                                LTC_SSHDATA_STRING, strbuf, &size,
                                 LTC_SSHDATA_EOL,    NULL));
+   ENSURE(strlen("testing") == size);
    ENSURE(XSTRCMP(strbuf, "testing") == 0);
 
    /* mpint */
@@ -266,21 +274,27 @@ static int _ssh_decoding_test(void)
 
    /* name-list */
    zeromem(strbuf, BUFSIZE);
+   size = BUFSIZE;
    DO(ssh_decode_sequence_multi(nlist1, sizeof(nlist1),
-                                LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
+                                LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_EOL,      NULL));
+   ENSURE(strlen("") == size);
    ENSURE(XSTRCMP(strbuf, "") == 0);
 
    zeromem(strbuf, BUFSIZE);
+   size = BUFSIZE;
    DO(ssh_decode_sequence_multi(nlist2, sizeof(nlist2),
-                                LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
+                                LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_EOL,      NULL));
+   ENSURE(strlen("zlib") == size);
    ENSURE(XSTRCMP(strbuf, "zlib") == 0);
 
    zeromem(strbuf, BUFSIZE);
+   size = BUFSIZE;
    DO(ssh_decode_sequence_multi(nlist3, sizeof(nlist3),
-                                LTC_SSHDATA_NAMELIST, strbuf, BUFSIZE,
+                                LTC_SSHDATA_NAMELIST, strbuf, &size,
                                 LTC_SSHDATA_EOL,      NULL));
+   ENSURE(strlen("zlib,none") == size);
    ENSURE(XSTRCMP(strbuf, "zlib,none") == 0);