OBJECT IDENTIFIER and RELATIVE-OID OER encoding and randomized testing
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index 039a973..86fee46 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -27,8 +27,8 @@
 	0,
 	0,
 #else
-	0,
-	0,
+	OBJECT_IDENTIFIER_decode_oer,
+	OBJECT_IDENTIFIER_encode_oer,
 #endif  /* ASN_DISABLE_OER_SUPPORT */
 #ifdef	ASN_DISABLE_PER_SUPPORT
 	0,
@@ -784,17 +784,23 @@
  * value up to the upper limit.
  */
 static uint32_t
-OBJECT_IDENTIFIER__biased_random_arc(int32_t upper_bound) {
+OBJECT_IDENTIFIER__biased_random_arc(uint32_t upper_bound) {
     static const uint16_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
+    size_t idx;
 
-    size_t idx = asn_random_between(0, 2 * sizeof(values)/sizeof(values[0]));
-    if(idx < sizeof(values) / sizeof(values[0])) {
+    switch(asn_random_between(0, 2)) {
+    case 0:
+        idx = asn_random_between(0, sizeof(values) / sizeof(values[0]) - 1);
         if(values[idx] < upper_bound) {
             return values[idx];
         }
+        /* Fall through */
+    case 1:
+        return asn_random_between(0, upper_bound);
+    case 2:
+    default:
+        return upper_bound;
     }
-
-    return asn_random_between(0, upper_bound);
 }
 
 asn_random_fill_result_t
@@ -821,9 +827,9 @@
 
     arcs[0] = asn_random_between(0, 2);
     arcs[1] =
-        OBJECT_IDENTIFIER__biased_random_arc(arcs[0] <= 1 ? 39 : INT32_MAX);
+        OBJECT_IDENTIFIER__biased_random_arc(arcs[0] <= 1 ? 39 : UINT_MAX);
     for(i = 2; i < arcs_len; i++) {
-        arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(INT32_MAX);
+        arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(UINT_MAX);
     }
 
     if(OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(arcs[0]), arcs_len)) {
diff --git a/skeletons/OBJECT_IDENTIFIER.h b/skeletons/OBJECT_IDENTIFIER.h
index 02dde9c..d160e43 100644
--- a/skeletons/OBJECT_IDENTIFIER.h
+++ b/skeletons/OBJECT_IDENTIFIER.h
@@ -30,6 +30,8 @@
 #define OBJECT_IDENTIFIER_compare        OCTET_STRING_compare
 #define OBJECT_IDENTIFIER_decode_ber     ber_decode_primitive
 #define OBJECT_IDENTIFIER_encode_der     der_encode_primitive
+#define OBJECT_IDENTIFIER_decode_oer     oer_decode_primitive
+#define OBJECT_IDENTIFIER_encode_oer     oer_encode_primitive
 #define OBJECT_IDENTIFIER_decode_uper    OCTET_STRING_decode_uper
 #define OBJECT_IDENTIFIER_encode_uper    OCTET_STRING_encode_uper
 
diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c
index 6edecfa..33bfd4a 100644
--- a/skeletons/RELATIVE-OID.c
+++ b/skeletons/RELATIVE-OID.c
@@ -28,8 +28,8 @@
 	0,
 	0,
 #else
-	0,
-	0,
+	RELATIVE_OID_decode_oer,
+	RELATIVE_OID_encode_oer,
 #endif  /* ASN_DISABLE_OER_SUPPORT */
 #ifdef	ASN_DISABLE_PER_SUPPORT
 	0,
@@ -262,12 +262,16 @@
 RELATIVE_OID__biased_random_arc() {
     static const uint16_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
 
-    size_t idx = asn_random_between(0, 2 * sizeof(values)/sizeof(values[0]));
-    if(idx < sizeof(values) / sizeof(values[0])) {
-        return values[idx];
+    switch(asn_random_between(0, 2)) {
+    case 0:
+        return values[asn_random_between(
+            0, sizeof(values) / sizeof(values[0]) - 1)];
+    case 1:
+        return asn_random_between(0, UINT_MAX);
+    case 2:
+    default:
+        return UINT_MAX;
     }
-
-    return asn_random_between(0, INT32_MAX);
 }
 
 asn_random_fill_result_t
@@ -278,8 +282,9 @@
     asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
     asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
     RELATIVE_OID_t *st;
+    const int min_arcs = 1; /* A minimum of 1 arc is required */
+    size_t arcs_len = asn_random_between(min_arcs, 3);
     uint32_t arcs[3];
-    size_t arcs_len = asn_random_between(0, 3);
     size_t i;
 
     (void)constraints;
diff --git a/skeletons/RELATIVE-OID.h b/skeletons/RELATIVE-OID.h
index f24c392..1eaf559 100644
--- a/skeletons/RELATIVE-OID.h
+++ b/skeletons/RELATIVE-OID.h
@@ -27,6 +27,8 @@
 #define RELATIVE_OID_constraint   asn_generic_no_constraint
 #define RELATIVE_OID_decode_ber   ber_decode_primitive
 #define RELATIVE_OID_encode_der   der_encode_primitive
+#define RELATIVE_OID_decode_oer   oer_decode_primitive
+#define RELATIVE_OID_encode_oer   oer_encode_primitive
 #define RELATIVE_OID_decode_uper  OCTET_STRING_decode_uper
 #define RELATIVE_OID_encode_uper  OCTET_STRING_encode_uper
 
diff --git a/skeletons/oer_decoder.c b/skeletons/oer_decoder.c
index e803ad2..386e846 100644
--- a/skeletons/oer_decoder.c
+++ b/skeletons/oer_decoder.c
@@ -3,6 +3,7 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
+#include <asn_codecs_prim.h>
 
 /*
  * The OER decoder of any type.
@@ -91,3 +92,58 @@
     }
 }
 
+
+asn_dec_rval_t
+oer_decode_primitive(const asn_codec_ctx_t *opt_codec_ctx,
+                     asn_TYPE_descriptor_t *td,
+                     const asn_oer_constraints_t *constraints, void **sptr,
+                     const void *ptr, size_t size) {
+    ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr;
+    asn_dec_rval_t rval = {RC_OK, 0};
+    size_t expected_length = 0;
+    ssize_t len_len;
+
+    (void)opt_codec_ctx;
+    (void)constraints;
+
+    if(!st) {
+        st = (ASN__PRIMITIVE_TYPE_t *)(*sptr = CALLOC(
+                                           1, sizeof(ASN__PRIMITIVE_TYPE_t)));
+        if(!st) ASN__DECODE_FAILED;
+    }
+
+
+    /*
+     * X.696 (08/2015) #27.2
+     * Encode length determinant as _number of octets_, but only
+     * if upper bound is not equal to lower bound.
+     */
+    len_len = oer_fetch_length(ptr, size, &expected_length);
+    if(len_len > 0) {
+        rval.consumed = len_len;
+        ptr = (const char *)ptr + len_len;
+        size -= len_len;
+    } else if(len_len == 0) {
+        ASN__DECODE_STARVED;
+    } else if(len_len < 0) {
+        ASN__DECODE_FAILED;
+    }
+
+    if(size < expected_length) {
+        ASN__DECODE_STARVED;
+    } else {
+        uint8_t *buf = MALLOC(expected_length + 1);
+        if(buf == NULL) {
+            ASN__DECODE_FAILED;
+        } else {
+            memcpy(buf, ptr, expected_length);
+            buf[expected_length] = '\0';
+        }
+        FREEMEM(st->buf);
+        st->buf = buf;
+        st->size = expected_length;
+
+        rval.consumed += expected_length;
+        return rval;
+    }
+}
diff --git a/skeletons/oer_decoder.h b/skeletons/oer_decoder.h
index bf4bc08..c5e9744 100644
--- a/skeletons/oer_decoder.h
+++ b/skeletons/oer_decoder.h
@@ -59,6 +59,11 @@
                           const asn_oer_constraints_t *constraints,
                           void **struct_ptr, const void *bufptr, size_t size);
 
+/*
+ * Length-prefixed buffer decoding for primitive types.
+ */
+oer_type_decoder_f oer_decode_primitive;
+
 
 #ifdef __cplusplus
 }
