Wednesday, April 15, 2009

RHEL 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 Installation 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) << mask =" mask" _d =" (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]
Read More..