LinuxCzar

Engineering Software, Linux, and Observability. The website of Jack Neely.    

RHEL Installation Numbers

  May 28, 2008

Looking for Free RHEL?

Then go elsewhere.  In fact please consider using CentOS.  CentOS is a completely free rebuild of RHEL and is almost identical to RHEL in every way save the removal of the Red Hat logos, graphics, and Installation Numbers.

Note that RHEL 6 does not require the use of Installation Numbers.

Red Hat’s Installation Numbers

Red Hat Enterprise Linux 5 introduces “Installation Numbers.”  Its basically an activation code that you receive from Red Hat’s web site when you buy RHEL and configures the installer to install the bits you bought.  Its also sent to RHN when you register to subscribe your machine to the proper sub channels so that you get errata for the bits you bought.

This is Open Source.  Anaconda, the installer is GPL’d and needs to be able to parse these codes.  Tools on the system also need to be able to parse these codes when they communicate with RHN.  So there’s no hiding of the magic behind these installation numbers.  In fact you can find this very easily on a RHEL 5 machine.

$ head /usr/lib/python2.4/site-packages/instnum.py
#!/usr/bin/python    

# instnum.py - parse and decode RHEL Installation Numbers
# Copyright (c) 2006 Red Hat, Inc.
# Authors: Dave Lehman
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

The full source: instnum.py

Its even covered under the GPL.  I’ve included a link to the complete file for your reading pleasure.  It contains detailed documentation for how these codes work.  To quote:

        16 hex digits:
         KK KK KK CC OO OS VT PP
         |        |   |    || |- Product defining the format.
         |        |   |    ||- Virt limit code used to look up the limit
         |        |   |    |   in a dictionary. The least bit actually is
         |        |   |    |   used for the Type field.
         |        |   |    |- Socket (phys. CPUs) limit code used to look
         |        |   |       up the limit in the list of all possible limits.
         |        |   |- Option code to look up the combination of
         |        |      options in a dictionary.
         |        |- Checksum - Keyed hash Key and the other fields.
         |-  Key generated with Peter's algorithm

        On a bit level it looks like this:
      60   56   52   48   44   40   36   32   28   24   20   16   12    8    4    0
    0    4    8    12   16   20   24   28   32   36   40   44   48   52   56   60
    KKKK KKKK KKKK KKKK KKKK KKKK CCCC CCCC OOOO OOOO OOOO OOSS SSVV VTTP PPPP PPPP

        Bits:
        Key part:
        [40 - 63]   - K
                    - Key generated with the old HACK algorithm. Source of entropy
                      and used to 'encrypt' parts of the payload.
        Checksum:
        [32 - 39]   - C
                    - Checksum - first two hex digits of the keyed sha1 hash of the
                      payload with the key.
        Payload:
        [18 - 31]   - O
                    - Options - Index of the actual option combination in the list
                      of all possible combinations for the product. Xored with the
                      highest 14 bits of the key.
        [14 - 17]   - S
                    - Socket (physical CPU) limit. Encoded as the index of the
                      limit in the list of all possible socket limits. Xored with
                      the next highest 4 bit of the key.
        [11 - 13]   - V
                    - Virt Limit - Limit of the number of virtual instances allowed.
                      Encoded as the index of the limit in the list of all possible
                      virtualization limits. Xored with the next highest 3 bits of
                      the key.
        [9 - 10]    - T
                    - EN type - 0 => does not create Entitlement,
                                1 => creates Entitlement,
                                2 => installeronly.
                      Not Xored.
        [0 - 8]     - P
                    - Product code - 0 for Server and 1 for Client. Defines the
                      format. Xored with the lowest 9 bits of the key.

See the file for even more gory details about how these codes work.

Generating Installtion Numbers

I’ve written some of my own code to help generate Installation Numbers:

#!python
# genkey.py - Generate fake RHEL 5 installation numbers
# Copyright (c) 2007 Jack Neely
# Authors: Jack Neely
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

import hmac
import sha

# 24 bits
key = 0x0

# The following class taken from ASPN:
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/113799

class BitField(object):

    def __init__(self,value=0):
        self._d = value

    def __getitem__(self, index):
        return (self._d >> index) & 1

    def __setitem__(self,index,value):
        value    = (value&1L)<> start) & mask

    def __setslice__(self, start, end, value):
        mask = 2L**(end - start) -1
        value = (value & mask) << start
        mask = mask << start
        self._d = (self._d & ~mask) | value
        return (self._d >> start) & mask

    def __int__(self):
        return self._d