diff --git a/skeletons/oer_encoder.c b/skeletons/oer_encoder.c
index af3c7d1..a6f7a78 100644
--- a/skeletons/oer_encoder.c
+++ b/skeletons/oer_encoder.c
@@ -3,6 +3,7 @@
  * Redistribution and modifications are permitted subject to BSD license.
  */
 #include <asn_internal.h>
+#include <asn_codecs_prim.h>
 
 /*
  * The OER encoder of any type.
@@ -76,3 +77,35 @@
     }
     return ec;
 }
+
+asn_enc_rval_t
+oer_encode_primitive(asn_TYPE_descriptor_t *td,
+                     const asn_oer_constraints_t *constraints, void *sptr,
+                     asn_app_consume_bytes_f *cb, void *app_key) {
+    const ASN__PRIMITIVE_TYPE_t *st = (const ASN__PRIMITIVE_TYPE_t *)sptr;
+    asn_enc_rval_t er = {0, 0, 0};
+    ssize_t ret;
+
+    (void)constraints;
+
+    if(!st) ASN__ENCODE_FAILED;
+
+    ASN_DEBUG("Encoding %s (%zu bytes)", td ? td->name : "", st->size);
+
+    /*
+     * X.696 (08/2015) #27.2
+     */
+    ret = oer_serialize_length(st->size, cb, app_key);
+    if(ret < 0) {
+        ASN__ENCODE_FAILED;
+    }
+    er.encoded += ret;
+
+    er.encoded += st->size;
+    if(cb(st->buf, st->size, app_key) < 0) {
+        ASN__ENCODE_FAILED;
+    } else {
+        ASN__ENCODED_OK(er);
+    }
+}
+
diff --git a/skeletons/oer_encoder.h b/skeletons/oer_encoder.h
index f474a7b..3150b5c 100644
--- a/skeletons/oer_encoder.h
+++ b/skeletons/oer_encoder.h
@@ -46,6 +46,11 @@
     );
 
 
+/*
+ * Length-prefixed buffer encoding for primitive types.
+ */
+oer_type_encoder_f oer_encode_primitive;
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/tests/tests-randomized/Makefile.am b/tests/tests-randomized/Makefile.am
index 1547da0..a02982b 100644
--- a/tests/tests-randomized/Makefile.am
+++ b/tests/tests-randomized/Makefile.am
@@ -31,6 +31,8 @@
 TESTS += bundles/05-BIT-STRING-bundle.txt
 TESTS += bundles/06-OCTET-STRING-bundle.txt
 TESTS += bundles/07-VisibleString-bundle.txt
+TESTS += bundles/08-OBJECT-IDENTIFIER-bundle.txt
+TESTS += bundles/09-RELATIVE-OID-bundle.txt
 
 EXTRA_DIST =                    \
     random-test-driver.c        \