- int lastpos, i;
- X509_EXTENSION *ex, *found_ex = NULL;
- if(!x) {
- if(idx) *idx = -1;
- if(crit) *crit = -1;
- return NULL;
- }
- if(idx) lastpos = *idx + 1;
- else lastpos = 0;
- if(lastpos < 0) lastpos = 0;
- for(i = lastpos; i < sk_X509_EXTENSION_num(x); i++)
- {
- ex = sk_X509_EXTENSION_value(x, i);
- if(OBJ_obj2nid(ex->object) == nid) {
- if(idx) {
- *idx = i;
- break;
- } else if(found_ex) {
- /* Found more than one */
- if(crit) *crit = -2;
- return NULL;
- }
- found_ex = ex;
- }
- }
- if(found_ex) {
- /* Found it */
- if(crit) *crit = found_ex->critical;
- return X509V3_EXT_d2i(found_ex);
- }
-
- /* Extension not found */
- if(idx) *idx = -1;
- if(crit) *crit = -1;
- return NULL;
+ int extidx = -1;
+ int errcode;
+ X509_EXTENSION *ext, *extmp;
+ unsigned long ext_op = flags & X509V3_ADD_OP_MASK;
+
+ /*
+ * If appending we don't care if it exists, otherwise look for existing
+ * extension.
+ */
+ if (ext_op != X509V3_ADD_APPEND)
+ extidx = X509v3_get_ext_by_NID(*x, nid, -1);
+
+ /* See if extension exists */
+ if (extidx >= 0) {
+ /* If keep existing, nothing to do */
+ if (ext_op == X509V3_ADD_KEEP_EXISTING)
+ return 1;
+ /* If default then its an error */
+ if (ext_op == X509V3_ADD_DEFAULT) {
+ errcode = X509V3_R_EXTENSION_EXISTS;
+ goto err;
+ }
+ /* If delete, just delete it */
+ if (ext_op == X509V3_ADD_DELETE) {
+ if (!sk_X509_EXTENSION_delete(*x, extidx))
+ return -1;
+ return 1;
+ }
+ } else {
+ /*
+ * If replace existing or delete, error since extension must exist
+ */
+ if ((ext_op == X509V3_ADD_REPLACE_EXISTING) ||
+ (ext_op == X509V3_ADD_DELETE)) {
+ errcode = X509V3_R_EXTENSION_NOT_FOUND;
+ goto err;
+ }
+ }
+
+ /*
+ * If we get this far then we have to create an extension: could have
+ * some flags for alternative encoding schemes...
+ */
+
+ ext = X509V3_EXT_i2d(nid, crit, value);
+
+ if (!ext) {
+ X509V3err(X509V3_F_X509V3_ADD1_I2D,
+ X509V3_R_ERROR_CREATING_EXTENSION);
+ return 0;
+ }
+
+ /* If extension exists replace it.. */
+ if (extidx >= 0) {
+ extmp = sk_X509_EXTENSION_value(*x, extidx);
+ X509_EXTENSION_free(extmp);
+ if (!sk_X509_EXTENSION_set(*x, extidx, ext))
+ return -1;
+ return 1;
+ }
+
+ if (*x == NULL
+ && (*x = sk_X509_EXTENSION_new_null()) == NULL)
+ return -1;
+ if (!sk_X509_EXTENSION_push(*x, ext))
+ return -1;
+
+ return 1;
+
+ err:
+ if (!(flags & X509V3_ADD_SILENT))
+ X509V3err(X509V3_F_X509V3_ADD1_I2D, errcode);
+ return 0;