ソースを参照

Make the server send the original DER-encoded certificate of a peer to other peers, rather than re-encoding it. Preserve compatibility with old clients by
still sending them the re-encoded certificate.

ambrop7 15 年 前
コミット
80a9510c0c
4 ファイル変更35 行追加40 行削除
  1. 3 26
      client/StreamPeerIO.c
  2. 2 1
      protocol/scproto.h
  3. 25 13
      server/server.c
  4. 5 0
      server/server.h

+ 3 - 26
client/StreamPeerIO.c

@@ -481,36 +481,13 @@ int compare_certificate (StreamPeerIO *pio, CERTCertificate *cert)
 {
     ASSERT(pio->ssl)
     
-    int ret = 0;
-    
-    // alloc arena
-    PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
-    if (!arena) {
-        BLog(BLOG_ERROR, "PORT_NewArena failed");
-        goto fail0;
-    }
-    
-    // encode server certificate
-    SECItem der;
-    der.len = 0;
-    der.data = NULL;
-    if (!SEC_ASN1EncodeItem(arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate))) {
-        BLog(BLOG_ERROR, "SEC_ASN1EncodeItem failed");
-        goto fail1;
-    }
-    
-    // byte compare
+    SECItem der = cert->derCert;
     if (der.len != pio->ssl_peer_cert_len || memcmp(der.data, pio->ssl_peer_cert, der.len)) {
         BLog(BLOG_NOTICE, "Client certificate doesn't match");
-        goto fail1;
+        return 0;
     }
     
-    ret = 1;
-    
-fail1:
-    PORT_FreeArena(arena, PR_FALSE);
-fail0:
-    return ret;
+    return 1;
 }
 
 void reset_state (StreamPeerIO *pio)

+ 2 - 1
protocol/scproto.h

@@ -54,7 +54,8 @@
 
 #include <stdint.h>
 
-#define SC_VERSION 26
+#define SC_VERSION 27
+#define SC_OLDVERSION 26
 
 #define SC_KEEPALIVE_INTERVAL 10000
 

+ 25 - 13
server/server.c

@@ -1099,6 +1099,15 @@ void client_try_handshake (struct client_data *client)
         goto fail0;
     }
     
+    // store certificate
+    SECItem der = cert->derCert;
+    if (der.len > sizeof(client->cert)) {
+        client_log(client, BLOG_NOTICE, "client certificate too big");
+        goto fail1;
+    }
+    memcpy(client->cert, der.data, der.len);
+    client->cert_len = der.len;
+    
     PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
     if (!arena) {
         client_log(client, BLOG_ERROR, "PORT_NewArena failed");
@@ -1106,21 +1115,19 @@ void client_try_handshake (struct client_data *client)
     }
     
     // encode certificate
-    SECItem der;
-    der.len = 0;
-    der.data = NULL;
+    memset(&der, 0, sizeof(der));
     if (!SEC_ASN1EncodeItem(arena, &der, cert, SEC_ASN1_GET(CERT_CertificateTemplate))) {
         client_log(client, BLOG_ERROR, "SEC_ASN1EncodeItem failed");
         goto fail2;
     }
     
-    // store certificate
-    if (der.len > sizeof(client->cert)) {
+    // store re-encoded certificate (for compatibility with old clients)
+    if (der.len > sizeof(client->cert_old)) {
         client_log(client, BLOG_NOTICE, "client certificate too big");
         goto fail2;
     }
-    memcpy(client->cert, der.data, der.len);
-    client->cert_len = der.len;
+    memcpy(client->cert_old, der.data, der.len);
+    client->cert_old_len = der.len;
     
     // remember common name
     if (!(client->common_name = CERT_GetCommonName(&cert->subject))) {
@@ -1379,15 +1386,20 @@ int client_send_newclient (struct client_data *client, struct client_data *nc, i
         flags |= SCID_NEWCLIENT_FLAG_RELAY_CLIENT;
     }
     
+    uint8_t *cert_data = NULL;
+    int cert_len = 0;
+    if (options.ssl) {
+        cert_data = (client->version == SC_OLDVERSION ?  nc->cert_old : nc->cert);
+        cert_len = (client->version == SC_OLDVERSION ?  nc->cert_old_len : nc->cert_len);
+    }
+    
     struct sc_server_newclient *pack;
-    if (client_start_control_packet(client, (void **)&pack, sizeof(struct sc_server_newclient) + (options.ssl ? nc->cert_len : 0)) < 0) {
+    if (client_start_control_packet(client, (void **)&pack, sizeof(struct sc_server_newclient) + cert_len) < 0) {
         return -1;
     }
     pack->id = htol16(nc->id);
     pack->flags = htol16(flags);
-    if (options.ssl) {
-        memcpy(pack + 1, nc->cert, nc->cert_len);
-    }
+    memcpy(pack + 1, cert_data, cert_len);
     client_end_control_packet(client, SCID_NEWCLIENT);
     
     return 0;
@@ -1469,9 +1481,9 @@ void process_packet_hello (struct client_data *client, uint8_t *data, int data_l
     }
     
     struct sc_client_hello *msg = (struct sc_client_hello *)data;
-    uint16_t version = ltoh16(msg->version);
+    client->version = ltoh16(msg->version);
     
-    if (version != SC_VERSION) {
+    if (client->version != SC_VERSION && client->version != SC_OLDVERSION) {
         client_log(client, BLOG_NOTICE, "hello: unknown version");
         client_remove(client);
         return;

+ 5 - 0
server/server.h

@@ -111,8 +111,13 @@ struct client_data {
     // client data if using SSL
     uint8_t cert[SCID_NEWCLIENT_MAX_CERT_LEN];
     int cert_len;
+    uint8_t cert_old[SCID_NEWCLIENT_MAX_CERT_LEN];
+    int cert_old_len;
     char *common_name;
     
+    // client version
+    int version;
+    
     // no data timer
     BTimer disconnect_timer;