ASRANGE_NEW(3)

πŸ“¦ version 4.4.0, in alpine 3.24, arch rolling

πŸŽ€ ASRANGE_NEW(3) πŸŽ€

okay so bestie, we're in the Library Functions Manual today and the vibe is very specific: this is the whole RFC 3779 autonomous-system-identifier family β€” ASRange, ASIdOrRange, and ASIdentifierChoice β€” plus all their _new, _free, d2i_ and i2d_ besties. RFC 3779 autonomous system identifiers and ranges. Buckle up, it's giving ✨X.509 extension lore✨.


🌸 SYNOPSIS 🌸

library β€œlibcrypto” #include <openssl/x509v3.h>

ASRange *
ASRange_new(void);

void
ASRange_free(ASRange *asrange);

ASRange *
d2i_ASRange(ASRange **asrange, const unsigned char **der_in,
    long length);

int
i2d_ASRange(ASRange *asrange, unsigned char **der_out);

ASIdOrRange *
ASIdOrRange_new(void);

void
ASIdOrRange_free(ASIdOrRange *aor);

ASIdOrRange *
d2i_ASIdOrRange(ASIdOrRange **aor, const unsigned char **der_in,
    long length);

int
i2d_ASIdOrRange(ASIdOrRange *aor, unsigned char **der_out);

ASIdentifierChoice *
ASIdentifierChoice_new(void);

void
ASIdentifierChoice_free(ASIdentifierChoice *aic);

ASIdentifierChoice *
d2i_ASIdentifierChoice(ASIdentifierChoice **aic,
    const unsigned char **der_in, long length);

int
i2d_ASIdentifierChoice(ASIdentifierChoice *aic,
    unsigned char **der_out);

πŸ’œ DESCRIPTION πŸ’œ

So ASRange, ASIdOrRange, and ASIdentifierChoice are literally the building blocks of the ASIdentifiers type β€” the thing that represents the RFC 3779 autonomous system identifier delegation extension. The holy trinity of AS delegation, if you will πŸ‘‘

⚠️ real talk first: all ASN1_INTEGERs in this manual must be representable as unsigned 32-bit integers. And does the API check that for you? No ma'am, it does not. The API performs no corresponding checks. You can set one with ASN1_INTEGER_set_uint64(3).

πŸ¦‹ the ASRange type

ASRange, defined in RFC 3779 section 3.2.3.8, is implemented like this:

typedef struct ASRange_st {
        ASN1_INTEGER *min;
        ASN1_INTEGER *max;
} ASRange;

It represents the closed range [min,max] of AS identifiers between min and max, where min should be strictly smaller than max. yes, strictly. we do not do equal here πŸ’€

  • ASRange_new() β€” allocates a brand new ASRange object with allocated, empty min and max, which means it represents the invalid range [0,0]. iconic but useless energy.
  • ASRange_free() β€” frees asrange including any data contained in it. If asrange is NULL, no action occurs. safe, chill, no notes 🫢

🧚 the ASIdOrRange type

ASIdOrRange, defined in RFC 3779 section 3.2.3.5, is implemented as:

typedef struct ASIdOrRange_st {
        int type;
        union {
                ASN1_INTEGER *id;
                ASRange *range;
        } u;
} ASIdOrRange;

