1//
2//  SSLRecordInternal.c
3//  Security
4//
5//  Created by Fabrice Gautier on 10/25/11.
6//  Copyright (c) 2011 Apple, Inc. All rights reserved.
7//
8
9/* THIS FILE CONTAINS KERNEL CODE */
10
11#include "sslBuildFlags.h"
12#include "SSLRecordInternal.h"
13#include "sslDebug.h"
14#include "cipherSpecs.h"
15#include "symCipher.h"
16#include "sslUtils.h"
17#include "tls_record.h"
18
19#include <AssertMacros.h>
20#include <string.h>
21
22#include <inttypes.h>
23
24#define DEFAULT_BUFFER_SIZE 4096
25
26
27/*
28 * Redirect SSLBuffer-based I/O call to user-supplied I/O.
29 */
30static
31int sslIoRead(SSLBuffer                        buf,
32              size_t                           *actualLength,
33              struct SSLRecordInternalContext  *ctx)
34{
35	size_t  dataLength = buf.length;
36	int     ortn;
37
38	*actualLength = 0;
39	ortn = (ctx->read)(ctx->ioRef,
40                       buf.data,
41                       &dataLength);
42	*actualLength = dataLength;
43	return ortn;
44}
45
46static
47int sslIoWrite(SSLBuffer                       buf,
48               size_t                          *actualLength,
49               struct SSLRecordInternalContext *ctx)
50{
51	size_t  dataLength = buf.length;
52	int     ortn;
53
54	*actualLength = 0;
55	ortn = (ctx->write)(ctx->ioRef,
56                        buf.data,
57                        &dataLength);
58	*actualLength = dataLength;
59	return ortn;
60}
61
62
63static int
64SSLDisposeCipherSuite(CipherContext *cipher, struct SSLRecordInternalContext *ctx)
65{   int      err;
66
67	/* symmetric encryption context */
68	if(cipher->symCipher) {
69		if ((err = cipher->symCipher->finish(cipher->cipherCtx)) != 0) {
70			return err;
71		}
72	}
73
74	/* per-record hash/hmac context */
75	ctx->sslTslCalls->freeMac(cipher);
76
77    return 0;
78}
79
80
81
82/* common for sslv3 and tlsv1, except for the computeMac callout */
83int SSLVerifyMac(uint8_t type,
84                 SSLBuffer *data,
85                 uint8_t *compareMAC,
86                 struct SSLRecordInternalContext *ctx)
87{
88	int        err;
89    uint8_t           macData[SSL_MAX_DIGEST_LEN];
90    SSLBuffer       secret, mac;
91
92    secret.data = ctx->readCipher.macSecret;
93    secret.length = ctx->readCipher.macRef->hash->digestSize;
94    mac.data = macData;
95    mac.length = ctx->readCipher.macRef->hash->digestSize;
96
97	check(ctx->sslTslCalls != NULL);
98    if ((err = ctx->sslTslCalls->computeMac(type,
99                                            *data,
100                                            mac,
101                                            &ctx->readCipher,
102                                            ctx->readCipher.sequenceNum,
103                                            ctx)) != 0)
104        return err;
105
106    if ((memcmp(mac.data, compareMAC, mac.length)) != 0) {
107		sslErrorLog("SSLVerifyMac: Mac verify failure\n");
108        return errSSLRecordProtocol;
109    }
110    return 0;
111}
112
113#include "cipherSpecs.h"
114#include "symCipher.h"
115
116static const HashHmacReference *sslCipherSuiteGetHashHmacReference(uint16_t selectedCipher)
117{
118    HMAC_Algs alg = sslCipherSuiteGetMacAlgorithm(selectedCipher);
119
120    switch (alg) {
121        case HA_Null:
122            return &HashHmacNull;
123        case HA_MD5:
124            return &HashHmacMD5;
125        case HA_SHA1:
126            return &HashHmacSHA1;
127        case HA_SHA256:
128            return &HashHmacSHA256;
129        case HA_SHA384:
130            return &HashHmacSHA384;
131        default:
132            sslErrorLog("Invalid hashAlgorithm %d", alg);
133            check(0);
134            return &HashHmacNull;
135    }
136}
137
138static const SSLSymmetricCipher *sslCipherSuiteGetSymmetricCipher(uint16_t selectedCipher)
139{
140
141    SSL_CipherAlgorithm alg = sslCipherSuiteGetSymmetricCipherAlgorithm(selectedCipher);
142    switch(alg) {
143        case SSL_CipherAlgorithmNull:
144            return &SSLCipherNull;
145#if ENABLE_RC2
146        case SSL_CipherAlgorithmRC2_128:
147            return &SSLCipherRC2_128;
148#endif
149#if ENABLE_RC4
150        case SSL_CipherAlgorithmRC4_128:
151            return &SSLCipherRC4_128;
152#endif
153#if ENABLE_DES
154        case SSL_CipherAlgorithmDES_CBC:
155            return &SSLCipherDES_CBC;
156#endif
157        case SSL_CipherAlgorithm3DES_CBC:
158            return &SSLCipher3DES_CBC;
159        case SSL_CipherAlgorithmAES_128_CBC:
160            return &SSLCipherAES_128_CBC;
161        case SSL_CipherAlgorithmAES_256_CBC:
162            return &SSLCipherAES_256_CBC;
163#if ENABLE_AES_GCM
164        case SSL_CipherAlgorithmAES_128_GCM:
165            return &SSLCipherAES_128_GCM;
166        case SSL_CipherAlgorithmAES_256_GCM:
167            return &SSLCipherAES_256_GCM;
168#endif
169        default:
170            check(0);
171            return &SSLCipherNull;
172    }
173}
174
175static void InitCipherSpec(struct SSLRecordInternalContext *ctx, uint16_t selectedCipher)
176{
177    SSLRecordCipherSpec *dst = &ctx->selectedCipherSpec;
178
179    ctx->selectedCipher = selectedCipher;
180    dst->cipher = sslCipherSuiteGetSymmetricCipher(selectedCipher);
181    dst->macAlgorithm = sslCipherSuiteGetHashHmacReference(selectedCipher);
182};
183
184/* Entry points to Record Layer */
185
186static int SSLRecordReadInternal(SSLRecordContextRef ref, SSLRecord *rec)
187{   int        err;
188    size_t          len, contentLen;
189    uint8_t           *charPtr;
190    SSLBuffer       readData, cipherFragment;
191    size_t          head=5;
192    int             skipit=0;
193    struct SSLRecordInternalContext *ctx = ref;
194
195    if(ctx->isDTLS)
196        head+=8;
197
198    if (!ctx->partialReadBuffer.data || ctx->partialReadBuffer.length < head)
199    {   if (ctx->partialReadBuffer.data)
200        if ((err = SSLFreeBuffer(&ctx->partialReadBuffer)) != 0)
201        {
202            return err;
203        }
204        if ((err = SSLAllocBuffer(&ctx->partialReadBuffer,
205                                  DEFAULT_BUFFER_SIZE)) != 0)
206        {
207            return err;
208        }
209    }
210
211    if (ctx->negProtocolVersion == SSL_Version_Undetermined) {
212        if (ctx->amountRead < 1)
213        {   readData.length = 1 - ctx->amountRead;
214            readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
215            len = readData.length;
216            err = sslIoRead(readData, &len, ctx);
217            if(err != 0)
218            {   if (err == errSSLRecordWouldBlock) {
219                ctx->amountRead += len;
220                return err;
221            }
222            else {
223                /* abort */
224                err = errSSLRecordClosedAbort;
225#if 0 // TODO: revisit this in the transport layer
226                if((ctx->protocolSide == kSSLClientSide) &&
227                   (ctx->amountRead == 0) &&
228                   (len == 0)) {
229                    /*
230                     * Detect "server refused to even try to negotiate"
231                     * error, when the server drops the connection before
232                     * sending a single byte.
233                     */
234                    switch(ctx->state) {
235                        case SSL_HdskStateServerHello:
236                            sslHdskStateDebug("Server dropped initial connection\n");
237                            err = errSSLConnectionRefused;
238                            break;
239                        default:
240                            break;
241                    }
242                }
243#endif
244                return err;
245            }
246            }
247            ctx->amountRead += len;
248        }
249    }
250
251    if (ctx->amountRead < head)
252    {   readData.length = head - ctx->amountRead;
253        readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
254        len = readData.length;
255        err = sslIoRead(readData, &len, ctx);
256        if(err != 0)
257        {
258			switch(err) {
259				case errSSLRecordWouldBlock:
260					ctx->amountRead += len;
261					break;
262#if	SSL_ALLOW_UNNOTICED_DISCONNECT
263				case errSSLClosedGraceful:
264					/* legal if we're on record boundary and we've gotten past
265					 * the handshake */
266					if((ctx->amountRead == 0) && 				/* nothing pending */
267					   (len == 0) &&							/* nothing new */
268					   (ctx->state == SSL_HdskStateClientReady)) {	/* handshake done */
269					    /*
270						 * This means that the server has disconnected without
271						 * sending a closure alert notice. This is technically
272						 * illegal per the SSL3 spec, but about half of the
273						 * servers out there do it, so we report it as a separate
274						 * error which most clients - including (currently)
275						 * URLAccess - ignore by treating it the same as
276						 * a errSSLClosedGraceful error. Paranoid
277						 * clients can detect it and handle it however they
278						 * want to.
279						 */
280						SSLChangeHdskState(ctx, SSL_HdskStateNoNotifyClose);
281						err = errSSLClosedNoNotify;
282						break;
283					}
284					else {
285						/* illegal disconnect */
286						err = errSSLClosedAbort;
287						/* and drop thru to default: fatal alert */
288					}
289#endif	/* SSL_ALLOW_UNNOTICED_DISCONNECT */
290				default:
291					break;
292            }
293            return err;
294        }
295        ctx->amountRead += len;
296    }
297
298    check(ctx->amountRead >= head);
299
300    charPtr = ctx->partialReadBuffer.data;
301    rec->contentType = *charPtr++;
302    if (rec->contentType < SSL_RecordTypeV3_Smallest ||
303        rec->contentType > SSL_RecordTypeV3_Largest)
304        return errSSLRecordProtocol;
305
306    rec->protocolVersion = (SSLProtocolVersion)SSLDecodeInt(charPtr, 2);
307    charPtr += 2;
308
309    if(ctx->isDTLS)
310    {
311        sslUint64 seqNum;
312        SSLDecodeUInt64(charPtr, 8, &seqNum);
313        charPtr += 8;
314        sslLogRecordIo("Read DTLS Record %016llx (seq is: %016llx)",
315                       seqNum, ctx->readCipher.sequenceNum);
316
317        /* if the epoch of the record is different of current read cipher, just drop it */
318        if((seqNum>>48)!=(ctx->readCipher.sequenceNum>>48)) {
319            skipit=1;
320        } else {
321            ctx->readCipher.sequenceNum=seqNum;
322        }
323    }
324
325    contentLen = SSLDecodeInt(charPtr, 2);
326    charPtr += 2;
327    if (contentLen > (16384 + 2048))    /* Maximum legal length of an
328										 * SSLCipherText payload */
329    {
330        return errSSLRecordRecordOverflow;
331    }
332
333    if (ctx->partialReadBuffer.length < head + contentLen)
334    {   if ((err = SSLReallocBuffer(&ctx->partialReadBuffer, head + contentLen)) != 0)
335    {
336        return err;
337    }
338    }
339
340    if (ctx->amountRead < head + contentLen)
341    {   readData.length = head + contentLen - ctx->amountRead;
342        readData.data = ctx->partialReadBuffer.data + ctx->amountRead;
343        len = readData.length;
344        err = sslIoRead(readData, &len, ctx);
345        if(err != 0)
346        {   if (err == errSSLRecordWouldBlock)
347            ctx->amountRead += len;
348            return err;
349        }
350        ctx->amountRead += len;
351    }
352
353    check(ctx->amountRead >= head + contentLen);
354
355    cipherFragment.data = ctx->partialReadBuffer.data + head;
356    cipherFragment.length = contentLen;
357
358    ctx->amountRead = 0;        /* We've used all the data in the cache */
359
360    /* We dont decrypt if we were told to skip this record */
361    if(skipit) {
362        return errSSLRecordUnexpectedRecord;
363    }
364	/*
365	 * Decrypt the payload & check the MAC, modifying the length of the
366	 * buffer to indicate the amount of plaintext data after adjusting
367	 * for the block size and removing the MAC */
368	check(ctx->sslTslCalls != NULL);
369    if ((err = ctx->sslTslCalls->decryptRecord(rec->contentType,
370                                               &cipherFragment, ctx)) != 0)
371        return err;
372
373	/*
374	 * We appear to have sucessfully received a record; increment the
375	 * sequence number
376	 */
377    IncrementUInt64(&ctx->readCipher.sequenceNum);
378
379	/* Allocate a buffer to return the plaintext in and return it */
380    if ((err = SSLAllocBuffer(&rec->contents, cipherFragment.length)) != 0)
381    {
382        return err;
383    }
384    memcpy(rec->contents.data, cipherFragment.data, cipherFragment.length);
385
386
387    return 0;
388}
389
390static int SSLRecordWriteInternal(SSLRecordContextRef ref, SSLRecord rec)
391{
392    int err;
393    struct SSLRecordInternalContext *ctx = ref;
394
395    err=ctx->sslTslCalls->writeRecord(rec, ctx);
396
397    check_noerr(err);
398
399    return err;
400}
401
402/* Record Layer Entry Points */
403
404static int
405SSLRollbackInternalRecordLayerWriteCipher(SSLRecordContextRef ref)
406{
407    int err;
408    struct SSLRecordInternalContext *ctx = ref;
409
410    if ((err = SSLDisposeCipherSuite(&ctx->writePending, ctx)) != 0)
411        return err;
412
413    ctx->writePending = ctx->writeCipher;
414    ctx->writeCipher = ctx->prevCipher;
415
416    /* Zero out old data */
417    memset(&ctx->prevCipher, 0, sizeof(CipherContext));
418
419    return 0;
420}
421
422static int
423SSLAdvanceInternalRecordLayerWriteCipher(SSLRecordContextRef ref)
424{
425    int err;
426    struct SSLRecordInternalContext *ctx = ref;
427
428    if ((err = SSLDisposeCipherSuite(&ctx->prevCipher, ctx)) != 0)
429        return err;
430
431    ctx->prevCipher = ctx->writeCipher;
432    ctx->writeCipher = ctx->writePending;
433
434    /* Zero out old data */
435    memset(&ctx->writePending, 0, sizeof(CipherContext));
436
437    return 0;
438}
439
440static int
441SSLAdvanceInternalRecordLayerReadCipher(SSLRecordContextRef ref)
442{
443    struct SSLRecordInternalContext *ctx = ref;
444    int err;
445
446    if ((err = SSLDisposeCipherSuite(&ctx->readCipher, ctx)) != 0)
447        return err;
448
449    ctx->readCipher = ctx->readPending;
450    memset(&ctx->readPending, 0, sizeof(CipherContext)); 	/* Zero out old data */
451
452    return 0;
453}
454
455static int
456SSLInitInternalRecordLayerPendingCiphers(SSLRecordContextRef ref, uint16_t selectedCipher, bool isServer, SSLBuffer key)
457{   int        err;
458    uint8_t         *keyDataProgress, *keyPtr, *ivPtr;
459    CipherContext   *serverPending, *clientPending;
460
461    struct SSLRecordInternalContext *ctx = ref;
462
463    InitCipherSpec(ctx, selectedCipher);
464
465    ctx->readPending.macRef = ctx->selectedCipherSpec.macAlgorithm;
466    ctx->writePending.macRef = ctx->selectedCipherSpec.macAlgorithm;
467    ctx->readPending.symCipher = ctx->selectedCipherSpec.cipher;
468    ctx->writePending.symCipher = ctx->selectedCipherSpec.cipher;
469    /* This need to be reinitialized because the whole thing is zeroed sometimes */
470    ctx->readPending.encrypting = 0;
471    ctx->writePending.encrypting = 1;
472
473    if(ctx->negProtocolVersion == DTLS_Version_1_0)
474    {
475        ctx->readPending.sequenceNum = (ctx->readPending.sequenceNum & (0xffffULL<<48)) + (1ULL<<48);
476        ctx->writePending.sequenceNum = (ctx->writePending.sequenceNum & (0xffffULL<<48)) + (1ULL<<48);
477    } else {
478        ctx->writePending.sequenceNum = 0;
479        ctx->readPending.sequenceNum = 0;
480    }
481
482    if (isServer)
483    {   serverPending = &ctx->writePending;
484        clientPending = &ctx->readPending;
485    }
486    else
487    {   serverPending = &ctx->readPending;
488        clientPending = &ctx->writePending;
489    }
490
491    /* Check the size of the 'key' buffer - <rdar://problem/11204357> */
492    if(key.length != ctx->selectedCipherSpec.macAlgorithm->hash->digestSize*2
493                   + ctx->selectedCipherSpec.cipher->params->keySize*2
494                   + ctx->selectedCipherSpec.cipher->params->ivSize*2)
495    {
496        return errSSLRecordInternal;
497    }
498
499    keyDataProgress = key.data;
500    memcpy(clientPending->macSecret, keyDataProgress,
501           ctx->selectedCipherSpec.macAlgorithm->hash->digestSize);
502    keyDataProgress += ctx->selectedCipherSpec.macAlgorithm->hash->digestSize;
503    memcpy(serverPending->macSecret, keyDataProgress,
504           ctx->selectedCipherSpec.macAlgorithm->hash->digestSize);
505    keyDataProgress += ctx->selectedCipherSpec.macAlgorithm->hash->digestSize;
506
507    if (ctx->selectedCipherSpec.cipher->params->cipherType == aeadCipherType)
508        goto skipInit;
509
510    /* init the reusable-per-record MAC contexts */
511    err = ctx->sslTslCalls->initMac(clientPending);
512    if(err) {
513        goto fail;
514    }
515    err = ctx->sslTslCalls->initMac(serverPending);
516    if(err) {
517        goto fail;
518    }
519
520    keyPtr = keyDataProgress;
521    keyDataProgress += ctx->selectedCipherSpec.cipher->params->keySize;
522    /* Skip server write key to get to IV */
523    ivPtr = keyDataProgress + ctx->selectedCipherSpec.cipher->params->keySize;
524    if ((err = ctx->selectedCipherSpec.cipher->c.cipher.initialize(clientPending->symCipher->params, clientPending->encrypting, keyPtr, ivPtr,
525                                                                   &clientPending->cipherCtx)) != 0)
526        goto fail;
527    keyPtr = keyDataProgress;
528    keyDataProgress += ctx->selectedCipherSpec.cipher->params->keySize;
529    /* Skip client write IV to get to server write IV */
530    ivPtr = keyDataProgress + ctx->selectedCipherSpec.cipher->params->ivSize;
531    if ((err = ctx->selectedCipherSpec.cipher->c.cipher.initialize(serverPending->symCipher->params, serverPending->encrypting, keyPtr, ivPtr,
532                                                                   &serverPending->cipherCtx)) != 0)
533        goto fail;
534
535skipInit:
536    /* Ciphers are ready for use */
537    ctx->writePending.ready = 1;
538    ctx->readPending.ready = 1;
539
540    /* Ciphers get swapped by sending or receiving a change cipher spec message */
541    err = 0;
542
543fail:
544    return err;
545}
546
547static int
548SSLSetInternalRecordLayerProtocolVersion(SSLRecordContextRef ref, SSLProtocolVersion negVersion)
549{
550    struct SSLRecordInternalContext *ctx = ref;
551
552    switch(negVersion) {
553        case SSL_Version_3_0:
554            ctx->sslTslCalls = &Ssl3RecordCallouts;
555            break;
556        case TLS_Version_1_0:
557        case TLS_Version_1_1:
558        case DTLS_Version_1_0:
559        case TLS_Version_1_2:
560            ctx->sslTslCalls = &Tls1RecordCallouts;
561            break;
562        case SSL_Version_2_0:
563        case SSL_Version_Undetermined:
564        default:
565            return errSSLRecordNegotiation;
566    }
567    ctx->negProtocolVersion = negVersion;
568
569    return 0;
570}
571
572static int
573SSLRecordFreeInternal(SSLRecordContextRef ref, SSLRecord rec)
574{
575    return SSLFreeBuffer(&rec.contents);
576}
577
578static int
579SSLRecordServiceWriteQueueInternal(SSLRecordContextRef ref)
580{
581    int             err = 0, werr = 0;
582    size_t          written = 0;
583    SSLBuffer       buf;
584    WaitingRecord   *rec;
585    struct SSLRecordInternalContext *ctx= ref;
586
587    while (!werr && ((rec = ctx->recordWriteQueue) != 0))
588    {   buf.data = rec->data + rec->sent;
589        buf.length = rec->length - rec->sent;
590        werr = sslIoWrite(buf, &written, ctx);
591        rec->sent += written;
592        if (rec->sent >= rec->length)
593        {
594            check(rec->sent == rec->length);
595            check(err == 0);
596            ctx->recordWriteQueue = rec->next;
597			sslFree(rec);
598        }
599        if (err) {
600            check_noerr(err);
601            return err;
602        }
603    }
604
605    return werr;
606}
607
608/***** Internal Record Layer APIs *****/
609
610SSLRecordContextRef
611SSLCreateInternalRecordLayer(bool dtls)
612{
613    struct SSLRecordInternalContext *ctx;
614
615    ctx = sslMalloc(sizeof(struct SSLRecordInternalContext));
616    if(ctx==NULL)
617        return NULL;
618
619    memset(ctx, 0, sizeof(struct SSLRecordInternalContext));
620
621    ctx->negProtocolVersion = SSL_Version_Undetermined;
622
623    ctx->sslTslCalls = &Ssl3RecordCallouts;
624    ctx->recordWriteQueue = NULL;
625
626    InitCipherSpec(ctx, TLS_NULL_WITH_NULL_NULL);
627
628    ctx->writeCipher.macRef    = ctx->selectedCipherSpec.macAlgorithm;
629    ctx->readCipher.macRef     = ctx->selectedCipherSpec.macAlgorithm;
630    ctx->readCipher.symCipher  = ctx->selectedCipherSpec.cipher;
631    ctx->writeCipher.symCipher = ctx->selectedCipherSpec.cipher;
632    ctx->readCipher.encrypting = 0;
633    ctx->writeCipher.encrypting = 1;
634
635    ctx->isDTLS = dtls;
636
637    return ctx;
638
639}
640
641int
642SSLSetInternalRecordLayerIOFuncs(
643                                 SSLRecordContextRef ref,
644                                 SSLIOReadFunc    readFunc,
645                                 SSLIOWriteFunc   writeFunc)
646{
647    struct SSLRecordInternalContext *ctx = ref;
648
649    ctx->read = readFunc;
650    ctx->write = writeFunc;
651
652    return 0;
653}
654
655int
656SSLSetInternalRecordLayerConnection(
657                                    SSLRecordContextRef ref,
658                                    SSLIOConnectionRef ioRef)
659{
660    struct SSLRecordInternalContext *ctx = ref;
661
662    ctx->ioRef = ioRef;
663
664    return 0;
665}
666
667void
668SSLDestroyInternalRecordLayer(SSLRecordContextRef ref)
669{
670    struct SSLRecordInternalContext *ctx = ref;
671	WaitingRecord   *waitRecord, *next;
672
673    /* RecordContext cleanup : */
674    SSLFreeBuffer(&ctx->partialReadBuffer);
675    waitRecord = ctx->recordWriteQueue;
676    while (waitRecord)
677    {   next = waitRecord->next;
678        sslFree(waitRecord);
679        waitRecord = next;
680    }
681
682
683    /* Cleanup cipher structs */
684    SSLDisposeCipherSuite(&ctx->readCipher, ctx);
685    SSLDisposeCipherSuite(&ctx->writeCipher, ctx);
686    SSLDisposeCipherSuite(&ctx->readPending, ctx);
687    SSLDisposeCipherSuite(&ctx->writePending, ctx);
688    SSLDisposeCipherSuite(&ctx->prevCipher, ctx);
689
690    sslFree(ctx);
691
692}
693
694struct SSLRecordFuncs SSLRecordLayerInternal =
695{
696    .read  = SSLRecordReadInternal,
697    .write = SSLRecordWriteInternal,
698    .initPendingCiphers = SSLInitInternalRecordLayerPendingCiphers,
699    .advanceWriteCipher = SSLAdvanceInternalRecordLayerWriteCipher,
700    .advanceReadCipher = SSLAdvanceInternalRecordLayerReadCipher,
701    .rollbackWriteCipher = SSLRollbackInternalRecordLayerWriteCipher,
702    .setProtocolVersion = SSLSetInternalRecordLayerProtocolVersion,
703    .free = SSLRecordFreeInternal,
704    .serviceWriteQueue = SSLRecordServiceWriteQueueInternal,
705};
706
707