secport.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /*
  5. * secport.c - portability interfaces for security libraries
  6. *
  7. * This file abstracts out libc functionality that libsec depends on
  8. *
  9. * NOTE - These are not public interfaces
  10. */
  11. #include "seccomon.h"
  12. #include "prmem.h"
  13. #include "prerror.h"
  14. #include "plarena.h"
  15. #include "secerr.h"
  16. #include "prmon.h"
  17. #include "nssilock.h"
  18. #include "secport.h"
  19. #include "prenv.h"
  20. #include "prinit.h"
  21. #include <stdint.h>
  22. #ifdef DEBUG
  23. #define THREADMARK
  24. #endif /* DEBUG */
  25. #ifdef THREADMARK
  26. #include "prthread.h"
  27. #endif /* THREADMARK */
  28. #if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
  29. #include <stdlib.h>
  30. #else
  31. #include "wtypes.h"
  32. #endif
  33. #define SET_ERROR_CODE /* place holder for code to set PR error code. */
  34. #ifdef THREADMARK
  35. typedef struct threadmark_mark_str {
  36. struct threadmark_mark_str *next;
  37. void *mark;
  38. } threadmark_mark;
  39. #endif /* THREADMARK */
  40. /* The value of this magic must change each time PORTArenaPool changes. */
  41. #define ARENAPOOL_MAGIC 0xB8AC9BDF
  42. #define CHEAP_ARENAPOOL_MAGIC 0x3F16BB09
  43. typedef struct PORTArenaPool_str {
  44. PLArenaPool arena;
  45. PRUint32 magic;
  46. PRLock *lock;
  47. #ifdef THREADMARK
  48. PRThread *marking_thread;
  49. threadmark_mark *first_mark;
  50. #endif
  51. } PORTArenaPool;
  52. /* locations for registering Unicode conversion functions.
  53. * XXX is this the appropriate location? or should they be
  54. * moved to client/server specific locations?
  55. */
  56. PORTCharConversionFunc ucs4Utf8ConvertFunc;
  57. PORTCharConversionFunc ucs2Utf8ConvertFunc;
  58. PORTCharConversionWSwapFunc ucs2AsciiConvertFunc;
  59. /* NSPR memory allocation functions (PR_Malloc, PR_Calloc, and PR_Realloc)
  60. * use the PRUint32 type for the size parameter. Before we pass a size_t or
  61. * unsigned long size to these functions, we need to ensure it is <= half of
  62. * the maximum PRUint32 value to avoid truncation and catch a negative size.
  63. */
  64. #define MAX_SIZE (PR_UINT32_MAX >> 1)
  65. void *
  66. PORT_Alloc(size_t bytes)
  67. {
  68. void *rv = NULL;
  69. if (bytes <= MAX_SIZE) {
  70. /* Always allocate a non-zero amount of bytes */
  71. rv = PR_Malloc(bytes ? bytes : 1);
  72. }
  73. if (!rv) {
  74. PORT_SetError(SEC_ERROR_NO_MEMORY);
  75. }
  76. return rv;
  77. }
  78. void *
  79. PORT_Realloc(void *oldptr, size_t bytes)
  80. {
  81. void *rv = NULL;
  82. if (bytes <= MAX_SIZE) {
  83. rv = PR_Realloc(oldptr, bytes);
  84. }
  85. if (!rv) {
  86. PORT_SetError(SEC_ERROR_NO_MEMORY);
  87. }
  88. return rv;
  89. }
  90. void *
  91. PORT_ZAlloc(size_t bytes)
  92. {
  93. void *rv = NULL;
  94. if (bytes <= MAX_SIZE) {
  95. /* Always allocate a non-zero amount of bytes */
  96. rv = PR_Calloc(1, bytes ? bytes : 1);
  97. }
  98. if (!rv) {
  99. PORT_SetError(SEC_ERROR_NO_MEMORY);
  100. }
  101. return rv;
  102. }
  103. /* aligned_alloc is C11. This is an alternative to get aligned memory. */
  104. void *
  105. PORT_ZAllocAligned(size_t bytes, size_t alignment, void **mem)
  106. {
  107. size_t x = alignment - 1;
  108. /* This only works if alignment is a power of 2. */
  109. if ((alignment == 0) || (alignment & (alignment - 1))) {
  110. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  111. return NULL;
  112. }
  113. if (!mem) {
  114. return NULL;
  115. }
  116. /* Always allocate a non-zero amount of bytes */
  117. *mem = PORT_ZAlloc((bytes ? bytes : 1) + x);
  118. if (!*mem) {
  119. PORT_SetError(SEC_ERROR_NO_MEMORY);
  120. return NULL;
  121. }
  122. return (void *)(((uintptr_t)*mem + x) & ~(uintptr_t)x);
  123. }
  124. void *
  125. PORT_ZAllocAlignedOffset(size_t size, size_t alignment, size_t offset)
  126. {
  127. PORT_Assert(offset < size);
  128. if (offset > size) {
  129. return NULL;
  130. }
  131. void *mem = NULL;
  132. void *v = PORT_ZAllocAligned(size, alignment, &mem);
  133. if (!v) {
  134. return NULL;
  135. }
  136. PORT_Assert(mem);
  137. *((void **)((uintptr_t)v + offset)) = mem;
  138. return v;
  139. }
  140. void
  141. PORT_Free(void *ptr)
  142. {
  143. if (ptr) {
  144. PR_Free(ptr);
  145. }
  146. }
  147. void
  148. PORT_ZFree(void *ptr, size_t len)
  149. {
  150. if (ptr) {
  151. memset(ptr, 0, len);
  152. PR_Free(ptr);
  153. }
  154. }
  155. char *
  156. PORT_Strdup(const char *str)
  157. {
  158. size_t len = PORT_Strlen(str) + 1;
  159. char *newstr;
  160. newstr = (char *)PORT_Alloc(len);
  161. if (newstr) {
  162. PORT_Memcpy(newstr, str, len);
  163. }
  164. return newstr;
  165. }
  166. void
  167. PORT_SetError(int value)
  168. {
  169. PR_SetError(value, 0);
  170. return;
  171. }
  172. int
  173. PORT_GetError(void)
  174. {
  175. return (PR_GetError());
  176. }
  177. /********************* Arena code follows *****************************
  178. * ArenaPools are like heaps. The memory in them consists of large blocks,
  179. * called arenas, which are allocated from the/a system heap. Inside an
  180. * ArenaPool, the arenas are organized as if they were in a stack. Newly
  181. * allocated arenas are "pushed" on that stack. When you attempt to
  182. * allocate memory from an ArenaPool, the code first looks to see if there
  183. * is enough unused space in the top arena on the stack to satisfy your
  184. * request, and if so, your request is satisfied from that arena.
  185. * Otherwise, a new arena is allocated (or taken from NSPR's list of freed
  186. * arenas) and pushed on to the stack. The new arena is always big enough
  187. * to satisfy the request, and is also at least a minimum size that is
  188. * established at the time that the ArenaPool is created.
  189. *
  190. * The ArenaMark function returns the address of a marker in the arena at
  191. * the top of the arena stack. It is the address of the place in the arena
  192. * on the top of the arena stack from which the next block of memory will
  193. * be allocated. Each ArenaPool has its own separate stack, and hence
  194. * marks are only relevant to the ArenaPool from which they are gotten.
  195. * Marks may be nested. That is, a thread can get a mark, and then get
  196. * another mark.
  197. *
  198. * It is intended that all the marks in an ArenaPool may only be owned by a
  199. * single thread. In DEBUG builds, this is enforced. In non-DEBUG builds,
  200. * it is not. In DEBUG builds, when a thread gets a mark from an
  201. * ArenaPool, no other thread may acquire a mark in that ArenaPool while
  202. * that mark exists, that is, until that mark is unmarked or released.
  203. * Therefore, it is important that every mark be unmarked or released when
  204. * the creating thread has no further need for exclusive ownership of the
  205. * right to manage the ArenaPool.
  206. *
  207. * The ArenaUnmark function discards the ArenaMark at the address given,
  208. * and all marks nested inside that mark (that is, acquired from that same
  209. * ArenaPool while that mark existed). It is an error for a thread other
  210. * than the mark's creator to try to unmark it. When a thread has unmarked
  211. * all its marks from an ArenaPool, then another thread is able to set
  212. * marks in that ArenaPool. ArenaUnmark does not deallocate (or "pop") any
  213. * memory allocated from the ArenaPool since the mark was created.
  214. *
  215. * ArenaRelease "pops" the stack back to the mark, deallocating all the
  216. * memory allocated from the arenas in the ArenaPool since that mark was
  217. * created, and removing any arenas from the ArenaPool that have no
  218. * remaining active allocations when that is done. It implicitly releases
  219. * any marks nested inside the mark being explicitly released. It is the
  220. * only operation, other than destroying the arenapool, that potentially
  221. * reduces the number of arenas on the stack. Otherwise, the stack grows
  222. * until the arenapool is destroyed, at which point all the arenas are
  223. * freed or returned to a "free arena list", depending on their sizes.
  224. */
  225. PLArenaPool *
  226. PORT_NewArena(unsigned long chunksize)
  227. {
  228. PORTArenaPool *pool;
  229. if (chunksize > MAX_SIZE) {
  230. PORT_SetError(SEC_ERROR_NO_MEMORY);
  231. return NULL;
  232. }
  233. pool = PORT_ZNew(PORTArenaPool);
  234. if (!pool) {
  235. return NULL;
  236. }
  237. pool->magic = ARENAPOOL_MAGIC;
  238. pool->lock = PZ_NewLock(nssILockArena);
  239. if (!pool->lock) {
  240. PORT_Free(pool);
  241. return NULL;
  242. }
  243. PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
  244. return (&pool->arena);
  245. }
  246. void
  247. PORT_InitCheapArena(PORTCheapArenaPool *pool, unsigned long chunksize)
  248. {
  249. pool->magic = CHEAP_ARENAPOOL_MAGIC;
  250. PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
  251. }
  252. void *
  253. PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
  254. {
  255. void *p = NULL;
  256. PORTArenaPool *pool = (PORTArenaPool *)arena;
  257. if (size <= 0) {
  258. size = 1;
  259. }
  260. if (size > MAX_SIZE) {
  261. /* you lose. */
  262. } else
  263. /* Is it one of ours? Assume so and check the magic */
  264. if (ARENAPOOL_MAGIC == pool->magic) {
  265. PZ_Lock(pool->lock);
  266. #ifdef THREADMARK
  267. /* Most likely one of ours. Is there a thread id? */
  268. if (pool->marking_thread &&
  269. pool->marking_thread != PR_GetCurrentThread()) {
  270. /* Another thread holds a mark in this arena */
  271. PZ_Unlock(pool->lock);
  272. PORT_SetError(SEC_ERROR_NO_MEMORY);
  273. PORT_Assert(0);
  274. return NULL;
  275. } /* tid != null */
  276. #endif /* THREADMARK */
  277. PL_ARENA_ALLOCATE(p, arena, size);
  278. PZ_Unlock(pool->lock);
  279. } else {
  280. PL_ARENA_ALLOCATE(p, arena, size);
  281. }
  282. if (!p) {
  283. PORT_SetError(SEC_ERROR_NO_MEMORY);
  284. }
  285. return (p);
  286. }
  287. void *
  288. PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
  289. {
  290. void *p;
  291. if (size <= 0)
  292. size = 1;
  293. p = PORT_ArenaAlloc(arena, size);
  294. if (p) {
  295. PORT_Memset(p, 0, size);
  296. }
  297. return (p);
  298. }
  299. static PRCallOnceType setupUseFreeListOnce;
  300. static PRBool useFreeList;
  301. static PRStatus
  302. SetupUseFreeList(void)
  303. {
  304. useFreeList = (PR_GetEnvSecure("NSS_DISABLE_ARENA_FREE_LIST") == NULL);
  305. return PR_SUCCESS;
  306. }
  307. /*
  308. * If zero is true, zeroize the arena memory before freeing it.
  309. */
  310. void
  311. PORT_FreeArena(PLArenaPool *arena, PRBool zero)
  312. {
  313. PORTArenaPool *pool = (PORTArenaPool *)arena;
  314. PRLock *lock = (PRLock *)0;
  315. size_t len = sizeof *arena;
  316. if (!pool)
  317. return;
  318. if (ARENAPOOL_MAGIC == pool->magic) {
  319. len = sizeof *pool;
  320. lock = pool->lock;
  321. PZ_Lock(lock);
  322. }
  323. if (zero) {
  324. PL_ClearArenaPool(arena, 0);
  325. }
  326. (void)PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList);
  327. if (useFreeList) {
  328. PL_FreeArenaPool(arena);
  329. } else {
  330. PL_FinishArenaPool(arena);
  331. }
  332. PORT_ZFree(arena, len);
  333. if (lock) {
  334. PZ_Unlock(lock);
  335. PZ_DestroyLock(lock);
  336. }
  337. }
  338. void
  339. PORT_DestroyCheapArena(PORTCheapArenaPool *pool)
  340. {
  341. (void)PR_CallOnce(&setupUseFreeListOnce, &SetupUseFreeList);
  342. if (useFreeList) {
  343. PL_FreeArenaPool(&pool->arena);
  344. } else {
  345. PL_FinishArenaPool(&pool->arena);
  346. }
  347. }
  348. void *
  349. PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
  350. {
  351. PORTArenaPool *pool = (PORTArenaPool *)arena;
  352. PORT_Assert(newsize >= oldsize);
  353. if (newsize > MAX_SIZE) {
  354. PORT_SetError(SEC_ERROR_NO_MEMORY);
  355. return NULL;
  356. }
  357. if (ARENAPOOL_MAGIC == pool->magic) {
  358. PZ_Lock(pool->lock);
  359. /* Do we do a THREADMARK check here? */
  360. PL_ARENA_GROW(ptr, arena, oldsize, (newsize - oldsize));
  361. PZ_Unlock(pool->lock);
  362. } else {
  363. PL_ARENA_GROW(ptr, arena, oldsize, (newsize - oldsize));
  364. }
  365. return (ptr);
  366. }
  367. void *
  368. PORT_ArenaMark(PLArenaPool *arena)
  369. {
  370. void *result;
  371. PORTArenaPool *pool = (PORTArenaPool *)arena;
  372. if (ARENAPOOL_MAGIC == pool->magic) {
  373. PZ_Lock(pool->lock);
  374. #ifdef THREADMARK
  375. {
  376. threadmark_mark *tm, **pw;
  377. PRThread *currentThread = PR_GetCurrentThread();
  378. if (!pool->marking_thread) {
  379. /* First mark */
  380. pool->marking_thread = currentThread;
  381. } else if (currentThread != pool->marking_thread) {
  382. PZ_Unlock(pool->lock);
  383. PORT_SetError(SEC_ERROR_NO_MEMORY);
  384. PORT_Assert(0);
  385. return NULL;
  386. }
  387. result = PL_ARENA_MARK(arena);
  388. PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
  389. if (!tm) {
  390. PZ_Unlock(pool->lock);
  391. PORT_SetError(SEC_ERROR_NO_MEMORY);
  392. return NULL;
  393. }
  394. tm->mark = result;
  395. tm->next = (threadmark_mark *)NULL;
  396. pw = &pool->first_mark;
  397. while (*pw) {
  398. pw = &(*pw)->next;
  399. }
  400. *pw = tm;
  401. }
  402. #else /* THREADMARK */
  403. result = PL_ARENA_MARK(arena);
  404. #endif /* THREADMARK */
  405. PZ_Unlock(pool->lock);
  406. } else {
  407. /* a "pure" NSPR arena */
  408. result = PL_ARENA_MARK(arena);
  409. }
  410. return result;
  411. }
  412. /*
  413. * This function accesses the internals of PLArena, which is why it needs
  414. * to use the NSPR internal macro PL_MAKE_MEM_UNDEFINED before the memset
  415. * calls.
  416. *
  417. * We should move this function to NSPR as PL_ClearArenaAfterMark or add
  418. * a PL_ARENA_CLEAR_AND_RELEASE macro.
  419. *
  420. * TODO: remove the #ifdef PL_MAKE_MEM_UNDEFINED tests when NSPR 4.10+ is
  421. * widely available.
  422. */
  423. static void
  424. port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark)
  425. {
  426. PLArena *a = arena->current;
  427. if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
  428. /* fast path: mark falls in the current arena */
  429. #ifdef PL_MAKE_MEM_UNDEFINED
  430. PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark);
  431. #endif
  432. memset(mark, 0, a->avail - (PRUword)mark);
  433. } else {
  434. /* slow path: need to find the arena that mark falls in */
  435. for (a = arena->first.next; a; a = a->next) {
  436. PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
  437. if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
  438. #ifdef PL_MAKE_MEM_UNDEFINED
  439. PL_MAKE_MEM_UNDEFINED(mark, a->avail - (PRUword)mark);
  440. #endif
  441. memset(mark, 0, a->avail - (PRUword)mark);
  442. a = a->next;
  443. break;
  444. }
  445. }
  446. for (; a; a = a->next) {
  447. PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
  448. #ifdef PL_MAKE_MEM_UNDEFINED
  449. PL_MAKE_MEM_UNDEFINED((void *)a->base, a->avail - a->base);
  450. #endif
  451. memset((void *)a->base, 0, a->avail - a->base);
  452. }
  453. }
  454. }
  455. static void
  456. port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
  457. {
  458. PORTArenaPool *pool = (PORTArenaPool *)arena;
  459. if (ARENAPOOL_MAGIC == pool->magic) {
  460. PZ_Lock(pool->lock);
  461. #ifdef THREADMARK
  462. {
  463. threadmark_mark **pw;
  464. if (PR_GetCurrentThread() != pool->marking_thread) {
  465. PZ_Unlock(pool->lock);
  466. PORT_SetError(SEC_ERROR_NO_MEMORY);
  467. PORT_Assert(0);
  468. return /* no error indication available */;
  469. }
  470. pw = &pool->first_mark;
  471. while (*pw && (mark != (*pw)->mark)) {
  472. pw = &(*pw)->next;
  473. }
  474. if (!*pw) {
  475. /* bad mark */
  476. PZ_Unlock(pool->lock);
  477. PORT_SetError(SEC_ERROR_NO_MEMORY);
  478. PORT_Assert(0);
  479. return /* no error indication available */;
  480. }
  481. *pw = (threadmark_mark *)NULL;
  482. if (zero) {
  483. port_ArenaZeroAfterMark(arena, mark);
  484. }
  485. PL_ARENA_RELEASE(arena, mark);
  486. if (!pool->first_mark) {
  487. pool->marking_thread = (PRThread *)NULL;
  488. }
  489. }
  490. #else /* THREADMARK */
  491. if (zero) {
  492. port_ArenaZeroAfterMark(arena, mark);
  493. }
  494. PL_ARENA_RELEASE(arena, mark);
  495. #endif /* THREADMARK */
  496. PZ_Unlock(pool->lock);
  497. } else {
  498. if (zero) {
  499. port_ArenaZeroAfterMark(arena, mark);
  500. }
  501. PL_ARENA_RELEASE(arena, mark);
  502. }
  503. }
  504. void
  505. PORT_ArenaRelease(PLArenaPool *arena, void *mark)
  506. {
  507. port_ArenaRelease(arena, mark, PR_FALSE);
  508. }
  509. /*
  510. * Zeroize the arena memory before releasing it.
  511. */
  512. void
  513. PORT_ArenaZRelease(PLArenaPool *arena, void *mark)
  514. {
  515. port_ArenaRelease(arena, mark, PR_TRUE);
  516. }
  517. void
  518. PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
  519. {
  520. #ifdef THREADMARK
  521. PORTArenaPool *pool = (PORTArenaPool *)arena;
  522. if (ARENAPOOL_MAGIC == pool->magic) {
  523. threadmark_mark **pw;
  524. PZ_Lock(pool->lock);
  525. if (PR_GetCurrentThread() != pool->marking_thread) {
  526. PZ_Unlock(pool->lock);
  527. PORT_SetError(SEC_ERROR_NO_MEMORY);
  528. PORT_Assert(0);
  529. return /* no error indication available */;
  530. }
  531. pw = &pool->first_mark;
  532. while (((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark)) {
  533. pw = &(*pw)->next;
  534. }
  535. if ((threadmark_mark *)NULL == *pw) {
  536. /* bad mark */
  537. PZ_Unlock(pool->lock);
  538. PORT_SetError(SEC_ERROR_NO_MEMORY);
  539. PORT_Assert(0);
  540. return /* no error indication available */;
  541. }
  542. *pw = (threadmark_mark *)NULL;
  543. if (!pool->first_mark) {
  544. pool->marking_thread = (PRThread *)NULL;
  545. }
  546. PZ_Unlock(pool->lock);
  547. }
  548. #endif /* THREADMARK */
  549. }
  550. char *
  551. PORT_ArenaStrdup(PLArenaPool *arena, const char *str)
  552. {
  553. int len = PORT_Strlen(str) + 1;
  554. char *newstr;
  555. newstr = (char *)PORT_ArenaAlloc(arena, len);
  556. if (newstr) {
  557. PORT_Memcpy(newstr, str, len);
  558. }
  559. return newstr;
  560. }
  561. /********************** end of arena functions ***********************/
  562. /****************** unicode conversion functions ***********************/
  563. /*
  564. * NOTE: These conversion functions all assume that the multibyte
  565. * characters are going to be in NETWORK BYTE ORDER, not host byte
  566. * order. This is because the only time we deal with UCS-2 and UCS-4
  567. * are when the data was received from or is going to be sent out
  568. * over the wire (in, e.g. certificates).
  569. */
  570. void
  571. PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
  572. {
  573. ucs4Utf8ConvertFunc = convFunc;
  574. }
  575. void
  576. PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
  577. {
  578. ucs2AsciiConvertFunc = convFunc;
  579. }
  580. void
  581. PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
  582. {
  583. ucs2Utf8ConvertFunc = convFunc;
  584. }
  585. PRBool
  586. PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
  587. unsigned int inBufLen, unsigned char *outBuf,
  588. unsigned int maxOutBufLen, unsigned int *outBufLen)
  589. {
  590. if (!ucs4Utf8ConvertFunc) {
  591. return sec_port_ucs4_utf8_conversion_function(toUnicode,
  592. inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
  593. }
  594. return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
  595. maxOutBufLen, outBufLen);
  596. }
  597. PRBool
  598. PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
  599. unsigned int inBufLen, unsigned char *outBuf,
  600. unsigned int maxOutBufLen, unsigned int *outBufLen)
  601. {
  602. if (!ucs2Utf8ConvertFunc) {
  603. return sec_port_ucs2_utf8_conversion_function(toUnicode,
  604. inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
  605. }
  606. return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
  607. maxOutBufLen, outBufLen);
  608. }
  609. PRBool
  610. PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
  611. unsigned int inBufLen, unsigned char *outBuf,
  612. unsigned int maxOutBufLen, unsigned int *outBufLen)
  613. {
  614. return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen,
  615. outBuf, maxOutBufLen, outBufLen);
  616. }
  617. PRBool
  618. PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
  619. unsigned int inBufLen, unsigned char *outBuf,
  620. unsigned int maxOutBufLen, unsigned int *outBufLen,
  621. PRBool swapBytes)
  622. {
  623. if (!ucs2AsciiConvertFunc) {
  624. return PR_FALSE;
  625. }
  626. return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
  627. maxOutBufLen, outBufLen, swapBytes);
  628. }
  629. /* Portable putenv. Creates/replaces an environment variable of the form
  630. * envVarName=envValue
  631. */
  632. int
  633. NSS_PutEnv(const char *envVarName, const char *envValue)
  634. {
  635. SECStatus result = SECSuccess;
  636. char *encoded;
  637. int putEnvFailed;
  638. #ifdef _WIN32
  639. PRBool setOK;
  640. setOK = SetEnvironmentVariable(envVarName, envValue);
  641. if (!setOK) {
  642. SET_ERROR_CODE
  643. return SECFailure;
  644. }
  645. #endif
  646. encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue));
  647. if (!encoded) {
  648. return SECFailure;
  649. }
  650. strcpy(encoded, envVarName);
  651. strcat(encoded, "=");
  652. strcat(encoded, envValue);
  653. putEnvFailed = putenv(encoded); /* adopt. */
  654. if (putEnvFailed) {
  655. SET_ERROR_CODE
  656. result = SECFailure;
  657. PORT_Free(encoded);
  658. }
  659. return result;
  660. }
  661. /*
  662. * Perform a constant-time compare of two memory regions. The return value is
  663. * 0 if the memory regions are equal and non-zero otherwise.
  664. */
  665. int
  666. NSS_SecureMemcmp(const void *ia, const void *ib, size_t n)
  667. {
  668. const unsigned char *a = (const unsigned char *)ia;
  669. const unsigned char *b = (const unsigned char *)ib;
  670. size_t i;
  671. unsigned char r = 0;
  672. for (i = 0; i < n; ++i) {
  673. r |= *a++ ^ *b++;
  674. }
  675. return r;
  676. }
  677. /*
  678. * Perform a constant-time check if a memory region is all 0. The return value
  679. * is 0 if the memory region is all zero.
  680. */
  681. unsigned int
  682. NSS_SecureMemcmpZero(const void *mem, size_t n)
  683. {
  684. PRUint8 zero = 0;
  685. size_t i;
  686. for (i = 0; i < n; ++i) {
  687. zero |= *(PRUint8 *)((uintptr_t)mem + i);
  688. }
  689. return zero;
  690. }