Browse Source

[tls] Use iPXE native RSA algorithm

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 12 years ago
parent
commit
dc87161c30
4 changed files with 68 additions and 202 deletions
  1. 14
    142
      src/crypto/x509.c
  2. 0
    3
      src/include/ipxe/tls.h
  3. 3
    20
      src/include/ipxe/x509.h
  4. 51
    37
      src/net/tls.c

+ 14
- 142
src/crypto/x509.c View File

33
  * documented in RFC2313.
33
  * documented in RFC2313.
34
  */
34
  */
35
 
35
 
36
-/** Object Identifier for "rsaEncryption" (1.2.840.113549.1.1.1) */
37
-static const uint8_t oid_rsa_encryption[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7,
38
-					      0x0d, 0x01, 0x01, 0x01 };
39
-
40
 /**
36
 /**
41
- * Identify X.509 certificate public key
37
+ * Identify X.509 certificate RSA public key
42
  *
38
  *
43
  * @v certificate	Certificate
39
  * @v certificate	Certificate
44
- * @v algorithm		Public key algorithm to fill in
45
- * @v pubkey		Public key value to fill in
40
+ * @v rsa		RSA public key to fill in
46
  * @ret rc		Return status code
41
  * @ret rc		Return status code
47
  */
42
  */
48
-static int x509_public_key ( const struct asn1_cursor *certificate,
49
-			     struct asn1_cursor *algorithm,
50
-			     struct asn1_cursor *pubkey ) {
51
-	struct asn1_cursor cursor;
43
+int x509_rsa_public_key ( const struct asn1_cursor *certificate,
44
+			  struct x509_rsa_public_key *key ) {
45
+	struct asn1_cursor *cursor = &key->raw;
52
 	int rc;
46
 	int rc;
53
 
47
 
54
 	/* Locate subjectPublicKeyInfo */
48
 	/* Locate subjectPublicKeyInfo */
55
-	memcpy ( &cursor, certificate, sizeof ( cursor ) );
56
-	rc = ( asn1_enter ( &cursor, ASN1_SEQUENCE ), /* Certificate */
57
-	       asn1_enter ( &cursor, ASN1_SEQUENCE ), /* tbsCertificate */
58
-	       asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/
59
-	       asn1_skip ( &cursor, ASN1_INTEGER ), /* serialNumber */
60
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* signature */
61
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* issuer */
62
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* validity */
63
-	       asn1_skip ( &cursor, ASN1_SEQUENCE ), /* name */
64
-	       asn1_enter ( &cursor, ASN1_SEQUENCE )/* subjectPublicKeyInfo*/);
49
+	memcpy ( cursor, certificate, sizeof ( *cursor ) );
50
+	rc = ( asn1_enter ( cursor, ASN1_SEQUENCE ), /* Certificate */
51
+	       asn1_enter ( cursor, ASN1_SEQUENCE ), /* tbsCertificate */
52
+	       asn1_skip_if_exists ( cursor, ASN1_EXPLICIT_TAG(0) ),/*version*/
53
+	       asn1_skip ( cursor, ASN1_INTEGER ), /* serialNumber */
54
+	       asn1_skip ( cursor, ASN1_SEQUENCE ), /* signature */
55
+	       asn1_skip ( cursor, ASN1_SEQUENCE ), /* issuer */
56
+	       asn1_skip ( cursor, ASN1_SEQUENCE ), /* validity */
57
+	       asn1_skip ( cursor, ASN1_SEQUENCE ) /* name */ );
65
 	if ( rc != 0 ) {
58
 	if ( rc != 0 ) {
66
 		DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
59
 		DBG ( "Cannot locate subjectPublicKeyInfo in:\n" );
67
 		DBG_HDA ( 0, certificate->data, certificate->len );
60
 		DBG_HDA ( 0, certificate->data, certificate->len );
68
 		return rc;
61
 		return rc;
69
 	}
62
 	}
70
 
63
 
71
-	/* Locate algorithm */
72
-	memcpy ( algorithm, &cursor, sizeof ( *algorithm ) );
73
-	rc = ( asn1_enter ( algorithm, ASN1_SEQUENCE ) /* algorithm */ );
74
-	if ( rc != 0 ) {
75
-		DBG ( "Cannot locate algorithm in:\n" );
76
-		DBG_HDA ( 0, certificate->data, certificate->len );
77
-		return rc;
78
-	}
79
-
80
-	/* Locate subjectPublicKey */
81
-	memcpy ( pubkey, &cursor, sizeof ( *pubkey ) );
82
-	rc = ( asn1_skip ( pubkey, ASN1_SEQUENCE ), /* algorithm */
83
-	       asn1_enter ( pubkey, ASN1_BIT_STRING ) /* subjectPublicKey*/ );
84
-	if ( rc != 0 ) {
85
-		DBG ( "Cannot locate subjectPublicKey in:\n" );
86
-		DBG_HDA ( 0, certificate->data, certificate->len );
87
-		return rc;
88
-	}
89
-
90
-	return 0;
91
-}
92
-
93
-/**
94
- * Identify X.509 certificate RSA modulus and public exponent
95
- *
96
- * @v certificate	Certificate
97
- * @v rsa		RSA public key to fill in
98
- * @ret rc		Return status code
99
- *
100
- * The caller is responsible for eventually calling
101
- * x509_free_rsa_public_key() to free the storage allocated to hold
102
- * the RSA modulus and exponent.
103
- */
104
-int x509_rsa_public_key ( const struct asn1_cursor *certificate,
105
-			  struct x509_rsa_public_key *rsa_pubkey ) {
106
-	struct asn1_cursor algorithm;
107
-	struct asn1_cursor pubkey;
108
-	struct asn1_cursor modulus;
109
-	struct asn1_cursor exponent;
110
-	int rc;
111
-
112
-	/* First, extract the public key algorithm and key data */
113
-	if ( ( rc = x509_public_key ( certificate, &algorithm,
114
-				      &pubkey ) ) != 0 )
115
-		return rc;
116
-
117
-	/* Check that algorithm is RSA */
118
-	rc = ( asn1_enter ( &algorithm, ASN1_OID ) /* algorithm */ );
119
-	if ( rc != 0 ) {
120
-		DBG ( "Cannot locate algorithm:\n" );
121
-		DBG_HDA ( 0, certificate->data, certificate->len );
122
-	return rc;
123
-	}
124
-	if ( ( algorithm.len != sizeof ( oid_rsa_encryption ) ) ||
125
-	     ( memcmp ( algorithm.data, &oid_rsa_encryption,
126
-			sizeof ( oid_rsa_encryption ) ) != 0 ) ) {
127
-		DBG ( "algorithm is not rsaEncryption in:\n" );
128
-		DBG_HDA ( 0, certificate->data, certificate->len );
129
-		return -ENOTSUP;
130
-	}
131
-
132
-	/* Check that public key is a byte string, i.e. that the
133
-	 * "unused bits" byte contains zero.
134
-	 */
135
-	if ( ( pubkey.len < 1 ) ||
136
-	     ( ( *( uint8_t * ) pubkey.data ) != 0 ) ) {
137
-		DBG ( "subjectPublicKey is not a byte string in:\n" );
138
-		DBG_HDA ( 0, certificate->data, certificate->len );
139
-		return -ENOTSUP;
140
-	}
141
-	pubkey.data++;
142
-	pubkey.len--;
143
-
144
-	/* Pick out the modulus and exponent */
145
-	rc = ( asn1_enter ( &pubkey, ASN1_SEQUENCE ) /* RSAPublicKey */ );
146
-	if ( rc != 0 ) {
147
-		DBG ( "Cannot locate RSAPublicKey in:\n" );
148
-		DBG_HDA ( 0, certificate->data, certificate->len );
149
-		return -ENOTSUP;
150
-	}
151
-	memcpy ( &modulus, &pubkey, sizeof ( modulus ) );
152
-	rc = ( asn1_enter ( &modulus, ASN1_INTEGER ) /* modulus */ );
153
-	if ( rc != 0 ) {
154
-		DBG ( "Cannot locate modulus in:\n" );
155
-		DBG_HDA ( 0, certificate->data, certificate->len );
156
-		return -ENOTSUP;
157
-	}
158
-	if ( modulus.len && ( ! *( ( uint8_t * ) modulus.data ) ) ) {
159
-		/* Skip positive sign byte */
160
-		modulus.data++;
161
-		modulus.len--;
162
-	}
163
-	memcpy ( &exponent, &pubkey, sizeof ( exponent ) );
164
-	rc = ( asn1_skip ( &exponent, ASN1_INTEGER ), /* modulus */
165
-	       asn1_enter ( &exponent, ASN1_INTEGER ) /* publicExponent */ );
166
-	if ( rc != 0 ) {
167
-		DBG ( "Cannot locate publicExponent in:\n" );
168
-		DBG_HDA ( 0, certificate->data, certificate->len );
169
-		return -ENOTSUP;
170
-	}
171
-	if ( exponent.len && ( ! *( ( uint8_t * ) exponent.data ) ) ) {
172
-		/* Skip positive sign byte */
173
-		exponent.data++;
174
-		exponent.len--;
175
-	}
176
-
177
-	/* Allocate space and copy out modulus and exponent */
178
-	rsa_pubkey->modulus = malloc ( modulus.len + exponent.len );
179
-	if ( ! rsa_pubkey->modulus )
180
-		return -ENOMEM;
181
-	rsa_pubkey->exponent = ( rsa_pubkey->modulus + modulus.len );
182
-	memcpy ( rsa_pubkey->modulus, modulus.data, modulus.len );
183
-	rsa_pubkey->modulus_len = modulus.len;
184
-	memcpy ( rsa_pubkey->exponent, exponent.data, exponent.len );
185
-	rsa_pubkey->exponent_len = exponent.len;
186
-
187
-	DBG2 ( "RSA modulus:\n" );
188
-	DBG2_HDA ( 0, rsa_pubkey->modulus, rsa_pubkey->modulus_len );
189
-	DBG2 ( "RSA exponent:\n" );
190
-	DBG2_HDA ( 0, rsa_pubkey->exponent, rsa_pubkey->exponent_len );
191
-
192
 	return 0;
64
 	return 0;
193
 }
65
 }

