libidn: idna.c Source File

libidn 1.44

idna.c
Go to the documentation of this file.
1/* idna.c --- Prototypes for Internationalized Domain Name library.
2 Copyright (C) 2002-2026 Simon Josefsson
3
4 This file is part of GNU Libidn.
5
6 GNU Libidn is free software: you can redistribute it and/or
7 modify it under the terms of either:
8
9 * the GNU Lesser General Public License as published by the Free
10 Software Foundation; either version 3 of the License, or (at
11 your option) any later version.
12
13 or
14
15 * the GNU General Public License as published by the Free
16 Software Foundation; either version 2 of the License, or (at
17 your option) any later version.
18
19 or both in parallel, as here.
20
21 GNU Libidn is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received copies of the GNU General Public License and
27 the GNU Lesser General Public License along with this program. If
28 not, see <https://www.gnu.org/licenses/>. */
29
30#ifdef HAVE_CONFIG_H
31# include "config.h"
32#endif
33
34#include <stdlib.h>
35#include <string.h>
36#include <stringprep.h>
37#include <punycode.h>
38
39#include "idna.h"
40
41/* Get c_strcasecmp. */
42#include <c-strcase.h>
43
44#define DOTP(c) ((c) == 0x002E || (c) == 0x3002 || \
45 (c) == 0xFF0E || (c) == 0xFF61)
46
47/* Core functions */
48
80int
81idna_to_ascii_4i (const uint32_t *in, size_t inlen, char *out, int flags)
82{
83 size_t len, outlen;
84 uint32_t *src; /* XXX don't need to copy data? */
85 int rc;
86
87 /*
88 * ToASCII consists of the following steps:
89 *
90 * 1. If all code points in the sequence are in the ASCII range (0..7F)
91 * then skip to step 3.
92 */
93
94 {
95 size_t i;
96 int inasciirange;
97
98 inasciirange = 1;
99 for (i = 0; i < inlen; i++)
100 if (in[i] > 0x7F)
101 inasciirange = 0;
102 if (inasciirange)
103 {
104 src = malloc (sizeof (in[0]) * (inlen + 1));
105 if (src == NULL)
106 return IDNA_MALLOC_ERROR;
107
108 memcpy (src, in, sizeof (in[0]) * inlen);
109 src[inlen] = 0;
110
111 goto step3;
112 }
113 }
114
115 /*
116 * 2. Perform the steps specified in [NAMEPREP] and fail if there is
117 * an error. The AllowUnassigned flag is used in [NAMEPREP].
118 */
119
120 {
121 char *p;
122
123 p = stringprep_ucs4_to_utf8 (in, (ssize_t) inlen, NULL, NULL);
124 if (p == NULL)
125 return IDNA_MALLOC_ERROR;
126
127 len = strlen (p);
128 do
129 {
130 char *newp;
131
132 len = 2 * len + 10; /* XXX better guess? */
133 newp = realloc (p, len);
134 if (newp == NULL)
135 {
136 free (p);
137 return IDNA_MALLOC_ERROR;
138 }
139 p = newp;
140
141 if (flags & IDNA_ALLOW_UNASSIGNED)
142 rc = stringprep_nameprep (p, len);
143 else
144 rc = stringprep_nameprep_no_unassigned (p, len);
145 }
146 while (rc == STRINGPREP_TOO_SMALL_BUFFER);
147
148 if (rc != STRINGPREP_OK)
149 {
150 free (p);
151 return IDNA_STRINGPREP_ERROR;
152 }
153
154 src = stringprep_utf8_to_ucs4 (p, -1, NULL);
155
156 free (p);
157
158 if (!src)
159 return IDNA_MALLOC_ERROR;
160 }
161
162step3:
163 /*
164 * 3. If the UseSTD3ASCIIRules flag is set, then perform these checks:
165 *
166 * (a) Verify the absence of non-LDH ASCII code points; that is,
167 * the absence of 0..2C, 2E..2F, 3A..40, 5B..60, and 7B..7F.
168 *
169 * (b) Verify the absence of leading and trailing hyphen-minus;
170 * that is, the absence of U+002D at the beginning and end of
171 * the sequence.
172 */
173
174 if (flags & IDNA_USE_STD3_ASCII_RULES)
175 {
176 size_t i;
177
178 for (i = 0; src[i]; i++)
179 if (src[i] <= 0x2C || src[i] == 0x2E || src[i] == 0x2F ||
180 (src[i] >= 0x3A && src[i] <= 0x40) ||
181 (src[i] >= 0x5B && src[i] <= 0x60) ||
182 (src[i] >= 0x7B && src[i] <= 0x7F))
183 {
184 free (src);
185 return IDNA_CONTAINS_NON_LDH;
186 }
187
188 if (src[0] == 0x002D || (i > 0 && src[i - 1] == 0x002D))
189 {
190 free (src);
191 return IDNA_CONTAINS_MINUS;
192 }
193 }
194
195 /*
196 * 4. If all code points in the sequence are in the ASCII range
197 * (0..7F), then skip to step 8.
198 */
199
200 {
201 size_t i;
202 int inasciirange;
203
204 inasciirange = 1;
205 for (i = 0; src[i]; i++)
206 {
207 if (src[i] > 0x7F)
208 inasciirange = 0;
209 /* copy string to output buffer if we are about to skip to step8 */
210 if (i < 64)
211 out[i] = src[i];
212 }
213 if (i < 64)
214 out[i] = '\0';
215 else
216 {
217 free (src);
218 return IDNA_INVALID_LENGTH;
219 }
220 if (inasciirange)
221 goto step8;
222 }
223
224 /*
225 * 5. Verify that the sequence does NOT begin with the ACE prefix.
226 *
227 */
228
229 {
230 size_t i;
231 int match;
232
233 match = 1;
234 for (i = 0; match && i < strlen (IDNA_ACE_PREFIX); i++)
235 if (((uint32_t) IDNA_ACE_PREFIX[i] & 0xFF) != src[i])
236 match = 0;
237 if (match)
238 {
239 free (src);
240 return IDNA_CONTAINS_ACE_PREFIX;
241 }
242 }
243
244 /*
245 * 6. Encode the sequence using the encoding algorithm in [PUNYCODE]
246 * and fail if there is an error.
247 */
248 for (len = 0; src[len]; len++)
249 ;
250 src[len] = '\0';
251 outlen = 63 - strlen (IDNA_ACE_PREFIX);
252 rc = punycode_encode (len, src, NULL,
253 &outlen, &out[strlen (IDNA_ACE_PREFIX)]);
254 if (rc != PUNYCODE_SUCCESS)
255 {
256 free (src);
257 return IDNA_PUNYCODE_ERROR;
258 }
259 out[strlen (IDNA_ACE_PREFIX) + outlen] = '\0';
260
261 /*
262 * 7. Prepend the ACE prefix.
263 */
264
265 memcpy (out, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX));
266
267 /*
268 * 8. Verify that the number of code points is in the range 1 to 63
269 * inclusive (0 is excluded).
270 */
271
272step8:
273 free (src);
274 if (strlen (out) < 1)
275 return IDNA_INVALID_LENGTH;
276
277 return IDNA_SUCCESS;
278}
279
280/* ToUnicode(). May realloc() utf8in. Will free utf8in unconditionally. */
281static int
282idna_to_unicode_internal (char *utf8in,
283 uint32_t *out, size_t *outlen, int flags)
284{
285 int rc;
286 char tmpout[64];
287 size_t utf8len = strlen (utf8in) + 1;
288 size_t addlen = 0, addinc = utf8len / 10 + 1;
289
290 /*
291 * ToUnicode consists of the following steps:
292 *
293 * 1. If the sequence contains any code points outside the ASCII range
294 * (0..7F) then proceed to step 2, otherwise skip to step 3.
295 */
296
297 {
298 size_t i;
299 int inasciirange;
300
301 inasciirange = 1;
302 for (i = 0; utf8in[i]; i++)
303 if (utf8in[i] & ~0x7F)
304 inasciirange = 0;
305 if (inasciirange)
306 goto step3;
307 }
308
309 /*
310 * 2. Perform the steps specified in [NAMEPREP] and fail if there is an
311 * error. (If step 3 of ToASCII is also performed here, it will not
312 * affect the overall behavior of ToUnicode, but it is not
313 * necessary.) The AllowUnassigned flag is used in [NAMEPREP].
314 */
315 do
316 {
317 char *newp = realloc (utf8in, utf8len + addlen);
318 if (newp == NULL)
319 {
320 free (utf8in);
321 return IDNA_MALLOC_ERROR;
322 }
323 utf8in = newp;
324 if (flags & IDNA_ALLOW_UNASSIGNED)
325 rc = stringprep_nameprep (utf8in, utf8len + addlen);
326 else
327 rc = stringprep_nameprep_no_unassigned (utf8in, utf8len + addlen);
328 addlen += addinc;
329 addinc *= 2;
330 }
331 while (rc == STRINGPREP_TOO_SMALL_BUFFER);
332
333 if (rc != STRINGPREP_OK)
334 {
335 free (utf8in);
336 return IDNA_STRINGPREP_ERROR;
337 }
338
339 /* 3. Verify that the sequence begins with the ACE prefix, and save a
340 * copy of the sequence.
341 * ... The ToASCII and ToUnicode operations MUST recognize the ACE
342 prefix in a case-insensitive manner.
343 */
344
345step3:
346 if (c_strncasecmp (utf8in, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX)) != 0)
347 {
348 free (utf8in);
349 return IDNA_NO_ACE_PREFIX;
350 }
351
352 /* 4. Remove the ACE prefix.
353 */
354
355 memmove (utf8in, &utf8in[strlen (IDNA_ACE_PREFIX)],
356 strlen (utf8in) - strlen (IDNA_ACE_PREFIX) + 1);
357
358 /* 5. Decode the sequence using the decoding algorithm in [PUNYCODE]
359 * and fail if there is an error. Save a copy of the result of
360 * this step.
361 */
362
363 (*outlen)--; /* reserve one for the zero */
364
365 rc = punycode_decode (strlen (utf8in), utf8in, outlen, out, NULL);
366 if (rc != PUNYCODE_SUCCESS)
367 {
368 free (utf8in);
369 return IDNA_PUNYCODE_ERROR;
370 }
371
372 out[*outlen] = 0; /* add zero */
373
374 /* 6. Apply ToASCII.
375 */
376
377 rc = idna_to_ascii_4i (out, *outlen, tmpout, flags);
378 if (rc != IDNA_SUCCESS)
379 {
380 free (utf8in);
381 return rc;
382 }
383
384 /* 7. Verify that the result of step 6 matches the saved copy from
385 * step 3, using a case-insensitive ASCII comparison.
386 */
387
388 if (c_strncasecmp (tmpout, IDNA_ACE_PREFIX, strlen (IDNA_ACE_PREFIX)) != 0
389 || c_strcasecmp (utf8in, tmpout + strlen (IDNA_ACE_PREFIX)) != 0)
390 {
391 free (utf8in);
392 return IDNA_ROUNDTRIP_VERIFY_ERROR;
393 }
394
395 /* 8. Return the saved copy from step 5.
396 */
397
398 free (utf8in);
399 return IDNA_SUCCESS;
400}
401
437int
438idna_to_unicode_44i (const uint32_t *in, size_t inlen,
439 uint32_t *out, size_t *outlen, int flags)
440{
441 int rc;
442 size_t outlensave = *outlen;
443 char *p;
444
445 p = stringprep_ucs4_to_utf8 (in, (ssize_t) inlen, NULL, NULL);
446 if (p == NULL)
447 return IDNA_MALLOC_ERROR;
448
449 rc = idna_to_unicode_internal (p, out, outlen, flags);
450 if (rc != IDNA_SUCCESS)
451 {
452 memcpy (out, in, sizeof (in[0]) * (inlen < outlensave ?
453 inlen : outlensave));
454 *outlen = inlen;
455 }
456
457 /* p is freed in idna_to_unicode_internal. */
458
459 return rc;
460}
461
462/* Wrappers that handle several labels */
463
477int
478idna_to_ascii_4z (const uint32_t *input, char **output, int flags)
479{
480 const uint32_t *start = input;
481 const uint32_t *end;
482 char buf[64];
483 char *out = NULL;
484 int rc;
485
486 /* 1) Whenever dots are used as label separators, the following
487 characters MUST be recognized as dots: U+002E (full stop),
488 U+3002 (ideographic full stop), U+FF0E (fullwidth full stop),
489 U+FF61 (halfwidth ideographic full stop). */
490
491 if (input[0] == 0)
492 {
493 /* Handle implicit zero-length root label. */
494 *output = malloc (1);
495 if (!*output)
496 return IDNA_MALLOC_ERROR;
497 strcpy (*output, "");
498 return IDNA_SUCCESS;
499 }
500
501 if (DOTP (input[0]) && input[1] == 0)
502 {
503 /* Handle explicit zero-length root label. */
504 *output = malloc (2);
505 if (!*output)
506 return IDNA_MALLOC_ERROR;
507 strcpy (*output, ".");
508 return IDNA_SUCCESS;
509 }
510
511 *output = NULL;
512 do
513 {
514 end = start;
515
516 for (; *end && !DOTP (*end); end++)
517 ;
518
519 if (*end == '\0' && start == end)
520 {
521 /* Handle explicit zero-length root label. */
522 buf[0] = '\0';
523 }
524 else
525 {
526 rc = idna_to_ascii_4i (start, (size_t) (end - start), buf, flags);
527 if (rc != IDNA_SUCCESS)
528 {
529 free (out);
530 return rc;
531 }
532 }
533
534 if (out)
535 {
536 size_t l = strlen (out) + 1 + strlen (buf) + 1;
537 char *newp = realloc (out, l);
538 if (!newp)
539 {
540 free (out);
541 return IDNA_MALLOC_ERROR;
542 }
543 out = newp;
544 strcat (out, ".");
545 strcat (out, buf);
546 }
547 else
548 {
549 out = strdup (buf);
550 if (!out)
551 return IDNA_MALLOC_ERROR;
552 }
553
554 start = end + 1;
555 }
556 while (*end);
557
558 *output = out;
559
560 return IDNA_SUCCESS;
561}
562
576int
577idna_to_ascii_8z (const char *input, char **output, int flags)
578{
579 uint32_t *ucs4;
580 size_t ucs4len;
581 int rc;
582
583 ucs4 = stringprep_utf8_to_ucs4 (input, -1, &ucs4len);
584 if (!ucs4)
585 return IDNA_ICONV_ERROR;
586
587 rc = idna_to_ascii_4z (ucs4, output, flags);
588
589 free (ucs4);
590
591 return rc;
592
593}
594
609int
610idna_to_ascii_lz (const char *input, char **output, int flags)
611{
612 char *utf8;
613 int rc;
614
615 utf8 = stringprep_locale_to_utf8 (input);
616 if (!utf8)
617 return IDNA_ICONV_ERROR;
618
619 rc = idna_to_ascii_8z (utf8, output, flags);
620
621 free (utf8);
622
623 return rc;
624}
625
640int
641idna_to_unicode_4z4z (const uint32_t *input, uint32_t **output, int flags)
642{
643 const uint32_t *start = input;
644 const uint32_t *end;
645 uint32_t *buf;
646 size_t buflen;
647 uint32_t *out = NULL;
648 size_t outlen = 0;
649 int rc;
650
651 *output = NULL;
652
653 do
654 {
655 end = start;
656
657 for (; *end && !DOTP (*end); end++)
658 ;
659
660 buflen = (size_t) (end - start);
661 buf = malloc (sizeof (buf[0]) * (buflen + 1));
662 if (!buf)
663 {
664 free (out);
665 return IDNA_MALLOC_ERROR;
666 }
667
668 /* don't check for non-malloc return codes as per
669 specification! */
670 rc = idna_to_unicode_44i (start, (size_t) (end - start),
671 buf, &buflen, flags);
672 if (rc == IDNA_MALLOC_ERROR)
673 {
674 free (out);
675 return IDNA_MALLOC_ERROR;
676 }
677
678 if (out)
679 {
680 uint32_t *newp = realloc (out,
681 sizeof (out[0])
682 * (outlen + 1 + buflen + 1));
683 if (!newp)
684 {
685 free (buf);
686 free (out);
687 return IDNA_MALLOC_ERROR;
688 }
689 out = newp;
690 out[outlen++] = 0x002E; /* '.' (full stop) */
691 memcpy (out + outlen, buf, sizeof (buf[0]) * buflen);
692 outlen += buflen;
693 out[outlen] = 0x0;
694 free (buf);
695 }
696 else
697 {
698 out = buf;
699 outlen = buflen;
700 out[outlen] = 0x0;
701 }
702
703 start = end + 1;
704 }
705 while (*end);
706
707 *output = out;
708
709 return IDNA_SUCCESS;
710}
711
726int
727idna_to_unicode_8z4z (const char *input, uint32_t **output, int flags)
728{
729 uint32_t *ucs4;
730 size_t ucs4len;
731 int rc;
732
733 ucs4 = stringprep_utf8_to_ucs4 (input, -1, &ucs4len);
734 if (!ucs4)
735 return IDNA_ICONV_ERROR;
736
737 rc = idna_to_unicode_4z4z (ucs4, output, flags);
738 free (ucs4);
739
740 return rc;
741}
742
757int
758idna_to_unicode_8z8z (const char *input, char **output, int flags)
759{
760 uint32_t *ucs4;
761 int rc;
762
763 rc = idna_to_unicode_8z4z (input, &ucs4, flags);
764 if (rc != IDNA_SUCCESS)
765 return rc;
766
767 *output = stringprep_ucs4_to_utf8 (ucs4, -1, NULL, NULL);
768 free (ucs4);
769
770 if (!*output)
771 return IDNA_ICONV_ERROR;
772
773 return IDNA_SUCCESS;
774}
775
791int
792idna_to_unicode_8zlz (const char *input, char **output, int flags)
793{
794 char *utf8;
795 int rc;
796
797 rc = idna_to_unicode_8z8z (input, &utf8, flags);
798 if (rc != IDNA_SUCCESS)
799 return rc;
800
801 *output = stringprep_utf8_to_locale (utf8);
802 free (utf8);
803
804 if (!*output)
805 return IDNA_ICONV_ERROR;
806
807 return IDNA_SUCCESS;
808}
809
826int
827idna_to_unicode_lzlz (const char *input, char **output, int flags)
828{
829 char *utf8;
830 int rc;
831
832 utf8 = stringprep_locale_to_utf8 (input);
833 if (!utf8)
834 return IDNA_ICONV_ERROR;
835
836 rc = idna_to_unicode_8zlz (utf8, output, flags);
837 free (utf8);
838
839 return rc;
840}
841
847
880
881
idna_to_unicode_8zlz
int idna_to_unicode_8zlz(const char *input, char **output, int flags)
Definition idna.c:792
DOTP
#define DOTP(c)
Definition idna.c:44
idna_to_unicode_4z4z
int idna_to_unicode_4z4z(const uint32_t *input, uint32_t **output, int flags)
Definition idna.c:641
idna_to_ascii_8z
int idna_to_ascii_8z(const char *input, char **output, int flags)
Definition idna.c:577
idna_to_ascii_4z
int idna_to_ascii_4z(const uint32_t *input, char **output, int flags)
Definition idna.c:478
idna_to_unicode_lzlz
int idna_to_unicode_lzlz(const char *input, char **output, int flags)
Definition idna.c:827
idna_to_unicode_8z4z
int idna_to_unicode_8z4z(const char *input, uint32_t **output, int flags)
Definition idna.c:727
idna_to_unicode_44i
int idna_to_unicode_44i(const uint32_t *in, size_t inlen, uint32_t *out, size_t *outlen, int flags)
Definition idna.c:438
idna_to_unicode_8z8z
int idna_to_unicode_8z8z(const char *input, char **output, int flags)
Definition idna.c:758
idna_to_ascii_4i
int idna_to_ascii_4i(const uint32_t *in, size_t inlen, char *out, int flags)
Definition idna.c:81
idna_to_ascii_lz
int idna_to_ascii_lz(const char *input, char **output, int flags)
Definition idna.c:610
idna.h
IDNA_ROUNDTRIP_VERIFY_ERROR
@ IDNA_ROUNDTRIP_VERIFY_ERROR
Definition idna.h:83
IDNA_PUNYCODE_ERROR
@ IDNA_PUNYCODE_ERROR
Definition idna.h:76
IDNA_SUCCESS
@ IDNA_SUCCESS
Definition idna.h:74
IDNA_NO_ACE_PREFIX
@ IDNA_NO_ACE_PREFIX
Definition idna.h:82
IDNA_CONTAINS_MINUS
@ IDNA_CONTAINS_MINUS
Definition idna.h:80
IDNA_ICONV_ERROR
@ IDNA_ICONV_ERROR
Definition idna.h:85
IDNA_STRINGPREP_ERROR
@ IDNA_STRINGPREP_ERROR
Definition idna.h:75
IDNA_CONTAINS_ACE_PREFIX
@ IDNA_CONTAINS_ACE_PREFIX
Definition idna.h:84
IDNA_CONTAINS_NON_LDH
@ IDNA_CONTAINS_NON_LDH
Definition idna.h:77
IDNA_INVALID_LENGTH
@ IDNA_INVALID_LENGTH
Definition idna.h:81
IDNA_MALLOC_ERROR
@ IDNA_MALLOC_ERROR
Definition idna.h:87
IDNA_USE_STD3_ASCII_RULES
@ IDNA_USE_STD3_ASCII_RULES
Definition idna.h:95
IDNA_ALLOW_UNASSIGNED
@ IDNA_ALLOW_UNASSIGNED
Definition idna.h:94
IDNA_ACE_PREFIX
#define IDNA_ACE_PREFIX
Definition idna.h:99
stringprep_ucs4_to_utf8
char * stringprep_ucs4_to_utf8(const uint32_t *str, ssize_t len, size_t *items_read, size_t *items_written)
Definition nfkc.c:1019
stringprep_utf8_to_ucs4
uint32_t * stringprep_utf8_to_ucs4(const char *str, ssize_t len, size_t *items_written)
Definition nfkc.c:986
punycode_decode
int punycode_decode(size_t input_length, const char input[], size_t *output_length, punycode_uint output[], unsigned char case_flags[])
Definition punycode.c:348
punycode_encode
int punycode_encode(size_t input_length, const punycode_uint input[], const unsigned char case_flags[], size_t *output_length, char output[])
Definition punycode.c:196
punycode.h
PUNYCODE_SUCCESS
@ PUNYCODE_SUCCESS
Definition punycode.h:110
stringprep.h
STRINGPREP_TOO_SMALL_BUFFER
@ STRINGPREP_TOO_SMALL_BUFFER
Definition stringprep.h:75
STRINGPREP_OK
@ STRINGPREP_OK
Definition stringprep.h:67
stringprep_utf8_to_locale
IDNAPI char * stringprep_utf8_to_locale(const char *str)
Definition toutf8.c:161
stringprep_nameprep
#define stringprep_nameprep(in, maxlen)
Definition stringprep.h:202
stringprep_locale_to_utf8
IDNAPI char * stringprep_locale_to_utf8(const char *str)
Definition toutf8.c:145
stringprep_nameprep_no_unassigned
#define stringprep_nameprep_no_unassigned(in, maxlen)
Definition stringprep.h:205