def checksum(regkey):

    keystr = "%06x" % regkey[40:64]
    payloadstr = "%08x" % regkey[0:32]

    hash = hmac.new(keystr, payloadstr, sha)
    sum = hash.hexdigest()[:2]

    return int(sum, 16)

def generateKey(key, options, sockets, virtlimit, type, product):
    """Create an installation number based from the given codes.
       All parameters are int."""

    # Okay we are using python slices here so 0:3 represents bits 0, 1, and 2
    # and does not include/modify bit 3

    regkey = BitField()

    # Make the payload
    regkey[18:32] = options
    regkey[14:18] = sockets
    regkey[11:14] = virtlimit
    regkey[9:11]  = type
    regkey[0:9]   = product

    # Tack on the key
    regkey[40:64] = key

    # calculate checksum
    regkey[32:40] = checksum(regkey)

    return "%016x" % int(regkey)

def main():
    print "a client key"
    print generateKey(key, 0x5, 0xf, 0xf, 0x2, 0x1)
    print
    print "a server key"
    print generateKey(key, 0x1, 0xf, 0xf, 0x2, 0x0)
    print
    print "A server key with Cluster"
    print generateKey(key, 0x2, 0xf, 0xf, 0x2, 0x0)
    print
    print "A server key with ClusterStorage"
    print generateKey(key, 0x3, 0xf, 0xf, 0x2, 0x0)
    print
    print "server with HPC"
    print generateKey(key, 0x4, 0xf, 0xf, 0x2, 0x0)
    print
    print "server with Directory"
    print generateKey(key, 0x5, 0xf, 0xf, 0x2, 0x0)
    print
    print "server with SMB"
    print generateKey(key, 0x6, 0xf, 0xf, 0x2, 0x0)

if __name__ == "__main__":
    main()

Download: genkey.py

Once you know where to place the bits and generate the checksum its pretty easy. This generates the following table of keys. Each key below has unlimited CPU sockets and unlimited VM guests.

------------------------------- ---------------------
Client                          0000000e0017fc01
Red Hat Global Desktop          000000990007fc02
Server                          000000e90007fc00
Server with Cluster             00000065000bfc00
Server with ClusterStorage      000000ab000ffc00
Server with HPC                 000000e30013fc00
Server with Directory           000000890017fc00
Server with SMB                 00000052001bfc00
------------------------------- ---------------------

These codes are purposely generated with the key field equal to 0. They are perfectly valid but anyone in the “know” should be able to realize these are not installtion numbers from Red Hat. Creating codes with other key values (used to more obscure the fields and generate many different codes that unlock the same features) or creating a handy web app that I would post here is left as an exercise for the reader.

The codes don’t really contain much information. Instead they contain a series of indexes into tables containing feature combinations, socket limits, etc. Those tables are all in the above instnum.py file. For socket limits and VM limits a value of -1 represents an unlimited value. What’s the 2’s complment of 1? 0xFF. The type and product fields are not indexes. Values for the type field represent if the code can create an RHN entitlement and the product field is simply 2 for RHGD, 1 for Client, or 0 for Server. That’s how I create the hex values used in the generateKey() function.

Looking at Your Installation Numbers

Finally any key you create or have been given by Red Hat can be examined by the code in instnum.py. This gives you all the gory details about what the key activates. For example, I’ll run it on my first Client key.

$ python instnum.py 0000000e0017fc01
Product: RHEL Client
Type: Installer Only
Options: NoSLA FullProd Virt Workstation
Allowed CPU Sockets: Unlimited
Allowed Virtual Instances: Unlimited
Package Repositories: Client VT Workstation

key: 0 '000000'
checksum: 14 '0e'
options: 4865 'NoSLA FullProd Virt Workstation'
socklimit: -1 'Unlimited'
virtlimit: -1 'Unlimited'
type: 2 'Installer Only'
product: 1 'client'

{'Virt': 'VT', 'Workstation': 'Workstation', 'Base': 'Client'}

0000-000e-0017-fc01

From a normal RHEL 5 install you can also call this script like so:

$ python /usr/lib/python2.4/site-packages/instnum.py [Installation Number]