+ 0
- 3
src/include/ipxe/tls.h View File

182
 	/** SHA256 context for handshake verification */
182
 	/** SHA256 context for handshake verification */
183
 	uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE];
183
 	uint8_t handshake_sha256_ctx[SHA256_CTX_SIZE];
184
 
184
 
185
-	/** Hack: server RSA public key */
186
-	struct x509_rsa_public_key rsa;
187
-
188
 	/** TX sequence number */
185
 	/** TX sequence number */
189
 	uint64_t tx_seq;
186
 	uint64_t tx_seq;
190
 	/** TX pending transmissions */
187
 	/** TX pending transmissions */

+ 3
- 20
src/include/ipxe/x509.h View File

11
 
11
 
12
 #include <stdint.h>
12
 #include <stdint.h>
13
 #include <stdlib.h>
13
 #include <stdlib.h>
14
-
15
-struct asn1_cursor;
14
+#include <ipxe/asn1.h>
16
 
15
 
17
 /** An X.509 RSA public key */
16
 /** An X.509 RSA public key */
18
 struct x509_rsa_public_key {
17
 struct x509_rsa_public_key {
19
-	/** Modulus */
20
-	uint8_t *modulus;
21
-	/** Modulus length */
22
-	size_t modulus_len;
23
-	/** Exponent */
24
-	uint8_t *exponent;
25
-	/** Exponent length */
26
-	size_t exponent_len;
18
+	/** Raw public key */
19
+	struct asn1_cursor raw;
27
 };
20
 };
