+DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn);
+DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln);
+DECLARE_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, obj);
+
+#define ADDED_DATA 0
+#define ADDED_SNAME 1
+#define ADDED_LNAME 2
+#define ADDED_NID 3
+
+struct added_obj_st {
+ int type;
+ ASN1_OBJECT *obj;
+};
+
+static int new_nid = NUM_NID;
+static LHASH_OF(ADDED_OBJ) *added = NULL;
+
+static int sn_cmp(const ASN1_OBJECT *const *a, const unsigned int *b)
+{
+ return strcmp((*a)->sn, nid_objs[*b].sn);
+}
+
+IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, sn);
+
+static int ln_cmp(const ASN1_OBJECT *const *a, const unsigned int *b)
+{
+ return strcmp((*a)->ln, nid_objs[*b].ln);
+}
+
+IMPLEMENT_OBJ_BSEARCH_CMP_FN(const ASN1_OBJECT *, unsigned int, ln);
+
+static unsigned long added_obj_hash(const ADDED_OBJ *ca)
+{
+ const ASN1_OBJECT *a;
+ int i;
+ unsigned long ret = 0;
+ unsigned char *p;
+
+ a = ca->obj;
+ switch (ca->type) {
+ case ADDED_DATA:
+ ret = a->length << 20L;
+ p = (unsigned char *)a->data;
+ for (i = 0; i < a->length; i++)
+ ret ^= p[i] << ((i * 3) % 24);
+ break;
+ case ADDED_SNAME:
+ ret = OPENSSL_LH_strhash(a->sn);
+ break;
+ case ADDED_LNAME:
+ ret = OPENSSL_LH_strhash(a->ln);
+ break;
+ case ADDED_NID:
+ ret = a->nid;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ ret &= 0x3fffffffL;
+ ret |= ((unsigned long)ca->type) << 30L;
+ return ret;
+}
+
+static int added_obj_cmp(const ADDED_OBJ *ca, const ADDED_OBJ *cb)
+{
+ ASN1_OBJECT *a, *b;
+ int i;
+
+ i = ca->type - cb->type;
+ if (i)
+ return i;
+ a = ca->obj;
+ b = cb->obj;
+ switch (ca->type) {
+ case ADDED_DATA:
+ i = (a->length - b->length);
+ if (i)
+ return i;
+ return memcmp(a->data, b->data, (size_t)a->length);
+ case ADDED_SNAME:
+ if (a->sn == NULL)
+ return -1;
+ else if (b->sn == NULL)
+ return 1;
+ else
+ return strcmp(a->sn, b->sn);
+ case ADDED_LNAME:
+ if (a->ln == NULL)
+ return -1;
+ else if (b->ln == NULL)
+ return 1;
+ else
+ return strcmp(a->ln, b->ln);
+ case ADDED_NID:
+ return a->nid - b->nid;
+ default:
+ /* abort(); */
+ return 0;
+ }
+}
+
+static int init_added(void)
+{
+ if (added != NULL)
+ return 1;
+ added = lh_ADDED_OBJ_new(added_obj_hash, added_obj_cmp);
+ return added != NULL;
+}
+
+static void cleanup1_doall(ADDED_OBJ *a)
+{
+ a->obj->nid = 0;
+ a->obj->flags |= ASN1_OBJECT_FLAG_DYNAMIC |
+ ASN1_OBJECT_FLAG_DYNAMIC_STRINGS | ASN1_OBJECT_FLAG_DYNAMIC_DATA;
+}
+
+static void cleanup2_doall(ADDED_OBJ *a)
+{
+ a->obj->nid++;
+}
+
+static void cleanup3_doall(ADDED_OBJ *a)
+{
+ if (--a->obj->nid == 0)
+ ASN1_OBJECT_free(a->obj);
+ OPENSSL_free(a);
+}
+
+void ossl_obj_cleanup_int(void)
+{
+ if (added == NULL)
+ return;
+ lh_ADDED_OBJ_set_down_load(added, 0);
+ lh_ADDED_OBJ_doall(added, cleanup1_doall); /* zero counters */
+ lh_ADDED_OBJ_doall(added, cleanup2_doall); /* set counters */
+ lh_ADDED_OBJ_doall(added, cleanup3_doall); /* free objects */
+ lh_ADDED_OBJ_free(added);
+ added = NULL;
+}
+
+int OBJ_new_nid(int num)
+{
+ int i;
+
+ i = new_nid;
+ new_nid += num;
+ return i;
+}
+
+int OBJ_add_object(const ASN1_OBJECT *obj)
+{
+ ASN1_OBJECT *o;
+ ADDED_OBJ *ao[4] = { NULL, NULL, NULL, NULL }, *aop;
+ int i;
+
+ if (added == NULL)
+ if (!init_added())
+ return 0;
+ if ((o = OBJ_dup(obj)) == NULL)
+ goto err;
+ if ((ao[ADDED_NID] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
+ goto err2;
+ if ((o->length != 0) && (obj->data != NULL))
+ if ((ao[ADDED_DATA] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
+ goto err2;
+ if (o->sn != NULL)
+ if ((ao[ADDED_SNAME] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
+ goto err2;
+ if (o->ln != NULL)
+ if ((ao[ADDED_LNAME] = OPENSSL_malloc(sizeof(*ao[0]))) == NULL)
+ goto err2;
+
+ for (i = ADDED_DATA; i <= ADDED_NID; i++) {
+ if (ao[i] != NULL) {
+ ao[i]->type = i;
+ ao[i]->obj = o;
+ aop = lh_ADDED_OBJ_insert(added, ao[i]);
+ /* memory leak, but should not normally matter */
+ OPENSSL_free(aop);
+ }
+ }
+ o->flags &=
+ ~(ASN1_OBJECT_FLAG_DYNAMIC | ASN1_OBJECT_FLAG_DYNAMIC_STRINGS |
+ ASN1_OBJECT_FLAG_DYNAMIC_DATA);
+
+ return o->nid;
+ err2:
+ ERR_raise(ERR_LIB_OBJ, ERR_R_MALLOC_FAILURE);
+ err:
+ for (i = ADDED_DATA; i <= ADDED_NID; i++)
+ OPENSSL_free(ao[i]);
+ ASN1_OBJECT_free(o);
+ return NID_undef;
+}
+
+ASN1_OBJECT *OBJ_nid2obj(int n)
+{
+ ADDED_OBJ ad, *adp;
+ ASN1_OBJECT ob;
+
+ if ((n >= 0) && (n < NUM_NID)) {
+ if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) {
+ ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID);
+ return NULL;
+ }
+ return (ASN1_OBJECT *)&(nid_objs[n]);
+ }
+
+ /* Make sure we've loaded config before checking for any "added" objects */
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+
+ if (added == NULL)
+ return NULL;
+
+ ad.type = ADDED_NID;
+ ad.obj = &ob;
+ ob.nid = n;
+ adp = lh_ADDED_OBJ_retrieve(added, &ad);
+ if (adp != NULL)
+ return adp->obj;
+
+ ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID);
+ return NULL;
+}
+
+const char *OBJ_nid2sn(int n)
+{
+ ADDED_OBJ ad, *adp;
+ ASN1_OBJECT ob;
+
+ if ((n >= 0) && (n < NUM_NID)) {
+ if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) {
+ ERR_raise(ERR_LIB_OBJ, OBJ_R_UNKNOWN_NID);
+ return NULL;
+ }
+ return nid_objs[n].sn;
+ }
+
+ /* Make sure we've loaded config before checking for any "added" objects */
+ OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, NULL);
+
+ if (added == NULL)
+ return NULL;
+
+ ad.type = ADDED_NID;
+ ad.obj = &ob;
+ ob.nid = n;
+ adp = lh_ADDED_OBJ_retrieve(added, &ad);
+ if (adp != NULL)
+ return adp->obj->sn;