It represents either an individual AS identifier or a range. When you're populating an ASIdOrRange object by hand, set its type to ASIdOrRange_id or ASIdOrRange_range to indicate which member of the union u is the valid one. pick a lane bestie ✨

  • ASIdOrRange_new() β€” returns a new ASIdOrRange object with an invalid type and NULL members of the union u.
  • ASIdOrRange_free() β€” frees aor including any data contained in it, provided type is set correctly. If asrange is NULL, no action occurs. (and like… yes, the page really does say asrange here even though the parameter is aor β€” not me pointing it out, that's just what it says πŸ™ˆ)

πŸ’… the ASIdOrRanges stack

To express a list of AS identifiers and ranges, RFC 3779 section 3.2.3.4 uses an ASN.1 SEQUENCE, which is implemented via a STACK_OF(3) construction over ASIdOrRange:

typedef STACK_OF(ASIdOrRange) ASIdOrRanges;

Now, an ASIdOrRanges object should be sorted in a specific way (peep X509v3_asid_canonize(3)), so you need a comparison function for a correct instantiation with sk_new(3). And here's the tea: ASIdOrRange_cmp() is not directly exposed and not easily accessible from outside the library, and it's non-trivial to implement. So it is therefore discouraged to use ASIdOrRanges objects that are not part of an ASIdentifiers object. don't do it, it's not worth it, I'm begging 😭

🌈 the β€œinherit” marker

The β€œinherit” marker from RFC 3779 section 3.2.3.3 is implemented as ASN1_NULL. It has no dedicated type or API β€” you can instantiate it with ASN1_NULL_new(3). shy icon behavior, honestly.

🌸 the ASIdentifierChoice type

ASIdentifierChoice, defined in RFC 3779 section 3.2.3.2, is implemented as:

typedef struct ASIdentifierChoice_st {
        int type;
        union {
                ASN1_NULL *inherit;
                ASIdOrRanges *asIdsOrRanges;
        } u;
} ASIdentifierChoice;

The type member should be set to ASIdentifierChoice_inherit or ASIdentifierChoice_asIdsOrRanges, so everyone knows whether that ASIdentifierChoice object is representing an inherited list or an explicit list. choose your fighter πŸŽ€

  • ASIdentifierChoice_new() β€” returns a new ASIdentifierChoice object with invalid type and NULL members of the union u.
  • ASIdentifierChoice_free() β€” frees aic including any data contained in it, provided type is set correctly.

πŸ‘‘ the ASIdentifiers type

And the big boss, ASIdentifiers, defined in RFC 3779 section 3.2.3.1:

typedef struct ASIdentifiers_st {
        ASIdentifierChoice *asnum;
        ASIdentifierChoice *rdi;
} ASIdentifiers;

It should be instantiated with ASIdentifiers_new(3) and populated with X509v3_asid_add_id_or_range(3). that's the whole workflow, slay πŸ’–

πŸ”₯ the d2i / i2d crew

d2i_ASRange(), i2d_ASRange(), d2i_ASIdOrRange(), i2d_ASIdOrRange(), d2i_ASIdentifierChoice(), and i2d_ASIdentifierChoice() decode and encode ASN.1 ASRange, ASIdOrRange, and ASIdentifierChoice objects. For all the details about the semantics, examples, caveats, and bugs, see ASN1_item_d2i(3) β€” go read it, iykyk πŸ“š

⚠️ for the encoding produced by i2d_ASRange() to be correct, min must be strictly less than max. Same energy for i2d_ASIdOrRange() and an ASIdOrRange object of type ASIdOrRange_range. no pressure but also all of the pressure πŸ’€

✨ RETURN VALUES ✨

  • ASRange_new() β€” returns a new ASRange object with allocated, empty members, or NULL if an error occurs.
  • ASIdOrRange_new() β€” returns a new, empty ASIdOrRange object or NULL if an error occurs.
  • ASIdentifierChoice_new() β€” returns a new, empty ASIdentifierChoice object or NULL if an error occurs.
  • the decoding girlies β€” d2i_ASRange(), d2i_ASIdOrRange(), and d2i_ASIdentifierChoice() return an ASRange, an ASIdOrRange, or an ASIdentifierChoice object, respectively, or NULL if an error occurs.
  • the encoding girlies β€” i2d_ASRange(), i2d_ASIdOrRange(), and i2d_ASIdentifierChoice() return the number of bytes successfully encoded, or a value <= 0 if an error occurs.

πŸ¦‹ SEE ALSO πŸ¦‹

ASIdentifiers_new(3), ASN1_INTEGER_set_uint64(3), crypto(3), IPAddressRange_new(3), s2i_ASN1_INTEGER(3), STACK_OF(3), X509_new(3), X509v3_asid_add_id_or_range(3)


πŸ“œ STANDARDS πŸ“œ

RFC 3779: X.509 Extensions for IP Addresses and AS Identifiers β€” read it, it's right there:

  • section 3.2.3: Syntax
  • section 3.2.3.1: Type ASIdentifiers
  • section 3.2.3.2: Elements asnum, rdi, and Type ASIdentifierChoice
  • section 3.2.3.3: Element inherit
  • section 3.2.3.4: Element asIdsOrRanges
  • section 3.2.3.5: Type ASIdOrRange
  • section 3.2.3.6: Element id
  • section 3.2.3.7: Element range
  • section 3.2.3.8: Type ASRange
  • section 3.2.3.9: Elements min and max

πŸ•°οΈ HISTORY πŸ•°οΈ

These functions first appeared in OpenSSL 0.9.8e and have been available since OpenBSD 7.1. vintage. retro. old money πŸ’…


πŸ’€ BUGS πŸ’€

okay, the complaints section, gather round:

  • An ASIdOrRanges_new() function that installs the correct comparison function on the stack of ASIdOrRange should have been part of the API to make it usable. should have. didn't. we move 🫠
  • ASIdentifierChoice_new() is of very limited use because ASIdOrRanges_new() is missing. it's giving "here's a key but no door".
  • There is no way of ensuring that an ASIdOrRanges object is in canonical form unless it's part of an ASIdentifiers object. So it is therefore difficult to guarantee that the output of i2d_ASIdentifierChoice() is conformant. yikes, fr fr 😭
  • RFC 3779 3.2.3.4 has β€œasIdsOrRanges” while its type in this implementation is ASIdOrRanges. a little spelling divergence, a little chaos, we live.

and that's the page, bestie πŸ’– this one's from the Debian build, dated June 13, 2025, filed under ASRANGE_NEW(3) β€” go forth and delegate those autonomous system identifiers responsibly, mwah πŸŽ€βœ¨

πŸ“¦ where this page comes from