28
 
21
 
29
-/**
30
- * Free X.509 RSA public key
31
- *
32
- * @v rsa_pubkey	RSA public key
33
- */
34
-static inline void
35
-x509_free_rsa_public_key ( struct x509_rsa_public_key *rsa_pubkey ) {
36
-	free ( rsa_pubkey->modulus );
37
-}
38
-
39
 extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
22
 extern int x509_rsa_public_key ( const struct asn1_cursor *certificate,
40
 				 struct x509_rsa_public_key *rsa_pubkey );
23
 				 struct x509_rsa_public_key *rsa_pubkey );
41
 
24
 

+ 51
- 37
src/net/tls.c View File

39
 #include <ipxe/iobuf.h>
39
 #include <ipxe/iobuf.h>
40
 #include <ipxe/xfer.h>
40
 #include <ipxe/xfer.h>
41
 #include <ipxe/open.h>
41
 #include <ipxe/open.h>
42
-#include <ipxe/asn1.h>
43
 #include <ipxe/x509.h>
42
 #include <ipxe/x509.h>
44
 #include <ipxe/rbg.h>
43
 #include <ipxe/rbg.h>
45
 #include <ipxe/tls.h>
44
 #include <ipxe/tls.h>
90
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
89
 	tls_clear_cipher ( tls, &tls->tx_cipherspec_pending );
