xref: /freebsd/crypto/openssl/crypto/bio/bio_print.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include "internal/cryptlib.h"
13 #include "crypto/ctype.h"
14 #include "internal/numbers.h"
15 #include <openssl/bio.h>
16 #include <openssl/configuration.h>
17 
18 /*
19  * Copyright Patrick Powell 1995
20  * This code is based on code written by Patrick Powell <papowell@astart.com>
21  * It may be used for any purpose as long as this notice remains intact
22  * on all source code distributions.
23  */
24 
25 #ifdef HAVE_LONG_DOUBLE
26 #define LDOUBLE long double
27 #else
28 #define LDOUBLE double
29 #endif
30 
31 static int fmtstr(char **, char **, size_t *, size_t *,
32     const char *, int, int, int);
33 static int fmtint(char **, char **, size_t *, size_t *,
34     int64_t, int, int, int, int);
35 #ifndef OPENSSL_SYS_UEFI
36 static int fmtfp(char **, char **, size_t *, size_t *,
37     LDOUBLE, int, int, int, int);
38 #endif
39 static int doapr_outch(char **, char **, size_t *, size_t *, int);
40 static int _dopr(char **sbuffer, char **buffer,
41     size_t *maxlen, size_t *retlen, int *truncated,
42     const char *format, va_list args);
43 
44 /* format read states */
45 #define DP_S_DEFAULT 0
46 #define DP_S_FLAGS 1
47 #define DP_S_MIN 2
48 #define DP_S_DOT 3
49 #define DP_S_MAX 4
50 #define DP_S_MOD 5
51 #define DP_S_CONV 6
52 #define DP_S_DONE 7
53 
54 /* format flags - Bits */
55 /* left-aligned padding */
56 #define DP_F_MINUS (1 << 0)
57 /* print an explicit '+' for a value with positive sign */
58 #define DP_F_PLUS (1 << 1)
59 /* print an explicit ' ' for a value with positive sign */
60 #define DP_F_SPACE (1 << 2)
61 /* print 0/0x prefix for octal/hex and decimal point for floating point */
62 #define DP_F_NUM (1 << 3)
63 /* print leading zeroes */
64 #define DP_F_ZERO (1 << 4)
65 /* print HEX in UPPERcase */
66 #define DP_F_UP (1 << 5)
67 /* treat value as unsigned */
68 #define DP_F_UNSIGNED (1 << 6)
69 
70 /* conversion flags */
71 #define DP_C_SHORT 1
72 #define DP_C_LONG 2
73 #define DP_C_LDOUBLE 3
74 #define DP_C_LLONG 4
75 #define DP_C_SIZE 5
76 
77 /* Floating point formats */
78 #define F_FORMAT 0
79 #define E_FORMAT 1
80 #define G_FORMAT 2
81 
82 /* some handy macros */
83 #define char_to_int(p) (p - '0')
84 #define OSSL_MAX(p, q) ((p >= q) ? p : q)
85 
86 static int
_dopr(char ** sbuffer,char ** buffer,size_t * maxlen,size_t * retlen,int * truncated,const char * format,va_list args)87 _dopr(char **sbuffer,
88     char **buffer,
89     size_t *maxlen,
90     size_t *retlen, int *truncated, const char *format, va_list args)
91 {
92     char ch;
93     int64_t value;
94 #ifndef OPENSSL_SYS_UEFI
95     LDOUBLE fvalue;
96 #endif
97     char *strvalue;
98     int min;
99     int max;
100     int state;
101     int flags;
102     int cflags;
103     size_t currlen;
104 
105     state = DP_S_DEFAULT;
106     flags = currlen = cflags = min = 0;
107     max = -1;
108     ch = *format++;
109 
110     while (state != DP_S_DONE) {
111         if (ch == '\0' || (buffer == NULL && currlen >= *maxlen))
112             state = DP_S_DONE;
113 
114         switch (state) {
115         case DP_S_DEFAULT:
116             if (ch == '%')
117                 state = DP_S_FLAGS;
118             else if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
119                 return 0;
120             ch = *format++;
121             break;
122         case DP_S_FLAGS:
123             switch (ch) {
124             case '-':
125                 flags |= DP_F_MINUS;
126                 ch = *format++;
127                 break;
128             case '+':
129                 flags |= DP_F_PLUS;
130                 ch = *format++;
131                 break;
132             case ' ':
133                 flags |= DP_F_SPACE;
134                 ch = *format++;
135                 break;
136             case '#':
137                 flags |= DP_F_NUM;
138                 ch = *format++;
139                 break;
140             case '0':
141                 flags |= DP_F_ZERO;
142                 ch = *format++;
143                 break;
144             default:
145                 state = DP_S_MIN;
146                 break;
147             }
148             break;
149         case DP_S_MIN:
150             if (ossl_isdigit(ch)) {
151                 min = 10 * min + char_to_int(ch);
152                 ch = *format++;
153             } else if (ch == '*') {
154                 min = va_arg(args, int);
155                 ch = *format++;
156                 state = DP_S_DOT;
157             } else
158                 state = DP_S_DOT;
159             break;
160         case DP_S_DOT:
161             if (ch == '.') {
162                 state = DP_S_MAX;
163                 ch = *format++;
164             } else
165                 state = DP_S_MOD;
166             break;
167         case DP_S_MAX:
168             if (ossl_isdigit(ch)) {
169                 if (max < 0)
170                     max = 0;
171                 max = 10 * max + char_to_int(ch);
172                 ch = *format++;
173             } else if (ch == '*') {
174                 max = va_arg(args, int);
175                 ch = *format++;
176                 state = DP_S_MOD;
177             } else
178                 state = DP_S_MOD;
179             break;
180         case DP_S_MOD:
181             switch (ch) {
182             case 'h':
183                 cflags = DP_C_SHORT;
184                 ch = *format++;
185                 break;
186             case 'l':
187                 if (*format == 'l') {
188                     cflags = DP_C_LLONG;
189                     format++;
190                 } else
191                     cflags = DP_C_LONG;
192                 ch = *format++;
193                 break;
194             case 'q':
195             case 'j':
196                 cflags = DP_C_LLONG;
197                 ch = *format++;
198                 break;
199             case 'L':
200                 cflags = DP_C_LDOUBLE;
201                 ch = *format++;
202                 break;
203             case 'z':
204                 cflags = DP_C_SIZE;
205                 ch = *format++;
206                 break;
207             default:
208                 break;
209             }
210             state = DP_S_CONV;
211             break;
212         case DP_S_CONV:
213             switch (ch) {
214             case 'd':
215             case 'i':
216                 switch (cflags) {
217                 case DP_C_SHORT:
218                     value = (short int)va_arg(args, int);
219                     break;
220                 case DP_C_LONG:
221                     value = va_arg(args, long int);
222                     break;
223                 case DP_C_LLONG:
224                     value = va_arg(args, int64_t);
225                     break;
226                 case DP_C_SIZE:
227                     value = va_arg(args, ossl_ssize_t);
228                     break;
229                 default:
230                     value = va_arg(args, int);
231                     break;
232                 }
233                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min,
234                         max, flags))
235                     return 0;
236                 break;
237             case 'X':
238                 flags |= DP_F_UP;
239                 /* FALLTHROUGH */
240             case 'x':
241             case 'o':
242             case 'u':
243                 flags |= DP_F_UNSIGNED;
244                 switch (cflags) {
245                 case DP_C_SHORT:
246                     value = (unsigned short int)va_arg(args, unsigned int);
247                     break;
248                 case DP_C_LONG:
249                     value = va_arg(args, unsigned long int);
250                     break;
251                 case DP_C_LLONG:
252                     value = va_arg(args, uint64_t);
253                     break;
254                 case DP_C_SIZE:
255                     value = va_arg(args, size_t);
256                     break;
257                 default:
258                     value = va_arg(args, unsigned int);
259                     break;
260                 }
261                 if (!fmtint(sbuffer, buffer, &currlen, maxlen, value,
262                         ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
263                         min, max, flags))
264                     return 0;
265                 break;
266 #ifndef OPENSSL_SYS_UEFI
267             case 'f':
268                 if (cflags == DP_C_LDOUBLE)
269                     fvalue = va_arg(args, LDOUBLE);
270                 else
271                     fvalue = va_arg(args, double);
272                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
273                         flags, F_FORMAT))
274                     return 0;
275                 break;
276             case 'E':
277                 flags |= DP_F_UP;
278                 /* fall through */
279             case 'e':
280                 if (cflags == DP_C_LDOUBLE)
281                     fvalue = va_arg(args, LDOUBLE);
282                 else
283                     fvalue = va_arg(args, double);
284                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
285                         flags, E_FORMAT))
286                     return 0;
287                 break;
288             case 'G':
289                 flags |= DP_F_UP;
290                 /* fall through */
291             case 'g':
292                 if (cflags == DP_C_LDOUBLE)
293                     fvalue = va_arg(args, LDOUBLE);
294                 else
295                     fvalue = va_arg(args, double);
296                 if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max,
297                         flags, G_FORMAT))
298                     return 0;
299                 break;
300 #else
301             case 'f':
302             case 'E':
303             case 'e':
304             case 'G':
305             case 'g':
306                 /* not implemented for UEFI */
307                 ERR_raise(ERR_LIB_BIO, ERR_R_UNSUPPORTED);
308                 return 0;
309 #endif
310             case 'c':
311                 if (!doapr_outch(sbuffer, buffer, &currlen, maxlen,
312                         va_arg(args, int)))
313                     return 0;
314                 break;
315             case 's':
316                 strvalue = va_arg(args, char *);
317                 if (max < 0) {
318                     if (buffer)
319                         max = INT_MAX;
320                     else
321                         max = *maxlen;
322                 }
323                 if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue,
324                         flags, min, max))
325                     return 0;
326                 break;
327             case 'p':
328                 value = (size_t)va_arg(args, void *);
329                 if (!fmtint(sbuffer, buffer, &currlen, maxlen,
330                         value, 16, min, max, flags | DP_F_NUM))
331                     return 0;
332                 break;
333             case 'n': {
334                 int *num;
335                 num = va_arg(args, int *);
336                 *num = currlen;
337             } break;
338             case '%':
339                 if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch))
340                     return 0;
341                 break;
342             case 'w':
343                 /* not supported yet, treat as next char */
344                 format++;
345                 break;
346             default:
347                 /* unknown, skip */
348                 break;
349             }
350             ch = *format++;
351             state = DP_S_DEFAULT;
352             flags = cflags = min = 0;
353             max = -1;
354             break;
355         case DP_S_DONE:
356             break;
357         default:
358             break;
359         }
360     }
361     /*
362      * We have to truncate if there is no dynamic buffer and we have filled the
363      * static buffer.
364      */
365     if (buffer == NULL) {
366         *truncated = (currlen > *maxlen - 1);
367         if (*truncated)
368             currlen = *maxlen - 1;
369     }
370     if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0'))
371         return 0;
372     *retlen = currlen - 1;
373     return 1;
374 }
375 
376 static int
fmtstr(char ** sbuffer,char ** buffer,size_t * currlen,size_t * maxlen,const char * value,int flags,int min,int max)377 fmtstr(char **sbuffer,
378     char **buffer,
379     size_t *currlen,
380     size_t *maxlen, const char *value, int flags, int min, int max)
381 {
382     int padlen;
383     size_t strln;
384     int cnt = 0;
385 
386     if (value == 0)
387         value = "<NULL>";
388 
389     strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max);
390 
391     padlen = min - strln;
392     if (min < 0 || padlen < 0)
393         padlen = 0;
394     if (max >= 0) {
395         /*
396          * Calculate the maximum output including padding.
397          * Make sure max doesn't overflow into negativity
398          */
399         if (max < INT_MAX - padlen)
400             max += padlen;
401         else
402             max = INT_MAX;
403     }
404     if (flags & DP_F_MINUS)
405         padlen = -padlen;
406 
407     while ((padlen > 0) && (max < 0 || cnt < max)) {
408         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
409             return 0;
410         --padlen;
411         ++cnt;
412     }
413     while (strln > 0 && (max < 0 || cnt < max)) {
414         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++))
415             return 0;
416         --strln;
417         ++cnt;
418     }
419     while ((padlen < 0) && (max < 0 || cnt < max)) {
420         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
421             return 0;
422         ++padlen;
423         ++cnt;
424     }
425     return 1;
426 }
427 
428 static int
fmtint(char ** sbuffer,char ** buffer,size_t * currlen,size_t * maxlen,int64_t value,int base,int min,int max,int flags)429 fmtint(char **sbuffer,
430     char **buffer,
431     size_t *currlen,
432     size_t *maxlen, int64_t value, int base, int min, int max, int flags)
433 {
434     int signvalue = 0;
435     const char *prefix = "";
436     uint64_t uvalue;
437     char convert[DECIMAL_SIZE(value) + 3];
438     int place = 0;
439     int spadlen = 0;
440     int zpadlen = 0;
441     int caps = 0;
442 
443     if (max < 0)
444         max = 0;
445     uvalue = value;
446     if (!(flags & DP_F_UNSIGNED)) {
447         if (value < 0) {
448             signvalue = '-';
449             uvalue = 0 - (uint64_t)value;
450         } else if (flags & DP_F_PLUS)
451             signvalue = '+';
452         else if (flags & DP_F_SPACE)
453             signvalue = ' ';
454     }
455     if (flags & DP_F_NUM) {
456         if (base == 8)
457             prefix = "0";
458         if (base == 16)
459             prefix = "0x";
460     }
461     if (flags & DP_F_UP)
462         caps = 1;
463     do {
464         convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef")
465             [uvalue % (unsigned)base];
466         uvalue = (uvalue / (unsigned)base);
467     } while (uvalue && (place < (int)sizeof(convert)));
468     if (place == sizeof(convert))
469         place--;
470     convert[place] = 0;
471 
472     zpadlen = max - place;
473     spadlen = min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix);
474     if (zpadlen < 0)
475         zpadlen = 0;
476     if (spadlen < 0)
477         spadlen = 0;
478     if (flags & DP_F_ZERO) {
479         zpadlen = OSSL_MAX(zpadlen, spadlen);
480         spadlen = 0;
481     }
482     if (flags & DP_F_MINUS)
483         spadlen = -spadlen;
484 
485     /* spaces */
486     while (spadlen > 0) {
487         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
488             return 0;
489         --spadlen;
490     }
491 
492     /* sign */
493     if (signvalue)
494         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
495             return 0;
496 
497     /* prefix */
498     while (*prefix) {
499         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix))
500             return 0;
501         prefix++;
502     }
503 
504     /* zeros */
505     if (zpadlen > 0) {
506         while (zpadlen > 0) {
507             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
508                 return 0;
509             --zpadlen;
510         }
511     }
512     /* digits */
513     while (place > 0) {
514         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place]))
515             return 0;
516     }
517 
518     /* left justified spaces */
519     while (spadlen < 0) {
520         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
521             return 0;
522         ++spadlen;
523     }
524     return 1;
525 }
526 
527 #ifndef OPENSSL_SYS_UEFI
528 
abs_val(LDOUBLE value)529 static LDOUBLE abs_val(LDOUBLE value)
530 {
531     LDOUBLE result = value;
532     if (value < 0)
533         result = -value;
534     if (result > 0 && result / 2 == result) /* INF */
535         result = 0;
536     else if (result != result) /* NAN */
537         result = 0;
538     return result;
539 }
540 
pow_10(int in_exp)541 static LDOUBLE pow_10(int in_exp)
542 {
543     LDOUBLE result = 1;
544     while (in_exp) {
545         result *= 10;
546         in_exp--;
547     }
548     return result;
549 }
550 
roundv(LDOUBLE value)551 static long roundv(LDOUBLE value)
552 {
553     long intpart;
554     intpart = (long)value;
555     value = value - intpart;
556     if (value >= 0.5)
557         intpart++;
558     return intpart;
559 }
560 
561 static int
fmtfp(char ** sbuffer,char ** buffer,size_t * currlen,size_t * maxlen,LDOUBLE fvalue,int min,int max,int flags,int style)562 fmtfp(char **sbuffer,
563     char **buffer,
564     size_t *currlen,
565     size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style)
566 {
567     int signvalue = 0;
568     LDOUBLE ufvalue;
569     LDOUBLE tmpvalue;
570     char iconvert[20];
571     char fconvert[20];
572     char econvert[20];
573     int iplace = 0;
574     int fplace = 0;
575     int eplace = 0;
576     int padlen = 0;
577     int zpadlen = 0;
578     long exp = 0;
579     unsigned long intpart;
580     unsigned long fracpart;
581     unsigned long max10;
582     int realstyle;
583 
584     if (max < 0)
585         max = 6;
586 
587     if (fvalue < 0)
588         signvalue = '-';
589     else if (flags & DP_F_PLUS)
590         signvalue = '+';
591     else if (flags & DP_F_SPACE)
592         signvalue = ' ';
593     ufvalue = abs_val(fvalue);
594     if (ufvalue == 0 && fvalue != 0) /* INF or NAN? */
595         signvalue = '?';
596 
597     /*
598      * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT
599      * depending on the number to be printed. Work out which one it is and use
600      * that from here on.
601      */
602     if (style == G_FORMAT) {
603         if (ufvalue == 0.0) {
604             realstyle = F_FORMAT;
605         } else if (ufvalue < 0.0001) {
606             realstyle = E_FORMAT;
607         } else if ((max == 0 && ufvalue >= 10)
608             || (max > 0 && ufvalue >= pow_10(max))) {
609             realstyle = E_FORMAT;
610         } else {
611             realstyle = F_FORMAT;
612         }
613     } else {
614         realstyle = style;
615     }
616 
617     if (style != F_FORMAT) {
618         tmpvalue = ufvalue;
619         /* Calculate the exponent */
620         if (ufvalue != 0.0) {
621             while (tmpvalue < 1) {
622                 tmpvalue *= 10;
623                 exp--;
624             }
625             while (tmpvalue > 10) {
626                 tmpvalue /= 10;
627                 exp++;
628             }
629         }
630         if (style == G_FORMAT) {
631             /*
632              * In G_FORMAT the "precision" represents significant digits. We
633              * always have at least 1 significant digit.
634              */
635             if (max == 0)
636                 max = 1;
637             /* Now convert significant digits to decimal places */
638             if (realstyle == F_FORMAT) {
639                 max -= (exp + 1);
640                 if (max < 0) {
641                     /*
642                      * Should not happen. If we're in F_FORMAT then exp < max?
643                      */
644                     (void)doapr_outch(sbuffer, buffer, currlen, maxlen, '\0');
645                     return 0;
646                 }
647             } else {
648                 /*
649                  * In E_FORMAT there is always one significant digit in front
650                  * of the decimal point, so:
651                  * significant digits == 1 + decimal places
652                  */
653                 max--;
654             }
655         }
656         if (realstyle == E_FORMAT)
657             ufvalue = tmpvalue;
658     }
659 
660     /*
661      * By subtracting 65535 (2^16-1) we cancel the low order 15 bits
662      * of ULONG_MAX to avoid using imprecise floating point values.
663      */
664     if (ufvalue >= (double)(ULONG_MAX - 65535) + 65536.0) {
665         /* Number too big */
666         (void)doapr_outch(sbuffer, buffer, currlen, maxlen, '\0');
667         return 0;
668     }
669     intpart = (unsigned long)ufvalue;
670 
671     /*
672      * sorry, we only support 9 digits past the decimal because of our
673      * conversion method
674      */
675     if (max > 9)
676         max = 9;
677 
678     /*
679      * we "cheat" by converting the fractional part to integer by multiplying
680      * by a factor of 10
681      */
682     max10 = roundv(pow_10(max));
683     fracpart = roundv(pow_10(max) * (ufvalue - intpart));
684 
685     if (fracpart >= max10) {
686         intpart++;
687         fracpart -= max10;
688     }
689 
690     /* convert integer part */
691     do {
692         iconvert[iplace++] = "0123456789"[intpart % 10];
693         intpart = (intpart / 10);
694     } while (intpart && (iplace < (int)sizeof(iconvert)));
695     if (iplace == sizeof(iconvert))
696         iplace--;
697     iconvert[iplace] = 0;
698 
699     /* convert fractional part */
700     while (fplace < max) {
701         if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) {
702             /* We strip trailing zeros in G_FORMAT */
703             max--;
704             fracpart = fracpart / 10;
705             if (fplace < max)
706                 continue;
707             break;
708         }
709         fconvert[fplace++] = "0123456789"[fracpart % 10];
710         fracpart = (fracpart / 10);
711     }
712 
713     fconvert[fplace] = 0;
714 
715     /* convert exponent part */
716     if (realstyle == E_FORMAT) {
717         int tmpexp;
718         if (exp < 0)
719             tmpexp = -exp;
720         else
721             tmpexp = exp;
722 
723         do {
724             econvert[eplace++] = "0123456789"[tmpexp % 10];
725             tmpexp = (tmpexp / 10);
726         } while (tmpexp > 0 && eplace < (int)sizeof(econvert));
727         /* Exponent is huge!! Too big to print */
728         if (tmpexp > 0) {
729             (void)doapr_outch(sbuffer, buffer, currlen, maxlen, '\0');
730             return 0;
731         }
732         /* Add a leading 0 for single digit exponents */
733         if (eplace == 1)
734             econvert[eplace++] = '0';
735     }
736 
737     /*
738      * -1 for decimal point (if we have one, i.e. max > 0),
739      * another -1 if we are printing a sign
740      */
741     padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0);
742     /* Take some off for exponent prefix "+e" and exponent */
743     if (realstyle == E_FORMAT)
744         padlen -= 2 + eplace;
745     zpadlen = max - fplace;
746     if (zpadlen < 0)
747         zpadlen = 0;
748     if (padlen < 0)
749         padlen = 0;
750     if (flags & DP_F_MINUS)
751         padlen = -padlen;
752 
753     if ((flags & DP_F_ZERO) && (padlen > 0)) {
754         if (signvalue) {
755             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
756                 return 0;
757             --padlen;
758             signvalue = 0;
759         }
760         while (padlen > 0) {
761             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
762                 return 0;
763             --padlen;
764         }
765     }
766     while (padlen > 0) {
767         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
768             return 0;
769         --padlen;
770     }
771     if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue))
772         return 0;
773 
774     while (iplace > 0) {
775         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace]))
776             return 0;
777     }
778 
779     /*
780      * Decimal point. This should probably use locale to find the correct
781      * char to print out.
782      */
783     if (max > 0 || (flags & DP_F_NUM)) {
784         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.'))
785             return 0;
786 
787         while (fplace > 0) {
788             if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
789                     fconvert[--fplace]))
790                 return 0;
791         }
792     }
793     while (zpadlen > 0) {
794         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0'))
795             return 0;
796         --zpadlen;
797     }
798     if (realstyle == E_FORMAT) {
799         char ech;
800 
801         if ((flags & DP_F_UP) == 0)
802             ech = 'e';
803         else
804             ech = 'E';
805         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech))
806             return 0;
807         if (exp < 0) {
808             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-'))
809                 return 0;
810         } else {
811             if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+'))
812                 return 0;
813         }
814         while (eplace > 0) {
815             if (!doapr_outch(sbuffer, buffer, currlen, maxlen,
816                     econvert[--eplace]))
817                 return 0;
818         }
819     }
820 
821     while (padlen < 0) {
822         if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' '))
823             return 0;
824         ++padlen;
825     }
826     return 1;
827 }
828 
829 #endif /* OPENSSL_SYS_UEFI */
830 
831 #define BUFFER_INC 1024
832 
833 static int
doapr_outch(char ** sbuffer,char ** buffer,size_t * currlen,size_t * maxlen,int c)834 doapr_outch(char **sbuffer,
835     char **buffer, size_t *currlen, size_t *maxlen, int c)
836 {
837     /* If we haven't at least one buffer, someone has done a big booboo */
838     if (!ossl_assert(*sbuffer != NULL || buffer != NULL))
839         return 0;
840 
841     /* |currlen| must always be <= |*maxlen| */
842     if (!ossl_assert(*currlen <= *maxlen))
843         return 0;
844 
845     if (buffer && *currlen == *maxlen) {
846         if (*maxlen > INT_MAX - BUFFER_INC)
847             return 0;
848 
849         *maxlen += BUFFER_INC;
850         if (*buffer == NULL) {
851             if ((*buffer = OPENSSL_malloc(*maxlen)) == NULL)
852                 return 0;
853             if (*currlen > 0) {
854                 if (!ossl_assert(*sbuffer != NULL))
855                     return 0;
856                 memcpy(*buffer, *sbuffer, *currlen);
857             }
858             *sbuffer = NULL;
859         } else {
860             char *tmpbuf;
861 
862             tmpbuf = OPENSSL_realloc(*buffer, *maxlen);
863             if (tmpbuf == NULL)
864                 return 0;
865             *buffer = tmpbuf;
866         }
867     }
868 
869     if (*currlen < *maxlen) {
870         if (*sbuffer)
871             (*sbuffer)[(*currlen)++] = (char)c;
872         else
873             (*buffer)[(*currlen)++] = (char)c;
874     }
875 
876     return 1;
877 }
878 
879 /***************************************************************************/
880 
BIO_printf(BIO * bio,const char * format,...)881 int BIO_printf(BIO *bio, const char *format, ...)
882 {
883     va_list args;
884     int ret;
885 
886     va_start(args, format);
887 
888     ret = BIO_vprintf(bio, format, args);
889 
890     va_end(args);
891     return ret;
892 }
893 
BIO_vprintf(BIO * bio,const char * format,va_list args)894 int BIO_vprintf(BIO *bio, const char *format, va_list args)
895 {
896     int ret;
897     size_t retlen;
898     char hugebuf[1024 * 2]; /* Was previously 10k, which is unreasonable
899                              * in small-stack environments, like threads
900                              * or DOS programs. */
901     char *hugebufp = hugebuf;
902     size_t hugebufsize = sizeof(hugebuf);
903     char *dynbuf = NULL;
904     int ignored;
905 
906     dynbuf = NULL;
907     if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format,
908             args)) {
909         OPENSSL_free(dynbuf);
910         return -1;
911     }
912     if (dynbuf) {
913         ret = BIO_write(bio, dynbuf, (int)retlen);
914         OPENSSL_free(dynbuf);
915     } else {
916         ret = BIO_write(bio, hugebuf, (int)retlen);
917     }
918     return ret;
919 }
920 
921 /*
922  * As snprintf is not available everywhere, we provide our own
923  * implementation. This function has nothing to do with BIOs, but it's
924  * closely related to BIO_printf, and we need *some* name prefix ... (XXX the
925  * function should be renamed, but to what?)
926  */
BIO_snprintf(char * buf,size_t n,const char * format,...)927 int BIO_snprintf(char *buf, size_t n, const char *format, ...)
928 {
929     va_list args;
930     int ret;
931 
932     va_start(args, format);
933 
934     ret = BIO_vsnprintf(buf, n, format, args);
935 
936     va_end(args);
937     return ret;
938 }
939 
BIO_vsnprintf(char * buf,size_t n,const char * format,va_list args)940 int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args)
941 {
942     size_t retlen;
943     int truncated;
944 
945     if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args))
946         return -1;
947 
948     if (truncated)
949         /*
950          * In case of truncation, return -1 like traditional snprintf.
951          * (Current drafts for ISO/IEC 9899 say snprintf should return the
952          * number of characters that would have been written, had the buffer
953          * been large enough.)
954          */
955         return -1;
956     return (retlen <= INT_MAX) ? (int)retlen : -1;
957 }
958