91
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
90
 	tls_clear_cipher ( tls, &tls->rx_cipherspec );
92
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
91
 	tls_clear_cipher ( tls, &tls->rx_cipherspec_pending );
93
-	x509_free_rsa_public_key ( &tls->rsa );
94
 	free ( tls->rx_data );
92
 	free ( tls->rx_data );
95
 
93
 
96
 	/* Free TLS structure itself */
94
 	/* Free TLS structure itself */
437
 	{
435
 	{
438
 		.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
436
 		.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA256 ),
439
 		.key_len = ( 256 / 8 ),
437
 		.key_len = ( 256 / 8 ),
440
-		.pubkey = &pubkey_null, /* FIXME */
438
+		.pubkey = &rsa_algorithm,
441
 		.cipher = &aes_cbc_algorithm,
439
 		.cipher = &aes_cbc_algorithm,
442
 		.digest = &sha256_algorithm,
440
 		.digest = &sha256_algorithm,
443
 	},
441
 	},
444
 	{
442
 	{
445
 		.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
443
 		.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA256 ),
446
 		.key_len = ( 128 / 8 ),
444
 		.key_len = ( 128 / 8 ),
447
-		.pubkey = &pubkey_null, /* FIXME */
445
+		.pubkey = &rsa_algorithm,
448
 		.cipher = &aes_cbc_algorithm,
446
 		.cipher = &aes_cbc_algorithm,
449
 		.digest = &sha256_algorithm,
447
 		.digest = &sha256_algorithm,
450
 	},
448
 	},
451
 	{
449
 	{
452
 		.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
450
 		.code = htons ( TLS_RSA_WITH_AES_256_CBC_SHA ),
453
 		.key_len = ( 256 / 8 ),
451
 		.key_len = ( 256 / 8 ),
454
-		.pubkey = &pubkey_null, /* FIXME */
452
+		.pubkey = &rsa_algorithm,
455
 		.cipher = &aes_cbc_algorithm,
453
 		.cipher = &aes_cbc_algorithm,
456
 		.digest = &sha1_algorithm,
454
 		.digest = &sha1_algorithm,
457
 	},
455
 	},
458
 	{
456
 	{
459
 		.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
457
 		.code = htons ( TLS_RSA_WITH_AES_128_CBC_SHA ),
460
 		.key_len = ( 128 / 8 ),
458
 		.key_len = ( 128 / 8 ),
461
-		.pubkey = &pubkey_null, /* FIXME */
459
+		.pubkey = &rsa_algorithm,
462
 		.cipher = &aes_cbc_algorithm,
460
 		.cipher = &aes_cbc_algorithm,
463
 		.digest = &sha1_algorithm,
461
 		.digest = &sha1_algorithm,
464
 	},
462
 	},
496
  */
494
  */
497
 static void tls_clear_cipher ( struct tls_session *tls __unused,
495
 static void tls_clear_cipher ( struct tls_session *tls __unused,
498
 			       struct tls_cipherspec *cipherspec ) {
496
 			       struct tls_cipherspec *cipherspec ) {
497
+
498
+	if ( cipherspec->suite ) {
499
+		pubkey_final ( cipherspec->suite->pubkey,
500
+			       cipherspec->pubkey_ctx );
501
+	}
499
 	free ( cipherspec->dynamic );
502
 	free ( cipherspec->dynamic );
500
 	memset ( cipherspec, 0, sizeof ( cipherspec ) );
503
 	memset ( cipherspec, 0, sizeof ( cipherspec ) );
501
 	cipherspec->suite = &tls_cipher_suite_null;
504
 	cipherspec->suite = &tls_cipher_suite_null;
523
 	
526
 	
524
 	/* Allocate dynamic storage */
527
 	/* Allocate dynamic storage */
525
 	total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
528
 	total = ( pubkey->ctxsize + 2 * cipher->ctxsize + digest->digestsize );
526
-	dynamic = malloc ( total );
529
+	dynamic = zalloc ( total );
527
 	if ( ! dynamic ) {
530
 	if ( ! dynamic ) {
528
 		DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
531
 		DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto "
529
 		       "context\n", tls, total );
532
 		       "context\n", tls, total );
530
 		return -ENOMEM;
533
 		return -ENOMEM;
531
 	}
534
 	}
532
-	memset ( dynamic, 0, total );
533
 
535
 
534
 	/* Assign storage */
536
 	/* Assign storage */
535
 	cipherspec->dynamic = dynamic;
537
 	cipherspec->dynamic = dynamic;
793
  * @ret rc		Return status code
795
  * @ret rc		Return status code
794
  */
796
  */
795
 static int tls_send_client_key_exchange ( struct tls_session *tls ) {
797
 static int tls_send_client_key_exchange ( struct tls_session *tls ) {
796
-	/* FIXME: Hack alert */
797
-	RSA_CTX *rsa_ctx = NULL;
798
-	RSA_pub_key_new ( &rsa_ctx, tls->rsa.modulus, tls->rsa.modulus_len,
799
-			  tls->rsa.exponent, tls->rsa.exponent_len );
798
+	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
799
+	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
800
+	size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx );
800
 	struct {
801
 	struct {
801
 		uint32_t type_length;
802
 		uint32_t type_length;
802
 		uint16_t encrypted_pre_master_secret_len;
803
 		uint16_t encrypted_pre_master_secret_len;
803
-		uint8_t encrypted_pre_master_secret[rsa_ctx->num_octets];
804
+		uint8_t encrypted_pre_master_secret[max_len];
804
 	} __attribute__ (( packed )) key_xchg;
805
 	} __attribute__ (( packed )) key_xchg;
806
+	size_t unused;
807
+	int len;
808
+	int rc;
805
 
809
 
810
+	/* Encrypt pre-master secret using server's public key */
806
 	memset ( &key_xchg, 0, sizeof ( key_xchg ) );
811
 	memset ( &key_xchg, 0, sizeof ( key_xchg ) );
807
-	key_xchg.type_length = ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
808
-				 htonl ( sizeof ( key_xchg ) -
809
-					 sizeof ( key_xchg.type_length ) ) );
810
-	key_xchg.encrypted_pre_master_secret_len
811
-		= htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) );
812
-
813
-	/* FIXME: Hack alert */
814
-	DBGC ( tls, "RSA encrypting plaintext, modulus, exponent:\n" );
815
-	DBGC_HD ( tls, &tls->pre_master_secret,
816
-		  sizeof ( tls->pre_master_secret ) );
817
-	DBGC_HD ( tls, tls->rsa.modulus, tls->rsa.modulus_len );
818
-	DBGC_HD ( tls, tls->rsa.exponent, tls->rsa.exponent_len );
819
-	RSA_encrypt ( rsa_ctx, ( const uint8_t * ) &tls->pre_master_secret,
820
-		      sizeof ( tls->pre_master_secret ),
821
-		      key_xchg.encrypted_pre_master_secret, 0 );
822
-	DBGC ( tls, "RSA encrypt done.  Ciphertext:\n" );
823
-	DBGC_HD ( tls, &key_xchg.encrypted_pre_master_secret,
824
-		  sizeof ( key_xchg.encrypted_pre_master_secret ) );
825
-	RSA_free ( rsa_ctx );
826
-
812
+	len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx,
813
+			       &tls->pre_master_secret,
814
+			       sizeof ( tls->pre_master_secret ),
815
+			       key_xchg.encrypted_pre_master_secret );
816
+	if ( len < 0 ) {
817
+		rc = len;
818
+		DBGC ( tls, "TLS %p could not encrypt pre-master secret: %s\n",
819
+		       tls, strerror ( rc ) );
820
+		return rc;
821
+	}
822
+	unused = ( max_len - len );
823
+	key_xchg.type_length =
824
+		( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) |
825
+		  htonl ( sizeof ( key_xchg ) -
826
+			  sizeof ( key_xchg.type_length ) - unused ) );
827
+	key_xchg.encrypted_pre_master_secret_len =
828
+		htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) -
829
+			unused );
827
 
830
 
828
 	return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
831
 	return tls_send_handshake ( tls, &key_xchg, sizeof ( key_xchg ) );
829
 }
832
 }
1021
 		  ( ( void * ) certificate->certificates );
1024
 		  ( ( void * ) certificate->certificates );
1022
 	size_t elements_len = tls_uint24 ( certificate->length );
1025
 	size_t elements_len = tls_uint24 ( certificate->length );
1023
 	const void *end = ( certificate->certificates + elements_len );
1026
 	const void *end = ( certificate->certificates + elements_len );
1027
+	struct tls_cipherspec *cipherspec = &tls->tx_cipherspec_pending;
1028
+	struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey;
1024
 	struct asn1_cursor cursor;
1029
 	struct asn1_cursor cursor;
1030
+	struct x509_rsa_public_key key;
1025
 	int rc;
1031
 	int rc;
1026
 
1032
 
1027
 	/* Sanity check */
1033
 	/* Sanity check */
1044
 		}
1050
 		}
1045
 
1051
 
1046
 		// HACK
1052
 		// HACK
1047
-		if ( ( rc = x509_rsa_public_key ( &cursor,
1048
-						  &tls->rsa ) ) != 0 ) {
1049
-			DBGC ( tls, "TLS %p cannot determine RSA public key: "
1050
-			       "%s\n", tls, strerror ( rc ) );
1053
+		if ( ( rc = x509_rsa_public_key ( &cursor, &key ) ) != 0 ) {
1054
+			DBGC ( tls, "TLS %p cannot parse public key: %s\n",
1055
+			       tls, strerror ( rc ) );
1056
+			return rc;
1057
+		}
1058
+
1059
+		/* Initialise public key algorithm */
1060
+		if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx,
1061
+					  key.raw.data, key.raw.len ) ) != 0){
1062
+			DBGC ( tls, "TLS %p cannot initialise public key: %s\n",
1063
+			       tls, strerror ( rc ) );
1051
 			return rc;
1064
 			return rc;
1052
 		}
1065
 		}
1066
+
1053
 		return 0;
1067
 		return 0;
1054
 
1068
 
1055
 		element = ( cursor.data + cursor.len );
1069
 		element = ( cursor.data + cursor.len );

Loading…
Cancel
Save